//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2010, 2026 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available
// under the terms of the MIT License which is available at
// https://opensource.org/licenses/MIT
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////

include::../_part_attributes.asciidoc[]

:leveloffset: -2

[[tools-plcgen-chapter-index]]
== CIF PLC code generator (stable)

indexterm:[PLC code generator]
indexterm:[tools,PLC code generator]
indexterm:[see: PLC,PLC code generator]

The CIF PLC code generator takes a CIF specification and creates real-time **P**rogrammable **L**ogic **C**ontroller (PLC) code that can read values from external inputs, evaluate the state and perform event transitions, and finally write values to external outputs.
The resulting code is written in the Structured Text programming language, one of the programming languages that is part of the IEC 61131-3 standard.
The code adheres to the <<tools-controller-checker-execution-scheme,execution scheme>> defined by the CIF controller properties checker.

The generated code is not intended to be modified directly.
Instead, the original CIF models should be modified, and from them new PLC code should be generated.

To successfully deploy the generated code at a real system, the CIF model should satisfy <<tools-plcgen-supported-specifications,certain conditions>> and the used PLC should have a sufficiently short cycle-time to catch all input changes.

indexterm:[PLC code generator,start]

=== Starting the generator

The CIF PLC generator can be started in the following ways:

* In Eclipse, right click a `.cif` or `.cifx` file in the _Project Explorer_ tab or _Package Explorer_ tab and choose menu:CIF implementation tools[Generate PLC code for CIF specification... (stable)].

* In Eclipse, right click an open text editor for a `.cif` or `.cifx` file and choose menu:CIF implementation tools[Generate PLC code for CIF specification... (stable)].

* Use the `cifplcgen` tool in a ToolDef script.
See the <<tools-scripting-chapter-intro,scripting documentation>> and <<tools-scripting-chapter-tools,tools overview>> page for details.

* Use the `cifplcgen` command line tool.

indexterm:[PLC code generator,options]

=== Options

Besides the general application options, this application has the following options:

==== Basic settings of the CIF PLC code generator

As different PLC systems have different expectations and limitations in what they accept as input, behavior of the PLC code generator heavily depends on the chosen PLC target.
This is configured with the _PLC target type_ option:

* _PLC target type_: The PLC code <<tools-plcgen-target-type,target type>> specifies the form of the desired output for the PLC model that eventually will run the generated code.
Default value is _PLCopen XML_.

Other important settings are the _Input file_ path for the CIF specification, the _I/O table file_ path to the file that contains the connections to the external inputs and outputs, and the _Output file_ for writing the generated PLC code:

* _Input file_: The absolute or relative local file system path to the input CIF specification.

* _I/O table path_: The absolute or relative file system path to the I/O table path file that contains the I/O connections.
For more information, consult the <<tools-plcgen-io-table-file, I/O table>> section.
Default path is derived from the CIF _Input file_ option value.
The `.cif` file extension is removed if it exists.
Then, a `.csv` file extension is appended.
+
If the file path does not exist, code generation will continue with a warning that the generated code will not perform I/O with its environment.

* _Program header text file path_: The absolute or relative local file system path to the text file to include at the start of the generated PLC program.
The program recognizes text patterns `+${app-name}+`, `+${app-version}+`, `+${time-stamp}+` and `+${brief-explanation}+`.
They get replaced by the name of the PLC code generator application, its current version number, the current time/date and a short explanation of how to interpret CIF terminology in the PLC program, respectively.
Non-printable and non-ASCII characters are ignored, `+(*+` is replaced by `+(-*+`, and `+*)+` is replaced by `+*-)+`.
If no file path is provided, the program uses the following as input for the program header text:
+
[source]
----
This file is generated with CIF's PLC code generator from the Eclipse ESCET toolkit.

Generator name:    ${app-name}
Generator version: ${app-version}
Generation time:   ${time-stamp}

${brief-explanation}
----

* _Output file_: The absolute or relative local file system path to the output file or directory.
If not specified, the output path will depend on the _Input file_ option value.
The result also depends on the chosen <<tools-plcgen-target-type, target type>>.

[[tools-plcgen-tailoring-output-of-the-code-generator]]
==== Tailoring the output of the code generator

Additional options exist to tailor the output of the code generator:

