Merge pull request #293 from thiagoralves/dev-python-runtime

Dev python runtime
This commit is contained in:
Thiago Alves
2025-09-08 12:05:30 -04:00
committed by GitHub
19 changed files with 305 additions and 121 deletions

View File

@@ -802,7 +802,7 @@ void S7API EventCallBack(void* usrPtr, PSrvEvent PEvent, int Size)
// log the event
Srv_EventText(PEvent, s7text, sizeof(s7text));
sprintf(log_msg, "Snap7: %s\n", s7text);
log(log_msg);
openplc_log(log_msg);
};
//------------------------------------------------------------------------------

View File

@@ -52,7 +52,7 @@ int connect_to_tcp_server(uint8_t *ip_address, uint16_t port, int method)
if (sockfd == -1)
{
sprintf(log_msg, "TCP Client: error creating TCP socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
bzero(&servaddr, sizeof(servaddr));
@@ -66,7 +66,7 @@ int connect_to_tcp_server(uint8_t *ip_address, uint16_t port, int method)
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
{
sprintf(log_msg, "TCP Client: error connecting to server => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
close(sockfd);
return -1;
}
@@ -76,14 +76,14 @@ int connect_to_tcp_server(uint8_t *ip_address, uint16_t port, int method)
if (flags == -1)
{
sprintf(log_msg, "TCP Client: error reading flags from TCP socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
flags = (flags | O_NONBLOCK);
if (fcntl(sockfd, F_SETFL, flags) != 0)
{
sprintf(log_msg, "TCP Client: error setting flags for TCP socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
@@ -98,7 +98,7 @@ int send_tcp_message(uint8_t *msg, size_t msg_size, int socket_id)
if (bytes_sent < 0)
{
sprintf(log_msg, "TCP Client: error sending msg to server => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
@@ -114,14 +114,14 @@ int receive_tcp_message(uint8_t *msg_buffer, size_t buffer_size, int socket_id)
if (bytes_received < 0 && bytes_received != EAGAIN && bytes_received != EWOULDBLOCK)
{
//sprintf(log_msg, "TCP Client: error receiving msg from server => %s\n", strerror(errno));
//log(log_msg);
//openplc_log(log_msg);
return -1;
}
else
{
msg_buffer[bytes_received] = 0;
sprintf(log_msg, "TCP Client: msg from server => %s\n", msg_buffer);
log(log_msg);
openplc_log(log_msg);
}
return bytes_received;

View File

@@ -412,7 +412,7 @@ void ConsoleLogger::Log(const openpal::LogEntry& entry)
{
char log_msg[1000];
sprintf(log_msg, "DNP3 ID %s: %s\n", entry.loggerid, entry.message);
log(log_msg);
openplc_log(log_msg);
}

View File

@@ -564,7 +564,7 @@ int processEnipMessage(unsigned char *buffer, int buffer_size)
{
// log UNKNOWN Enip Type message to open plc
sprintf(log_msg, "ENIP: Received unsupported EtherNet/IP Type\n");
log(log_msg);
openplc_log(log_msg);
}
//writeDataContents(&enipDataUnknown);
@@ -603,7 +603,7 @@ int processEnipMessage(unsigned char *buffer, int buffer_size)
p += sprintf(p, "%02x ", (unsigned char)buffer[i]);
}
p += sprintf(p, "\n");
log(log_msg);
openplc_log(log_msg);
return -1;
}

View File

@@ -100,7 +100,7 @@ void searchForIO()
char log_msg[1000];
sprintf(log_msg, "Neuron: Searching for I/O...\n");
log(log_msg);
openplc_log(log_msg);
/* look for digital inputs */
strcpy(path_fmt, "/sys/devices/platform/unipi_plc/io_group%d/di_%d_%02d/di_value");
@@ -232,37 +232,37 @@ void searchForIO()
/* print found I/Os on console log */
sprintf(log_msg, "Neuron: Done!\n\nNeuron Digital Inputs\n");
log(log_msg);
openplc_log(log_msg);
index = 0;
while (digital_inputs[index][0] != '\0')
{
sprintf(log_msg, "%s\t=>\t%%IX%d.%d\n", digital_inputs[index], (index/8), (index%8));
log(log_msg);
openplc_log(log_msg);
index++;
}
sprintf(log_msg, "\nNeuron Digital Outputs\n");
log(log_msg);
openplc_log(log_msg);
index = 0;
while (digital_outputs[index][0] != '\0')
{
sprintf(log_msg, "%s\t=>\t%%QX%d.%d\n", digital_outputs[index], (index/8), (index%8));
log(log_msg);
openplc_log(log_msg);
index++;
}
sprintf(log_msg, "\nNeuron Analog Inputs\n");
log(log_msg);
openplc_log(log_msg);
index = 0;
while (analog_inputs[index][0] != '\0')
{
sprintf(log_msg, "%s\t=>\t%%IW%d\n", analog_inputs[index], index);
log(log_msg);
openplc_log(log_msg);
index++;
}
sprintf(log_msg, "\nNeuron Analog Outputs\n");
log(log_msg);
openplc_log(log_msg);
index = 0;
while (analog_outputs[index][0] != '\0')
{
@@ -273,7 +273,7 @@ void searchForIO()
else
sprintf(log_msg, "%s\t=>\t%%QW%d\n", analog_outputs[index], index);
log(log_msg);
openplc_log(log_msg);
index++;
}
}

View File

@@ -60,7 +60,7 @@ void check_error_count()
{
char log_msg[1000];
sprintf(log_msg, "PSM: Too many errors!\nPSM: PSM is disabled\n");
log(log_msg);
openplc_log(log_msg);
}
}
@@ -72,26 +72,26 @@ void *start_psm()
{
char log_msg[BUFFER_LIMIT];
sprintf(log_msg, "PSM: Starting PSM...\n");
log(log_msg);
openplc_log(log_msg);
char *cmd = "../.venv/bin/python3 -u ./core/psm/main.py 2>&1";
FILE *psm_proc;
if ((psm_proc = popen(cmd, "r")) == NULL)
{
sprintf(log_msg, "PSM: Error opening pipe!\n");
log(log_msg);
openplc_log(log_msg);
return;
}
while (fgets(log_msg, BUFFER_LIMIT, psm_proc) != NULL)
{
log(log_msg);
openplc_log(log_msg);
}
if (pclose(psm_proc))
{
sprintf(log_msg, "PSM: Error while starting Python interpreter\n");
log(log_msg);
openplc_log(log_msg);
return;
}
}
@@ -110,7 +110,7 @@ int connect_to_psm(int debug)
if (debug)
{
sprintf(log_msg, "PSM: Socket creation error \n");
log(log_msg);
openplc_log(log_msg);
}
return -1;
}
@@ -123,7 +123,7 @@ int connect_to_psm(int debug)
if (debug)
{
sprintf(log_msg, "PSM: Invalid address or address not supported\n");
log(log_msg);
openplc_log(log_msg);
}
return -1;
}
@@ -133,7 +133,7 @@ int connect_to_psm(int debug)
if (debug)
{
sprintf(log_msg, "PSM: Connection to psm failed\n");
log(log_msg);
openplc_log(log_msg);
}
return -1;
}
@@ -175,7 +175,7 @@ void read_ana_inp(int psm)
if (buffer[8] < 50)
{
sprintf(log_msg, "PSM: Error reading from analog inputs!\n");
log(log_msg);
openplc_log(log_msg);
error_count++;
check_error_count();
}
@@ -221,7 +221,7 @@ void write_ana_out(int psm)
if (buffer[11] < 25)
{
sprintf(log_msg, "PSM: Error writing to analog outputs!\n");
log(log_msg);
openplc_log(log_msg);
error_count++;
check_error_count();
}
@@ -249,7 +249,7 @@ void write_ana_out(int psm)
if (buffer[11] < 25)
{
sprintf(log_msg, "PSM: Error writing to analog outputs!\n");
log(log_msg);
openplc_log(log_msg);
error_count++;
check_error_count();
}
@@ -271,7 +271,7 @@ void read_dig_inp(int psm)
if (buffer[8] < 50)
{
sprintf(log_msg, "PSM: Error reading from digital inputs!\n");
log(log_msg);
openplc_log(log_msg);
error_count++;
check_error_count();
}
@@ -327,7 +327,7 @@ void write_dig_out(int psm)
if (buffer[10] != 0x01 && buffer[11] != 0x90)
{
sprintf(log_msg, "PSM: Error writing to digital outputs!\n");
log(log_msg);
openplc_log(log_msg);
error_count++;
check_error_count();
}
@@ -344,7 +344,7 @@ void stop_psm(int psm)
unsigned char buffer[1024];
sprintf(log_msg, "PSM: Stopping PSM...\n");
log(log_msg);
openplc_log(log_msg);
send(psm, request, 12, 0);
/*
@@ -354,7 +354,7 @@ void stop_psm(int psm)
if (buffer[11] != 127)
{
sprintf(log_msg, "PSM: Error while trying to stop PSM!\n");
log(log_msg);
openplc_log(log_msg);
}
*/
}
@@ -366,14 +366,14 @@ void kill_psm()
{
char log_msg[BUFFER_LIMIT];
sprintf(log_msg, "PSM: Killing previous PSM modules...\n");
log(log_msg);
openplc_log(log_msg);
char *cmd = "ps aux | grep ./core/psm/main.py | awk '{print $2}'";
FILE *psm_proc;
if ((psm_proc = popen(cmd, "r")) == NULL)
{
sprintf(log_msg, "PSM: Error while trying to kill background PSM.\n Could not open pipe!\n");
log(log_msg);
openplc_log(log_msg);
return;
}
@@ -404,7 +404,7 @@ void kill_psm()
if (pclose(psm_proc))
{
sprintf(log_msg, "PSM: Error while trying to kill background PSM\n");
log(log_msg);
openplc_log(log_msg);
return;
}
}
@@ -439,12 +439,12 @@ void initializeHardware()
if (psm < 0)
{
sprintf(log_msg, "PSM: Error connecting to psm!\nPSM: PSM is disabled\n");
log(log_msg);
openplc_log(log_msg);
}
else
{
sprintf(log_msg, "PSM: Connected to PSM\n");
log(log_msg);
openplc_log(log_msg);
}
}

