--- /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