C_runtime/posix_main.cpp
changeset 3937 e13543d716b6
--- /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 <stdlib.h>
+#include <vector>
+#include <filesystem>
+
+#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 <transport>",
+                                             "b:baudrate <baudrate>",
+                                             "p:port <port>",
+                                             "h:host <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 <transport>   Type of transport.\n\
+  -b/--baudrate <baudrate>     Baud rate.\n\
+  -p/--port <port>             Port name or port number.\n\
+  -h/--host <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> 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