* _Event transitions form_: Select the desired form of the generated event transitions.
Code generated by the PLC code generator executes the CIF specification by performing event transitions, similar to how the <<tools-cifsim-chapter-index,CIF simulator>> does (especially when enabling the simulator's <<tools-cifsim-chapter-execution-mode,execution mode>>).
That part of the code can be generated in two different forms:
** Use _All event code in main program_ to obtain all event code directly in the main program,
** Use _Event code is combined into a function by event controllability and CIF scope_ to obtain event functions for all (un)controllable events in each scope, or
** Use _Each event in a separate function_ to obtain an event function for each event.

+
The main program calls the event functions as needed.
The former avoids function calls while the latter splits the code in several smaller functions.
Which form is better depends on the target as well as the program.

* _Input/output code form_: Select the desired form of the generated input/output code.
The generated code to read values from external input and the generated code to write values to external output can be created in the following forms:
** Use _Both input and output code are in the main program_ to obtain the code that reads input and the code that writes output directly in the main program,
** Use _Input code in the main program and output code in a function_ to obtain the code that reads input in the main program and the code that writes output in a function,
** Use _Input code in a function and output code in the main program_ to obtain the code that reads input in a function and the code that writes output in the main program, or
** Use _Both input and output code each in their own function_ to obtain the code that reads input in a function and the code that writes output in a function.

+
The main program calls the input and/or output function as needed.
Moving input and/or output code to function(s) reduces the size of the main program at the cost of one or two function calls.
Which form is better depends on the target as well as the program.

* _Simplify values_: Enable this option to simplify values in the generated PLC code.
The resulting code expresses more directly what values it actually uses as the cost of less abstractions in the generated code.
This may make reviewing more difficult.
This option is by default enabled.

* _Rename warnings_: Names in the CIF specification are re-used to improve linking generated PLC code back to the CIF file.
However, as PLC code has different requirements for names, the names from the CIF specification are not always used as-is.
By enabling this option, the generator prints a warning whenever a CIF name is not used as-is in the PLC code.
This allows to obtain the original CIF name for the adapted name that is used in the generated PLC code.
For more information, see the section about <<tools-plcgen-names,names>>.
This option is by default disabled.

==== Overriding target type choices

Selecting the target type is usually enough to get PLC code for that PLC model.
If that is not sufficient, the PLC code generator also allows overriding choices to tailor the generated PLC code.

Note that these options do not take limitations of the PLC model into account.
An incorrect choice in these options may thus make the generated PLC code unusable for the specified target type.
When using these options, always make sure the intended PLC model supports the configured values.

* _Convert enumerations_: Enumerations may have been used in the CIF specification.
In addition, the PLC code generator introduces enumerations in its conversion of automata.
This option controls how all enumerations are converted to PLC code:

** Use _Automatically decide how to handle enumerations_ (`--convert-enums=auto`) to let the code generator decide based on the configured target PLC model.
This is the default value of the option.
It will either preserve enumerations if the PLC model supports them, or it will convert the enumerations by one of the alternatives described below.

** Use _Preserve enumerations_ (`--convert-enums=keep`) if the target PLC supports enumerations.
It is generally the preferred value because using enumeration names improves readability of the generated PLC code.

** Use _Convert enumerations to constants_ (`--convert-enums=consts`) if the target PLC does not support enumerations but does support constants.
This option value also causes generation of names in the PLC code, but information about which names belong together is lost.

** Use _Convert enumerations to integers_ (`--convert-enums=ints`) if the target PLC neither supports enumerations nor supports constants.
This option value causes numeric values to be generated for values of the enumerations.
That may cause difficulties in reviewing the generated PLC code.

* _PLC maximum iterations_: This option decides how maximum iteration loop limits are applied in the generated PLC code.
In a CIF specification, performing events has priority over delaying in time.
To get the same behavior as the CIF specification in the generated PLC code, the generated PLC code must also give priority to performing events.
As a PLC is not fast enough to indefinitely perform events before the end of a PLC cycle, it is paramount that the PLC code will always eventually run out of events to perform.
The <<tools-controller-checker-bounded-response,bounded response property>> should hold for the specification to ensure that this is always the case.
This property can be checked using the <<tools-chapter-controller-checker,controller properties checker>>.
+
The option takes two loop limits.
The first loop limit defines the limit for uncontrollable events, while the second loop limit defines the limit for controllable events.
There are three kinds of loop limits:

** The limit `ctrl-props-anno` means that the PLC code generator derives the loop bound limit from the controller properties annotation in the specification.
That is, the bound of the bounded response property is used, incremented by one to check at runtime that the bound is indeed sufficient.
This is recommended, as it is the lowest loop limit that preserves CIF behavior in the generated PLC code.
If the annotation is not available, or the specification does not have bounded response, the `inf` limit is used instead.

** The limit `inf` means 'infinite'.
The PLC code keeps trying to perform events, until no more (uncontrollable or controllable) events are enabled.

** A limit consisting of a numeric value expresses the maximum number of loop iterations for deciding that all possible (uncontrollable or controllable) events have been done.
It should be a positive number of at least `1`.
Also, it should be large enough such that the PLC program will always run out of events it can perform, before reaching the loop limit.
That is the case when the last iteration does not perform an event.
If a lower value is used, the amount of processing time used by the PLC system in a single cycle to compute a response can be reduced.
That results in a more timely response of the PLC, but it may not always compute the entire response.
Whether this is acceptable should be decided on a case-by-case basis.
Section <<tools-plcgen-resulting-plc-code>> explains how this affects processing.

+
For example, if `20,inf` is given to the option, the PLC system will allow at most 20 loop iterations for uncontrollable events and it does not enforce a limit for controllable events.
The default value of this option is `ctrl-props-anno,ctrl-props-anno`.

* _PLC task name_: The name of the generated PLC task that runs the converted CIF specification.
If not specified, the option defaults to `PlcTask`.

* _PLC project name_: The name of the generated PLC project.
If not specified, defaults to `Untitled1`.

* _PLC configuration name_: The name of the generated PLC configuration.
If not specified, the option defaults to `Untitled1`.

* _PLC resource name_: The name of the generated PLC resource.
If not specified, the option defaults to `Untitled1`.

* _PLC task cycle time_: If periodic task scheduling is desired, set the scheduling interval in milliseconds for the task in the generated PLC code.
To disable periodic task scheduling, disable the option.
This option takes positive integer values and defaults to periodic task scheduling with a cycle time of 10 milliseconds.

* _PLC task priority_: The scheduling priority of the task to generate.
The priority must be in the range [0 .. 65535], where priority 0 is the highest priority, and priority 65535 is the lowest priority.
The priority can be used for preemptive or non-preemptive scheduling.
If not specified, the priority defaults to 20.

* _PLC integer type size_: The number of bits of an integer value in the PLC.
The default value of this option lets the target type decide.
In general that is 32 bit, which is also the size of an `int` in CIF.
If the PLC supports only smaller integer values, the largest available size is chosen.

* _PLC real type size_: The number of bits of a floating point value in the PLC.
The default value of this option lets the target type decide.
In general that is 64 bit, which is also the size of a `real` in CIF.
If the PLC supports only smaller floating point values, the largest available size is chosen.

indexterm:[PLC code generator,supported specifications]

[[tools-plcgen-supported-specifications]]
=== Supported specifications

The CIF PLC code generator assumes that the given CIF file has the following properties:

* It does not suffer from runtime evaluation errors.
For instance, it should not be prone to division by zero, accessing out of bound array indices, assignments of out of range values to variables, and so on.
To ensure such problems do not occur, apply <<tools-chapter-datasynth,synthesis>> to the model.
Alternatively, the <<tools-chapter-cif-explorer,CIF explorer>> may be used to verify that the specification does not contain runtime errors.
* It has bounded response.
This property can be checked using the <<tools-chapter-controller-checker,controller properties checker>> tool.
* It is confluent.
This property can be checked using the <<tools-chapter-controller-checker,controller properties checker>> tool.
* It is non-blocking under control.
This property can be checked using the <<tools-chapter-controller-checker,controller properties checker>> tool.

==== Pre-processing

To enlarge the accepted set of CIF files, the following transformations are first performed:

* <<tools-cif2cif-chapter-remove-annos>> (all <<lang-tut-annotations,annotations>> except <<lang-tut-annotations-documentation,documentation annotations>> are removed)
* <<tools-cif2cif-chapter-elim-comp-def-inst>>
* <<tools-cif2cif-chapter-elim-state-event-excl-invs>>
* <<tools-cif2cif-chapter-simplify-values>> (if _Simplify values_ option is enabled)
* <<tools-cif2cif-chapter-elim-consts>> (if _Simplify values_ option is enabled)
* <<tools-cif2cif-chapter-simplify-others>>
* <<tools-cif2cif-chapter-remove-io-decls>>

==== Specification checks

After pre-processing, a check is performed whether the CIF file meets all the requirements of the CIF PLC code generator:

* For components, the following conditions must be met:
** No initialization predicates outside locations that restrict initialization.
** No equations outside locations.
** No events that can occur infinitely many times.
The CIF PLC code generator only contains a partial check.
A more complete check can be done by checking the bounded response property of the input specification with the <<tools-chapter-controller-checker,controller properties checker>> tool.

* For automata and invariants, the following conditions must be met:
** At least one automaton.
** All automata must have a single initial location that can be statically decided.
** Discrete variables must have a single initial value.
** No state invariants that restrict behavior.
** Only events that are either controllable or uncontrollable.
This rejects events declared without `controllable` or `uncontrollable` keyword, edges with the `tau` event and edges without an event.
** No urgent locations and edges.
** No equations.

* For user-defined functions, the following conditions must be met:
** No internal user-defined functions.
//* No `continue` statement in internal user-defined functions.
** No external user-defined functions.
//* No parameter-less functions.

* For continuous variables the following conditions must be met:
** Restricted continuous variables, see the <<tools-plcgen-continuous-behavior,continuous behavior>> section for details.

* For expressions and data types, the following conditions must be met:
+
--
** No sets, dictionaries, strings, and stochastic distributions.
** Only arrays, so no non-array lists.
** Arrays must have at least one element, since `list[0]` cannot be expressed in a PLC system.
** No nested arrays.
** No arrays for the S7 targets.
** For arrays: no `+`, `-`, `=`, `!=`, `empty`, `delete`, `in`, `pop`, `size`, and slicing.
** For tuples: no `=` and `!=`.
** Standard library functions: no `acosh`, `asinh`, `atanh`, `cbrt`, `cosh`, `pow`, `sinh`, and `tanh`.
** No functions used as data values or stored in variables.
Functions must thus only be used to call the function.
** No use of variable `time`.
** No `switch` expressions on array or tuple typed values (or parts of values).
--
The restrictions on types and expressions do not apply to their use in values of <<lang-tut-annotations-documentation,documentation annotation>> arguments.
+
Depending on the PLC target type, additional restrictions may apply.
Please consult the next section for details.

* Furthermore:
** I/O declarations are ignored.
A warning is printed if a CIF/SVG input declaration is encountered.
** Annotations are ignored.

[[tools-plcgen-target-type]]
=== Target types

The PLC code generator output contains a single program called `MAIN`.
This program is instantiated in a task, which is part of a resource, which in turn is part of a configuration.
The configuration is put in a project, but that is outside the range of the IEC 61131-3 standard.
Most implementations however, work with projects.

The effect of the project, configuration, resource, and task is dependent on the configured target.
Unless overridden with options, the target also affects the shape of lower level details such as the form of the function calls, selected size of integers, and other configuration that tends to be different for different PLC systems.
Last but not least, the target affects how the generated output gets written to files.

The PLC code generator supports the following targets:

* _ABB_:
+
WARNING: Code generation for ABB is currently experimental.
+
Output for the ABB target generates multiple files in a directory.
By default, if no output directory is specified, it defaults to the input file path, where the `.cif` file extension is removed (if present), and a `+_abb+` directory extension is added.
The `MAIN` program gets a `.plcprog` file extension, functions get a `.plcfunc` file extension, type declarations get a `.plctype` file extension, and the configuration gets a `.plccfg` file extension.
+
The _PLC project name_ and _PLC resource name_ options have no effect for this target type.

* _IEC 61131-3_:
+
WARNING: When deploying code to a PLC, use a target specific to the PLC brand.
+
Output for the IEC 61131-3 target generates multiple files in a directory.
By default, if no output directory is specified, it defaults to the input file path, where the `.cif` file extension is removed (if present), and a `+_plc+` directory extension is added.
The `MAIN` program gets a `.plcprog` file extension, functions get a `.plcfunc` file extension, type declarations get a `.plctype` file extension, and the configuration gets a `.plccfg` file extension.
+
The _PLC project name_ and _PLC resource name_ options have no effect for this target type.

* _PLCopen XML_:
+
WARNING: When deploying code to a PLC, use a target specific to the PLC brand.
+
PLCopen XML is an link:https://en.wikipedia.org/wiki/XML[XML]-based file format standardized by the PLCopen organization, intended for the exchange of complete projects of PLC code, even across different tools and vendors.
The generated PLCopen XML file is compliant with version 2.01 of the PLCopen XML standard.
+
Output for the PLCopen target generates a single file.
By default, if no output file is specified, it defaults to the input file path, where the `.cif` file extension is removed (if present), and a `.plcopen.xml` file extension is added.

* _SIMATIC S7-300, S7-400, S7-1200, or S7-1500_:
+
WARNING: Code generation for S7-1200 and S7-1500 is currently experimental.
+
Totally Integrated Automation Portal (TIA Portal) is an link:https://en.wikipedia.org/wiki/Integrated_development_environment[IDE] for the development and testing of SIMATIC controllers.
Using the S7 target, the generated PLC code can be imported in TIA Portal.
+
Output for the SIMATIC target generates multiple files in a directory.
By default, if no output directory is specified, it defaults to the input file path, where the `.cif` file extension is removed (if present), and a `+_s7_<ver>+` (`<ver`> being either 1500, 1200, 400 or 300) directory extension is added.
The `MAIN` programs and functions get a `.scl` file extension, type declarations get a `.udt` file extension, the persistent variables databases get a `.db` file extension, and the global variable lists get a `.xml` file extension.
+
The _PLC task name_, _PLC task cycle time_, _PLC task priority_, _PLC project name_, _PLC configuration name_, and _PLC resource name_ options have no effect for this target type.
Currently, the PLC code generator cannot generate code for arrays for these systems.
Therefore, all forms of CIF lists are forbidden for these target types.
+
See the <<tools-plcgen-chapter-s7,S7 PLC output>> section for details on how to transfer generated code to the PLC system.

* _TwinCAT_:
+
TwinCAT is a complete link:https://en.wikipedia.org/wiki/Integrated_development_environment[IDE] for the development and testing of PLC controllers.
Using the TwinCAT PLC target type, the generated PLC code is written to the native file formats of the TwinCAT IDE.
+
Output for the TwinCAT target generates multiple files in a directory tree.
By default, if no output directory is specified, it defaults to the input file path, where the `.cif` file extension is removed (if present), and a `+_twincat+` directory extension is added.
+
See the <<tools-plcgen-chapter-twincat,TwinCAT PLC output>> section for details on how to transfer generated code to the PLC system.

indexterm:[PLC code generator,I/O table]
indexterm:[PLC code generator,inputs]
indexterm:[PLC code generator,outputs]

[[tools-plcgen-io-table-file]]
=== I/O table file

The PLC code generator generates PLC code that reads input values from external inputs and writes output values to external outputs.
Inside the PLC these values are transferred using variables with an I/O address.
To make such connections in CIF, some of the input variables should be connected to input addresses, and some of the discrete and/or algebraic variables should be connected to output addresses.
This is done by writing an I/O table file (details follow below), and giving it to the PLC code generator.

The generated PLC code will automatically read all inputs at the start of a PLC cycle and store them in the connected input variables.
The values of the variables can for instance be used in a guard or a computation, or get copied to other variables.
At the end of a cycle, outputs are written in a similar way by using the values of the connected discrete and algebraic variables.

The I/O table file is a **C**omma **S**eperated **V**alues (CSV) file.
The CIF PLC code generator assumes the https://www.rfc-editor.org/rfc/rfc4180[RFC-4180] format for this file, which is compatible with many spreadsheet programs.
It is generally recommended to use a spreadsheet program to create and edit a CSV file.

Each line describes one connection with a variable.
There are three or four columns in the CSV file.
The first three columns are mandatory.
The fourth column must either be completely omitted, or it must be added at all lines but entries can be empty.
The information that should be provided in the columns is as follows:

* The first column contains the PLC input or output address.
+
An example address is `%IX35.2.15`.
It always starts with a `%`.
The other parts are:

** The `I` is the kind of connection.
The `I` means it reads from an external input, a `Q` at that position means writing to an external output, and an `M` means reading or writing memory inside the PLC.
** The `X` describes the amount of data being transferred.
The `X` or not specifying a letter means 1 bit is transferred (in CIF, a `bool` type).
A `B` at that position means transfer of a byte (8 bits), a `W` means transfer of a word (16 bits), a `D` means transfer of a double word (32 bits), and an `L` means transfer of a long word (64 bits).
** The last part of an address is a sequence of numbers separated by dots.
In the example it is `35.2.15`.
The length and meaning of the sequence can vary between different PLC systems.
Consult the manual of the target PLC system for details.
In general the sequence indicates which of several available I/O ports is being used.

* The second column optionally contains the PLC type of the input or output.
If left empty, the type of the CIF variable is used instead.
In any case the fundamental type of the CIF variable must match with the fundamental type of the I/O port (both sides an integer, both sides a real, or both sides a boolean).

* The third column contains the <<lang-ref-syntax-lexical-identifier,non-escaped>> absolute name of the CIF variable connected to the I/O address.
For example, the variable of the automaton below is named `G.A.v`:
+
[source, cif]
----
group G:
  automaton A:
    disc int v;
    ...
  end
end
----

* The fourth column optionally contains the name of the variable with the input or output address.
+
If supplied, this name is used for the I/O variable declaration (in the PLC input/output variable table).
Otherwise, the PLC code generator will generate a name from the CIF variable connected to the I/O address.
+
Names must use the ASCII character set, and must be valid variable names for the used PLC target.
The PLC code generator will automatically convert the name to the required form in the PLC code.
For example, it may surround certain names with double quote characters.
+
If at least one line specifies a name of the variable in the fourth column, then all lines must have a fourth column.
An empty name is allowed for the lines where the default variable name suffices.

Depending on the PLC target type, additional restrictions may apply on addresses.
Consult the manual of the target PLC system for details.

The kind of connection, the direction of the connection, and the allowed kind of variable are related in the following way:

[cols="1, 1, 1"]
|===
| Connection kind | Direction | Variable kind

| `I` | from input | input variable
| `Q` | to output | discrete or algebraic variable
| `M` | from memory | input variable
| `M` | to memory | discrete or algebraic variable
|===

It is highly recommended that the number of transferred bits from the I/O matches with the CIF type of the variable as follows:

[cols="1, 1, 4"]
|===
| Transfer size | PLC type | CIF type

| 1 | `BOOL` | `bool`
| 16 | `INT` | `int` (for PLC systems that do not support 32 bit integers)
| 32 | `DINT` | `int` (for PLC systems that support 32 bit integers)
| 32 | `REAL` | `real` (for PLC systems that do not support 64 floating point)
| 64 | `LINT` | `int` (for PLC systems that support 64 bit integers)
| 64 | `LREAL` | `real` (for PLC systems that support 64 floating point)
|===

If the size of the CIF variable type does not match with the size of the I/O port type, a cast expression is automatically inserted.

Note that the PLC code generator has no means to verify that the specified or derived type of the I/O port is compatible with the hardware device connected to the given I/O address.

indexterm:[PLC code generator,continuous behavior]
indexterm:[PLC code generator,timers]

[[tools-plcgen-continuous-behavior]]
=== Continuous behavior

Within PLC systems, a major use for continuous behavior is timers to detect (sufficient) passage of time.
For instance, a reaction could be expected to happen within some period of time, but if it does not happen something else must be done.
Another use case is to wait for a certain amount of time before a next action may be started.
The PLC code generator assumes that continuous variables are always used for such purposes.

To reduce possible confusion with timer values, the common case of checking for timeout should be done against `0`.
In that way, the check is always the same no matter what the initial timer value is.
It is simpler to reason about positive values, so initial timer values should be positive.
Finally, time is measured in seconds, since that is an SI unit, and a common amount of time for PLC controlled systems.
This leads to a derivative of `-1` for the continuous variables.
Unlike continuous variables in CIF, timers in the PLC stop measuring when they reach timeout.
To preserve CIF behavior when generating PLC code, values used in comparisons against timers are restricted to non-negative values.

The following conditions therefore apply to continuous variables in the input CIF specification:

* The derivative of a continuous variable must always be `-1` or `-1.0`, and this value must be statically decidable.
* Continuous variables must only be compared to an inclusive upper-bound that is zero or larger.
The upper-bound value must be statically decidable.
+
For example, for a continuous variable `c`, the comparisons `c <= 0` or `5 >= c` could be used.
The former example checks for timeout (zero seconds left), the latter example checks whether there are five seconds or less remaining.
* Each assignment of a new value to a continuous variable should be separate.
That is, use `do c := 1.0, d := 2.0` on edges.
Other forms like `do (c, d) := (1.0, 2.0)` are not allowed.
* Values used to initialize a continuous variable, or to assign to a continuous variable must be larger or equal to zero, and this must be statically decidable.

An example with a timer is shown in the next section.

indexterm:[PLC code generator,@doc]
indexterm:[PLC code generator,doc annotations]

[[tools-plcgen-documenting-code]]
=== Documenting PLC code

CIF has <<lang-tut-annotations-documentation,documentation annotations>> that can be attached to elements in a CIF specification.
In such an annotation, design related information can be written about the element it is attached to.
In that way, design information is available within the model, and it can be used, transported or converted by CIF applications.

The PLC code generator understands documentation annotations of specifications, groups, automata, events, locations, edges, and discrete, continuous and input variables.
Indirectly it also understand documentation annotations of invariants, since it uses CIF conversions to convert these to one of the previously mentioned CIF elements.

All documentation annotations that it understands in the input specification and that affect behavior of the system are copied into the generated PLC code as comments, where appropriate.
For example, documentation annotations of the specification are only shown in the overall model overview.
Documentation annotations of variables are shown whenever the variable is updated.
Edge documentation annotations are shown when the edge is considered to be taken, and when it is actually taken.

Documentation annotations for CIF elements that are eliminated to other concepts or that are irrelevant are ignored.
The former causes documentation of algebraic variables (these are inlined), constants, enumerations and their literals and type declarations to be ignored.
Irrelevant CIF elements are for example empty automata, empty locations, or unused events.
As these are not included in the PLC program, the documentation of such elements is also ignored.

As an example of how documentation gets added, consider the following CIF specification:

[source, cif]
----
@doc("Enabled when the system is triggered to become active.")
uncontrollable reset;

@doc("Enabled when the system has been active long enough.")
uncontrollable timed_out;

@doc("Tracker to monitor activity of the system.")
plant ActivityTimer:
  @doc("Clock variable measuring remaining time until the system can be idle again.",
       "Currently configured to 10 seconds.")
  cont t der -1;

  @doc("System is idle.",
       "Waiting for the next reset.")
  location idle:
    initial;
    @@doc("Detected reset, jump into action.")
    edge reset do t := 10 goto active;

  @doc("System is active.")
  @doc("Should normally become idle again in 10 seconds.")
  location active:
    @@doc("Trigger detected while active, extend the active state.")
    edge reset do t := 10;

    @@doc("Time-out detected while active, go back to being idle.")
    edge timed_out when t <= 0 goto idle;
end
----

The example is extensively documented.
Note that documentation annotations for the specification and for the edges must have a double `@@`.

Below are a few examples of what can be generated in the PLC code.
For all details, and to see the code generated for your specific target, please convert the example yourself and check what the PLC code generator produces.

A global overview description of the specification is created in the PLC code.
It looks like:

[source,plcst]
----
(*------------------------------------------------------
 * Model overview:
 *
 * ----
 * Automaton "ActivityTimer":
 * Tracker to monitor activity of the system.
 *
 * - Current location of automaton "ActivityTimer".
 * - Continuous variable "ActivityTimer.t".
 *   Clock variable measuring remaining time until the system can be idle again.
 *   Currently configured to 10 seconds.
 *
 * - PLC edge selection variable "edge_ActivityTimer_1".
 *
 * - Uncontrollable event "reset".
 *   Enabled when the system is triggered to become active.
 *
 * - Uncontrollable event "timed_out".
 *   Enabled when the system has been active long enough.
 *------------------------------------------------------ *)
----

PLC code that tests whether event `timed_out` can occur has a comment describing the CIF elements involved together with their documentation:

[source,plcst]
----
(***********
 * Test edge of automaton "ActivityTimer" to synchronize for event "timed_out".
 * This automaton must have an edge with a true guard to allow the event.
 *
 * Edge being tested:
 * - Location "active":
 *   System is active.
 *
 *   Should normally become idle again in 10 seconds.
 *
 *   - 2nd edge in the location
 *     Time-out detected while active, go back to being idle.
 ***********)
IF "DB".ActivityTimer = ActivityTimer_active AND "DB".ActivityTimer_t <= DINT_TO_REAL(0) THEN
    edge_ActivityTimer_1 := 1;
ELSE
    (* The automaton has no edge with a true guard. Skip to the next event. *)
    eventEnabled := FALSE;
END_IF;
----

PLC Code that performs an edge (after deciding it should be taken) has a comment with the documentation of the edge:

[source,plcst]
----
ELSIF edge_ActivityTimer_1 = 2 THEN
    (***********
     * Perform assignments of the 1st edge in location "ActivityTimer.active".
     * Trigger detected while active, extend the active state.
     ***********)
    (* Perform update of continuous variable "ActivityTimer.t". *)
    "DB".ActivityTimer_t := 10.0;

    (* Reset timer of "ActivityTimer_t". *)
    ...  // Omitted for brevity.
END_IF;
----

indexterm:[PLC code generator,resulting PLC code]
indexterm:[PLC code generator,generated code]

[[tools-plcgen-resulting-plc-code]]
=== Resulting PLC code

In general, the PLC code generator attempts to preserve as much (of the structure) of the original CIF specification as possible.
For example, names of elements in CIF are also used for their converted equivalents in the generated PLC program.
This makes it simpler to compare a CIF model against the generated code.

However, some parts of CIF specifications are not directly supported by any PLC system.
For example, multiple automata and synchronizing on events or channels cannot be directly expressed in a PLC system.
A PLC system does not have events, natively.
For these cases the generator produces significantly different code, compared to the CIF specification.
For example, for taking an event transition, all edges are grouped by event instead of grouping by automaton.

Other parts are supported only by some of the supported PLC systems.
For these cases, the generator tries to generate the form that fits best within the abilities of the targeted PLC system and the configured options.
For example, enumerations and constants are not always supported.
The PLC code generator may change enumerations to constants or plain numbers in such a case.

From a bird's-eye view, the PLC code generator generates one main program that performs the entire PLC cycle.
This main program adheres to the <<tools-controller-checker-execution-scheme,execution scheme>> defined by the CIF controller properties checker.
Concretely, the main program consists of the following steps:

* Read values from the external inputs.
* For the first cycle, initialize the CIF variables and automata locations.
For every next cycle, update the continuous variables for the passed time.
* Perform as many uncontrollable events as possible (within loop limits for uncontrollable events, see the _PLC maximum iterations_ option for details).
* Perform as many controllable events as possible (within loop limits for controllable events, see the _PLC maximum iterations_ option for details).
* Write values to the external outputs.

Performing as many uncontrollable (or controllable) events as possible is done as follows:

* A loop is entered.
The loop tries to perform each uncontrollable (or controllable) event in turn.
* If none of the events was possible, the loop terminates.
* If the number of times that the loop was performed reaches the upper limit set by the _PLC maximum iterations_ option for uncontrollable (or controllable) events, the loop terminates.
* Otherwise, the loop is executed again, looking for more uncontrollable (or controllable) events to perform.

The maximum number of iterations of a loop can be configured with the _PLC maximum iterations_ option.
Also explained there is the need to have a large enough maximum number of iterations in order to obtain the behavior as specified in the CIF model.
If the specified maximum number of iterations is not `inf`, it may be difficult to judge whether the applied loop limits for controllable and uncontrollable event loops are large enough.
The PLC code generator assists here by counting the number of times that a loop was exhausted, and storing this count in the `loopsExhausted` variable.
The variable starts at `0` and increments by one each time an exhausted loop is detected, up to `MAX_LOOPS_EXHAUSTED` times (which is `9999`).
By looking at the `loopsExhausted` variable in the running PLC, information can be obtained about the number of potentially prematurely aborted event loops since it started counting.
If the value is `0`, everything is going well.
A value larger than `0` indicates that in some PLC cycles more loop iterations were done than deemed possible at the time of generating the PLC code.
Whether all necessary transitions were performed in those cases is not known, because the PLC code did not check further beyond the configured _PLC maximum iterations_ limit.

indexterm:[PLC code generator,names in the PLC code]
indexterm:[PLC code generator,PLC code names]

[[tools-plcgen-names]]
==== Names

Generated PLC code contains names for PLC elements like functions, variables, enumeration literals, and so on.
If such an element represents a CIF element in the PLC code, the absolute name of the CIF element is used as name in the PLC code.
In this way it is easier to link parts of a CIF specification with parts of the generated PLC code.

However, name requirements in CIF are different from name requirements in a PLC system.
As as result, names of CIF elements cannot always be used as-is in the PLC code, and must be changed before they can be used in the PLC code.

In general, names are preserved as much as possible.
However, in case of confusion where a PLC name originates from, the PLC code generator has a _Rename warnings_ option in <<tools-plcgen-tailoring-output-of-the-code-generator,its options>>.
By enabling the option, the code generator will print warnings whenever a CIF name is not used as-is.

Note that the PLC code generator also generates output that is closely related to CIF elements, but not directly representing the CIF element itself.
In such cases the variable may get a slightly different name to keep the name of the CIF element available for other uses, but at the same time still show the connection with the CIF element.

=== Tests

To test the code generator, ESCET ships with a set of 'self-certification' tests.
These tests can be used to generate code for specific targets and check that these execute correctly in the PLC development environment of that target.

The tests can be obtained from the ESCET IDE's welcome screen, by clicking the _Import CIF PLC code generator tests_ button to start the import wizard for importing the tests.
Alternatively, the wizard can be started from menu:File[New > Example...], by selecting _CIF PLC code generator tests_ under the _CIF_ category.

Currently, these tests are only meant for testing the TwinCAT and S7 targets.
