ESCET PLCgen development step plan
#679, please use that issue instead of this one
Remaining plans have been moved toIn #383 (closed) 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 (closed) 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.
Current 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
-
application infra structure files, [issue #400 (closed)] -
a PLC target option to specify the desired PLC target, [issue #400 (closed)] -
ability to read CIF files, [issue #400 (closed) using standard CIF functionality] -
ability to generate text files and writing them to the file system, [issue #400 (closed), uses writer classes] -
for each supported PLC model the code or data that generates the empty main program. [issue #400 (closed), uses model classes] -
construct test infra structure for enabling checking that an extension in the transformation does not break old behaviour. [issue #400 (closed), plcgen tests in the CIF tests
project]
-
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
-
finding type declaration in CIF model, [issue #418 (closed), CIF functionality] -
notion of types in the transformation, [issue #418 (closed), uses model classes] -
target-specific mapping of CIF data types to PLC data types, for the basic types (bool, int, real) [issue #418 (closed), TypeGenerator
class] -
notion of types in the PLC code, [issue #418 (closed), uses model classes] -
type equality [originally supposed to be added in issue #418 (closed), added in #594 (closed) ] -
type ordering [Unlikely to be needed at all]
-
-
Add support for constants with simple types. Needs
-
finding constants in the CIF model, [standard CIF functionality] -
creating constants in the PLC program, [using model classes] -
representation of values associated with types in the transformation, [using model classes] -
representation of constants in the transformation. [using model classes]
-
-
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 (closed)]
-
processing CIF model and storing found information by modelautomaton (there should be previous art), [issue #418 (closed), there doesn't seem to be much need for splitting discrete variables by automaton] -
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), [issue #418 (closed), #559 (closed) adds CifDataProvider
] -
constructing and writing tables of variables for each support PLC system (global variables?), [issue #418 (closed)] -
constructing an initialization step in the generated PLC. [issue #418 (closed)]
-
-
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, [ plcgen0
hasCSVParser
, needs a review before merge, doesn't belong inplcgen
] -
target-specific IO address verification, -
target-specific IO addresses specification in the generated output, -
generating assignments in PLC code for basic types, [!516 (merged) adds expression and statement objects] -
storage and output of such generated assignments. [!516 (merged) adds model to text conversion]
-
-
Extract continuous variables from the CIF model, generate PLC code that performs delay steps. [#630 (closed) adds continuous variables] Needs
-
initialization step for first execution run, -
delay-step update code of continuous variables for all supported PLC systems, [may not be needed if all continuous variables are timers implemented by timer function blocks] -
declaration of continuous variables in the PLC, possibly in function blocks, eg timers, -
extension of variable tables to continuous variables. [may be obsolete if continuous variables are implemented with timer blocks]
!553 (comment 1105002) has a first discussion about using timer function blocks.
-
-
Cleanup generated expressions.
-
Reduce number of parentheses. [implemented in #559 (closed)]
-
-
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. [#596 (closed) covers discussion of a data structure to store the results] Needs
-
target-specific notion of (location) enum values in the PLC (for those targets that support enum values), [ #558 (closed) ] -
representation of locations by integers (for those targets that don't support enum values) [ #558 (closed) ] -
constructing a mapping between automaton location in CIF and value of a location variable in PLC. [ #558 (closed) ] -
initialization of the location variables. [ #558 (closed) ]
Used the CIF to CIF
ElimLocRefExprs
rewriter here. This moves location handling into plain state variables. -
-
Perform empty edges in an automaton. [#596 (closed) contains the global code plan for event transitions] Needs
-
code for computing edges to take, and updating of location pointer variables. -
old and new state separation, [#559 (closed) CifDataProvidder
supports this notion] -
A way to convert new state 'back' to old state for the next transition. [the better solution is to see 'new state' as "the current state" and make a temporary copy to 'old' for use in a transition] Code now makes copies of all possibly assigned variables. Is trivially correct. Performance can be improved by eliminating needless copying. The follow-up point is in a TODO. -
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.[#596 (closed) contains the global code plan for event transitions] 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. [#596 (closed) contains the global code plan for event transitions] 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. [#596 (closed) contains the global code plan for event transitions] Needs
-
conversion of expressions on basic types, [#559 (closed) provides support] -
code generation of expressions, [#559 (closed) provides support] -
selecting condition checks based on current location.
-
-
Take updates into account (only assignments) for simple types. [#596 (closed) contains the global code plan for event transitions] Needs
-
writing to discrete variables. [#559 (closed) provides support, #596 (closed)] -
writing to continuous variables, derivatives. [#559 (closed) provides support, #596 (closed) provides much of the needed implemention] -
old and new state data for variables. [old state exists only while computing updates of edges in #596 (closed)] -
add maximal progress.
-
-
Implement channels. [#596 (closed) contains the global code plan for event transitions] 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, [ TypeGenerator
uses model classes] -
array type in the program, array values in the program, [ TypeGenerator
uses model classes, #559 (closed)] -
initialization of array values in the PLC, -
Extension of the analysis framework. -
assignment of fields in the array [ !516 (merged), #559 (closed) ] -
obtaining values of fields from the array [ !516 (merged), #559 (closed) ] -
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 [ TypeGenerator
uses model` classes] -
tuple type in the program, tuple values in the program, [ TypeGenerator
uses model classes, #559 (closed)] -
Extension of the analysis framework. -
initialization of tuples in the PLC, -
assignment of fields in the tuple [ !516 (merged), #559 (closed) ] -
obtaining values of fields from the tuple [ !516 (merged), #559 (closed) ] -
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. [!516 (merged), #559 (closed) adds the starting point for calling internal functions ]
-
-
Implement if-updates, if expression, switch expression. [#559 (closed) implements if expression conversion, #596 (closed) generates PLC code for all expressions and updates]
-
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.
-
-
Implement nested lists, nested tuples, lists in tuples, tuples in lists.
-
While in CIF this is all feasible, how much of it can be supported in the PLC needs careful consideration. -
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. [ #559 (closed) expands the definition at every occurrence ]
-
-
Sequencing of event processing for smarter maximal progress using DSM techniques.
-
Implement a sequencing algorithm [ issue #601 (closed) ]. -
Collect querying of state data in guards and state updates. [See issue #595 ] -
Construct a graph as input for the algorithm.
-
-
Implement confluence checking (needed by plcgen, may possibly be done independently.
-
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. [#145 (closed)]
-
-
Implement non-blocking under control checking (needed by plcgen, may possibly be done independently.
-
Implement it. [issue #410]
-
-
Address
TODO
comments in the entire PLCgen code generator.-
Check all TODO
s, see whether they are still relevant, and address them.
-
-
Integrate
cif2plc
classes used inplcgen
. Currently, the former are used as-is in the latter. By improving integration,plcgen
becomes less dependent oncif2plc
. Also it opens opportunities for improved representation and handling of generated artefacts.-
Copy the used cif2plc
classes intoplcgen
. [ issue #588 (closed) ]
Change the copied classes to match better with their use in the
plcgen
project. [ issue #592 (closed) ]-
Both projects have model classes ( oee.cif.cif2plc.plcdata
andoee.cif.plcgen.model
packages) where improved integration seems very useful. -
The code writers could be more integrated into the targets, that might also help in avoiding the need to have a target to create the settings. -
The S7Writer
class seems very much tailored to its specific use, it might be possible to generalize some parts. This may also apply to other copied code. -
Check for other opportunities to clean up or integrate the classes.
-
-
Connect generated code with notes in the original specification [ see issue #587 (closed) for a rationale and the details ]
-
Find a technically viable solution to do this. -
Collect the notes from the original specification. -
Connect the notes to the right code block. -
Generate comment in the PLC code. (The plcgen
model already has a comment statement for this.)
-
-
Improve generated PLC code
-
In event transition code magic numbers are used to point at automata and edges. It should likely use CIF automata and CIF location names instead. -
Event transition code could use more comments what is being done to guide the viewer. Eg mention the automaton that owns the edges being checked. Some empty lines eg between different events could be useful too. -
Use better names or add comments to make it easier to find the connection between guard checking code and update code of the same edge.
This item may be expanded, as likely more improvements can be found.
-
-
Replace
WarnOutput
in PLCgen with the one fromcommon.java
.-
Replace WarnOutput
in PLCgen with the one fromcommon.java
. (#666 / !665 (merged))
-
-
Other code improvements/fixes/cleanup
-
PLCgen Siemens target: location variables get assigned non-existing values. (#675 (closed)) -
Code still has some root[Cif]Provider
names, they should be renamed toscopeCifProvider
. -
The VarContTimers
checker class can be generalized to a proper generic check. Also, it may be useful to split derivative constraint checks from value assignment checks. -
Currently there is a requirement "The continuous variable is only assigned in a single-variable assignment, not in multi-assingments.". This seems an unnecessary limitation.
-
-
Check whether it is feature complete
-
Does it support all tool options, properly. -
Does it have all the features of the current/old PLC code generator? Is it a full replacement? -
Is there any documentation, are there test, etc, from the current/old PLC code generator that have not yet been migrated.
-
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.
- As noted in !619 (comment 1159022) the chosen approach of performing event transitions by first deciding complete feasibility of an event before even considering performing it means that guard checking code of an edge and the update code that the edge may perform are not close to each other in the source code. This complicates code review.
- #628 (closed) should be decided at some point.