INDUSTRIAL CONTROLLERS: PAC,PLC & LINUX
Este proyecto tambien esta disponible en Español haciendo clic aqui
Linux support for industrial hardware like PAC or PLC, in the case of the big and well known brands is basically non-existent. Some hardware is based on "exotic" architectures, however the vast majority have in their guts an x86 or ARM based system (Linux friendly architectures!), but the development and management tools remain developed for Windows operating system!
There are so many reasons (commercial, technical, philosophic) that perpetuates same situation. Searching on the web, we can find some PLC/PAC related applications developed for Linux, but practically all of them are communication drivers (for the open and well documented protocols!) , developed by enthusiasts
For more info visit Absolutelyautomation.com
Some time ago, developing a little implementation of RFB protocol in an PAC, in a Wireshark session deliberate unintentionally left open, when uploading a new program, some clear text strings were visible, probably control commands or parts of the program being downloaded!
Digging a bit more in the application for program loading, an interesting option was discovered: "Download FORTH File". Searching in the web "Opto22" and "FORTH" throws some papyri scanned manuals: How to program Opto22 LC2/LC4 (very outdated hardware!) controllers in FORTH!
With that document, the next natural thing was to open all the generated files with a HEX editor and search some FORTH code inside. The results of the analysis were:
- Manufacturer's application generates many types of files (config, initializations, program code)
- All files were encoded in clear text.
- The programming language used wasn't strictly FORTH
Finding that not a single standard programming language was used to program a PAC is a little pitfall, however, finding that all files were encoded in clear text are good news for programming PACs from non factory supported operating systems like Linux, Mac, etc.
The first step for an approaching to an alternative programming tool, is to know how the original application download an already created program. A simple blink application was used and the way the application talks with the PAC was analyzed using Wireshark. After downloading many different programs, the event sequence was discovered:
- A F (Handshake?) commands sent
AcquireLC (Session Lock command?) sent (probably to avoid other applications accessing the PAC while downloading)
.crn1 file sent line by line
.crn2 file sent line by line
.ccd task files sent line by line
.crn3 file sent line by line
DATESTAMP sent (control strategy file last modification date)
TIMESTAMP sent (control strategy file last modification time)
CRCSTAMP sent (seems like 00112233445566778899AABBCCDDEEFF value means: "ignore" or "don't use" CRC)
MAKECHECK, CLEAR.BREAKS, [ ABORT (Finishing commands?) sent
ReleaseLC (Session unlock command?) sent
Also, there are a couple of additional commands like get PAC info (available memory, errors, etc), stop program, start program, erase program, etc. that were investigated and implemented! A python app named O22termeng was developed, is capable of downloading programs to the PAC and send the aforementioned commands
GENERAL STRUCTURE OF A PROGRAM
Now, having a very basic PAC management tool, the control strategy files were studied in detail, and the info gathered is the following:
- All files with extension .crn1, .crn2, .crn3, should have the same name as the "main" program
- .crn1 file contains the line : FILENAME ." PNAME " ; where PNAME is the "main" program name. The rest of the lines of this file never changed when different programs were created
- .crn2 files contain the tasks or "charts" names than composes a program, the variables to be used and I/O pin assignation
- .crn3 files contains initializations for: tasks, variables and I/O hardware
- There should be a .ccd file for every task that composes a program, the name should coincide with the information contained in the .crn2 file
A sample control strategy "BLINK" was created. It is composed of two tasks: One toggles a digital output and increments a counter every second. The second one look if the counter is exactly divisible by 5 (modulo 5) and turns on a digital output if the condition is valid, if not turns it off
In this file there is a line where lies the name of the program " BLINK ". The rest of the lines look like some kind of memory space assignation for variables and I/O. No changes were noticed in those lines with different downloaded and analyzed programs.
_END NEW $$$.RUN
: FILENAME ." BLINK " ;
1 0 $VAR *_HSV_SEMA
1024 0 $VAR *_HSV_TEMP
200 0 $VAR *_HSV_INIT_IO
0 IVAR ^_HNV_INIT_IO
In this file three things were found:
Tasks that compose the program: Powerup, slowblink, _INI_IO. Powerup is the default task, can't be renamed nor deleted. slowblink was created in the manufacturer program, and _INIT_IO is probably is an internal task that initializes hardware automatically.
- Variables used in the program: countervar and modvar
I/O hardware pin alias: In this particular case digital pins 0 and 3 were assigned alias: DIGITAL_OUT_1 and DIGITAL_OUT_4
0 TASK &_INIT_IO
0 TASK &Powerup
0 TASK &slowblink
0 IVAR ^countervar
0 IVAR ^modvar
$0000000000000000.. 32769 1.000000 0.010000 0.000000 2001 $7F000001 0 MBOARD %SELF_RACK SPOINT 0.0 OUTPUT 0 %SELF_RACK
0 POINT ~DIGITAL_OUT_1
SPOINT 0.0 OUTPUT 3 %SELF_RACK
0 POINT ~DIGITAL_OUT_4
This file is a little bit longer than the previous. Seems like in the initial part, tasks, and all types of variables are grouped in arrays and near the end initialization of countervar and modvar to 0 are visible. Notice also that the digital pins are by default inputs "0", and the ones that will be used as outputs must be written to "1" ($..0009 pins 0 and 3)
: W_INIT_IO CONFIG_PORTS $0000000000000009.. %SELF_RACK ENABLES!
" %SELF_RACK (1/1)" *_HSV_INIT_IO $MOVE 0 ^_HNV_INIT_IO @!
" Initializing variables" *_HSV_INIT_IO $MOVE
0 ^countervar @!
0 ^modvar @!
" " *_HSV_INIT_IO $MOVE
Task files (Powerup.ccd, slowblink.ccd)
In these files lies the program code, for each task programmed. There are two things here: code blocks, and code block list near the end.
T; &Powerup ' T0 SETTASK
Each block is labeled a_b, where a is task number and b is a "block id" inside that particular task. Block numbers coincide with the block numbers shown in the manufacturer's application and probably are used for the block-by-block debugging mode.
The following is an example of a code block:
IF -4 ELSE -3 THEN JUMP ;
Each label is preceded by a colon (:), next LINE.NUM instruction preceded by a line number. This line number coincides with line numbers shown in the manufacturer's development app and are probably used for line-by-line debugging mode
Some portions of the code, closely resemble FORTH specially the IF statement where the condition was BEFORE the word "IF" !
A block finishes with a JUMP instruction followed by a semicolon (;). JUMP instructions are relative, not absolute.
- It is feasible to build an application to program industrial grade hardware (at least in this specific case with Opto22 PAC) using alternative operating systems!
The manufacturer didn't use a single standard programming language for the control strategy files, making a little bit harder the task of making an open source tool.
A skeleton file could be modified to make more complex programs - There are LOTS of unknown things to investigate.
For more info visit Absolutelyautomation.com