C runtime: initial fixes. Now runs and traces first_steps example.
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Fri, 24 May 2024 18:55:46 +0200
changeset 3949 f64dce4e2f62
parent 3948 21e391fb5983
child 3950 79bdee48ced8
C runtime: initial fixes. Now runs and traces first_steps example.

beremiz_runtime -v -t tcp -p 61131 -h localhost
C_runtime/Makefile
C_runtime/PLCObject.cpp
C_runtime/PLCObject.hpp
C_runtime/posix_main.cpp
--- a/C_runtime/Makefile	Fri May 24 18:48:28 2024 +0200
+++ b/C_runtime/Makefile	Fri May 24 18:55:46 2024 +0200
@@ -41,9 +41,7 @@
                 $(ERPC_C_ROOT)/transports/erpc_serial_transport.cpp \
                 $(ERPC_C_ROOT)/transports/erpc_tcp_transport.cpp
 			
-SOURCES +=  $(RUNTIME_ROOT)/c_erpc_PLCObject_client.cpp \
-            $(RUNTIME_ROOT)/c_erpc_PLCObject_server.cpp \
-            $(RUNTIME_ROOT)/erpc_PLCObject_client.cpp \
+SOURCES +=  $(RUNTIME_ROOT)/erpc_PLCObject_client.cpp \
             $(RUNTIME_ROOT)/erpc_PLCObject_interface.cpp \
             $(RUNTIME_ROOT)/erpc_PLCObject_server.cpp \
 			$(RUNTIME_ROOT)/md5.cpp \
--- a/C_runtime/PLCObject.cpp	Fri May 24 18:48:28 2024 +0200
+++ b/C_runtime/PLCObject.cpp	Fri May 24 18:55:46 2024 +0200
@@ -4,6 +4,7 @@
 #include <dlfcn.h>
 #include <fstream>
 #include <iostream>
+#include <vector>
 
 #include "Logging.hpp"
 
@@ -26,10 +27,10 @@
     m_status.PLCstatus = Empty;
     m_handle = NULL;
     m_debugToken = 0;
-    m_plcID.ID = "N/A"; // TODO
-    m_plcID.PSK = "N/A"; // TODO
     m_argc = 0;
     m_argv = NULL;
+    m_PSK_ID = "";
+    m_PSK_secret = "";
 }
 
 PLCObject::~PLCObject(void)
@@ -43,8 +44,15 @@
     // Output new blob's md5 into newBlobID
     // Return 0 if success
 
-    auto nh = m_mapBlobIDToBlob.extract(std::vector<uint8_t>(
-        blobID->data, blobID->data + blobID->dataLength));
+    newBlobID->data = (uint8_t *)malloc(MD5::digestsize);
+    if (newBlobID->data == NULL)
+    {
+        return ENOMEM;
+    }
+
+    std::vector<uint8_t> k(blobID->data, blobID->data + blobID->dataLength);
+
+    auto nh = m_mapBlobIDToBlob.extract(k);
     if (nh.empty())
     {
         return ENOENT;
@@ -60,11 +68,14 @@
 
     MD5::digest_t digest = blob->digest();
 
-    nh.key() = std::vector<uint8_t>(
-        (uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize);
+    std::vector<uint8_t> nk((uint8_t*)digest.data, (uint8_t*)digest.data + MD5::digestsize);
+    nh.key() = nk;
 
     m_mapBlobIDToBlob.insert(std::move(nh));
 
+    memcpy(newBlobID->data, digest.data, MD5::digestsize);
+    newBlobID->dataLength = MD5::digestsize;
+
     return 0;
 }
 
@@ -106,8 +117,25 @@
 
 uint32_t PLCObject::GetPLCID(PSKID *plcID)
 {
-    // Get PLC ID
-    *plcID = m_plcID;
+    // Get PSK ID
+    plcID->ID = (char *)malloc(m_PSK_ID.size() + 1);
+    if (plcID->ID == NULL)
+    {
+        return ENOMEM;
+    }
+    memcpy(plcID->ID, m_PSK_ID.c_str(), m_PSK_ID.size());
+    plcID->ID[m_PSK_ID.size()] = '\0';
+
+    // Get PSK secret
+    plcID->PSK = (char *)malloc(m_PSK_secret.size() + 1);
+    if (plcID->PSK == NULL)
+    {
+        free(plcID->ID);
+        return ENOMEM;
+    }
+    memcpy(plcID->PSK, m_PSK_secret.c_str(), m_PSK_secret.size());
+    plcID->PSK[m_PSK_secret.size()] = '\0';
+
     return 0;
 }
 
@@ -129,37 +157,47 @@
     // Check if there are any traces
     m_tracesMutex.lock();
     size_t sz = m_traces.size();
-    if(sz == 0)
-    {
-        m_tracesMutex.unlock();
-        return ENOENT;
-    }
-
-    // Allocate memory for traces
-    traces->traces.elements = (trace_sample *)malloc(sz * sizeof(trace_sample));
-    if(traces->traces.elements == NULL)
-    {
-        m_tracesMutex.unlock();
-        return ENOMEM;
-    }
+    if(sz > 0)
+    {
+        // Allocate memory for traces
+        traces->traces.elements = (trace_sample *)malloc(sz * sizeof(trace_sample));
+        if(traces->traces.elements == NULL)
+        {
+            m_tracesMutex.unlock();
+            return ENOMEM;
+        }
+        // Copy traces from vector
+        memcpy(traces->traces.elements, m_traces.data(), sz * sizeof(trace_sample));
+
+        // Clear the vector
+        // note that the data is not freed here, it is meant to be freed by eRPC server code
+        m_traces.clear();
+    }
+    m_tracesMutex.unlock();
+
     traces->traces.elementsCount = sz;
-
-    // Copy traces from vector
-    memcpy(traces->traces.elements, m_traces.data(), sz * sizeof(trace_sample));
-
-    // Clear the vector
-    // note that the data is not freed here, it is meant to be freed by eRPC server code
-    m_traces.clear();
-    m_tracesMutex.unlock();
+    traces->PLCstatus = m_status.PLCstatus;
 
     return 0;
 }
 
 uint32_t PLCObject::MatchMD5(const char *MD5, bool *match)
 {
+    // an empty PLC is never considered to match
+    if(m_status.PLCstatus == Empty)
+    {
+        *match = false;
+        return 0;
+    }
+
     // Load the last transferred PLC md5 hex digest
     std::string md5sum;
-    std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+    try {
+        std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+    } catch (std::exception e) {
+        *match = false;
+        return 0;
+    }
 
     // Compare the given MD5 with the last transferred PLC md5
     *match = (md5sum == MD5);
@@ -208,11 +246,13 @@
 {
     if(m_status.PLCstatus == Started)
     {
+        *success = false;
         return EBUSY;
     }
 
     if(m_status.PLCstatus == Broken)
     {
+        *success = false;
         return EINVAL;
     }
 
@@ -246,38 +286,65 @@
         extra_files_log << extrafile->fname << std::endl;
     }
 
-    return 0;
-}
-
-#define DLSYM(sym)                                                      \
-    do                                                                  \
-    {                                                                   \
-        m_PLCSyms.sym = (decltype(m_PLCSyms.sym))dlsym(m_handle, #sym); \
-        if (m_PLCSyms.sym == NULL)                                      \
-        {                                                               \
-            return errno;                                               \
-        }                                                               \
+    // Load the PLC object
+    uint32_t res = LoadPLC();
+    if (res != 0)
+    {
+        *success = false;
+        return res;
+    }
+
+    m_status.PLCstatus = Stopped;
+    *success = true;
+
+    return 0;
+}
+
+#define DLSYM(sym)                                                           \
+    do                                                                       \
+    {                                                                        \
+        m_PLCSyms.sym = (decltype(m_PLCSyms.sym))dlsym(m_handle, #sym);      \
+        if (m_PLCSyms.sym == NULL)                                           \
+        {                                                                    \
+            /* TODO: use log instead */                                      \
+            std::cout << "Error dlsym " #sym ": " << dlerror() << std::endl; \
+            return errno;                                                    \
+        }                                                                    \
     } while (0);
 
 uint32_t PLCObject::LoadPLC(void)
 {
     // Load the last transferred PLC md5 hex digest
     std::string md5sum;
-    std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+    try {
+        std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+    } catch (std::exception e) {
+        return ENOENT;
+    }
 
     // Concatenate md5sum and shared object extension to obtain filename
-    std::filesystem::path filename = std::filesystem::path(md5sum) += SHARED_OBJECT_EXT;
+    std::filesystem::path filename(md5sum + SHARED_OBJECT_EXT);
 
     // Load the shared object file
-    m_handle = dlopen(filename.c_str(), RTLD_NOW);
+    m_handle = dlopen(std::filesystem::absolute(filename).c_str(), RTLD_NOW);
     if (m_handle == NULL)
     {
+        std::cout << "Error: " << dlerror() << std::endl;
         return errno;
     }
 
     // Resolve shared object symbols
     FOR_EACH_PLC_SYMBOLS_DO(DLSYM);
 
+    // Set content of PLC_ID to md5sum
+    m_PLCSyms.PLC_ID = (uint8_t *)malloc(md5sum.size() + 1);
+    if (m_PLCSyms.PLC_ID == NULL)
+    {
+        return ENOMEM;
+    }
+    memcpy(m_PLCSyms.PLC_ID, md5sum.c_str(), md5sum.size());
+    m_PLCSyms.PLC_ID[md5sum.size()] = '\0';
+
     return 0;
 }
 
@@ -312,9 +379,8 @@
     return 0;
 }
 
-uint32_t PLCObject::PurgePLC(void){
-    // Purge all blobs
-    PurgeBlobs();
+uint32_t PLCObject::PurgePLC(void)
+{
 
     // Open the extra files list
     std::ifstream extra_files_log(std::string(ExtraFilesList), std::ios::binary);
@@ -328,20 +394,24 @@
 
     // Load the last transferred PLC md5 hex digest
     std::string md5sum;
-    std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
-
-    // Concatenate md5sum and shared object extension to obtain filename
-    std::filesystem::path filename =
-        std::filesystem::path(md5sum) += SHARED_OBJECT_EXT;
-
-    // Remove the PLC object shared object file
-    std::filesystem::remove(filename);
-
-    // Remove the last transferred PLC md5 hex digest
-    std::filesystem::remove(std::string(LastTransferredPLC));
-
-    // Remove the extra files list
-    std::filesystem::remove(std::string(ExtraFilesList));
+    try {
+        std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+
+        // Remove the PLC object shared object file
+        std::filesystem::remove(md5sum + SHARED_OBJECT_EXT);
+    } catch (std::exception e) {
+        // ignored
+    }
+
+    try {
+        // Remove the last transferred PLC md5 hex digest
+        std::filesystem::remove(std::string(LastTransferredPLC));
+
+        // Remove the extra files list
+        std::filesystem::remove(std::string(ExtraFilesList));
+    } catch (std::exception e) {
+        // ignored
+    }
 
     return 0;
 }
@@ -388,7 +458,9 @@
 
     MD5::digest_t digest = blob->digest();
 
-    m_mapBlobIDToBlob[std::vector<uint8_t>((uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize)] = blob;
+    std::vector<uint8_t> k((uint8_t*)digest.data, (uint8_t*)digest.data + MD5::digestsize);
+
+    m_mapBlobIDToBlob[k] = blob;
 
     blobID->data = (uint8_t *)malloc(MD5::digestsize);
     if (blobID->data == NULL)
@@ -400,10 +472,25 @@
 
     return 0;
 }
+void PLCObject::PurgeTraceBuffer(void)
+{
+    // Free trace buffer
+    m_tracesMutex.lock();
+    for(trace_sample s : m_traces){
+        free(s.TraceBuffer.data);
+    }
+    m_traces.clear();
+    m_tracesMutex.unlock();
+}
 
 uint32_t PLCObject::SetTraceVariablesList(
     const list_trace_order_1_t *orders, int32_t *debugtoken)
 {
+    if(m_status.PLCstatus == Empty)
+    {
+        return EINVAL;
+    }
+
     // increment debug token
     m_debugToken++;
 
@@ -431,20 +518,23 @@
             {
                 // if any error, disable debug
                 // since debug is already suspended, resume it first
-                m_PLCSyms.ResumeDebug();
+                m_PLCSyms.resumeDebug();
                 m_PLCSyms.suspendDebug(1);
                 *debugtoken = -res;
                 return EINVAL;
             }
         }
 
+        // old traces are not valid anymore
+        PurgeTraceBuffer();
+
         // Start debug thread if not already started
         if(!m_traceThread.joinable())
         {
             m_traceThread = std::thread(&PLCObject::TraceThreadProc, this);
         }
 
-        m_PLCSyms.ResumeDebug();
+        m_PLCSyms.resumeDebug();
         *debugtoken = m_debugToken;
         return 0;
     }
@@ -487,6 +577,13 @@
 
 uint32_t PLCObject::LogMessage(uint8_t level, std::string message)
 {
+    // if PLC isn't loaded, log to stdout
+    if(m_PLCSyms.LogMessage == NULL)
+    {
+        std::cout << level << message << std::endl;
+        return ENOSYS;
+    }
+
     // Log std::string message with given level
     return m_PLCSyms.LogMessage(level, (char *)message.c_str(), message.size());
 }
@@ -495,7 +592,7 @@
 {
     uint32_t err = 0;
 
-    m_PLCSyms.ResumeDebug();
+    m_PLCSyms.resumeDebug();
 
     while(m_status.PLCstatus == Started)
     {
@@ -537,13 +634,7 @@
         }
     }
 
-    // Free trace buffer
-    m_tracesMutex.lock();
-    for(trace_sample s : m_traces){
-        free(s.TraceBuffer.data);
-    }
-    m_traces.clear();
-    m_tracesMutex.unlock();
+    PurgeTraceBuffer();
 
     LogMessage(err ? LOG_CRITICAL : LOG_INFO,
         err == ENOMEM ? "Out of memory in TraceThreadProc" : 
--- a/C_runtime/PLCObject.hpp	Fri May 24 18:48:28 2024 +0200
+++ b/C_runtime/PLCObject.hpp	Fri May 24 18:55:46 2024 +0200
@@ -10,7 +10,7 @@
 #include <vector>
 #include <mutex>
 #include <thread>
- 
+
 #include "blob.hpp"
 
 #include "erpc_PLCObject_interface.hpp"
@@ -26,28 +26,29 @@
     ACTION(FreeDebugData)\
     ACTION(GetDebugData)\
     ACTION(suspendDebug)\
-    ACTION(ResumeDebug)\
+    ACTION(resumeDebug)\
     ACTION(ResetLogCount)\
     ACTION(GetLogCount)\
     ACTION(LogMessage)\
     ACTION(GetLogMessage)
 
-typedef struct s_PLCSyms{
-    uint8_t *PLC_ID;
-    int (*startPLC)(int argc,char **argv);
-    int (*stopPLC)(void);
-    void (*ResetDebugVariables)(void);
-    int (*RegisterDebugVariable)(unsigned int idx, void* force, size_t force_size);
-    void (*FreeDebugData)(void);
-    int (*GetDebugData)(unsigned int *tick, unsigned int *size, void **buffer);
-    int (*suspendDebug)(int disable);
-    void (*ResumeDebug)(void);
-    void (*ResetLogCount)(void);
-    uint32_t (*GetLogCount)(uint8_t level);
-    int (*LogMessage)(uint8_t level, char* buf, uint32_t size);
-    uint32_t (*GetLogMessage)(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec);
-} PLCSyms;
-
+extern "C" {   
+    typedef struct s_PLCSyms{
+        uint8_t *PLC_ID;
+        int (*startPLC)(int argc,char **argv);
+        int (*stopPLC)(void);
+        void (*ResetDebugVariables)(void);
+        int (*RegisterDebugVariable)(unsigned int idx, void* force, size_t force_size);
+        void (*FreeDebugData)(void);
+        int (*GetDebugData)(unsigned int *tick, unsigned int *size, void **buffer);
+        int (*suspendDebug)(int disable);
+        void (*resumeDebug)(void);
+        void (*ResetLogCount)(void);
+        uint32_t (*GetLogCount)(uint8_t level);
+        int (*LogMessage)(uint8_t level, char* buf, uint32_t size);
+        uint32_t (*GetLogMessage)(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec);
+    } PLCSyms;
+}
 class PLCObject : public BeremizPLCObjectService_interface
 {
     public:
@@ -91,8 +92,9 @@
         // PLC status
         PLCstatus m_status;
 
-        // PLC ID
-        PSKID m_plcID;
+        // PSK
+        std::string m_PSK_ID;
+        std::string m_PSK_secret;
 
         // Debug token, used for consistency check of traces
         uint32_t m_debugToken;
@@ -111,6 +113,7 @@
         uint32_t UnLoadPLC(void);
         uint32_t LogMessage(uint8_t level, std::string message);
         uint32_t PurgePLC(void);
+        void PurgeTraceBuffer(void);
         void TraceThreadProc(void);
 };
 
--- a/C_runtime/posix_main.cpp	Fri May 24 18:48:28 2024 +0200
+++ b/C_runtime/posix_main.cpp	Fri May 24 18:55:46 2024 +0200
@@ -14,12 +14,16 @@
 #include <vector>
 #include <filesystem>
 
+// eRPC includes
 #include "erpc_basic_codec.hpp"
 #include "erpc_serial_transport.hpp"
 #include "erpc_tcp_transport.hpp"
 #include "erpc_simple_server.hpp"
 
+// eRPC generated includes
 #include "erpc_PLCObject_server.hpp"
+
+// erpcgen includes (re-uses erpcgen's logging system and options parser)
 #include "Logging.hpp"
 #include "options.hpp"
 
@@ -28,13 +32,14 @@
 using namespace erpc;
 using namespace std;
 
+#define MSG_SIZE 1024*6
 class MyMessageBufferFactory : public MessageBufferFactory
 {
 public:
     virtual MessageBuffer create()
     {
-        uint8_t *buf = new uint8_t[1024];
-        return MessageBuffer(buf, 1024);
+        uint8_t *buf = new uint8_t[MSG_SIZE];
+        return MessageBuffer(buf, MSG_SIZE);
     }
 
     virtual void dispose(MessageBuffer *buf)
@@ -351,6 +356,9 @@
                 }
             }
 
+            Crc16 crc;
+            _transport->setCrc16(&crc);
+
             MyMessageBufferFactory _msgFactory;
             BasicCodecFactory _basicCodecFactory;
             SimpleServer _server;