Over the last few weeks I have committed some changes relating to the file structure generated by the IEC 61131-3 compiler and employed by the IEC 61131-3 virtual machine run-time. Up until this point, the file structure has consisted of the flat binary byte code, encoded using the Intel hexadecimal object file format – See http://microsym.com/editor/assets/intelhex.pdf. This flat byte code format however does not encapsulate sufficient flexibility required to implement of the range of features – such as and initial values and retained variables – mandated for this project.
To this end, I have implemented a simple but expandable file header data structure that allows for the specification of meta-data associated with the compiled byte code application file. This packed data structure takes the form:
With respect to each of the elements of this data structure:
- Header – This member of the data structure is intended to provide scope for the specification of magic values and version information associated with the file structure.
- Symbols – This member of the data structure is intended to specify a byte offset into the encoded file where initial values for variables (symbol table) are specified. These values are specified in a byte aligned nature such that these raw values can be directly copied into the (RAM) memory space employed for the symbol table by the virtual machine run-time.
- Retain – This member of the data structure – where specified – is intended to specify a byte offset into the encoded file where a set of byte masks are specified for variables within the symbol table whose values should be retained, on a cycle-by-cycle basis, on the target controller across virtual machine run-time invocations.
- ByteCode – This member of the data structure is intended to specify a byte offset into the encoded file where the application byte code is located. This byte code, the output of the IEC 61131-3 compiler, specifies operations of the virtual machine run-time.
- Functions – This member of the data structure contains a MD5 hash created from the library of C-based functions linked to the IEC 61131-3 compiler. This is matched against a similarly generated hash for the virtual machine run-time which provides a level of surety of equivalence (or compatibility) of these C-based functions between the IEC 61131-3 compiler and IEC 61131-3 virtual machine run-time.
This file structure may be expanded in the future – most notably to include source variable information (such as variable names, types, size and scope) that may be required for debugging and controller redundancy synchronisation operations – but the above data structure gives me the scope for further immediate development.
Despite a number of other things occupying my time over the last weeks, I have been able to resolve the final blocking issues which required resolution ahead of opening public access to the IEC 61131-3 virtual machine project source code (https://bitbucket.org/rob_au/61131). One of the final concerns that I have had however has been the selection of an appropriate licence for distribution – While my natural proclivity is to opt for an Open Source Initiative (OSI) approved license such as the GNU General Public License (GPL) or the Apache License 2.0, there is a small concern that I have about the unrestricted use of this project code. This is primarily due to the industrial nature and domain within which IEC 61131-3 compatible controllers, one of the principle candidate areas where code from this project might be employed is automation and industrial control. In turn, my concern is that the unwary user might seek to employ code from this project in such a setting without taking appropriate duty or understanding of the appropriateness of the project code for the given purpose. This is not to say that this project code cannot be employed for such purposes, but believe that the state of this project code as it stands currently has not yet undergone sufficient testing, audit and/or code review.
Accordingly, I have adopted the Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) licence for the initial release of the IEC 61131-3 virtual machine project. Under this license, project users are free to:
- Share – copy and redistribute the material in any medium or format;
- Adapt – remix, transform and build upon the material.
Under the following terms:
- Attribution – You must give appropriate credit, provide a link to the license and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use;
- Non-Commercial – You may not use the material for commercial purposes.
Additional information about this licence can be found at https://creativecommons.org/licenses/by-nc/4.0/.
This license appears to strike a balance with respect to source code availability – for further development and educational purposes – while precluding commercial industrial use at this point in time. I would however encourage anybody for whom this license presents issue to contact me – I am happy to discuss the possibility of a commercial-friendly license for this project code, but want to ensure that appropriate engineering safe-guards and review are adopted such that the project code is not employed in a manner for which it is not best intended.
In my musings today, I started to give thought as to some of the mechanics associated with the implementation of a debugging interface for the IEC 61131-3 virtual machine run-time. More specifically, I have considering what form the debugger client and interface protocol might take – While one approach might be to start work on a development environment (or build upon an existing platform such as GEB Automation Integrated Development Environment [IDE], http://www.gebautomation.com), the scope of such development extends far beyond the core focus on this project. Such an extension of scope is neither desirable with respect to ensuring my own on-going interest in this project (which as already grown beyond my initial expectations of development scope) and overall project quality.
Beyond the development or debugging environment, there is also a question as to what communication protocol should be employed for debugging between the development environment and the IEC 61131-3 virtual machine run-time running on the target hardware. With a desire to ensure the interoperability of this platform, my preference would be for a published standard or protocol, however none of the existing, standard industrial protocols (with which I have experience), incorporate sufficient scope to necessarily support all operations required for debugging of IEC 61131-3 applications – such as start application, stop application, step execution, continue execution and the setting and/or clearing of breakpoints. Moreover, Google searches for “debugger protocols” returned links to protocols better suited to more capable host environments than those where I would expect the IEC 61131-3 virtual machine run-time to be executed.
Nevertheless, after having spent some time considering available options for remote debugging, an interesting idea emerged – Why not use the GNU Debugger (gdb, http://www.gnu.org/software/gdb/) for debugging applications running on the IEC 61131-3 virtual machine run-time?
Following on from the previous post where an interface to physical I/O was described, I have made some further progress on this project. Below is a short video of the implementation of this physical I/O on a Raspberry Pi single board computer with PiFace Digital I/O board (http://www.piface.org.uk/products/piface_digital/).
In this demonstration, the following Instruction List (IL) application is running that performs a bit shift of a value through output channels – This demonstration application also incorporates the calling of C-based functions in the form of the rotate-left (ROL) and logical AND mask (AND_MASK) operations.
Output0 AT %QX0: BOOL;
Output1 AT %QX1: BOOL;
Output2 AT %QX2: BOOL;
Output3 AT %QX3: BOOL;
Output4 AT %QX4: BOOL;
Output5 AT %QX5: BOOL;
Output6 AT %QX6: BOOL;
Output7 AT %QX7: BOOL;
(* Set and rotate bits through a byte variable *)
Rotate: CAL ROL( Value, INT#1 )
(* Set output lines 0 through to 7 based upon byte variable *)
(* Copy bit 0 to output 0 *)
CAL AND_MASK( Value, BYTE#1 )
(* Copy bit 1 to output 1 *)
CAL AND_MASK( Value, BYTE#2 )
(* Copy bit 2 to output 2 *)
CAL AND_MASK( Value, BYTE#4 )
(* Copy bit 3 to output 3 *)
CAL AND_MASK( Value, BYTE#8 )
(* Copy bit 4 to output 4 *)
CAL AND_MASK( Value, BYTE#16 )
(* Copy bit 5 to output 5 *)
CAL AND_MASK( Value, BYTE#32 )
(* Copy bit 6 to output 6 *)
CAL AND_MASK( Value, BYTE#64 )
(* Copy bit 7 to output 7 *)
CAL AND_MASK( Value, BYTE#128 )
Over the past month, code has been implemented to provide an interface for statically including drivers to the IEC 61131-3 virtual machine code base and in turn, to physical I/O.
Using this driver interface, the driver name and an initialisation function for the driver are registered in a static table – The initialisation function for this driver takes the prototype form:
typedef void * ( *DRIVER_INITIALISATION_POINTER )( void * );
This initialisation function is called with a contextual pointer as a sole argument which is used in calls to subsequent registration and interface functions – At the moment, there is only one such registration/interface function which permits the registration of a physical I/O interface (further details below). This initialisation function should return a pointer to a contextual data structure on success – which will subsequently passed back to functions from driver management code within the IEC 61131-3 virtual machine run-time – or NULL on error.
Well, it appears that I have reached that point in the development process for this project where I simply cannot function any longer without issue tracking. Up until this point all development has been relatively contained and straight-forward such that I have been able to address issues as a priority as I encountered them. With the branching of scope to include C-based functions and in turn, a wider set of operations in a meaningful context, issues are being encountered which, while important, are minor in nature and rightly take less precedent that other development efforts. As a result, I have enabled the issue tracker on the Bitbucket repository so that these issues and be logged (and forgotten) until a later time when they can be addressed.
It’s really amazing how much effort sometimes needs to be put in to make the smallest element of functionality work correctly. The case in point is the recent implementation of support for calling functions from within the IEC 61131-3 virtual machine. This implementation required the inclusion of new virtual machine operators (PUSH and POP) to appropriately manage the passing of parameters between the calling code and the function body. There were also considerations that had to be given to the conditional nature of calling functions – namely with respect to the difference defined in the IEC 61131-3 standard between the C and N modifiers that can be applied to the CAL (call) operator; parameter typing and return types; and how to ensure the integrity of the parameter stack between invocations.
All of this work was ultimately manifest in the following, very simple test application:
CAL Func( Count )
FUNCTION Func: INT
The result when all requisite functionality was implemented was the very simple increment of a program variable (Count), albeit by somewhat convoluted means whereby a function is called and the function result is stored in the program variable – rather than direct increment of the program variable. Nevertheless, this provided a very sure means by which function call operations could be tested and I must say that it was particularly rewarding when this test case “just worked” after implementing the final dependent code elements.