PLCnext on LinkedInPLCnext on Instagram  PLCnext on YouTube Github PLCnext CommunityStore PLCnext Community

 

 How to create a Blog Entry

Connecting PLCnext PLCs to remote RS232/RS485 via pseudo TTY

In this Makers Blog article we discuss the possibilities and advantages which a Com Server provides to the PLCnext platform.

Introduction

The extensions modules that Phoenix Contact offers for its PLCs can for example be serial adapters like:

All extensions modules have on thing in common: they can be accessed cyclically via processdata. This provides the possibility to directly interact with the serial device from our realtime application.

In some cases this is not what we want. Instead, we want to re-use existing (C/C++) libraries and do not need the realtime context. However, we will find that these libraries usually are programmed to have direct access to a COM or TTY interface.

There are two options to create a TTY interface for a PLCnext Control:

  1. Implement some functions (C++ / C#) that create a TTY interface for the AXL or IL serial adapters from inside the PLCnext Runtime.
  2. Use of a COM-Server devices such as the GW Device Server

The GW Device Server provides a transparent TCP to Serial interface. With the help of a tool like Socat we can forward the Serial/TCP traffic directly to a pseudo TTY interface. Using GW Device Server also provides the possibility to communicate with the serial device on remote locations via a TLS encrypted channel.

NOTE

In this tutorial, the PLC performs as client and establishes connection to a GW Device Server.

(However, it is also possible to switch the PLC Socat to a listening option and have the GW as client actively connect to the PLC.)

Setup

Setting up the GW Device Server

We connect to the GW Device Server via the Web Based Management. The default IP address of the GW Device Server is 192.168.254.254.

We use the following settings:

LAN Settings - Security
  • Enable SSH Server
  • Enable Telnet Server
  • Disable Secure Data Mode
  • Disable TFTP Server Network Settings
Serial Settings
  • Port 1 Configuration (COM1): Enable TCP Connection on Port 8000
  • Port 2 Configuration (COM2): Enable TCP Connection on Port 8001 Serial

Testing the GW Device Server

To test if we have set up the GW Device Server correctly, first we connect our PLC to the GW Device Server via Ethernet. Then we connect the two DSUB adapters of the GW Device Server with each other.

We can quickly test the setup using the tool Telnet. With this tool, we can send data from the PLC to the GW Device Server at Port8000/COM1 through the serial cable to Port8001/COM2 and finally recieve it back at the PLC.

We use the following commands:

ssh This email address is being protected from spambots. You need JavaScript enabled to view it.
sudo passwd root
su root
ip addr add 192.168.254.10 dev eth0
telnet 192.168.254.254 8000
## open another shell session
telnet 192.168.254.254 8001
# Type some messages

Demo

Building Socat

To build Socat easily on a Linux OS, we use the following commands:

mkdir tmp
cd tmp
git clone git://repo.or.cz/socat.git
cd socat

## TODO: Modify to your SDK location
source /opt/pxc/release/axcf2152/2020/0/environment-setup-cortexa9t2hf-neon-pxc-linux-gnueabi
. /opt/pxc/release/axcf2152/2020/0/site-config-cortexa9t2hf-neon-pxc-linux-gnueabi

mkdir install
autoconf
./configure $CONFIGURE_FLAGS --prefix=$(pwd)/install --enable-openssl-method
make -j2
make install

Deploying and installing Socat

To deploy the Socat installation, we execute the following script:

cd tmp
mkdir -p deploy
cd deploy
mkdir -p usr
cp -r ../../Daemon/* .
cp -r ../socat/install/* usr/

# Create package
tar -cf ../socat-binaries.tar .
cd ..
scp socat-binaries.tar This email address is being protected from spambots. You need JavaScript enabled to view it.:~/
ssh -ttt This email address is being protected from spambots. You need JavaScript enabled to view it. \
"mkdir -p /opt/plcnext/socat-binaries && \
tar -xf /opt/plcnext/socat-binaries.tar -C /opt/plcnext/socat-binaries"

After deploying, we can now ssh to our PLC. Therefore, we first prepare the PLC by setting up the directories and config files by running the following commands:

deploy$ ssh This email address is being protected from spambots. You need JavaScript enabled to view it.

This email address is being protected from spambots. You need JavaScript enabled to view it.:~$ su root
This email address is being protected from spambots. You need JavaScript enabled to view it.$ mkdir -p /etc/default/socat
This email address is being protected from spambots. You need JavaScript enabled to view it.$ touch /etc/default/socat/socat.conf
This email address is being protected from spambots. You need JavaScript enabled to view it.$ touch /etc/init.d/SocatDaemon

Now, we modify the socat.conf file to configure the parameters of the serial interface to our needs.

nano /etc/default/socat/socat.conf

The content of the file looks like this.

TARGETIP="192.168.254.254"
TARGETPORT="8000"
TTYNAME="/dev/ttyGWDeviceServer"
OPTIONS="pty,link=$TTYNAME tcp-connect:$TARGETIP:$TARGETPORT,forever,interval=15"

BAUD="9600"
PARITY=""
DATABITS="csN 8"
STOPBITS="-cstopb"
FLOWCONTROLL=""

If we need to modify further parameters, we will need to also modify the SocatDaemon file. More information on TTY parameters can be found in the stty manual pages.

Now we create a SocatDaemon file to automatically connect to the GW Device Server using a Socat daemon.

NOTE:

This SocatDaemon file is an example without error/disconnection management etc. please.

nano /etc/init.d/SocatDaemon

The file has the following content.

(click to see/hide code)

```bash
#! /bin/sh
### BEGIN INIT INFO
# Provides:          socat
# Required-Start:    $local_fs $time $network
# Required-Stop:     $local_fs $time $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Daemon to setup Socat connection to GWd
#
# Description: The Socat init script will start/stop Socat as specified in /etc/default/socat/socat.conf
#              Logs can be found at /var/log/socat.log
### END INIT INFO
NAME=socat
DAEMON=/usr/bin/socat
SOCAT_DEFAULTS='-d -d -d -lf /var/log/socat.log'
. /etc/default/socat/socat.conf
PATH=/bin:/usr/bin:/sbin:/usr/sbin
[ -x $DAEMON ] || exit 0
start_socat() {
        start-stop-daemon --oknodo --quiet --start \
                --pidfile /var/run/socat.pid \
                --background --make-pidfile \
                --exec $DAEMON -- $SOCAT_DEFAULTS $OPTIONS < /dev/null
        do_wait_tty
        chown admin:plcnext_firmware $TTYNAME
        init_tty
}
init_tty(){
        ## For Reference
        ## https://man7.org/linux/man-pages/man1/stty.1.html
        stty -F $TTYNAME
        echo "-----before-------"
        #BAUD=9600
        stty -F $TTYNAME $BAUD       
        #PARITY=""
        # "" or parodd or -parodd
        stty -F $PARITY 
        #DATABITS="csN 8"
        stty -F $TTYNAME $DATABITS
        #STOPBITS="-cstopb"
         stty -F $TTYNAME $STOPBITS
        #FLOWCONTROLL=none
        #RTS handshake crtscts
        echo "-----initialised-------"
        stty -F $TTYNAME
}
do_wait_tty()
{
  TIMEOUT_COUNTER=0
  TIMEOUT=25
  TIMEOUTREACHED=0;
  ttyFOUND=1;
  echo "Wait for TTYNAME  Files"
  while [ 0 -eq $TIMEOUTREACHED -a 1 -eq $ttyFOUND ]; do
   [ -a $TTYNAME ]
   ttyFOUND=$?
   [ $TIMEOUT_COUNTER -lt $TIMEOUT ]
   TIMEOUTREACHED=$?   
   TIMEOUT_COUNTER=$[$TIMEOUT_COUNTER + 1]
   sleep 1  
  done  
}
stop_socat() {
        start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/socat.pid --exec $DAEMON
        rm -f /var/run/socat.pid
}
start () {
        start_socat
        return $?
}
stop () {
        for PIDFILE in `ls /var/run/socat.pid 2> /dev/null`; do
                NAME=`echo $PIDFILE | cut -c16-`
                NAME=${NAME%%.pid}
                stop_socat
        done
}
case "$1" in
    start)
            echo "Starting socat"
            if start ; then
                    echo $?
            else
                    echo $?
            fi
            ;;
    stop)
            echo "Stopping socat"
            if stop ; then
                   echo $?
           else
                   echo $?
           fi
           ;;
    restart)
            echo "Restarting socat"
            stop
            if start ; then
                    echo $?
            else
                    echo $?
            fi
            ;;
    *)
        echo "Usage: /etc/init.d/$NAME {start|stop|restart}"
        exit 3
        ;;
esac
exit 0
```

Now that all config files are in place, we can proceed by setting up the Socat binaries and registering the Socat daemon.

chmod +x /etc/init.d/SocatDaemon
cd /opt/plcnext/socat-binaries
chmod +x usr/bin/*

cp -r usr /

update-rc.d -s -v SocatDaemon 99
/etc/init.d/SocatDaemon start

If everything is set up correctly, we can see the running daemon using a command like ps -e | grep socat. We can also check the Socat logs located at cat /var/log/socat.log.

Accessing the TTY interface from a terminal

Now we can send messages over the TTY interface.

sudo echo "PLC to GW $var" > /dev/GWDeviceServer

To continuously test the pseudo TTY, we can use a command like

while true; do sleep 5 && sudo echo "PLC to GW $var" >/dev/ttyUSB0 && var=$((var+1)); done

Incoming traffic can be displayed by executing cat /dev/GWDeviceServer. Now any application can access the Serial device connected to the GW Device Server as if it is directly connected to the PLC.