C runtime: initial fixes. Now runs and traces first_steps example.
beremiz_runtime -v -t tcp -p 61131 -h localhost
--- 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;