diff -r 129202e555e0 -r e13543d716b6 C_runtime/posix_main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C_runtime/posix_main.cpp Wed Apr 24 02:15:33 2024 +0200 @@ -0,0 +1,413 @@ + +#include +#include +#include + +#include "erpc_basic_codec.hpp" +#include "erpc_serial_transport.hpp" +#include "erpc_tcp_transport.hpp" +#include "erpc_simple_server.hpp" + +#include "erpc_PLCObject_server.hpp" +#include "Logging.hpp" +#include "options.hpp" + +#include "PLCObject.hpp" + +using namespace erpc; +using namespace std; + +class MyMessageBufferFactory : public MessageBufferFactory +{ +public: + virtual MessageBuffer create() + { + uint8_t *buf = new uint8_t[1024]; + return MessageBuffer(buf, 1024); + } + + virtual void dispose(MessageBuffer *buf) + { + erpc_assert(buf); + if (*buf) + { + delete[] buf->get(); + } + } +}; + + +namespace beremizRuntime { + +/*! The tool's name. */ +const char k_toolName[] = "beremizRuntime"; + +/*! Current version number for the tool. */ +const char k_version[] = __STRING(BEREMIZ_VERSION); + +/*! Copyright string. */ +const char k_copyright[] = "Copyright 2024 Beremiz SAS. All rights reserved."; + +static const char *k_optionsDefinition[] = { "?|help", + "V|version", + "v|verbose", + "t:transport ", + "b:baudrate ", + "p:port ", + "h:host ", + NULL }; + +/*! Help string. */ +const char k_usageText[] = + "\nOptions:\n\ + -?/--help Show this help\n\ + -V/--version Display tool version\n\ + -v/--verbose Print extra detailed log information\n\ + -t/--transport Type of transport.\n\ + -b/--baudrate Baud rate.\n\ + -p/--port Port name or port number.\n\ + -h/--host Host definition.\n\ +\n\ +Available transports (use with -t option):\n\ + tcp Tcp transport type (host, port number).\n\ + serial Serial transport type (port name, baud rate).\n\ +\n"; + + +/*! + * @brief Class that encapsulates the beremizRuntime tool. + * + * A single global logger instance is created during object construction. It is + * never freed because we need it up to the last possible minute, when an + * exception could be thrown. + */ +class beremizRuntimeCLI +{ +protected: + enum class verbose_type_t + { + kWarning, + kInfo, + kDebug, + kExtraDebug + }; /*!< Types of verbose outputs from beremizRuntime application. */ + + enum class transports_t + { + kNoneTransport, + kTcpTransport, + kSerialTransport + }; /*!< Type of transport to use. */ + + typedef vector string_vector_t; + + int m_argc; /*!< Number of command line arguments. */ + char **m_argv; /*!< String value for each command line argument. */ + StdoutLogger *m_logger; /*!< Singleton logger instance. */ + verbose_type_t m_verboseType; /*!< Which type of log is need to set (warning, info, debug). */ + const char *m_workingDir; /*!< working directory. */ + string_vector_t m_positionalArgs; + transports_t m_transport; /*!< Transport used for receiving messages. */ + uint32_t m_baudrate; /*!< Baudrate rate speed. */ + const char *m_port; /*!< Name or number of port. Based on used transport. */ + const char *m_host; /*!< Host name */ + +public: + /*! + * @brief Constructor. + * + * @param[in] argc Count of arguments in argv variable. + * @param[in] argv Pointer to array of arguments. + * + * Creates the singleton logger instance. + */ + beremizRuntimeCLI(int argc, char *argv[]) : + m_argc(argc), m_argv(argv), m_logger(0), m_verboseType(verbose_type_t::kWarning), + m_workingDir(NULL), m_transport(transports_t::kNoneTransport), m_baudrate(115200), m_port(NULL), + m_host(NULL) + { + // create logger instance + m_logger = new StdoutLogger(); + m_logger->setFilterLevel(Logger::log_level_t::kWarning); + Log::setLogger(m_logger); + } + + /*! + * @brief Destructor. + */ + ~beremizRuntimeCLI() {} + + /*! + * @brief Reads the command line options passed into the constructor. + * + * This method can return a return code to its caller, which will cause the + * tool to exit immediately with that return code value. Normally, though, it + * will return -1 to signal that the tool should continue to execute and + * all options were processed successfully. + * + * The Options class is used to parse command line options. See + * #k_optionsDefinition for the list of options and #k_usageText for the + * descriptive help for each option. + * + * @retval -1 The options were processed successfully. Let the tool run normally. + * @return A zero or positive result is a return code value that should be + * returned from the tool as it exits immediately. + */ + int processOptions() + { + Options options(*m_argv, k_optionsDefinition); + OptArgvIter iter(--m_argc, ++m_argv); + + // process command line options + int optchar; + const char *optarg; + while ((optchar = options(iter, optarg))) + { + switch (optchar) + { + case '?': + { + printUsage(options); + return 0; + } + + case 'V': + { + printf("%s %s\n%s\n", k_toolName, k_version, k_copyright); + return 0; + } + + case 'v': + { + if (m_verboseType != verbose_type_t::kExtraDebug) + { + m_verboseType = (verbose_type_t)(((int)m_verboseType) + 1); + } + break; + } + + case 't': + { + string transport = optarg; + if (transport == "tcp") + { + m_transport = transports_t::kTcpTransport; + } + else if (transport == "serial") + { + m_transport = transports_t::kSerialTransport; + } + else + { + Log::error("error: unknown transport type %s", transport.c_str()); + return 1; + } + break; + } + + case 'b': + { + m_baudrate = strtoul(optarg, NULL, 10); + break; + } + + case 'p': + { + m_port = optarg; + break; + } + + case 'h': + { + m_host = optarg; + break; + } + + default: + { + Log::error("error: unrecognized option\n\n"); + printUsage(options); + return 0; + } + } + } + + // handle positional args + if (iter.index() < m_argc) + { + if (m_argc - iter.index() > 1){ + Log::error("error: too many arguments\n\n"); + printUsage(options); + return 0; + } + int i; + for (i = iter.index(); i < m_argc; ++i) + { + m_positionalArgs.push_back(m_argv[i]); + } + } + + // all is well + return -1; + } + + /*! + * @brief Prints help for the tool. + * + * @param[in] options Options, which can be used. + */ + void printUsage(Options &options) + { + options.usage(cout, "[path]"); + printf(k_usageText); + } + + /*! + * @brief Core of the tool. + * + * Calls processOptions() to handle command line options before performing the + * real work the tool does. + * + * @retval 1 The functions wasn't processed successfully. + * @retval 0 The function was processed successfully. + * + * @exception Log::error This function is called, when function wasn't + * processed successfully. + * @exception runtime_error Thrown, when positional args is empty. + */ + int run() + { + try + { + // read command line options + int result; + if ((result = processOptions()) != -1) + { + return result; + } + + // set verbose logging + setVerboseLogging(); + + if (!m_positionalArgs.size()) + { + m_workingDir = std::filesystem::current_path().c_str(); + } else { + m_workingDir = m_positionalArgs[0].c_str(); + } + + Transport *_transport; + switch (m_transport) + { + case transports_t::kTcpTransport: + { + uint16_t portNumber = strtoul(m_port, NULL, 10); + TCPTransport *tcpTransport = new TCPTransport(m_host, portNumber, true); + if (erpc_status_t err = tcpTransport->open()) + { + return err; + } + _transport = tcpTransport; + break; + } + + case transports_t::kSerialTransport: + { + SerialTransport *serialTransport = new SerialTransport(m_port, m_baudrate); + + uint8_t vtime = 0; + uint8_t vmin = 1; + while (kErpcStatus_Success != serialTransport->init(vtime, vmin)) + ; + + _transport = serialTransport; + break; + } + + default: + { + break; + } + } + + MyMessageBufferFactory _msgFactory; + BasicCodecFactory _basicCodecFactory; + SimpleServer _server; + + BeremizPLCObjectService_service *svc; + + Log::info("Starting ERPC server...\n"); + + _server.setMessageBufferFactory(&_msgFactory); + _server.setTransport(_transport); + _server.setCodecFactory(&_basicCodecFactory); + + svc = new BeremizPLCObjectService_service(new PLCObject()); + + _server.addService(svc); + + _server.run(); + + return 0; + } + catch (exception &e) + { + Log::error("error: %s\n", e.what()); + return 1; + } + catch (...) + { + Log::error("error: unexpected exception\n"); + return 1; + } + + return 0; + } + + /*! + * @brief Turns on verbose logging. + */ + void setVerboseLogging() + { + // verbose only affects the INFO and DEBUG filter levels + // if the user has selected quiet mode, it overrides verbose + switch (m_verboseType) + { + case verbose_type_t::kWarning: + Log::getLogger()->setFilterLevel(Logger::log_level_t::kWarning); + break; + case verbose_type_t::kInfo: + Log::getLogger()->setFilterLevel(Logger::log_level_t::kInfo); + break; + case verbose_type_t::kDebug: + Log::getLogger()->setFilterLevel(Logger::log_level_t::kDebug); + break; + case verbose_type_t::kExtraDebug: + Log::getLogger()->setFilterLevel(Logger::log_level_t::kDebug2); + break; + } + } +}; + +} // namespace beremizRuntime + +/*! + * @brief Main application entry point. + * + * Creates a tool instance and lets it take over. + */ +int main(int argc, char *argv[], char *envp[]) +{ + (void)envp; + try + { + return beremizRuntime::beremizRuntimeCLI(argc, argv).run(); + } + catch (...) + { + Log::error("error: unexpected exception\n"); + return 1; + } + + return 0; +} \ No newline at end of file