Merge pull request #269 from davenardella/master

S7 Protocol driver update
This commit is contained in:
Thiago Alves
2025-03-19 08:30:02 -04:00
committed by GitHub
13 changed files with 174 additions and 67 deletions

View File

@@ -335,6 +335,8 @@ elif [ "$1" == "win_msys2" ]; then
exit 1
fi
cp -f ./utils/snap7_src/build/bin/win64/snap7.* ./webserver/core/
install_st_optimizer
install_glue_generator
disable_opendnp3

View File

@@ -749,6 +749,7 @@ bool TS7Partner::Linked()
//******************************************************************************
TS7Server *Server = NULL;
bool s7Inited = false;
#define MAX_S7IO BUFFER_SIZE*8
#define MK_SIZE 16
@@ -1248,32 +1249,56 @@ int S7API RWAreaCallBack(void* usrPtr, int Sender, int Operation, PS7Tag PTag, v
//------------------------------------------------------------------------------
void initializeSnap7()
{
s7mapUnusedVars();
if (!s7Inited)
{
s7mapUnusedVars();
Server = new TS7Server;
// With the next function we can limit the events to start/stop/client added etc.
// For a deep debug comment the line
Server->SetEventsMask(0x3ff);
// Set the Server events callback
Server->SetEventsCallback(EventCallBack, NULL);
Server = new TS7Server;
// With the next function we can limit the events to start/stop/client added etc.
// For a deep debug comment the line
Server->SetEventsMask(0x3ff);
// Set the Server events callback
Server->SetEventsCallback(EventCallBack, NULL);
// Shared resources:
// We cannot directly share OpenPLC internal buffers, because:
// 1 - They are array of pointers to vars
// 2 - The access would be not synchronized (i.e. not consistent)
// So, we will use a callback and, inside it, we will perform a synchronized data transfer.
Server->SetRWAreaCallback(RWAreaCallBack, NULL);
// Listen on S7 Port (102)
Server->StartTo("0.0.0.0"); // Success or fail will be logged into EventCallBack
// Shared resources:
// We cannot directly share OpenPLC internal buffers, because:
// 1 - They are array of pointers to vars
// 2 - The access would be not synchronized (i.e. not consistent)
// So, we will use a callback and, inside it, we will perform a synchronized data transfer.
Server->SetRWAreaCallback(RWAreaCallBack, NULL);
s7Inited = true;
}
}
//------------------------------------------------------------------------------
// Snap7 Server start
//------------------------------------------------------------------------------
void startSnap7()
{
// Listen on S7 Port 102.
// If Server is already running the command will be ignored.
if (s7Inited)
Server->StartTo("0.0.0.0"); // Success or fail will be logged into EventCallBack
}
//------------------------------------------------------------------------------
// Snap7 Server stop
//------------------------------------------------------------------------------
void stopSnap7()
{
// If Server is already stopped the command will be ignored.
if (s7Inited)
Server->Stop();
}
//------------------------------------------------------------------------------
// Snap7 Server destruction
//------------------------------------------------------------------------------
void finalizeSnap7()
{
if (Server != NULL)
if (s7Inited)
{
s7Inited = false;
Server->Stop();
delete Server;
Server = NULL;

View File

@@ -943,8 +943,8 @@ typedef TS7Partner *PS7Partner;
void initializeSnap7();
void finalizeSnap7();
void startSnap7();
void stopSnap7();
#endif // __cplusplus
#endif // snap7_h

View File

@@ -119,6 +119,7 @@ def checkTableSettings(conn):
checkSettingExists(conn, 'Modbus_port', '502')
checkSettingExists(conn, 'Dnp3_port', '20000')
checkSettingExists(conn, 'Start_run_mode', 'false')
checkSettingExists(conn, 'snap7', 'false')
checkSettingExists(conn, 'Slave_polling', '100')
checkSettingExists(conn, 'Slave_timeout', '1000')
checkSettingExists(conn, 'Enip_port', '44818')

View File

@@ -36,6 +36,8 @@
#include <time.h>
#include "ladder.h"
#include "oplc_snap7.h"
#define BUFFER_SIZE 1024
//Global Variables
@@ -43,6 +45,7 @@ bool ethercat_configured = 0;
char ethercat_conf_file[BUFFER_SIZE];
bool run_modbus = 0;
uint16_t modbus_port = 502;
bool run_snap7 = 0;
bool run_dnp3 = 0;
uint16_t dnp3_port = 20000;
bool run_enip = 0;
@@ -263,6 +266,13 @@ void processCommand(unsigned char *buffer, int client_fd)
sprintf(log_msg, "DNP3 server was stopped\n");
log(log_msg);
}
if (run_snap7)
{
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
}
run_openplc = 0;
processing_command = false;
}
@@ -314,6 +324,40 @@ void processCommand(unsigned char *buffer, int client_fd)
}
processing_command = false;
}
else if (strncmp(buffer, "start_snap7()", 13) == 0)
{
processing_command = true;
sprintf(log_msg, "Issued start_snap7() command\n");
log(log_msg);
if (run_snap7)
{
sprintf(log_msg, "Snap7 server already active. Restarting it\n");
log(log_msg);
//Stop Modbus server
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
}
//Start Modbus server
run_snap7 = 1;
startSnap7();
processing_command = false;
}
else if (strncmp(buffer, "stop_snap7()", 12) == 0)
{
processing_command = true;
sprintf(log_msg, "Issued stop_snap7() command\n");
log(log_msg);
if (run_snap7)
{
run_snap7 = 0;
stopSnap7();
sprintf(log_msg, "Snap7 server was stopped\n");
log(log_msg);
}
processing_command = false;
}
else if (strncmp(buffer, "start_dnp3(", 11) == 0)
{
processing_command = true;

View File

@@ -37,9 +37,7 @@
#include "ethercat_src.h"
#endif
#ifdef _snap7
#include "oplc_snap7.h"
#endif
#define OPLC_CYCLE 50000000
@@ -119,10 +117,11 @@ int main(int argc,char **argv)
readPersistentStorage();
//pthread_t persistentThread;
//pthread_create(&persistentThread, NULL, persistentStorage, NULL);
#ifdef _snap7
//======================================================
// S7 PROTOCOL INITIALIZATION
//======================================================
initializeSnap7();
#endif
@@ -253,10 +252,7 @@ int main(int argc,char **argv)
ethercat_terminate_src();
#endif
#ifdef _snap7
finalizeSnap7();
#endif
printf("Disabling outputs\n");
disableOutputs();
updateBuffersOut();

Binary file not shown.

View File

@@ -196,6 +196,12 @@ class runtime:
def stop_modbus(self):
return self._rpc(f'stop_modbus()')
def start_snap7(self):
return self._rpc(f'start_snap7()')
def stop_snap7(self):
return self._rpc(f'stop_snap7()')
def start_dnp3(self, port_num):
return self._rpc(f'start_dnp3({port_num})')

View File

@@ -1202,6 +1202,8 @@ settings_tail = """
var pstorage_text = document.getElementById('pstorage_thread_poll');
var auto_run_checkbox = document.getElementById('auto_run');
var auto_run_text = document.getElementById('auto_run_text');
var snap7_run_checkbox = document.getElementById('snap7_run');
var snap7_run_text = document.getElementById('snap7_run_text');
if (modbus_checkbox.checked == true)
{
@@ -1247,6 +1249,14 @@ settings_tail = """
{
auto_run_text.value = 'false';
}
if (snap7_run_checkbox.checked == true)
{
snap7_run_text.value = 'true';
}
else
{
snap7_run_text.value = 'false';
}
}
document.getElementById('modbus_server').onchange = function()
@@ -1274,6 +1284,11 @@ settings_tail = """
setupCheckboxes();
}
document.getElementById('snap7_run').onchange = function()
{
setupCheckboxes();
}
function validateForm()
{
var modbus_checkbox = document.forms["uploadForm"]["modbus_server"].checked;

View File

@@ -10,7 +10,6 @@ cd scripts &>/dev/null
OPENPLC_PLATFORM=$(cat openplc_platform)
ETHERCAT_OPT=$(cat ethercat)
OPENPLC_DRIVER=$(cat openplc_driver)
S7_OPT=$(cat s7protocol)
#store the active program filename
echo "$1" > ../active_program
@@ -30,26 +29,9 @@ if [ "$ETHERCAT_OPT" = "ethercat" ]; then
sed -i '7s/^/#include "ethercat_src.h" /' Res0.c
fi
#check for S7 Protocol option
if [ "$S7_OPT" = "s7protocol" ]; then
S7_LIB="-lsnap7"
S7_DEF="-D _snap7"
S7_WLIB="snap7.lib"
cp -f ../utils/snap7_src/wrapper/oplc_snap7.* ./core
if [ "$OPENPLC_PLATFORM" = "win" ]; then
cp -f ../utils/snap7_src/build/bin/win64/snap7.* ./core
fi
echo "Including Siemens S7 Protocol via snap7"
else
S7_LIB=""
S7_DEF=""
S7_WLIB=""
# remove snap7 references (if any)
rm -f ./core/oplc_snap7.*
if [ "$OPENPLC_PLATFORM" = "win" ]; then
rm -f ./core/snap7.*
fi
fi
# I prefer copying every time these two (small files) because could be useful to have a copy of them for testing
echo "Including Siemens S7 Protocol via snap7"
cp -f ../utils/snap7_src/wrapper/oplc_snap7.* ./core
echo "Moving Files..."
mv -f POUS.c POUS.h LOCATED_VARIABLES.h VARIABLES.csv Config0.c Config0.h Res0.c ./core/
@@ -86,7 +68,7 @@ if [ "$OPENPLC_PLATFORM" = "win" ]; then
echo "Generating glueVars..."
./glue_generator
echo "Compiling main program..."
g++ *.cpp *.o -o openplc -I ./lib -pthread -fpermissive -I /usr/local/include/modbus -L /usr/local/lib $S7_WLIB -lmodbus -w $S7_DEF
g++ *.cpp *.o -o openplc -I ./lib -pthread -fpermissive -I /usr/local/include/modbus -L /usr/local/lib snap7.lib -lmodbus -w
if [ $? -ne 0 ]; then
echo "Error compiling C files"
echo "Compilation finished with errors!"
@@ -99,9 +81,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
echo "Compiling for Linux"
echo "Generating object files..."
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSL_RP4
g++ -std=gnu++11 -I ./lib -c Config0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSL_RP4
else
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
g++ -std=gnu++11 -I ./lib -c Config0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -109,9 +91,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
exit 1
fi
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF -DSL_RP4
g++ -std=gnu++11 -I ./lib -c Res0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC -DSL_RP4
else
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF
g++ -std=gnu++11 -I ./lib -c Res0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -122,9 +104,9 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
./glue_generator
echo "Compiling main program..."
if [ "$OPENPLC_DRIVER" = "sl_rp4" ]; then
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF -DSL_RP4
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC -DSL_RP4
else
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC $S7_DEF
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $ETHERCAT_INC
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -138,9 +120,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
echo "Compiling for Raspberry Pi"
echo "Generating object files..."
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
g++ -std=gnu++11 -I ./lib -c Config0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
else
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
g++ -std=gnu++11 -I ./lib -c Config0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -148,9 +130,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
exit 1
fi
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
g++ -std=gnu++11 -I ./lib -c Res0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -DSEQUENT
else
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
g++ -std=gnu++11 -I ./lib -c Res0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -161,9 +143,9 @@ elif [ "$OPENPLC_PLATFORM" = "rpi" ]; then
./glue_generator
echo "Compiling main program..."
if [ "$OPENPLC_DRIVER" = "sequent" ]; then
g++ -DSEQUENT -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal $S7_DEF -w
g++ -DSEQUENT -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
else
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal $S7_DEF -w
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpigpio -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
fi
if [ $? -ne 0 ]; then
echo "Error compiling C files"
@@ -177,13 +159,13 @@ elif [ "$OPENPLC_PLATFORM" = "opi" ]; then
WIRINGOP_INC="-I/usr/local/include -L/usr/local/lib -lwiringPi -lwiringPiDev"
echo "Compiling for Orange Pi"
echo "Generating object files..."
g++ -std=gnu++11 -I ./lib -c Config0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
g++ -std=gnu++11 -I ./lib -c Config0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
if [ $? -ne 0 ]; then
echo "Error compiling C files"
echo "Compilation finished with errors!"
exit 1
fi
g++ -std=gnu++11 -I ./lib -c Res0.c $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
g++ -std=gnu++11 -I ./lib -c Res0.c -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
if [ $? -ne 0 ]; then
echo "Error compiling C files"
echo "Compilation finished with errors!"
@@ -192,7 +174,7 @@ elif [ "$OPENPLC_PLATFORM" = "opi" ]; then
echo "Generating glueVars..."
./glue_generator
echo "Compiling main program..."
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` $S7_LIB -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $S7_DEF $WIRINGOP_INC
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -lrt -lpthread -fpermissive `pkg-config --cflags --libs libmodbus` -lsnap7 -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w $WIRINGOP_INC
if [ $? -ne 0 ]; then
echo "Error compiling C files"
echo "Compilation finished with errors!"

View File

@@ -1 +0,0 @@
#s7protocol

View File

@@ -93,6 +93,13 @@ def configure_runtime():
else:
print("Disabling EtherNet/IP")
openplc_runtime.stop_enip()
elif (row[0] == "snap7"):
if (row[1] != "false"):
print("Enabling S7 Protocol")
openplc_runtime.start_snap7()
else:
print("Disabling S7 Protocol")
openplc_runtime.stop_snap7()
elif (row[0] == "Pstorage_polling"):
if (row[1] != "disabled"):
print("Enabling Persistent Storage with polling rate of " + str(int(row[1])) + " seconds")
@@ -2188,6 +2195,9 @@ def settings():
slave_polling = str(row[1])
elif (row[0] == "Slave_timeout"):
slave_timeout = str(row[1])
elif (row[0] == "snap7"):
start_snap7 = str(row[1])
if (modbus_port == 'disabled'):
return_str += """
@@ -2206,6 +2216,25 @@ def settings():
return_str += """
<br>
<br>
<br>
<label class="container">
<b>Enable S7 Protocol</b>"""
if (start_snap7 == 'false'):
return_str += """
<input id="snap7_run" type="checkbox">
<span class="checkmark"></span>
</label>
<input type='hidden' value='false' id='snap7_run_text' name='snap7_run_text'/>"""
else:
return_str += """
<input id="snap7_run" type="checkbox" checked>
<span class="checkmark"></span>
</label>
<input type='hidden' value='true' id='snap7_run_text' name='snap7_run_text'/>"""
return_str += """
<br>
<br>
<label class="container">
@@ -2288,8 +2317,8 @@ def settings():
<input id="auto_run" type="checkbox" checked>
<span class="checkmark"></span>
</label>
<input type='hidden' value='true' id='auto_run_text' name='auto_run_text'/>"""
<input type='hidden' value='true' id='auto_run_text' name='auto_run_text'/>"""
return_str += """
<br>
<h2>Slave Devices</h2>
@@ -2318,11 +2347,12 @@ def settings():
enip_port = flask.request.form.get('enip_server_port')
pstorage_poll = flask.request.form.get('pstorage_thread_poll')
start_run = flask.request.form.get('auto_run_text')
start_snap7 = flask.request.form.get('snap7_run_text')
slave_polling = flask.request.form.get('slave_polling_period')
slave_timeout = flask.request.form.get('slave_timeout')
device_hostname = flask.request.form.get('device_hostname')
(modbus_port, dnp3_port, enip_port, pstorage_poll, start_run, slave_polling, slave_timeout, device_hostname) = sanitize_input(modbus_port, dnp3_port, enip_port, pstorage_poll, start_run, slave_polling, slave_timeout, device_hostname)
(modbus_port, dnp3_port, enip_port, pstorage_poll, start_run, start_snap7, slave_polling, slave_timeout, device_hostname) = sanitize_input(modbus_port, dnp3_port, enip_port, pstorage_poll, start_run, start_snap7, slave_polling, slave_timeout, device_hostname)
# Change hostname if needed
current_hostname = socket.gethostname()
@@ -2369,6 +2399,13 @@ def settings():
cur.execute("UPDATE Settings SET Value = 'false' WHERE Key = 'Start_run_mode'")
conn.commit()
if (start_snap7 == 'true'):
cur.execute("UPDATE Settings SET Value = 'true' WHERE Key = 'snap7'")
conn.commit()
else:
cur.execute("UPDATE Settings SET Value = 'false' WHERE Key = 'snap7'")
conn.commit()
cur.execute("UPDATE Settings SET Value = ? WHERE Key = 'Slave_polling'", (str(slave_polling),))
conn.commit()