mirror of
https://github.com/thiagoralves/OpenPLC_v3.git
synced 2026-09-21 17:53:42 +08:00
@@ -15,3 +15,4 @@ CMakeSettings.json
|
||||
webserver/bin
|
||||
webserver/build
|
||||
obj/
|
||||
utils/dnp3_src/CMakeFiles/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "utils/ethercat_src"]
|
||||
path = utils/ethercat_src
|
||||
url = https://github.com/r2k-in-the-vortex/ethercat_src.git
|
||||
@@ -98,6 +98,16 @@ function install_all_libs {
|
||||
fi
|
||||
cd ../..
|
||||
|
||||
echo ""
|
||||
echo "[EtherCAT]"
|
||||
cd utils/ethercat_src
|
||||
mkdir -p build
|
||||
sudo cmake -S . -B build/
|
||||
sudo cmake --build build/
|
||||
sudo cmake --install build/
|
||||
sudo /sbin/ldconfig -v | grep ethercat
|
||||
cd ../..
|
||||
|
||||
echo ""
|
||||
echo "[OPEN DNP3]"
|
||||
cd utils/dnp3_src
|
||||
|
||||
Submodule
+1
Submodule utils/ethercat_src added at 9e7007f5f0
@@ -0,0 +1,156 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Checks and initializes default database if needed
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
import sqlite3
|
||||
from sqlite3 import Error
|
||||
import os
|
||||
|
||||
builddir = r"build/"
|
||||
dbfile = r"build/openplc.db"
|
||||
|
||||
createTablePrograms = r"""CREATE TABLE `Programs` (
|
||||
`Prog_ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`Name` TEXT NOT NULL,
|
||||
`Description` TEXT,
|
||||
`File` TEXT NOT NULL,
|
||||
`Date_upload` INTEGER NOT NULL
|
||||
)"""
|
||||
|
||||
insertblankProgram = r"INSERT INTO Programs VALUES (1, 'Blank Program', 'Dummy empty program', 'blank_program.st', 1527184953)"
|
||||
|
||||
createTableSettings = r"""CREATE TABLE `Settings` (
|
||||
`Key` TEXT NOT NULL UNIQUE,
|
||||
`Value` TEXT NOT NULL,
|
||||
PRIMARY KEY(`Key`)
|
||||
)"""
|
||||
|
||||
|
||||
createTableSlave_dev = r"""CREATE TABLE "Slave_dev" (
|
||||
"dev_id" INTEGER NOT NULL UNIQUE,
|
||||
"dev_name" TEXT NOT NULL UNIQUE,
|
||||
"dev_type" TEXT NOT NULL,
|
||||
"slave_id" INTEGER NOT NULL,
|
||||
"com_port" TEXT,
|
||||
"baud_rate" INTEGER,
|
||||
"parity" TEXT,
|
||||
"data_bits" INTEGER,
|
||||
"stop_bits" INTEGER,
|
||||
"ip_address" TEXT,
|
||||
"ip_port" INTEGER,
|
||||
"di_start" INTEGER NOT NULL,
|
||||
"di_size" INTEGER NOT NULL,
|
||||
"coil_start" INTEGER NOT NULL,
|
||||
"coil_size" INTEGER NOT NULL,
|
||||
"ir_start" INTEGER NOT NULL,
|
||||
"ir_size" INTEGER NOT NULL,
|
||||
"hr_read_start" INTEGER NOT NULL,
|
||||
"hr_read_size" INTEGER NOT NULL,
|
||||
"hr_write_start" INTEGER NOT NULL,
|
||||
"hr_write_size" INTEGER NOT NULL,
|
||||
"pause" INTEGER,
|
||||
PRIMARY KEY("dev_id" AUTOINCREMENT)
|
||||
)"""
|
||||
|
||||
createTableUsers = r"""CREATE TABLE "Users" (
|
||||
`user_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT NOT NULL,
|
||||
`username` TEXT NOT NULL UNIQUE,
|
||||
`email` TEXT,
|
||||
`password` TEXT NOT NULL,
|
||||
`pict_file` TEXT
|
||||
)"""
|
||||
|
||||
insertDefaultUser = r"INSERT INTO Users VALUES (10, 'OpenPLC User', 'openplc', 'openplc@openplc.com','openplc', NULL)"
|
||||
|
||||
|
||||
|
||||
gettablesQuery = r"""SELECT name FROM sqlite_master
|
||||
WHERE type='table';"""
|
||||
getsettingsQuery = r"""SELECT Key FROM Settings"""
|
||||
|
||||
# return true if created fresh table
|
||||
def checkTableExists(conn, tablename, tablecreatecommand):
|
||||
cur = conn.cursor()
|
||||
cur.execute(gettablesQuery)
|
||||
rows = cur.fetchall()
|
||||
for row in rows:
|
||||
if row[0] == tablename:
|
||||
cur.close()
|
||||
return False
|
||||
print(tablename, " didn't exist, creating")
|
||||
cur.execute(tablecreatecommand)
|
||||
cur.close()
|
||||
return True
|
||||
|
||||
def checkTablePrograms(conn):
|
||||
if checkTableExists(conn, "Programs", createTablePrograms):
|
||||
cur = conn.cursor()
|
||||
cur.execute(insertblankProgram)
|
||||
cur.close()
|
||||
return
|
||||
|
||||
def checkTableUsers(conn):
|
||||
if checkTableExists(conn, "Users", createTableUsers):
|
||||
cur = conn.cursor()
|
||||
cur.execute(insertDefaultUser)
|
||||
cur.close()
|
||||
return
|
||||
|
||||
# if code has new features, old database might not have required settings
|
||||
def checkSettingExists(conn, setting, defaultvalue):
|
||||
cur = conn.cursor()
|
||||
cur.execute(getsettingsQuery)
|
||||
rows = cur.fetchall()
|
||||
for row in rows:
|
||||
if row[0] == setting:
|
||||
cur.close()
|
||||
return False
|
||||
print(setting, " didn't exist, creating")
|
||||
cur.execute("INSERT INTO Settings VALUES (?, ?)", (setting, defaultvalue))
|
||||
cur.close()
|
||||
return
|
||||
|
||||
def checkTableSettings(conn):
|
||||
checkTableExists(conn, "Settings", createTableSettings)
|
||||
checkSettingExists(conn, 'Modbus_port', '502')
|
||||
checkSettingExists(conn, 'Dnp3_port', '20000')
|
||||
checkSettingExists(conn, 'Start_run_mode', 'false')
|
||||
checkSettingExists(conn, 'Slave_polling', '100')
|
||||
checkSettingExists(conn, 'Slave_timeout', '1000')
|
||||
checkSettingExists(conn, 'Enip_port', '44818')
|
||||
checkSettingExists(conn, 'Pstorage_polling', 'disabled')
|
||||
return
|
||||
|
||||
def checkTableSlave_dev(conn):
|
||||
checkTableExists(conn, "Slave_dev", createTableSlave_dev)
|
||||
return
|
||||
|
||||
def create_connection():
|
||||
""" create a database connection to a SQLite database """
|
||||
if not os.path.exists(builddir):
|
||||
os.mkdir(builddir)
|
||||
|
||||
conn = None
|
||||
try:
|
||||
conn = sqlite3.connect(dbfile)
|
||||
checkTablePrograms(conn)
|
||||
checkTableUsers(conn)
|
||||
checkTableSettings(conn)
|
||||
checkTableSlave_dev(conn)
|
||||
except Error as e:
|
||||
print(sqlite3.version)
|
||||
print(e)
|
||||
finally:
|
||||
if conn:
|
||||
# NB, if you close without commiting, last actions might not be saved
|
||||
conn.commit()
|
||||
return conn
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
conn = create_connection()
|
||||
conn.close()
|
||||
@@ -36,8 +36,11 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "ladder.h"
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
//Global Variables
|
||||
bool ethercat_configured = 0;
|
||||
char ethercat_conf_file[BUFFER_SIZE];
|
||||
bool run_modbus = 0;
|
||||
uint16_t modbus_port = 502;
|
||||
bool run_dnp3 = 0;
|
||||
@@ -58,6 +61,12 @@ pthread_t dnp3_thread;
|
||||
pthread_t enip_thread;
|
||||
pthread_t pstorage_thread;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Configure Ethercat
|
||||
//-----------------------------------------------------------------------------
|
||||
int configureEthercat(){
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Start the Modbus Thread
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -111,6 +120,28 @@ int readCommandArgument(unsigned char *command)
|
||||
|
||||
return atoi(argument);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Read string argument from a command function
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char *readCommandArgumentStr(unsigned char *command)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char *argument;
|
||||
argument = (unsigned char *)malloc(1024 * sizeof(unsigned char));
|
||||
|
||||
while (command[i] != '(' && command[i] != '\0') i++;
|
||||
if (command[i] == '(') i++;
|
||||
while (command[i] != ')' && command[i] != '\0')
|
||||
{
|
||||
argument[j] = command[i];
|
||||
i++;
|
||||
j++;
|
||||
argument[j] = '\0';
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Create the socket and bind it. Returns the file descriptor for the socket
|
||||
@@ -235,6 +266,19 @@ void processCommand(unsigned char *buffer, int client_fd)
|
||||
run_openplc = 0;
|
||||
processing_command = false;
|
||||
}
|
||||
else if (strncmp(buffer, "start_ethercat(", 15) == 0)
|
||||
{
|
||||
processing_command = true;
|
||||
char *argument;
|
||||
argument = (char)readCommandArgumentStr(buffer);
|
||||
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);
|
||||
//Configure ethercat
|
||||
ethercat_configured = configureEthercat();
|
||||
processing_command = false;
|
||||
}
|
||||
else if (strncmp(buffer, "start_modbus(", 13) == 0)
|
||||
{
|
||||
processing_command = true;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "iec_types.h"
|
||||
#include "ladder.h"
|
||||
#include "ethercat_src.h"
|
||||
|
||||
#define OPLC_CYCLE 50000000
|
||||
|
||||
@@ -181,6 +182,15 @@ void handleSpecialFunctions()
|
||||
//insert other special functions below
|
||||
}
|
||||
|
||||
// pointers to IO *array[const][const] from cpp to c and back again don't work as expected, so instead callbacks
|
||||
u_int8_t *bool_input_call_back(int a, int b){ return bool_input[a][b]; }
|
||||
u_int8_t *bool_output_call_back(int a, int b){ return bool_output[a][b]; }
|
||||
u_int8_t *byte_input_call_back(int a){ return byte_input[a]; }
|
||||
u_int8_t *byte_output_call_back(int a){ return byte_output[a]; }
|
||||
u_int16_t *int_input_call_back(int a){ return int_input[a]; }
|
||||
u_int16_t *int_output_call_back(int a){ return int_output[a]; }
|
||||
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
unsigned char log_msg[1000];
|
||||
@@ -209,6 +219,7 @@ int main(int argc,char **argv)
|
||||
//======================================================
|
||||
// HARDWARE INITIALIZATION
|
||||
//======================================================
|
||||
ethercat_configure("../utils/ethercat_src/conf/ethercatcfg.txt");
|
||||
initializeHardware();
|
||||
initializeMB();
|
||||
initCustomLayer();
|
||||
@@ -225,6 +236,8 @@ int main(int argc,char **argv)
|
||||
readPersistentStorage();
|
||||
//pthread_t persistentThread;
|
||||
//pthread_create(&persistentThread, NULL, persistentStorage, NULL);
|
||||
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
//======================================================
|
||||
@@ -261,9 +274,28 @@ int main(int argc,char **argv)
|
||||
//attached to the user variables
|
||||
glueVars();
|
||||
|
||||
boolvar_call_back bool_input_callback = bool_input_call_back;
|
||||
boolvar_call_back bool_output_callback = bool_output_call_back;
|
||||
int8var_call_back byte_input_callback = byte_input_call_back;
|
||||
int8var_call_back byte_output_callback = byte_output_call_back;
|
||||
int16var_call_back int_input_callback = int_input_call_back;
|
||||
int16var_call_back int_output_callback = int_output_call_back;
|
||||
|
||||
updateBuffersIn(); //read input image
|
||||
|
||||
pthread_mutex_lock(&bufferLock); //lock mutex
|
||||
|
||||
|
||||
if(ethercat_callcyclic(BUFFER_SIZE,
|
||||
bool_input_callback,
|
||||
bool_output_callback,
|
||||
byte_input_callback,
|
||||
byte_output_callback,
|
||||
int_input_callback,
|
||||
int_output_callback)){
|
||||
printf("EtherCAT cyclic failed\n");
|
||||
break;
|
||||
}
|
||||
updateCustomIn();
|
||||
updateBuffersIn_MB(); //update input image table with data from slave devices
|
||||
handleSpecialFunctions();
|
||||
|
||||
@@ -78,7 +78,7 @@ elif [ "$OPENPLC_PLATFORM" = "linux" ]; then
|
||||
echo "Generating glueVars..."
|
||||
./glue_generator
|
||||
echo "Compiling main program..."
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w
|
||||
g++ -std=gnu++11 *.cpp *.o -o openplc -I ./lib -pthread -fpermissive `pkg-config --cflags --libs libmodbus` -lasiodnp3 -lasiopal -lopendnp3 -lopenpal -w -L../../utils/ethercat_src/build/lib -lethercat_src -I../../utils/ethercat_src/src
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling C files"
|
||||
echo "Compilation finished with errors!"
|
||||
|
||||
Reference in New Issue
Block a user