View File

@@ -85,7 +85,7 @@ int log_error(int line)
#ifdef GEN_DEBUG
sprintf(log_msg, "!line %d\n", line);
log(log_msg);
openplc_log(log_msg);
#endif
return ERROR;
}
@@ -103,7 +103,7 @@ int i2cSetup(int addr)
if ( (file = open(filename, O_RDWR)) < 0)
{
sprintf(log_msg, "Failed to open the bus.\n");
log(log_msg);
openplc_log(log_msg);
return ERROR;
}
@@ -111,7 +111,7 @@ int i2cSetup(int addr)
if (ioctl(file, I2C_SLAVE, addr) < 0)
{
sprintf(log_msg, "Failed to acquire bus access and/or talk to slave.\n");
log(log_msg);
openplc_log(log_msg);
return ERROR;
}
return file;
@@ -138,7 +138,7 @@ int i2cMemRead(int dev, int add, uint8_t *buff, int size)
{
#ifdef I2C_DEBUG
sprintf(log_msg, "Fail to select 0x%02hhx mem add!\n", add);
log(log_msg);
openplc_log(log_msg);
#endif
return ERROR;
}
@@ -146,7 +146,7 @@ int i2cMemRead(int dev, int add, uint8_t *buff, int size)
{
#ifdef I2C_DEBUG
sprintf(log_msg, "Fail to read memory!\n");
log(log_msg);
openplc_log(log_msg);
#endif
return ERROR;
}
@@ -174,7 +174,7 @@ int i2cMemWrite(int dev, int add, uint8_t *buff, int size)
if (write(dev, intBuff, size + 1) != size + 1)
{
sprintf(log_msg, "Fail to write memory at 0x%02hhx address!\n", add);
log(log_msg);
openplc_log(log_msg);
return ERROR;
}
return OK;

