Merge branch 'master' into fix_defunct
This commit is contained in:
commit
ff8012068a
|
@ -0,0 +1,2 @@
|
|||
# Shell script files should never have line endings converted
|
||||
*.sh text eol=lf
|
|
@ -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/
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
FROM debian
|
||||
|
||||
COPY . /workdir
|
||||
RUN cd /workdir && ./install.sh docker
|
||||
WORKDIR /workdir
|
||||
ENTRYPOINT ["./start_openplc.sh"]
|
52
README.md
52
README.md
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
555
install.sh
555
install.sh
|
@ -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
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Flask==1.0.2
|
||||
Flask-Login==0.4.1
|
||||
pyserial==3.4
|
||||
|
|
@ -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()
|
|
@ -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
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue