ESCET Plcgen development step plan
In #383 an overview is presented of a plc code generator from an external project. That project has given permission to publish the code, and port the functionality to ESCET. In #382 the internal structure was discussed, and the decision was made that a 'plain copy' of the code (modulo renaming and ESCET project demands) is not am option. Instead, the idea is to make the code available here for reference and inspiration, and build a new implementation.
Therefore this issue is a development plan of getting very similar functionality available in ESCET for generating PLC code.
Short description of the functionality
plcgen is a code generator in the Eclipse ESCET project that transforms a CIF supervisor model with confluence and finite response properties to a PLC control program usable for controlling the physical system modeled by the CIF model.
It must perform this transformation for a variety of PLC systems including Siemens and ABB. It should be possible to add more PLC models models or systems from other PLC manufacturers to it. To enhance on-site maintenance and repairs, the conversion aims to reflect the CIF model structure in the generated PLC program code. In addition, an effort is made to make the generated code readable for judging its behavior independently.
Approach
Creating the transformation is broken down into several steps to globally guide the development and simplify reviewing and merging into ESCET.
This issue is created to provide a global picture of what is being added each step, as well as providing room for higher level discussions about the goal. For each step in the development a separate issue will be created for less technical discussion about the step. Code changes are discussed and attached to the latter issue of the step though a merge request to discuss the more technical aspects of the change.
When a step is done, this issue is updated to reflect the progress.
Currently planned steps
While the listed steps here are sequential, not all steps depend on all previous steps. Whether that is useful to do is not yet clear.
-
Construct an application that reads a CIF model, takes a option stating the desired PLC model to generate code for, and producing an empty main program for all supported PLC systems. Needs [issue #400 (closed)]
- application infra structure files,
- a PLC target option to specify the desired PLC target,
- ability to read CIF files,
- ability to generate text files and writing them to the file system,
- for each supported PLC model the code or data that generates the empty main program.
- construct test infra structure for enabling checking that an extension in the transformation does not break old behaviour.
Note: Every step below implements the extension for every supported PLC system. Also, tests are added by each step to confirm that the extension is working as intended.
-
Handle type declarations or simple types. Needs [issue #418]
- finding type declaration in CIF model,
- notion of types in the transformation,
- target-specific mapping of CIF data types to PLC data types, for the basic types (bool, int, real)
- notion of types in the PLC code,
- type equality and ordering
-
Add support for constants with simple types. Needs
- finding constants in the CIF model,
- creating constants in the PLC program,
- representation of values associated with types in the transformation,
- representation of constants in the transformation.
-
Extract discrete variables from the CIF model, organize them by automaton, and generate variable tables and initialization of the variables for each supported PLC system. Needs [issue #418]
- processing CIF model and storing found information by model (there should be previous art),
- converting CIF discrete variables to PLC while keeping the connection between both (CIF reading or writing a variable must eventually generate access to its PLC equivalent),
- constructing and writing tables of variables for each support PLC system (global variables?), and
- constructing an initialization step in the generated PLC.
-
Load input/output specification (CSV file), check IO addresses, generate PLC code for reading and writing the sensor and actuator hardware addresses. Needs
- CSV file reading,
- target-specific IO address verification,
- target-specific IO addresses specification in the generated output,
- generating assignments in PLC code for basic types,
- storage and output of such generated assignments.
-
Extract continuous variables from the CIF model, generate PLC code that performs delay steps. Needs
- initialization step for first execution run,
- delay-step update code of continuous variables for all supported PLC systems,
- declaration of continuous variables in the PLC, possibly in function blocks, eg timers,
- extension of variable tables to continuous variables.
-
Cleanup generated expressions (reduce number of parentheses).
-
Improve the generated code by analysis to find better ways of expressing the same operation.
Depending on how the generated code looks at this time, it may be better to move this one or two steps down. On the other hand, it should be added early as it is beneficial to the amount of work too. Needs
- an analysis framework for improving the generated code by analysing it, and rewriting while maintaining the functionality.
- implement the algorithms, decision making, and execution of those decisions. A limited amount of work should be done here at this point, further extensions are possible when considered beneficial.
-
Collect automata, and construct location pointer variables for each. Needs
- target-specific notion of (location) enum values in the PLC (for those targets that support enum values),
- representation of locations by integers (for those targets that don't support enum values)
- constructing a mapping between automaton location in CIF and value of a location variable in PLC.
- initialization of the location variables.
-
Perform empty edges in an automaton. Needs
- code for computing edges to take, and updating of location pointer variables.
- old and new state separation,
- A way to convert new state 'back' to old state for the next transition.
- have a transition 'function' for each event, except a POU is too much and will bite us.
- construct a high level code generation solution that guides the detailed code generation.
- While the number of different options is small, it does make life simpler as the detailed code generator doesn't need to bother with the overall structure.
- Note: Implementation should not perform maximal progress at this time, since that would trivially lead to live-lock.
-
Synchronize on events between multiple automata. Needs
- synchronization notion, collecting edges from different automata, and globally decide feasibility (decided on locations only for now)
- code for deciding feasibility of taking an event,
-
Add monitoring support. Needs
- expanded detection which automata participate in an event,
- allow events by monitoring automata if there is no edge for it,
- perform edge processing in monitoring automata when an edge exists.
-
Take edge conditions into account in synchronization. Needs
- conversion of expressions on basic types,
- code generation of expressions,
- selecting condition checks based on current location.
-
Take updates into account (only assignments) for simple types. Needs
- writing to discrete and continuous variables, derivatives.
- old and new state data for variables.
- add maximal progress.
-
Implement channels. Needs
- collecting senders and receivers,
- finding an enabled sender and receiver,
- computing send value, and
- storing received value.
-
Implement single level, fixed-size lists (arrays). Needs
- array type in the PLC,
- array type in the program, array values in the program,
- initialization of array values in the PLC,
- Extension of the analysis framework.
- assignment of fields in the array
- obtaining values of fields from the array
- handling array assignments (which is not a simple assignment).
-
Implement single level tuples of simple types. Hopefully very similar as lists, except with named fields and different type at different positions. Needs
- tuple type in the PLC
- tuple type in the program, tuple values in the program,
- Extension of the analysis framework.
- initialization of tuples in the PLC,
- assignment of fields in the tuple
- obtaining values of fields from the tuple
- handling tuple assignments (which is not a simple assignment).
-
Implement internal functions and calls to such functions.
- Under the assumption that CIF internal functions are translated to PLC functions.
-
Implement if-updates, if expression, switch expression.
- CIF has several variations on mixing control flow in expressions. The PLC expressions don't have such rich structure, except possibly for the
select
function. As a result, most of the control flow will and up in statements, thus splitting the expression computation. - This step may be too big to do all at once, but that needs further analysis at the time.
- Will cause need for branching support in the analysis framework, not sure if that is not needed earlier.
- CIF has several variations on mixing control flow in expressions. The PLC expressions don't have such rich structure, except possibly for the
-
Implement nested lists, nested tuples, lists in tuples, tuples in lists.
- Needs extended analysis framework for handling nested data values, may be useful to make room for that earlier.
-
Find a path to implement algvars. Algvars are easy to use, but they tend to hide a lot of computing complexity as users may nest algvars uses into each other.
The current ESCET PLC compiler uses PLC functions for computing algvars, for each use.
The previous
plcgen
attempts computed and cached the algvar values at some point in time (rather than re-computing the value on each use). This is likely cheaper in execution but also more complicated. It also introduces the cached (algebraic) value that may complicate understanding of the code, and makes correctness more difficult to establish.To avoid the complexity and correctness assessment worries, a simpler form may be useful, eg expand the algvar to its definition each time it is used as a statement. This is similar to using a PLC function. Obviously, this may lead to code bloat, which can be fought with the analysis framework. An alternative that fights that problem may be to introduce local variables holding the algvar computed results, which should reduce code duplication. Other unexplored paths are some sort of classification of algvars, and different treatment of different kinds of algvars. It would need deep insight in how algvars are used though.
Without further analysis of the algvar structure and its usage context I don't think there is much you can do. There is likely not a single answer that covers all needs.
-
Implement algvars.
- Algvar support is definitely needed. Implement something simple that works while avoiding some of the problems.
-
Sequencing of event processing for smarter maximal progress using DSM techniques.
-
Implement confluence checking (needed by plcgen, may possibly be done independently.[Added in #145 (closed) already]
- Reijnen wrote one checker based on heuristics that can be added. It is not yet known if that is sufficient or that other options should be explored.
Other considerations (currently considered out of scope)
- CIF assumes that both input and output variables are part of the state. This is debatable as often these variables are only pass-through copies of the read input data or created output data.