View File

@@ -163,7 +163,7 @@ int createSocket_interactive(int port)
if (socket_fd<0)
{
sprintf(log_msg, "Interactive Server: error creating stream socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
exit(1);
}
@@ -184,13 +184,13 @@ int createSocket_interactive(int port)
if (bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
{
sprintf(log_msg, "Interactive Server: error binding socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
exit(1);
}
// we accept max 5 pending connections
listen(socket_fd,5);
sprintf(log_msg, "Interactive Server: Listening on port %d\n", port);
log(log_msg);
openplc_log(log_msg);
return socket_fd;
}
@@ -253,27 +253,27 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued quit() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_modbus)
{
run_modbus = 0;
pthread_join(modbus_thread, NULL);
sprintf(log_msg, "Modbus server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
if (run_dnp3)
{
run_dnp3 = 0;
pthread_join(dnp3_thread, NULL);
sprintf(log_msg, "DNP3 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
if (run_snap7)
{
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
run_openplc = 0;
processing_command = false;
@@ -286,7 +286,7 @@ void processCommand(unsigned char *buffer, int client_fd)
strcpy(ethercat_conf_file, argument);
free(argument);
sprintf(log_msg, "Issued start_ethercat() command to start with config: %s\n", ethercat_conf_file);
log(log_msg);
openplc_log(log_msg);
//Configure ethercat
ethercat_configured = configureEthercat();
processing_command = false;
@@ -296,16 +296,16 @@ void processCommand(unsigned char *buffer, int client_fd)
processing_command = true;
modbus_port = readCommandArgument(buffer);
sprintf(log_msg, "Issued start_modbus() command to start on port: %d\n", modbus_port);
log(log_msg);
openplc_log(log_msg);
if (run_modbus)
{
sprintf(log_msg, "Modbus server already active. Restarting on port: %d\n", modbus_port);
log(log_msg);
openplc_log(log_msg);
//Stop Modbus server
run_modbus = 0;
pthread_join(modbus_thread, NULL);
sprintf(log_msg, "Modbus server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
//Start Modbus server
run_modbus = 1;
@@ -316,13 +316,13 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued stop_modbus() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_modbus)
{
run_modbus = 0;
pthread_join(modbus_thread, NULL);
sprintf(log_msg, "Modbus server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
processing_command = false;
}
@@ -330,16 +330,16 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued start_snap7() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_snap7)
{
sprintf(log_msg, "Snap7 server already active. Restarting it\n");
log(log_msg);
openplc_log(log_msg);
//Stop Modbus server
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
//Start Modbus server
run_snap7 = 1;
@@ -350,13 +350,13 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued stop_snap7() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_snap7)
{
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
processing_command = false;
}
@@ -365,16 +365,16 @@ void processCommand(unsigned char *buffer, int client_fd)
processing_command = true;
dnp3_port = readCommandArgument(buffer);
sprintf(log_msg, "Issued start_dnp3() command to start on port: %d\n", dnp3_port);
log(log_msg);
openplc_log(log_msg);
if (run_dnp3)
{
sprintf(log_msg, "DNP3 server already active. Restarting on port: %d\n", dnp3_port);
log(log_msg);
openplc_log(log_msg);
//Stop DNP3 server
run_dnp3 = 0;
pthread_join(dnp3_thread, NULL);
sprintf(log_msg, "DNP3 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
//Start DNP3 server
run_dnp3 = 1;
@@ -385,13 +385,13 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued stop_dnp3() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_dnp3)
{
run_dnp3 = 0;
pthread_join(dnp3_thread, NULL);
sprintf(log_msg, "DNP3 server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
processing_command = false;
}
@@ -400,16 +400,16 @@ void processCommand(unsigned char *buffer, int client_fd)
processing_command = true;
enip_port = readCommandArgument(buffer);
sprintf(log_msg, "Issued start_enip() command to start on port: %d\n", enip_port);
log(log_msg);
openplc_log(log_msg);
if (run_enip)
{
sprintf(log_msg, "EtherNet/IP server already active. Restarting on port: %d\n", enip_port);
log(log_msg);
openplc_log(log_msg);
//Stop Enip server
run_enip = 0;
pthread_join(enip_thread, NULL);
sprintf(log_msg, "EtherNet/IP server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
//Start Enip server
run_enip = 1;
@@ -420,13 +420,13 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued stop_enip() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_enip)
{
run_enip = 0;
pthread_join(enip_thread, NULL);
sprintf(log_msg, "EtherNet/IP server was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
processing_command = false;
}
@@ -435,11 +435,11 @@ void processCommand(unsigned char *buffer, int client_fd)
processing_command = true;
pstorage_polling = readCommandArgument(buffer);
sprintf(log_msg, "Issued start_pstorage() command with polling rate of %d seconds\n", pstorage_polling);
log(log_msg);
openplc_log(log_msg);
if (run_pstorage)
{
sprintf(log_msg, "Persistent Storage server already active. Changing polling rate to: %d\n", pstorage_polling);
log(log_msg);
openplc_log(log_msg);
}
//Start Enip server
run_pstorage = 1;
@@ -450,12 +450,12 @@ void processCommand(unsigned char *buffer, int client_fd)
{
processing_command = true;
sprintf(log_msg, "Issued stop_pstorage() command\n");
log(log_msg);
openplc_log(log_msg);
if (run_pstorage)
{
run_pstorage = 0;
sprintf(log_msg, "Persistent Storage thread was stopped\n");
log(log_msg);
openplc_log(log_msg);
}
processing_command = false;
}
@@ -564,7 +564,7 @@ void startInteractiveServer(int port)
if (client_fd < 0)
{
sprintf(log_msg, "Interactive Server: Error accepting client!\n");
log(log_msg);
openplc_log(log_msg);
}
else

View File

@@ -112,7 +112,7 @@ void updateBuffersOut();
//utils.cpp
void sleep_until(struct timespec *ts, long long delay);
void sleepms(int milliseconds);
void log(char *logmsg);
extern "C" void openplc_log(char *logmsg);
void handleSpecialFunctions();
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result);
void *interactiveServerThread(void *arg);
@@ -166,3 +166,7 @@ void dnp3StartServer(int port);
//persistent_storage.cpp
void startPstorage();
int readPersistentStorage();
//python_loader.cpp
extern "C" int create_shm_name(char *buf, size_t size);
extern "C" int python_block_loader(const char *script_name, const char *script_content, char *shm_name, size_t shm_in_size, size_t shm_out_size, void **shm_in_ptr, void **shm_out_ptr, pid_t pid);

View File

@@ -0,0 +1,8 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
extern "C" void openplc_log(char *logmsg);
extern "C" int create_shm_name(char *buf, size_t size);
extern "C" int python_block_loader(const char *script_name, const char *script_content, char *shm_name, size_t shm_in_size, size_t shm_out_size, void **shm_in_ptr, void **shm_out_ptr, pid_t pid);

View File

@@ -740,5 +740,6 @@ __ANY(__move_)
#include "iec_std_functions.h"
#include "iec_std_FB.h"
#include "iec_python.h"
#endif /* _IEC_STD_LIB_H */

View File

@@ -59,7 +59,7 @@ uint32_t *dint_input_call_back(int a){ return dint_input[a]; }
uint32_t *dint_output_call_back(int a){ return dint_output[a]; }
uint64_t *lint_input_call_back(int a){ return lint_input[a]; }
uint64_t *lint_output_call_back(int a){ return lint_output[a]; }
void logger_callback(char *msg){ log(msg);}
void logger_callback(char *msg){ openplc_log(msg);}
int main(int argc,char **argv)
{
@@ -75,7 +75,7 @@ int main(int argc,char **argv)
char log_msg[1000];
sprintf(log_msg, "OpenPLC Runtime starting...\n");
log(log_msg);
openplc_log(log_msg);
//======================================================
// PLC INITIALIZATION

View File

@@ -318,7 +318,7 @@ void parseConfig()
{
char log_msg[1000];
sprintf(log_msg, "Skipping configuration of Slave Devices (mbconfig.cfg file not found)\n");
log(log_msg);
openplc_log(log_msg);
}
//Parser Debug
@@ -391,12 +391,12 @@ void *querySlaveDevices(void *arg)
if (!mb_devices[i].isConnected && !rtu_port_connected)
{
sprintf(log_msg, "Device %s is disconnected. Attempting to reconnect...\n", mb_devices[i].dev_name);
log(log_msg);
openplc_log(log_msg);
if (modbus_connect(mb_devices[i].mb_ctx) == -1)
{
sprintf(log_msg, "Connection failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
if (special_functions[2] != NULL) *special_functions[2]++;
@@ -410,7 +410,7 @@ void *querySlaveDevices(void *arg)
else
{
sprintf(log_msg, "Connected to MB device %s\n", mb_devices[i].dev_name);
log(log_msg);
openplc_log(log_msg);
mb_devices[i].isConnected = true;
}
}
@@ -446,7 +446,7 @@ void *querySlaveDevices(void *arg)
}
sprintf(log_msg, "Modbus Read Discrete Input Registers failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
bool_input_index += (mb_devices[i].discrete_inputs.num_regs);
if (special_functions[2] != NULL) *special_functions[2]++;
}
@@ -490,7 +490,7 @@ void *querySlaveDevices(void *arg)
}
sprintf(log_msg, "Modbus Write Coils failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
if (special_functions[2] != NULL) *special_functions[2]++;
}
@@ -515,7 +515,7 @@ void *querySlaveDevices(void *arg)
}
sprintf(log_msg, "Modbus Read Input Registers failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
int_input_index += (mb_devices[i].input_registers.num_regs);
if (special_functions[2] != NULL) *special_functions[2]++;
}
@@ -550,7 +550,7 @@ void *querySlaveDevices(void *arg)
mb_devices[i].isConnected = false;
}
sprintf(log_msg, "Modbus Read Holding Registers failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
int_input_index += (mb_devices[i].holding_read_registers.num_regs);
if (special_functions[2] != NULL) *special_functions[2]++;
}
@@ -595,7 +595,7 @@ void *querySlaveDevices(void *arg)
}
sprintf(log_msg, "Modbus Write Holding Registers failed on MB device %s: %s\n", mb_devices[i].dev_name, modbus_strerror(errno));
log(log_msg);
openplc_log(log_msg);
if (special_functions[2] != NULL) *special_functions[2]++;
}
@@ -640,7 +640,7 @@ void initializeMB()
{
char log_msg[1000];
sprintf(log_msg, "Warning MB device %s port setting missmatch\n", mb_devices[i].dev_name);
log(log_msg);
openplc_log(log_msg);
}
mb_devices[i].mb_ctx = mb_devices[share_index].mb_ctx;
}

View File

@@ -175,7 +175,7 @@ uint16_t Command_Protocol(pccc_header header, unsigned char *buffer, int buffer_
/*initialize logging system*/
char log_msg[1000];
sprintf(log_msg, "PCCC: Unsupportedd Command/Data Function Code!\n");
log(log_msg);
openplc_log(log_msg);
return -1;
}//return length as -1 to signify that the CMD Code/Function Code was not recognize
}
@@ -217,7 +217,7 @@ uint16_t Protected_Logical_Read_Reply(pccc_header header, unsigned char *buffer,
{
char log_msg[1000];
sprintf(log_msg, "PCCC: Error occured while processing Protected Logical Read\n");
log(log_msg);
openplc_log(log_msg);
return -1;
}//return length as -1 to signify that the CMD Code/Function Code was not recognize

View File

@@ -86,7 +86,7 @@ void startPstorage()
char log_msg[1000];
sprintf(log_msg, "Starting Persistent Storage thread\n");
log(log_msg);
openplc_log(log_msg);
//Run the main thread
while (run_pstorage)
@@ -105,7 +105,7 @@ void startPstorage()
if (file == NULL)
{
sprintf(log_msg, "Persistent Storage: Error creating persistent memory file!\n");
log(log_msg);
openplc_log(log_msg);
return;
}
// Update the stored checksum
@@ -118,7 +118,7 @@ void startPstorage()
if (fwrite(&value, sizeof(uint16_t), 1, file) != 1)
{
sprintf(log_msg, "Persistent Storage: Error writing int_memory to file\n");
log(log_msg);
openplc_log(log_msg);
}
}
// Write the contents of dint_memory
@@ -128,7 +128,7 @@ void startPstorage()
if (fwrite(&value, sizeof(uint32_t), 1, file) != 1)
{
sprintf(log_msg, "Persistent Storage: Error writing dint_memory to file\n");
log(log_msg);
openplc_log(log_msg);
}
}
@@ -139,7 +139,7 @@ void startPstorage()
if (fwrite(&value, sizeof(uint64_t), 1, file) != 1)
{
sprintf(log_msg, "Persistent Storage: Error writing lint_memory to file\n");
log(log_msg);
openplc_log(log_msg);
}
}
@@ -171,7 +171,7 @@ int readPersistentStorage()
if (file == NULL)
{
sprintf(log_msg, "Persistent Storage is empty\n");
log(log_msg);
openplc_log(log_msg);
pstorage_read = true;
return 0;
}
@@ -186,7 +186,7 @@ int readPersistentStorage()
{
if (feof(file)) break; // Stop on end of file
sprintf(log_msg, "Error reading int_memory from file");
log(log_msg);
openplc_log(log_msg);
pthread_mutex_unlock(&bufferLock); //unlock mutex
fclose(file);
pstorage_read = true;
@@ -203,7 +203,7 @@ int readPersistentStorage()
if (int_memory[i] == NULL)
{
sprintf(log_msg, "Error allocating memory for int_memory[%d]", i);
log(log_msg);
openplc_log(log_msg);
continue;
}
}
@@ -220,7 +220,7 @@ int readPersistentStorage()
{
if (feof(file)) break; // Stop on end of file
sprintf(log_msg, "Error reading dint_memory from file");
log(log_msg);
openplc_log(log_msg);
pthread_mutex_unlock(&bufferLock); //unlock mutex
fclose(file);
pstorage_read = true;
@@ -237,7 +237,7 @@ int readPersistentStorage()
if (dint_memory[i] == NULL)
{
sprintf(log_msg, "Error allocating memory for dint_memory[%d]", i);
log(log_msg);
openplc_log(log_msg);
continue;
}
}
@@ -254,7 +254,7 @@ int readPersistentStorage()
{
if (feof(file)) break; // Stop on end of file
sprintf(log_msg, "Error reading lint_memory from file");
log(log_msg);
openplc_log(log_msg);
pthread_mutex_unlock(&bufferLock); //unlock mutex
fclose(file);
pstorage_read = true;
@@ -271,7 +271,7 @@ int readPersistentStorage()
if (lint_memory[i] == NULL)
{
sprintf(log_msg, "Error allocating memory for lint_memory[%d]", i);
log(log_msg);
openplc_log(log_msg);
continue;
}
}
@@ -283,7 +283,7 @@ int readPersistentStorage()
fclose(file);
sprintf(log_msg, "Persistent Storage: Finished reading persistent memory\n");
log(log_msg);
openplc_log(log_msg);
pstorage_read = true;
return 0;
}

View File

@@ -0,0 +1,171 @@
//-----------------------------------------------------------------------------
// Copyright 2025 Thiago Alves
// This file is part of the OpenPLC Runtime.
//
// OpenPLC is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenPLC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with OpenPLC. If not, see <http://www.gnu.org/licenses/>.
//------
//
// This file is responsible for loading function blocks written in Python
// Thiago Alves, Ago 2025
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "ladder.h"
void *runner_thread(void *arg)
{
char log_msg[1024];
const char *cmd = (const char *)arg;
FILE *fp = popen(cmd, "r");
if (fp == NULL)
{
snprintf(log_msg, sizeof(log_msg), "Failed to start process: %s\n", cmd);
openplc_log(log_msg);
return NULL;
}
char buffer[512];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
{
snprintf(log_msg, sizeof(log_msg), "[Python] %s", buffer);
openplc_log(log_msg);
}
pclose(fp);
return NULL;
}
int create_shm_name(char *buf, size_t size)
{
char log_msg[1024];
char shm_mask[] = "/tmp/shmXXXXXXXXXXXX";
int fd = mkstemp(shm_mask);
if (fd == -1)
{
snprintf(log_msg, sizeof(log_msg), "mkstemp failed: %s\n", strerror(errno));
openplc_log(log_msg);
return -1;
}
close(fd);
snprintf(buf, size, "/%s", strrchr(shm_mask, '/') + 1);
unlink(shm_mask);
return 0;
}
int python_block_loader(const char *script_name, const char *script_content, char *shm_name, size_t shm_in_size, size_t shm_out_size, void **shm_in_ptr, void **shm_out_ptr, pid_t pid)
{
char log_msg[1024];
char shm_in_name[1024];
char shm_out_name[1024];
FILE *fp = fopen(script_name, "w");
if (!fp)
{
snprintf(log_msg, sizeof(log_msg), "[Python loader] Failed to write Python script: %s\n", strerror(errno));
openplc_log(log_msg);
return -1;
}
chmod(script_name, 0640);
snprintf(log_msg, sizeof(log_msg), "Random shared memory location: %s\n", shm_name);
openplc_log(log_msg);
snprintf(shm_in_name, sizeof(shm_in_name), "%s_in", shm_name);
snprintf(shm_out_name, sizeof(shm_out_name), "%s_out", shm_name);
fprintf(fp, script_content, pid, shm_name, shm_name);
fflush(fp);
fsync(fileno(fp));
fclose(fp);
// Map shared memory (inputs)
int shm_in_fd = shm_open(shm_in_name, O_CREAT | O_RDWR, 0660);
if (shm_in_fd < 0)
{
snprintf(log_msg, sizeof(log_msg), "shm_open error: %s", strerror(errno));
openplc_log(log_msg);
return -1;
}
if (ftruncate(shm_in_fd, shm_in_size) == -1)
{
snprintf(log_msg, sizeof(log_msg), "ftruncate error: %s", strerror(errno));
openplc_log(log_msg);
close(shm_in_fd);
return -1;
}
*shm_in_ptr = mmap(NULL, shm_in_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_in_fd, 0);
if (*shm_in_ptr == MAP_FAILED)
{
snprintf(log_msg, sizeof(log_msg), "mmap error: %s", strerror(errno));
openplc_log(log_msg);
close(shm_in_fd);
return -1;
}
// Map shared memory (outputs)
int shm_out_fd = shm_open(shm_out_name, O_CREAT | O_RDWR, 0660);
if (shm_out_fd < 0)
{
snprintf(log_msg, sizeof(log_msg), "shm_open error: %s", strerror(errno));
openplc_log(log_msg);
close(shm_in_fd);
munmap(*shm_in_ptr, shm_in_size);
shm_unlink(shm_in_name);
return -1;
}
if (ftruncate(shm_out_fd, shm_out_size) == -1)
{
snprintf(log_msg, sizeof(log_msg), "ftruncate error: %s", strerror(errno));
openplc_log(log_msg);
close(shm_out_fd);
close(shm_in_fd);
munmap(*shm_in_ptr, shm_in_size);
shm_unlink(shm_in_name);
return -1;
}
*shm_out_ptr = mmap(NULL, shm_out_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_out_fd, 0);
if (*shm_out_ptr == MAP_FAILED)
{
snprintf(log_msg, sizeof(log_msg), "mmap error: %s", strerror(errno));
openplc_log(log_msg);
close(shm_out_fd);
close(shm_in_fd);
munmap(*shm_in_ptr, shm_in_size);
shm_unlink(shm_in_name);
return -1;
}
close(shm_in_fd);
close(shm_out_fd);
pthread_t tid;
char cmd[512];
snprintf(cmd, sizeof(cmd), "python3 -u %s 2>&1", script_name);
pthread_create(&tid, NULL, runner_thread, (void *)cmd);
pthread_detach(tid);
return 0;
}

View File

@@ -95,7 +95,7 @@ int createSocket(uint16_t port)
if (socket_fd<0)
{
sprintf(log_msg, "Server: error creating stream socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
@@ -116,14 +116,14 @@ int createSocket(uint16_t port)
if (bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
{
sprintf(log_msg, "Server: error binding socket => %s\n", strerror(errno));
log(log_msg);
openplc_log(log_msg);
return -1;
}
// we accept max 5 pending connections
listen(socket_fd,5);
sprintf(log_msg, "Server: Listening on port %d\n", port);
log(log_msg);
openplc_log(log_msg);
return socket_fd;
}
@@ -146,7 +146,7 @@ int waitForClient(int socket_fd, int protocol_type)
run_server = &run_enip;
sprintf(log_msg, "Server: waiting for new client...\n");
log(log_msg);
openplc_log(log_msg);
client_len = sizeof(client_addr);
while (*run_server)
@@ -196,7 +196,7 @@ void processMessage(unsigned char *buffer, int bufferSize, int client_fd, int pr
{
char log_msg[1000];
sprintf(log_msg, "Server: Error writing response: %zd\n", bytesWritten);
log(log_msg);
openplc_log(log_msg);
break;
}
buffer += bytesWritten;
@@ -223,7 +223,7 @@ void *handleConnections(void *arguments)
run_server = &run_enip;
sprintf(log_msg, "Server: Thread created for client ID: %d\n", client_fd);
log(log_msg);
openplc_log(log_msg);
while(*run_server)
{
@@ -244,12 +244,12 @@ void *handleConnections(void *arguments)
if (messageSize == 0)
{
sprintf(log_msg, "Modbus Server: client ID: %d has closed the connection\n", client_fd);
log(log_msg);
openplc_log(log_msg);
}
else
{
sprintf(log_msg, "Modbus Server: Something is wrong with the client ID: %d message Size : %i\n", client_fd, messageSize);
log(log_msg);
openplc_log(log_msg);
}
break;
}
@@ -259,7 +259,7 @@ void *handleConnections(void *arguments)
//printf("Debug: Closing client socket and calling pthread_exit in server.cpp\n");
close(client_fd);
sprintf(log_msg, "Terminating Modbus connections thread\r\n");
log(log_msg);
openplc_log(log_msg);
pthread_exit(NULL);
}
@@ -290,7 +290,7 @@ void startServer(uint16_t port, int protocol_type)
if (client_fd < 0)
{
sprintf(log_msg, "Server: Error accepting client!\n");
log(log_msg);
openplc_log(log_msg);
}
else
@@ -299,7 +299,7 @@ void startServer(uint16_t port, int protocol_type)
pthread_t thread;
int ret = -1;
sprintf(log_msg, "Server: Client accepted! Creating thread for the new client ID: %d...\n", client_fd);
log(log_msg);
openplc_log(log_msg);
arguments[0] = client_fd;
arguments[1] = protocol_type;
ret = pthread_create(&thread, NULL, handleConnections, (void*)arguments);
@@ -312,5 +312,5 @@ void startServer(uint16_t port, int protocol_type)
close(socket_fd);
close(client_fd);
sprintf(log_msg, "Terminating Server thread\r\n");
log(log_msg);
openplc_log(log_msg);
}

View File

@@ -112,7 +112,7 @@ void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *resu
*
* @param logmsg Pointer to a null-terminated string containing the message to be logged
*/
void log(char *logmsg)
void openplc_log(char *logmsg)
{
pthread_mutex_lock(&logLock); // lock mutex

View File

@@ -134,7 +134,7 @@ login_body = """
<button>login</button>
</form>
</div>
<h3 style="font-family:'roboto', sans-serif; font-size:14px; color:#ffffff;">Release: 2025-03-31</h3>
<h3 style="font-family:'roboto', sans-serif; font-size:14px; color:#ffffff;">Release: 2025-09-08</h3>
</div>
</div>
</body>