Merge branch 'master' into fix_defunct

This commit is contained in:
Thiago Alves 2019-04-25 08:55:26 -07:00 committed by GitHub
commit ff8012068a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 17934 additions and 493 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Shell script files should never have line endings converted
*.sh text eol=lf

21
.gitignore vendored
View File

@ -1,10 +1,17 @@
*.py[co]
*.DS_*
# Packages
*.egg
*.egg-info
# where docs are output to on gitlab.. MUST be named public/
public/
.sass-cache/
.idea/
*.pyc
/venv/
.vscode/
# IDE files for Visual Studio Code and Visual Studio
CMakeSettings.json
*.vscode/
*.vs/
# Build directories
webserver/bin
webserver/build
obj/

12
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,12 @@
image: ubuntu
pages:
script:
- apt-get update -qq
- apt-get install -y -qq doxygen graphviz
- doxygen doxygen.conf
artifacts:
paths:
- public
only:
- master

22
.travis.yml Normal file
View File

@ -0,0 +1,22 @@
language: bash
services:
- docker
addons:
apt:
packages:
- doxygen
script:
- docker build .
- doxygen doxygen.conf
#deploy:
# provider: pages
# skip_cleanup: true
# local_dir: public
# github_token: $GITHUB_TOKEN
# keep-history: true
# on:
# branch: master

6
Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM debian
COPY . /workdir
RUN cd /workdir && ./install.sh docker
WORKDIR /workdir
ENTRYPOINT ["./start_openplc.sh"]

View File

