Developers best friends

Attributes for expressing intended use cases, identifying real system properties and reacting with the live cycle of your plc application. We present here a collection of attributes which can be beneficial in the process of library development.

Specify the intended use

{attribute 'no_explicit_call' := 'Use method xy to ...'}
FUNCTION_BLOCK POU

With this attribute you can prevent the body of a certain function block instance from being called. If the call to the body of a function block is not intended the using of this attribute is highly recommended.

{attribute 'no_assign'}
FUNCTION_BLOCK POU

This pragma causes compiler errors to be displayed if an instance of a function block will be assigned to another instance of the same type. If a function block contains references e.g to external resources, using this attribute is highly recommended.

{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK POU

When you change a function block with this identification so that a online change is necessary, then CODESYS reacts with an error message. For a function block marked with this attribute, always a download is necessary after changing this function block.

{attribute 'no_instance_in_retain'}
FUNCTION_BLOCK POU

With this attribute you can prevent the instances of a certain function block from being stored in the retain area. After decorating a function block with this attribute, it will not further possible to store the memory of its instances in the retain area.

Monitoring Values of a Property

This concerns the monitoring of a property that is implemented with the Get and Set methods. In order for this to be displayed in the online view of the IEC editor or in a monitoring list, you must insert the attribute ‘monitoring’ together with one of the two auxiliary attributes ‘variable’ or ‘call’ into the declaration of the property.

Note

CODESYS displays the value of a property only, if the attribute ‘monitoring’ was inserted in the declaration of the property. Not using this attribute for a property results in a bad user experience.

{attribute 'monitoring' := 'variable'}

An implicit variable is created for the property, which is then always given the current property value when the application calls the Set or Get method. The value stored last in this variable is displayed in the monitoring.

{attribute 'monitoring' := 'call'}

You can use this attribute only for properties that return simple data types or pointers, not for structured types. The value to be monitored is read or written by directly calling the property; this means that the monitoring service of the runtime system executes the Get or Set method of the property function.

Note

It is a good choice placing {attribute 'monitoring' := 'variable'} in front of a property declaration as a default. If it is not intended to monitor the value of a property, do not use this attribute.

Identify your System

The following new constants are now available:

__SYSTEM.Constants.bLittleEndian // type BOOL, TRUE for Intel, ARM etc. FALSE for PPC etc.
__SYSTEM.Constants.bSimulationMode // Simulation mode: TRUE in simulation mode
__SYSTEM.Constants.nRegisterSize // 16 for C16x, 64 for X86-64 Bit, 32 for all other controllers
__SYSTEM.Constants.nPackMode
__SYSTEM.Constants.bFPUSupport // true if FPU support is available on the target

__SYSTEM.Constants.RuntimeVersion // type VERSION the version as described in the runtime system
__SYSTEM.Constants.RuntimeVersionNumeric // type DWORD the version as described in the runtime system
__SYSTEM.Constants.CompilerVersion // type VERSION: the version as defined in the compile options
__SYSTEM.Constants.CompilerVersionNumeric // type DWORD: the version as defined in the compile options

__SYSTEM.Constants.bMulticoreSupport // true if MultiCore support is available on the target

They can also be used in Pragmas:

{IF defined(IsSimulationMode)}

The operator causes the expression to be given the value TRUE if the application runs on a simulated device, i.e. in simulation mode.

{IF defined(IsLittleEndian)}

The operator causes the expression to be given the value FALSE, if the CPU is ‘Big-Endian (Motorola byte order)’.

{IF defined(IsFPUSupported)}

If this expression returns the value TRUE, the code generator generates FPU (Floating point unit) specific code for the calculations with REAL values. Otherwise CODESYS emulates FPU operations; however, this is much slower.

{IF hasvalue(RegisterSize, <register size>)}

This operator causes the expression to return the value TRUE if the size of a CPU register is equal to <register size>.

Examples of values for specific platforms

16 for C16x
64 for X86-64
32 for X86
{IF hasvalue(PackMode, <mode>)}

The checked pack mode depends on the device description, not on the pragma that can be specified for individual DUTs.

{IF defined(IsMulticoreSupported)}

If this expression returns the value TRUE, the runtime system is able to handle the task management in a multi core environment.

Note

In conjunction with optional libraries, conditional compilation can be used to react to certain properties of a system.

For a complete exploration of the possibilities, there are many hints in the CODESYS help.

Respond to specific Situations

{attribute 'call_after_init'}
{attribute 'call_after_global_init_slot' := '<slot>'}

The effect of this pragma is that all methods, functions and programs containing this attribute are called after the whole code for initialisation of the plc application is done. So this is a good place for scheduling some last actions before the application is able to run. You define the order of calling by means of the attribute <slot>. This integral value defines the ranking in the order of the calls: the lower the value, the earlier the call takes place. If several function blocks have the same ranking for the attribute, then the order of their calls remains indefinite.

{attribute 'call_before_online_change_concurrent_slot' := '<slot>'}

Just before the process of an online change will be started all methods, functions and programs containing this attribute are called. This is done concurrently to the normal plc cycle of the application. You define the order of calling by means of the attribute <slot>. This integral value defines the ranking in the order of the calls: the lower the value, the earlier the call takes place. If several function blocks have the same ranking for the attribute, then the order of their calls remains indefinite.

{attribute 'call_after_online_change_slot' := '<slot>'}

The effect of this pragma is that all methods, functions and programs containing this attribute are called after an online change. You define the order of calling by means of the attribute <slot>. This integral value defines the ranking in the order of the calls: the lower the value, the earlier the call takes place. If several function blocks have the same ranking for the attribute, then the order of their calls remains indefinite.

If a method possesses the attribute, then CODESYS determines all instances of the function block concerned. CODESYS calls all instances in the specified slot. In this case you have no influence on the order of the instances among themselves.

Attention

Since the application cannot run during the online change, each code executed in this situation can lead to a jitter. Therefore, keep the extent of the executive code as small as possible.

{attribute 'call_before_global_exit_slot' := '<slot>'}

Just before the process of cleaning up an plc application all methods, functions and programs containing this attribute will be called. You define the order of calling by means of the attribute <slot>. This integral value defines the ranking in the order of the calls: the lower the value, the earlier the call takes place. If several function blocks have the same ranking for the attribute, then the order of their calls remains indefinite.

{attribute 'call_on_type_change'}

With this pragma, you can mark a method of a function block A that should be called when the data type changes for one or more function blocks B, C, etc. that are referenced by A. The referencing can be defined by a POINTER variable or a REFERENCE variable.

{attribute 'init_on_onlchange'}

The effect of this pragma is that the variable to which the pragma is applied is initialized with each online change. For minor changes in the code part of a POU only the modified blocks are compiled and downloaded. In particular, no initialization code is generated. This means that also no code is generated when variables with the {attribute 'init_on_onlchange'} are initialized.

{attribute 'no-exit'}

This attribute suppresses the call of the FB_EXIT method of a function block for a certain one of its instances. To do this you insert the attribute in the line before the declaration of the function block instance.

The methods FB_INIT, FB_REINIT and FB_EXIT

The implementation of these methods can be appropriately respond to the different situations in the life cycle of a function block.

FB_INIT always is available implicitly and basically is used by CODESYS for the initialization. For selective influencing you can declare FB_INIT explicitly and supplement the given standard initialization code.

Interface of the FB_INIT method

METHOD FB_INIT : BOOL
VAR_INPUT
    bInitRetains : BOOL; // TRUE: The Retain-variables are initialized (reset warm / reset cold)
    bInCopyCode : BOOL; // TRUE: The instance will be copied afterward (online change)
END_VAR

FB_REINIT must be declared explicitly, there is no implicitly available declaration. If FB_REINIT is available, it will be called after the instance of the concerned function block has been copied (during an online change after modifications in the function block declaration). It reinitializes the new instance of a function block. In order to reach a reinitialization of the base implementation of a function block, you must call FB_REINIT explicitly for that function block.

Interface of the FB_REINIT method

METHOD FB_REINIT : BOOL

FB_EXIT is a special method for a function block. It is called, before the code of the function block is deleted from the controller. There is no implicit declaration, you must explicitly declare FB_EXIT.

Interface of the FB_EXIT method

METHOD FB_EXIT : BOOL
VAR_INPUT
    bInCopyCode : BOOL; // TRUE: the exit method is called in order to leave the instance, which will be copied afterward (Online Change).
END_VAR
First Download:

When downloading an application on a device in delivered stage, the memory locations of all variables must be brought to the desired initial state. As a result the data areas of function blocks get occupied by the desired values. Using an explicit implementation of FB_INIT for function blocks and structures you can selectively react on this situation by the application code. By evaluating the method parameters bInCopyCode (FALSE) and bInitRetains (TRUE) you can clearly detect this operation condition. (See “Online-Change” and “Renewed Download“)

Online-Change:

In the course of an online change you can use the methods FB_EXIT, FB_INIT and FB_REINIT to influence the initialization of function blocks and structures. During an online change the modifications, which have been made in offline mode in the application, get followed up in the running device. That’s why the “old” instances of function blocks get replaced by their “new” sisters as smooth as possible. If, before login, no changes have been made in the declaration part of a function block, but only in the implementation part, then there will be no replacement of data areas. Only code blocks will be replaced. Thus, the methods FB_EXIT , FB_INIT and FB_REINIT will not be called!

Note

If you have made changes in the declaration of a function block, which will lead to the above described copy process, then when going to an online change, you will get a message on the possible “unintended consequences”. In the Details of the message box you will find a list of all instances to be copied.

In the code of the methods FB_INIT and FB_EXIT you can use the values of the parameters bInCopyCode (TRUE) and bInitRetains (FALSE), to detect whether an online change is being executed.

During an online change the following calls are executed successively:

  1. FB_EXIT:

    You can use calling FB_EXIT to initiate certain cleanup work to be done before the copy process. Thus you can prepare the data for the next copy process and by that influence the condition of the “new” instance. You can inform other parts of the application about the forthcoming change of position in the memory. Pay special attention to variables of type POINTER or REFERENCE. Maybe that after an online change these variables not any longer refer to the desired memory locations. Variables of type INTERFACE are treated separately by the compiler and get adapted appropriately during online change. External resources like for example SOCKET, FILE or other handles possibly can be adopted by the new instance, and often need no separate treatment during online change. (See: “Download”)

  2. FB_INIT

    Calling FB_INIT is done after the copy process and can be used for executing online-change-specific operations. For example, this lets you appropriately initialize variables at the “new” memory location, or inform other parts of the application about the new position of certain variables.

  3. FB_REINIT

    This method is called subsequently to FB_INIT and is to set the variables of the instance to defined values. Design the implementation independently from online change, because the method might be called by the application anytime, when a function block should be reset to the original state.

Note

Using {attribute 'no_copy'} to prevent for a single variable of a function block, that it gets copied during online change. Then the variable in any case will have the initial value.

Renewed Download:

During the download of an application possibly an already existing application on the device will be replaced. That’s why the memory space for the existing function blocks must be released in a regulated way. You can use the FB_EXIT method for implementing the necessary steps. For example you can put external resources (like SOCKET or FILE Handles) in a defined state.

You can detect this operating condition in the code of the FB_EXIT method via the parameters bInCopyCode (FALSE).

Application Start:

Before the first cycle of the tasks of an application the initial assignments get processed.

Example

T1 : TON := (PT:=t#500ms);

Such assignments are executed after FB_INIT has been called! In order to become able to control the impacts of these assignments, you may decorate a function block and a specific method of a function block with {attribute 'call_after_init'}. You must insert this attribute above the declaration part of the function block and above the declaration part of the corresponding method. A function block that extends another function block, which is using the {attribute 'call_after_init'}, must also get this attribute. For comprehensibility reasons we recommend to overwrite the corresponding method by the same name, the same signature and the same attribute. This requires calling SUPER^.Init. The method name is freely selectable (exceptions: FB_INIT, FB_REINIT and FB_EXIT!). After the initial assignments have been processed, the method will be called before the application tasks start, and such can react on the user specifications.

However consider the following when using the FB_INIT or {attribute 'call_after_init'}: Detecting errors in the FB_INIT method or in methods decorated with {attribute 'call_after_init'} is difficult, because inter alia the setting of breakpoints might not have the desired effect.

Note

When the execution reaches the explicitly defined initialization code, then the function block is already initialized completely via the implicit initialization code. That’s why calling SUPER^.FB_INIT() is not allowed.

Example and Demonstration

The following example demonstrates the different usecases for attributes and special methods like FB_INIT and FB_EXIT. Please download the sensor.project and take a look to the source code.

Inside the project we will find two types of function blocks implementing a sensor (GenericSensor and SpecificSensor). The function block SpecificSensor extends the function block GenericSensor and this extends an CBML.LConC behaviour model. The other major function block in this project is the one with the name SensorList witch extends a LAT.IList implementation LAT.List. All sensors which are necessary to providing the recommended solution are declared inside a global variable list GVL. The FB_INIT method of the sensor implementation will automatically add each sensor to the sensor list. This collection of sensors is then processed in every cycle of the PLC_PRG main program.

_images/sensor.png

For testing, please open the GVL and open the various Sensor function blocks. You can use the xEnable input variable to start and stop a sensor and get some impression about the functionality by observing the counter variables.

Helper Structures for Generic Types

Using the generic types defines in IEC 61131-3 results in some new data structures:

The list of generic types supported in CODESYS:

Generic data types

Groups of elementary data types

ANY

STRUCT, ARRAY, POINTER, …

ANY_NUM

ANY_REAL

REAL, LREAL

ANY_INT

USINT, UINT, UDINT, ULINT, __UXINT,
SINT, INT, DINT, LINT, __XINT

ANY_DURATION 1

TIME, LTIME

ANY_STRING

STRING, WSTRING

ANY_DATE

DATE_AND_TIME, DATE, TIME_OF_DAY

1

Not yet implemented (CDS-60989)

Example

{attribute 'qualified_only'}
{attribute 'strict'}
TYPE ENCODINGS :
(
    UNKNOWN,
    WINDOWS1252,
    UCS2
);
END_TYPE

This enumerable data type represent the two different encoding schemes for strings in CODESYS.

FUNCTION Encoding : ENCODINGS
VAR_INPUT
    sValue : ANY_STRING;
END_VAR

A function which can be instructed to operate on variables (no literals!) of type STRING or WSTRING with any length.

IF sValue.TypeClass = __SYSTEM.TYPE_CLASS.TYPE_STRING THEN
    Encoding := ENCODINGS.WINDOWS1252;
ELSIF sValue.TypeClass = __SYSTEM.TYPE_CLASS.TYPE_WSTRING THEN
    Encoding := ENCODINGS.UCS2;
ELSE
    Encoding := ENCODINGS.UNKNOWN;
END_IF
The encoding for the content of a variable of type STRING is Windows-1252.
The encoding for the content of a variable of type WSTRING is UCS-2.