@ -1,24 +1,46 @@
# OpenPLC Runtime version 3
[![Build Status](https://travis-ci.org/thiagoralves/OpenPLC_v3.svg?branch=master)](https://travis-ci.org/thiagoralves/OpenPLC_v3)
[![Build status](https://ci.appveyor.com/api/projects/status/ut3466ixwtyf68qg?svg=true)](https://ci.appveyor.com/project/shrmrf/openplc-v3)
OpenPLC is an open-source [Programmable Logic Controller](https://en.wikipedia.org/wiki/Programmable_logic_controller) that is based on easy to use software. Our focus is to provide a low cost industrial solution for automation and research. OpenPLC has been used in [many research papers](https://scholar.google.com/scholar?as_ylo=2014&q=openplc&hl=en&as_sdt=0,1) as a framework for industrial cyber security research, given that it is the only controller to provide the entire source code.
The OpenPLC Project consists of three sub-projects:
1. [Runtime](https://github.com/thiagoralves/OpenPLC_v3)
2. [Programming editor](http://www.openplcproject.com/plcopen-editor)
3. [HMI builder](http://www.openplcproject.com/reference-installing-scadabr)
<br/>
To install:
<br/>
## Installation:
```bash
git clone https://github.com/thiagoralves/OpenPLC_v3.git
<br/>
cd OpenPLC_v3
<br/>
./install.sh [platform]
<br/>
where [platform] can be:
<br/>
win - Install OpenPLC on Windows over Cygwin
<br/>
linux - Install OpenPLC on a Debian-based Linux distribution
<br/>
rpi - Install OpenPLC on a Raspberry Pi
<br/>
custom - Skip all specific package installation and tries to install OpenPLC assuming your system already has all dependencies met. This option can be useful if you're trying to install OpenPLC on an unsuported Linux platform or had manually installed all the dependency packages before.
```
Where `[platform]` can be:
`win` - Install OpenPLC on Windows over Cygwin
`linux` - Install OpenPLC on a Debian-based Linux distribution
`docker` - Used by the `Dockerfile` (i.e. doesn't invoke `sudo`)
`rpi` - Install OpenPLC on a Raspberry Pi
`custom` - Skip all specific package installation and tries to install OpenPLC assuming your system already has all dependencies met. This option can be useful if you're trying to install OpenPLC on an unsuported Linux platform or had manually installed all the dependency packages before.
### Building, Installing and Running inside Docker
Make sure [`docker` is installed](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
#### Build
```
# instead of running install.sh as stated above, run:
docker build -t openplc:v3 .
```
#### RUN
_Devices can be passed to the `docker` daemon using the `-v` flag (e.g. `-v /dev/ttyACM0:/dev/ttyACM0`)_
```bash
docker run -it --rm --privileged -p 8080:8080 openplc:v3
```

14
appveyor.yml Normal file
View File

@ -0,0 +1,14 @@
image: Visual Studio 2015
init:
- git config --global core.autocrlf input
clone_folder: c:\projects
environment:
matrix:
- TARGET: cygwin-gcc
BUILD_ENVIRONMENT: cygwin
install:
# batch commands start from cmd:
- cmd: C:\\cygwin\\bin\\bash -l -c "cd C:/projects; ./install.sh win;"
build: off

2431
doxygen.conf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@ if [ $# -eq 0 ]; then
echo "Usage: ./install.sh [platform] where [platform] can be"
echo " win Install OpenPLC on Windows over Cygwin"
echo " linux Install OpenPLC on a Debian-based Linux distribution"
echo " docker Install OpenPLC in a Docker container"
echo " rpi Install OpenPLC on a Raspberry Pi"
echo " neuron Install OpenPLC on a UniPi Neuron PLC"
echo " custom Skip all specific package installation and tries to install"
@ -17,12 +18,127 @@ if [ $# -eq 0 ]; then
exit 1
fi
set -x
# arg1: sudo or blank
function linux_install_deps {
$1 apt-get update
$1 apt-get install -y build-essential pkg-config bison flex autoconf \
automake libtool make git python2.7 python-pip \
sqlite3 cmake git
}
function install_py_deps {
$1 pip install -r requirements.txt
}
function install_all_libs {
echo ""
echo "[MATIEC COMPILER]"
cd utils/matiec_src
autoreconf -i
./configure
make
cp ./iec2c ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling MatIEC"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
g++ st_optimizer.cpp -o st_optimizer
cp ./st_optimizer ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling ST Optimizer"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
g++ glue_generator.cpp -o glue_generator
cp ./glue_generator ../../webserver/core
if [ $? -ne 0 ]; then
echo "Error compiling Glue Generator"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd utils/dnp3_src
echo "creating swapfile..."
$1 dd if=/dev/zero of=swapfile bs=1M count=1000
$1 mkswap swapfile
$1 swapon swapfile
cmake ../dnp3_src
make
$1 make install
if [ $? -ne 0 ]; then
echo "Error installing OpenDNP3"
echo "OpenPLC was NOT installed!"
exit 1
fi
$1 ldconfig
echo "removing swapfile..."
$1 swapoff swapfile
$1 rm -f ./swapfile
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
./autogen.sh
./configure
$1 make install
if [ $? -ne 0 ]; then
echo "Error installing Libmodbus"
echo "OpenPLC was NOT installed!"
exit 1
fi
$1 ldconfig
cd ../..
if [ "$1" == "sudo" ]; then
echo ""
echo "[OPENPLC SERVICE]"
WORKING_DIR=$(pwd)
echo -e "[Unit]\n\
Description=OpenPLC Service\n\
After=network.target\n\
\n\
[Service]\n\
Type=simple\n\
Restart=always\n\
RestartSec=1\n\
User=root\n\
Group=root\n\
WorkingDirectory=$WORKING_DIR\n\
ExecStart=$WORKING_DIR/start_openplc.sh\n\
\n\
[Install]\n\
WantedBy=multi-user.target" >> openplc.service
$1 cp -rf ./openplc.service /lib/systemd/system/
rm -rf openplc.service
$1 "Enabling OpenPLC Service..."
$1 systemctl daemon-reload
$1 systemctl enable openplc
fi
}
if [ "$1" == "win" ]; then
echo "Installing OpenPLC on Windows"
cp ./utils/apt-cyg/apt-cyg ./
cp ./utils/apt-cyg/wget.exe /bin
install apt-cyg /bin
apt-cyg install lynx
apt-cyg install lynx
rm -f /bin/wget.exe
apt-cyg install wget gcc-core gcc-g++ git pkg-config automake autoconf libtool make python2 python2-pip sqlite3
lynx -source https://bootstrap.pypa.io/get-pip.py > get-pip.py
@ -30,7 +146,7 @@ if [ "$1" == "win" ]; then
pip install flask
pip install flask-login
pip install pyserial
echo ""
echo "[MATIEC COMPILER]"
cp ./utils/matiec_src/bin_win32/*.* ./webserver/
@ -39,7 +155,7 @@ if [ "$1" == "win" ]; then
echo "OpenPLC was NOT installed!"
exit 1
fi
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
@ -51,7 +167,7 @@ if [ "$1" == "win" ]; then
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
@ -63,7 +179,7 @@ if [ "$1" == "win" ]; then
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd webserver/core
@ -80,7 +196,7 @@ if [ "$1" == "win" ]; then
exit 1
fi
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
@ -93,124 +209,37 @@ if [ "$1" == "win" ]; then
exit 1
fi
cd ../..
echo ""
echo "[FINALIZING]"
cd webserver/scripts
./change_hardware_layer.sh blank
./compile_program.sh blank_program.st
cp ./start_openplc.sh ../../
elif [ "$1" == "linux" ]; then
echo "Installing OpenPLC on Linux"
sudo apt-get update
sudo apt-get install build-essential pkg-config bison flex autoconf automake libtool make git python2.7 python-pip sqlite3 cmake
pip install flask
pip install flask-login
pip install pyserial
#make sure that packages are also installed for the super user
sudo -H pip install flask
sudo -H pip install flask-login
sudo -H pip install pyserial
linux_install_deps sudo
install_py_deps
install_py_deps sudo
echo ""
echo "[MATIEC COMPILER]"
cd utils/matiec_src
autoreconf -i
./configure
make
cp ./iec2c ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling MatIEC"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
g++ st_optimizer.cpp -o st_optimizer
cp ./st_optimizer ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling ST Optimizer"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
g++ glue_generator.cpp -o glue_generator
cp ./glue_generator ../../webserver/core
if [ $? -ne 0 ]; then
echo "Error compiling Glue Generator"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd utils/dnp3_src
echo "creating swapfile..."
sudo dd if=/dev/zero of=swapfile bs=1M count=1000
sudo mkswap swapfile
sudo swapon swapfile
cmake ../dnp3_src
make
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing OpenDNP3"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
echo "removing swapfile..."
sudo swapoff swapfile
sudo rm -f ./swapfile
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
./autogen.sh
./configure
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing Libmodbus"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
cd ../..
echo ""
echo "[OPENPLC SERVICE]"
WORKING_DIR=$(pwd)
echo -e "[Unit]\n\
Description=OpenPLC Service\n\
After=network.target\n\
\n\
[Service]\n\
Type=simple\n\
Restart=always\n\
RestartSec=1\n\
User=root\n\
Group=root\n\
WorkingDirectory=$WORKING_DIR\n\
ExecStart=$WORKING_DIR/start_openplc.sh\n\
\n\
[Install]\n\
WantedBy=multi-user.target" >> openplc.service
sudo cp -rf ./openplc.service /lib/systemd/system/
rm -rf openplc.service
echo "Enabling OpenPLC Service..."
sudo systemctl daemon-reload
sudo systemctl enable openplc
install_all_libs sudo
echo ""
echo "[FINALIZING]"
cd webserver/scripts
./change_hardware_layer.sh blank_linux
./compile_program.sh blank_program.st
cp ./start_openplc.sh ../../
elif [ "$1" == "docker" ]; then
echo "Installing OpenPLC on Linux inside Docker"
linux_install_deps
install_py_deps
install_all_libs
echo ""
echo "[FINALIZING]"
@ -218,117 +247,17 @@ WantedBy=multi-user.target" >> openplc.service
./change_hardware_layer.sh blank_linux
./compile_program.sh blank_program.st
cp ./start_openplc.sh ../../
elif [ "$1" == "rpi" ]; then
echo "Installing OpenPLC on Raspberry Pi"
sudo apt-get update
sudo apt-get install build-essential pkg-config bison flex autoconf automake libtool make git python2.7 python-pip sqlite3 cmake wiringpi
pip install flask
pip install flask-login
pip install pyserial
#make sure that packages are also installed for the super user
sudo -H pip install flask
sudo -H pip install flask-login
sudo -H pip install pyserial
echo ""
echo "[MATIEC COMPILER]"
cd utils/matiec_src
autoreconf -i
./configure
make
cp ./iec2c ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling MatIEC"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
linux_install_deps sudo
sudo apt-get install -y wiringpi
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
g++ st_optimizer.cpp -o st_optimizer
cp ./st_optimizer ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling ST Optimizer"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
g++ glue_generator.cpp -o glue_generator
cp ./glue_generator ../../webserver/core
if [ $? -ne 0 ]; then
echo "Error compiling Glue Generator"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd utils/dnp3_src
echo "creating swapfile..."
sudo dd if=/dev/zero of=swapfile bs=1M count=1000
sudo mkswap swapfile
sudo swapon swapfile
cmake ../dnp3_src
make
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing OpenDNP3"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
echo "removing swapfile..."
sudo swapoff swapfile
sudo rm -f ./swapfile
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
./autogen.sh
./configure
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing Libmodbus"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
cd ../..
echo ""
echo "[OPENPLC SERVICE]"
WORKING_DIR=$(pwd)
echo -e "[Unit]\n\
Description=OpenPLC Service\n\
After=network.target\n\
\n\
[Service]\n\
Type=simple\n\
Restart=always\n\
RestartSec=1\n\
User=root\n\
Group=root\n\
WorkingDirectory=$WORKING_DIR\n\
ExecStart=$WORKING_DIR/start_openplc.sh\n\
\n\
[Install]\n\
WantedBy=multi-user.target" >> openplc.service
sudo cp -rf ./openplc.service /lib/systemd/system/
rm -rf openplc.service
echo "Enabling OpenPLC Service..."
sudo systemctl daemon-reload
sudo systemctl enable openplc
install_py_deps
install_py_deps sudo
install_all_libs sudo
echo ""
echo "[FINALIZING]"
@ -341,121 +270,22 @@ WantedBy=multi-user.target" >> openplc.service
elif [ "$1" == "neuron" ]; then
echo "Installing OpenPLC on UniPi Neuron PLC"
sudo apt-get update
sudo apt-get install build-essential pkg-config bison flex autoconf automake libtool make git python2.7 python-pip sqlite3 cmake
pip install flask
pip install flask-login
pip install pyserial
#make sure that packages are also installed for the super user
sudo -H pip install flask
sudo -H pip install flask-login
sudo -H pip install pyserial
echo ""
echo "[MATIEC COMPILER]"
cd utils/matiec_src
autoreconf -i
./configure
make
cp ./iec2c ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling MatIEC"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
g++ st_optimizer.cpp -o st_optimizer
cp ./st_optimizer ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling ST Optimizer"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
g++ glue_generator.cpp -o glue_generator
cp ./glue_generator ../../webserver/core
if [ $? -ne 0 ]; then
echo "Error compiling Glue Generator"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd utils/dnp3_src
echo "creating swapfile..."
sudo dd if=/dev/zero of=swapfile bs=1M count=1000
sudo mkswap swapfile
sudo swapon swapfile
cmake ../dnp3_src
make
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing OpenDNP3"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
echo "removing swapfile..."
sudo swapoff swapfile
sudo rm -f ./swapfile
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
./autogen.sh
./configure
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing Libmodbus"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
cd ../..
echo ""
echo "[DISABLING UNIPI SERVICES]"
echo "[DISABLING UNIPI SERVICES]"
sudo systemctl stop neuronhost.service
sudo systemctl disable neuronhost.service
sudo systemctl stop neurontcp.service
sudo systemctl disable neurontcp.service
sudo systemctl stop evok.service
sudo systemctl disable evok.service
linux_install_deps sudo
echo ""
echo "[OPENPLC SERVICE]"
WORKING_DIR=$(pwd)
echo -e "[Unit]\n\
Description=OpenPLC Service\n\
After=network.target\n\
\n\
[Service]\n\
Type=simple\n\
Restart=always\n\
RestartSec=1\n\
User=root\n\
Group=root\n\
WorkingDirectory=$WORKING_DIR\n\
ExecStart=$WORKING_DIR/start_openplc.sh\n\
\n\
[Install]\n\
WantedBy=multi-user.target" >> openplc.service
sudo cp -rf ./openplc.service /lib/systemd/system/
rm -rf openplc.service
echo "Enabling OpenPLC Service..."
sudo systemctl daemon-reload
sudo systemctl enable openplc
install_py_deps
install_py_deps sudo
install_all_libs sudo
echo ""
echo "[FINALIZING]"
@ -468,80 +298,9 @@ WantedBy=multi-user.target" >> openplc.service
elif [ "$1" == "custom" ]; then
echo "Installing OpenPLC on Custom Platform"
echo ""
echo "[MATIEC COMPILER]"
cd utils/matiec_src
autoreconf -i
./configure
make
cp ./iec2c ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling MatIEC"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[ST OPTIMIZER]"
cd utils/st_optimizer_src
g++ st_optimizer.cpp -o st_optimizer
cp ./st_optimizer ../../webserver/
if [ $? -ne 0 ]; then
echo "Error compiling ST Optimizer"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[GLUE GENERATOR]"
cd utils/glue_generator_src
g++ glue_generator.cpp -o glue_generator
cp ./glue_generator ../../webserver/core
if [ $? -ne 0 ]; then
echo "Error compiling Glue Generator"
echo "OpenPLC was NOT installed!"
exit 1
fi
cd ../..
echo ""
echo "[OPEN DNP3]"
cd utils/dnp3_src
echo "creating swapfile..."
sudo dd if=/dev/zero of=swapfile bs=1M count=1000
sudo mkswap swapfile
sudo swapon swapfile
cmake ../dnp3_src -DFULL=ON -DCMAKE_INSTALL_PREFIX=/usr
make
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing OpenDNP3"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
echo "removing swapfile..."
sudo swapoff swapfile
sudo rm -f ./swapfile
cd ../..
echo ""
echo "[LIBMODBUS]"
cd utils/libmodbus_src
./autogen.sh
./configure --prefix=/usr
sudo make install
if [ $? -ne 0 ]; then
echo "Error installing Libmodbus"
echo "OpenPLC was NOT installed!"
exit 1
fi
sudo ldconfig
cd ../..
install_all_libs
echo ""
echo "[FINALIZING]"
cd webserver/scripts

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
Flask==1.0.2
Flask-Login==0.4.1
pyserial==3.4

View File

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.0.0)
# CMake build for OpenPLC glue generator. The glue generator takes
# generated C code from the MATIEC compiler and then generates necessary
# glue to bind the MATIEC code with the OpenPLC runtime.
project(openplc_gluegenerator)
option(WERROR "Set all warnings to errors" ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
# Optional build capabilities
option(OPLCGLUE_ALL "Build all optional projects (tests)" ON)
option(OPLCGLUE_TEST "Build tests" OFF)
if(OPLCGLUE_ALL)
message("enabling all optional components")
set(OPLCGLUE_TEST ON)
endif()
# The main application that we always build
add_executable(glue_generator glue_generator.cpp)
#if(OPLCGLUE_TEST)
add_executable(glue_generator_test ./test/glue_generator_test.cpp)
#endif()

View File

@ -1,20 +1,16 @@
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <cstring>
#include <cstdlib>
using namespace std;
ifstream locatedVars;
ofstream glueVars;
void generateHeader()
/// Write the header to the output stream. The header is common among all glueVars files.
/// @param glueVars The output stream to write to.
void generateHeader(ostream& glueVars)
{
if (glueVars.is_open())
{
glueVars << "\
glueVars << "\
//-----------------------------------------------------------------------------\r\n\
// Copyright 2015 Thiago Alves\r\n\
// This file is part of the OpenPLC Software Stack.\r\n\
@ -78,58 +74,41 @@ IEC_LINT *special_functions[BUFFER_SIZE];\r\n\
\r\n\
void glueVars()\r\n\
{\r\n";
}
else
{
cout << "Error opening glueVars.cpp file!" << endl;
}
}
int parseIecVars(char *varName, char *varType)
int parseIecVars(istream& locatedVars, char *varName, char *varType)
{
string line;
char buffer[1024];
if (locatedVars.is_open())
{
if (getline(locatedVars, line))
{
int i = 0, j = 0;
strncpy(buffer, line.c_str(), 1024);
for (i = 0; buffer[i] != '('; i++);
i++;
if (getline(locatedVars, line))
{
int i = 0, j = 0;
strncpy(buffer, line.c_str(), 1024);
for (i = 0; buffer[i] != '('; i++);
i++;
while (buffer[i] != ',')
{
varType[j] = buffer[i];
i++; j++;
varType[j] = '\0';
}
i++; j=0;
while (buffer[i] != ',')
{
varType[j] = buffer[i];
i++; j++;
varType[j] = '\0';
}
i++; j=0;
while (buffer[i] != ',')
{
varName[j] = buffer[i];
i++; j++;
varName[j] = '\0';
}
while (buffer[i] != ',')
{
varName[j] = buffer[i];
i++; j++;
varName[j] = '\0';
}
return 1;
}
else
{
return 0;
}
}
else
{
cout << "Error opening located variables file!" << endl;
return 0;
}
return 1;
}
else
{
return 0;
}
}
void findPositions(char *varName, int *pos1, int *pos2)
@ -162,7 +141,7 @@ void findPositions(char *varName, int *pos1, int *pos2)
*pos2 = atoi(tempBuffer);
}
void glueVar(char *varName, char *varType)
void glueVar(ostream& glueVars, char *varName, char *varType)
{
cout << "varName: " << varName << "\tvarType: " << varType << endl;
int pos1, pos2;
@ -198,7 +177,7 @@ void glueVar(char *varName, char *varType)
case 'X':
glueVars << "\tbool_output[" << pos1 << "][" << pos2 << "] = " << varName << ";\r\n";
break;
case 'B':
case 'B':
glueVars << "\tbyte_output[" << pos1 << "] = " << varName << ";\r\n";
break;
case 'W':
@ -227,7 +206,7 @@ void glueVar(char *varName, char *varType)
}
}
void generateBottom()
void generateBottom(ostream& glueVars)
{
glueVars << "}\r\n\
\r\n\
@ -243,21 +222,66 @@ void updateTime()\r\n\
}";
}
int main()
void generateBody(istream& locatedVars, ostream& glueVars) {
// Start the generation process.
char iecVar_name[100];
char iecVar_type[100];
while (parseIecVars(locatedVars, iecVar_name, iecVar_type))
{
glueVar(glueVars, iecVar_name, iecVar_type);
}
}
/// This is our main function. We define it with a different name and then
/// call it from the main function so that we can mock it for the purpose
/// of testing.
int mainImpl(int argc, char *argv[])
{
char iecVar_name[100];
char iecVar_type[100];
locatedVars.open("LOCATED_VARIABLES.h", ios::in);
glueVars.open("glueVars.cpp", ios::trunc);
generateHeader();
while (parseIecVars(iecVar_name, iecVar_type))
{
glueVar(iecVar_name, iecVar_type);
// Parse the command line arguments - if they exist. Show the help if there are too many arguments
// or if the first argument is for help.
bool show_help = argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0);
if (show_help || (argc != 1 && argc != 3)) {
cout << "Usage " << endl << endl;
cout << " glue_generator [options] <path-to-located-variables.h> <path-to-glue-vars.cpp>" << endl << endl;
cout << "Reads the LOCATED_VARIABLES.h file generated by the MATIEC compiler and produces" << endl;
cout << "glueVars.cpp for the OpenPLC runtime. If not specified, paths are relative to" << endl;
cout << "the current directory." << endl << endl;
cout << "Options" << endl;
cout << " --help,-h = Print usage information and exit." << endl;
return 0;
}
generateBottom();
// If we have 3 arguments, then the user provided input and output paths
string input_file_name("LOCATED_VARIABLES.h");
string output_file_name("glueVars.cpp");
if (argc == 3) {
input_file_name = argv[1];
output_file_name = argv[2];
}
// Try to open the files for reading and writing.
ifstream locatedVars(input_file_name, ios::in);
if (!locatedVars.is_open()) {
cout << "Error opening located variables file at " << input_file_name << endl;
return 1;
}
ofstream glueVars(output_file_name, ios::trunc);
if (!glueVars.is_open()) {
cout << "Error opening glue variables file at " << output_file_name << endl;
return 2;
}
generateHeader(glueVars);
generateBody(locatedVars, glueVars);
generateBottom(glueVars);
return 0;
}
// For testing, we need to allow omitting the main function defined here.
#ifndef OPLCGLUE_OMIT_MAIN
int main(int argc, char *argv[]) {
return mainImpl(argc, argv);
}
#endif // OPLCGLUE_OMIT_MAIN

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
// Catch2 will provide a main() function
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <sstream>
// Our application is defined in a single CPP file, so to write tests against it
// we need to include it directly here. That's ok so long as the application is
// no more than one CPP file.
#define OPLCGLUE_OMIT_MAIN
#include "../glue_generator.cpp"
using namespace std;
SCENARIO("Commmand line", "[main]") {
GIVEN("<no pre-conditions>") {
WHEN("-h command line arguments") {
char* args[2] = { "glue_generator", "-h" };
REQUIRE(mainImpl(2, args) == 0);
}
WHEN("--help command line arguments") {
char* args[2] = { "glue_generator", "-h" };
REQUIRE(mainImpl(2, args) == 0);
}
}
}
SCENARIO("", "") {
GIVEN("IO as streams") {
std::stringstream output_stream;
WHEN("Contains single BOOL at %IX0") {
std::stringstream input_stream("__LOCATED_VAR(BOOL,__IX0,I,X,0)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbool_input[0][0] = __IX0;\r\n");
}
WHEN("Contains single BOOL at %QX0") {
std::stringstream input_stream("__LOCATED_VAR(BOOL,__QX0,Q,X,0)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbool_output[0][0] = __QX0;\r\n");
}
WHEN("Contains single BYTE at %IB0") {
std::stringstream input_stream("__LOCATED_VAR(BYTE,__IB0,I,B,0)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbyte_input[0] = __IB0;\r\n");
}
WHEN("Contains single SINT at %IB1") {
std::stringstream input_stream("__LOCATED_VAR(SINT,__IB1,I,B,1)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbyte_input[1] = __IB1;\r\n");
}
WHEN("Contains single SINT at %QB1") {
std::stringstream input_stream("__LOCATED_VAR(SINT,__QB1,Q,B,1)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbyte_output[1] = __QB1;\r\n");
}
WHEN("Contains single USINT at %IB2") {
std::stringstream input_stream("__LOCATED_VAR(USINT,__IB2,I,B,2)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tbyte_input[2] = __IB2;\r\n");
}
WHEN("Contains single WORD at %IW0") {
std::stringstream input_stream("__LOCATED_VAR(WORD,__IW0,I,W,0)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tint_input[0] = __IW0;\r\n");
}
WHEN("Contains single WORD at %QW0") {
std::stringstream input_stream("__LOCATED_VAR(WORD,__QW0,Q,W,0)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tint_output[0] = __QW0;\r\n");
}
WHEN("Contains single INT at %IW1") {
std::stringstream input_stream("__LOCATED_VAR(INT,__IW1,I,W,1)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tint_input[1] = __IW1;\r\n");
}
WHEN("Contains single UINT at %IW2") {
std::stringstream input_stream("__LOCATED_VAR(UINT,__IW2,I,W,2)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tint_input[2] = __IW2;\r\n");
}
WHEN("Contains single INT at %MW2") {
std::stringstream input_stream("__LOCATED_VAR(INT,__MW2,M,W,2)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tint_memory[2] = __MW2;\r\n");
}
WHEN("Contains single DWORD at %MD0") {
std::stringstream input_stream("__LOCATED_VAR(DWORD,__MD2,M,D,2)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tdint_memory[2] = (IEC_DINT *)__MD2;\r\n");
}
WHEN("Contains single LINT at %ML1") {
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1,M,L,1)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tlint_memory[1] = (IEC_LINT *)__ML1;\r\n");
}
WHEN("Contains single LINT at %ML1024") {
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1024,M,L,1024)");
generateBody(input_stream, output_stream);
REQUIRE(output_stream.str() == "\tspecial_functions[0] = (IEC_LINT *)__ML1024;\r\n");
}
}
}

View File

@ -462,7 +462,7 @@ void *querySlaveDevices(void *arg)
tempBuff = (uint16_t *)malloc(2*mb_devices[i].input_registers.num_regs);
nanosleep(&ts, NULL);
int return_val = modbus_read_input_registers( mb_devices[i].mb_ctx, mb_devices[i].input_registers.start_address,
mb_devices[i].input_registers.num_regs-1, tempBuff);
mb_devices[i].input_registers.num_regs, tempBuff);
if (return_val == -1)
{
if (mb_devices[i].protocol != MB_RTU)

View File

@ -51,16 +51,16 @@ event_buffer_size = 10
database_size = 8
# First data point offset for DI - required if slave device used (the address should represent 1st data point of slave device)
offset_di = 800
offset_di = 0
# First data point offset for DO - required if slave device used (the address should represent 1st data point of slave device)
offset_do = 800
offset_do = 0
# First data point offset for AI - required if slave device used (the address should represent 1st data point of slave device)
offset_ai = 100
offset_ai = 0
# First data point offset for AO - required if slave device used (the address should represent 1st data point of slave device)
offset_ao = 100
offset_ao = 0
#Timeout for solicited confirms
# in MS