Properties for implementing vendor blocks
This article contains statements that can be used when creating vendor blocks – in particular, the statements to create the interface of the vendor block. Moreover, there are some examples illustrating some of the possibilities for the interface.
The interface for a vendor block
(= vendor →function block or vendor →function)
is created in an ST-object whereas t
he implementation for a vendor block is created in →C.
Usually, a vendor block will be integrated in a custom library. But it is also possible to solely use a vendor block within the project in which the vendor block has been created.
Restrictions: The following variables are not supported in the interface of vendor blocks:
→temporary variables (VAR_TEMP...END)
If you need temporary variables without storing behavior, create them within the implementation functionality.→external variables (VAR_EXTERNAL...END)
Moreover, →methods are not supported for implementing a vendor block.
Please observe:
This article contains reference documentation of the statements that are designated to create the interface of vendor blocks. Of course, you will need to use other statements as well – for instance, the sections VAR_INPUT ... END_VAR, VAR_OUTPUT ... END_VAR, VAR_IN_OUT ... END_VAR. See "Supported ST-syntax" for information on these possibilities (or other statements that are not listed here).
The following files are needed for the implementation:
File
Contents
the H-file
the data type for the vendor block, initialization macros (INIT, WINIT) and – if no C-file is used – the implementation (usually by means of a macro)
See "The structure of the needed H-file", if you are interested in the basic structure of an H-file .an optional C-file
the implementation (if the implementation is not realized within the H-file)
All C-files are appended when the application is built so that one C-file is used for compiling. Therefore, the single C-files might have an impact on other C-files as well. logi.cals recommends resetting a define at the end of the C-file, if the define is valid for one C-file only.The fact, whether a C-file will be used, is controlled by the definition functionHasCFile within the statement { ImplementationProperties ( ) } . See below for more information.
optional O-files and/or lib-files
The fact, whether files for additional objects and/or libraries will be used, is controlled by the definitions additionalObjects and additionalLibraries within the statement { ImplementationProperties ( ) } . See below for more information.
The creation of the contents of the H-file and the C-file is beyond the scope of this article. See the article " Details: Creating a vendor block " for an instruction on how to have the implementation stubs in the C-/H-file created.
The statements {...} are also known as →pragmas according to the IEC-standard. The following statements may contain integer literals or →character string literals in pragmas. A character string literal in pragmas may be enclosed in the double quote character " as well as in the single quote character '. For the sake of convenience, this article uses the double quote character " for most of the character string literal in pragmas.
Basic statements
You need to insert one of the following statements as the first line of the ST-object that contains the interface of the required vendor block.
Statement |
Purpose |
{CustomImplementation} |
This statement identifies the block as vendor block to be used for a library. This statement has the following effects:
If you want to use a C-file, specify the definition functionHasCFile within the statement { ImplementationProperties ( ) } as well. See below for more information. |
{CustomImplementation, CustomNameSpace := Name} |
CustomNameSpace := Name is an optional part that you can use to better identify the code for the block.
Observe: logi.cals recommends using the NAMESPACE ... END_NAMESPACE statements for the vendor block interface in order to avoid possible conflicts with other blocks. See "Namespaces in ST" for details on these statements. The name specified for the optional definition implementationName within the statement { ImplementationProperties ( ) } (see below for more information) is also included in the file names for the H-/C–file. |
Interface statements
Specify the interface statements to determine the block interface (e.g. background color, height/width).
Do not save any changes done within the interface editor.
Usually, you would use the interface editor to create the block interface. But when creating vendor blocks, use the interface editor only to check the interface.
If you save any changes done within the interface editor, it might be possible that already existing statements required for the vendor block are deleted/destroyed. At present, the interface editor is not able to correctly display/handle all statements for vendor blocks.
{CustomImplementation}
NAMESPACE com.oem1.lib1
FUNCTION_BLOCK name | FUNCTION name : data-type
USING Namespace_1; (* possible statement, if a namespace should be used *)
{ IO-name_1 { IO_definition_1, IO_definition_2, IO_definition_3 };
IO-name_2 { IO_definition_1, IO_definition_2, IO_definition_3 };
...
Interface_definition_1;
Interface_definition_2;
...
};
{ ImplementationProperties (...) };
VAR | VAR_INPUT | VAR_OUTPUT | VAR_IN_OUT | VAR_GLOBAL | VAR_EXTERNAL
...
END_VAR
END_FUNCTION_BLOCK | END_FUNCTION
END_NAMESPACE
The definitions for IOs { IO_definition_1, IO_definition_2, IO_definition_3 } are applied to the specified variable of the vendor block, e.g. IO-name_1. logi.CAD 3 supports the definitions for IOs for
the return value of a function.
The general term will be "variable" in the following description.
IO definition |
Purpose |
loc := "orientation" |
determines the orientation of the specified variable
|
index := # |
determines the position of the specified variable If the variable is located outside of height and width and without the definition expandableGUI, a call of the block inserted into the FBD-editor will automatically be enlarged so that the call contains all variables. |
altName := "name" |
determines the alternative name of the specified variable |
The interface definitions, e.g. Interface_definition_1 , are applied to the vendor block.
Interface definition |
Purpose |
height := # |
determines the height of the block when the block is inserted into the FBD-editor |
width := # |
determines the width of the block when the block is inserted into the FBD-editor |
minHeight := # |
determines the minimum height of the block – After the block has been inserted into the FBD-Editor, the block can be made smaller up to the specified minimum height. |
maxHeight := # |
determines the maximum height of the block – After the block has been inserted into the FBD-Editor, the block can be enlarged up to the specified maximum height. |
minWidth := # |
determines the minimum width of the block – After the block has been inserted into the FBD-Editor, the block can be made smaller up to the specified minimum width. |
maxWidth := # |
determines the maximum width of the block – After the block has been inserted into the FBD-Editor, the block can be enlarged up to the specified maximum width. |
minInputs := # |
determines the number of inputs that are required for the correct functionality of the vendor block There will be a warning, if a call of the block is inserted into an editor and too few inputs of the block call are connected within the FBD-editor or if too few parameters are specified for the block call within the ST-editor. In order to avoid the warning, you must connect or specify the required number of inputs or at least the input which is the last of them. If you are specifying this definition, the best practice is to add the definition expandableGUI . The definition expandable within the statement { ImplementationProperties ( ) } might be needed as well (see below for more information). |
fixedSize |
makes the block to be of a fixed size
Subsequently, the specifications for minHeight, maxHeight, minWidth and maxWidth are ignored. Instead the specifications for height and width are applied only. |
hideIONames |
hides the names of the inputs, outputs, in-outs and the return value of a function |
hideOutputOfVarInOut |
applied for in-out variables (= VAR_IN_OUT) so that the following is valid: logi.CAD 3 displays the user interface of the block as it is in logi.CAD/32. This means that
only the input connection point of the in-out variable is displayed in logi.CAD 3. It is also possible that other variables are located on the opposite position of the input connection point.
This setting is automatically applied when a block with in-out variables is migrated from logi.CAD/32 to logi.CAD 3. The interface editor does not provide a matching GUI element for this interface statement. |
altName := "name" |
determines the alternative name for the block |
vNameAlignment := "value" |
determines the vertical alignment of the block name (or of the alternative name for the block)
See the following examples for alignment. |
bgColor := "value" |
determines the background color of the block logi.cals recommends that you and/or your system integrator do not use yellow shades when designing FBD-elements because the color "Yellow" is used for tracking safe signals when developing safety-related applications. logi.CAD 3 does not check if colors are already used elsewhere. So the use of the yellow shades by you and/or your system integrator could have the consequence that "yellow" might also identify a non-safe logic as well. |
fgColor := "value" |
determines the color of the block text; Possible values: see the background color of the block |
iofgColor := "value" |
determines the color of the inputs, outputs, in-outs and the return value of a function; Possible values: see the background color of the block |
expandableGUI |
determines that the vendor block is an extensible block, which means it can be expanded by additional inputs/outputs (when the block is made larger) |
pageSize := "valuexvalue" |
determines the page size when the FBD-logic is displayed within the graphical FBD-editor |
instanceName := {definitions}; |
determines the layout of the instance name for a function block instance
|
valueFields := {definitions}; |
add value fields for inputs within the interface and determines the layout of them
|
commentFields := {definitions}; |
add comment fields within the interface and determines the layout of them
|
Examples with interface statements
The interface of the following example... |
will look like this: |
Example
{CustomImplementation} NAMESPACE com.oem1.lib1 FUNCTION_BLOCK myFB_01 { IN1 {altName := "I1"}; IN2 {index := 2, altName := "I2"}; IN3 {index := 3, altName := "I3"}; IN4 {index := 4, altName := "I4"}; OUT {index := 1, altName := "O"}; minInputs := 2; altName := "TST"; vNameAlignment := "center"; height := 58; width := 100; minWidth := 70; maxWidth := 150; bgColor := "DodgerBlue"; expandableGUI; } VAR_INPUT IN1 : BOOL; IN2 : BOOL; IN3 : BOOL; IN4 : BOOL; END_VAR VAR_OUTPUT OUT : BOOL; END_VAR END_FUNCTION_BLOCK END_NAMESPACE |
Please note the warning icons due to minInputs := 2; |
Example for alignment
{CustomImplementation} NAMESPACE com.oem1.lib1 FUNCTION_BLOCK myFB_T { altName := "TOP"; vNameAlignment := "top"; bgColor := "DarkBlue"; instanceName := {visible}; } VAR_IN_OUT IO1 : BOOL; IO2 : BOOL; IO3 : BOOL; END_VAR END_FUNCTION_BLOCK END_NAMESPACE Example for alignment
{CustomImplementation} NAMESPACE com.oem1.lib1 FUNCTION_BLOCK myFB_BL { altName := "BASELINE"; vNameAlignment := "baseline"; bgColor := "DarkBlue"; instanceName := {visible}; } VAR_IN_OUT IO1 : BOOL; IO2 : BOOL; IO3 : BOOL; END_VAR END_FUNCTION_BLOCK END_NAMESPACE Example for alignment
{CustomImplementation} NAMESPACE com.oem1.lib1 FUNCTION_BLOCK myFB_C { altName := "CENTER"; vNameAlignment := "center"; bgColor := "DarkBlue"; instanceName := {visible}; } VAR_IN_OUT IO1 : BOOL; IO2 : BOOL; IO3 : BOOL; END_VAR END_FUNCTION_BLOCK END_NAMESPACE Example for alignment
{CustomImplementation} NAMESPACE com.oem1.lib1 FUNCTION_BLOCK myFB_B { altName := "BOTTOM"; vNameAlignment := "bottom"; bgColor := "DarkBlue"; instanceName := {visible}; } VAR_IN_OUT IO1 : BOOL; IO2 : BOOL; IO3 : BOOL; END_VAR END_FUNCTION_BLOCK END_NAMESPACE |
Please note the warning icons due to declared in-outs. |
Statement 'ImplementationProperties' and its definition
The statement { ImplementationProperties ( ) } is a container for definitions to control the code generation for the vendor blocks – within the application in which the vendor block is created as well as within a library in which the vendor block will be integrated.
{CustomImplementation}
NAMESPACE com.oem1.lib1
FUNCTION_BLOCK name | FUNCTION name : data-type
USING Namespace_1; (* possible statement,
if
a namespace should be used *)
{ list of
interface
statements; }
{ ImplementationProperties (definition_1; definition_2; ...) };
VAR | VAR_INPUT | VAR_OUTPUT | VAR_IN_OUT | VAR_GLOBAL | VAR_EXTERNAL
...
END_VAR
END_FUNCTION_BLOCK | END_FUNCTION
END_NAMESPACE
Definition |
Purpose |
Definitions that are affecting the structure of files |
|
additionalLibraries and additionalObjects |
determines additional objects and/or additional libraries to be integrated when the application is built for the target system Observe: When the library with the vendor block is generated, you are able to specify the following statements within the library configuration (see "Example for library configuration" below):
See the example below for more information. |
extraIncludes |
determines one or more additional required H-files By default, the additional files must be located in the sub-folder src-code of the project. If you want to change the location of the files, specify the statement COMMON_SOURCE := sub-folder of project; within the library configuration (see "Example for library configuration" below). In case of COMMON_SOURCE := MoreFiles; logi.CAD 3 searches within path project/MoreFiles/src-code for the additional files. |
functionHasCFile |
determines to
use a C-file as well (besides the H-file) |
implementationName |
determines a different POU name as part of file name for the H-file as well as for the C-file (if the definition functionHasCFile is specified as well) |
Definitions that are affecting the content of the H-file (type def structure, implementation) |
|
expandable |
This definition is necessary for the correct code generation of an extensible block (see the interface definition expandableGUI) It is sufficient for vendor blocks to only include the definition expandable (see the following examples). A better practice is to include the definition expandable as well as the interface definition expandableGUI. |
passConcreteTypeParameter |
determines to add the TYPE argument as 1st argument in the implementation within the H-file |
untypedCFunctionNameWhitelist and untypedCFunctionNameBlacklist |
maps the vendor block – Consequence: A list of concrete data types is created based on the specified values. For each one of these concrete data types, __ANY must be used instead of the concrete data type within the implementation (e.g. in the H-file).
See "The structure of the needed H-file"
and/or the following examples, if you are unsure which part of the H-file is the implementation. untypedCFunctionNameWhitelist specifies the data types for which the definition should be applied, untypedCFunctionNameBlacklist specifies the data types for which the definition should not be applied. It is allowed to use untypedCFunctionNameWhitelist without untypedCFunctionNameBlacklist but it is not allowed to just use untypedCFunctionNameBlacklist. Allowed values for both definitions (as a comma-separated list):
|
useUntypedTypeStructure |
determines that the concrete data type must not be added for the name of the typedef structure – instead the generic name of the block must be used |
Definitions that are affecting the validation when the vendor block is called |
|
allowedTypeWhitelist and allowedTypeBlacklist |
determines which data types are supported when the inputs/outputs of the vendor block call are connected allowedTypeWhitelist specifies the allowed data types, allowedTypeBlacklist specifies the illegal data types. It is allowed to use both definitions or just one of the definitions. Without the definition allowedTypeWhitelist, all data types are allowed (default is ANY). Without the definition allowedTypeBlacklist, no data type is illegal. Allowed values for both definitions (as a comma-separated list):
Please contact logi.cals, if your vendor block is to support the elementary data types CHAR or STRING . |
returnValueMustBeAssigned |
determines that – in the case of a function call – the return value must be assigned to a concrete variable |
What is a generic data type? What are the appropriate elementary data types? See →generic data types
Examples with implementation properties
The following examples are mostly using the system blocks of logi.CAD 3 to illustrate the usage of the above definitions. Observe that because of internal reasons, the system blocks are using the part CustomNameSpace := Name instead of the rather recommended statement NAMESPACE ... END_NAMESPACE statements.
If you are interested in how logi.cals has implemented the system blocks and you want to check out the appropriate H- and C-files in detail:
Contact logi.cals for the sources containing the appropriate system library.
Usually, the sources are a logi.CAD 3 project containing the system blocks and a library configuration.
Examples affecting the structure of files
Example with 'additionalLibraries' and 'additionalObjects'
{ CustomImplementation}
NAMESPACE Copies
FUNCTION_BLOCK myFB01
{ ImplementationProperties (additionalLibraries:="additionalLibrary1,additionalLibrary2"; additionalObjects:="additionalObject1, additionalObject2"; )}
VAR_INPUT
...
END_FUNCTION_BLOCK
END_NAMESPACE
The generation of the library MyLibWithVendorBlocks (see the next example) requires the additional library files additionalLibrary1 and additionalLibrary2 as well as the additional object files additionalObject and additionalObject2.
Please observe:
The location of these files depends on the statements COMMON_SOURCE and SUPPORTED_PTKS specified within the library configuration. For the following library configuration, the files are searched within the path project/MoreFiles/src-code/WindowsX86Without the statement COMMON_SOURCE, the files are searched within the path project/src-code/WindowsX86
The extension of these files depends on the statement SUPPORTED_PTKS as well. For the following library configuration, the files additionalLibrary1.lib and additionalLibrary2.lib, additionalObject.o and additionalObject2.o are searched.
LIBRARY MyLibWithVendorBlocks
Version := 0.0.1;
SUPPORTED_PTKS := WindowsX86;
COMMON_SOURCE := MoreFiles;
FOLDER "folderName"
IEC := myFB01;
END_FOLDER
END_LIBRARY
Special behaviors:
If you define the platform BuiltInPlc (instead of WindowsX86) within the library configuration, the file location depends on the operating system where the library is used. For Windows, the sub-folder is WindowsX86 (as already specified above), for Linux the sub-folder is LinuxX86.
If you are using the vendor block directly within the project (in which you have created the vendor block), the additional files are searched starting with the target platform. This means if the platform BuiltInPlc is specified within the resource for the project, the additional files are searched within the path project/src-code/BuiltInPlc.
Example with/without 'extraIncludes'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION GET_TYPE_FROM_VARNAME : UDINT
{ altName := ""; vNameAlignment := "center"; width:=208;}
{ ImplementationProperties ( extraIncludes := "RTSSNS.h,RTSSNSUtil.h"; functionHasCFile; ) }
VAR_INPUT
...
END_FUNCTION
The code generation requires the H-file lcfu_iec61131__GET_TYPE_FROM_VARNAME.h, the C-file lcfu_iec61131__GET_TYPE_FROM_VARNAME.c as well as the additional H-files RTSSNS.h, RTSSNSUtil.h.
If the library configuration does not specify otherwise, logi.CAD 3 searches within the path project/src-code for the additional files.
Example with/without 'functionHasCFile'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION FIND : ANY_INT { FIND { altName := "" }; ... }
{ ImplementationProperties ( functionHasCFile; ) }
VAR_INPUT
...
END_FUNCTION
The code generation requires the H-file lcfu_iec61131__FIND.h as well as the C-file named lcfu_iec61131__FIND.c.
Compare the following copy of the system block that has been slightly modified:
{ CustomImplementation}
NAMESPACE Copies
FUNCTION FIND_Copy : INT { FIND { altName := "" }; }
END_FUNCTION
END_NAMESPACE
The code generation requires only the H-file lcfu___copies.FIND_COPY.h. No C-file is required because of the missing definition functionHasCFile.
Example with/without 'implementationName'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION TO_SINT : SINT { hideIONames; ... }
{ ImplementationProperties ( ...; functionHasCFile; implementationName:="CONVERT"; ) }
VAR_INPUT
...
END_FUNCTION
...
FUNCTION TO_INT : INT { hideIONames; ... }
{ ImplementationProperties ( ...; functionHasCFile; implementationName:="CONVERT"; ) }
VAR_INPUT
...
END_FUNCTION
The code generation requires the H-file lcfu_iec61131__CONVERT.h and the C-file lcfu_iec61131__CONVERT.c – instead of the H-files lcfu_iec61131__TO_SINT.h , lcfu_iec61131__TO_INT.h and the C-files lcfu_iec61131__TO_SINT.c, lcfu_iec61131__TO_INT.c.
Please observe:
If the first ST-object containing the function TO_SINT is saved, logi.CAD 3 auto-generates the files lcfu_iec61131__CONVERT.h and the C-file lcfu_iec61131__CONVERT.c with the implementation stubs for TO_SINT.
If the second ST-object containing the function TO_INT is saved later on, logi.CAD 3 does not update the files lcfu_iec61131__CONVERT.h and the C-file lcfu_iec61131__CONVERT.c to include the implementation stubs for TO_INT.
If you require different implementation stubs for TO_SINT and TO_INT, best practice is to not use the definition implementationName. Only use the definition implementationName, if the same implementation is required within the same file.
Examples affecting the content of the H-file
Example with/without 'expandable'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION ADD : ANY_MAGNITUDE { minInputs := 2; ... }
{ ImplementationProperties ( expandable; untypedCFunctionNameWhitelist:="ANY_NUM,ANY_DURATION"; ) }
VAR_INPUT
IN1 : ANY_MAGNITUDE;
...
IN16 : ANY_MAGNITUDE;
END_VAR
END_FUNCTION
#define lcfu_iec61131__ADD__ANY__2(LC_this, IN1, IN2, pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_2(IN1,IN2)
#define lcfu_iec61131__ADD__ANY__3(LC_this, IN1, IN2, IN3,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_3(IN1,IN2,IN3)
#define lcfu_iec61131__ADD__ANY__4(LC_this, IN1, IN2, IN3,IN4,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_4(IN1,IN2,IN3,IN4)
#define lcfu_iec61131__ADD__ANY__5(LC_this, IN1, IN2, IN3,IN4,IN5,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_5(IN1,IN2,IN3,IN4,IN5)
#define lcfu_iec61131__ADD__ANY__6(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_6(IN1,IN2,IN3,IN4,IN5,IN6)
#define lcfu_iec61131__ADD__ANY__7(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_7(IN1,IN2,IN3,IN4,IN5,IN6,IN7)
#define lcfu_iec61131__ADD__ANY__8(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_8(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8)
#define lcfu_iec61131__ADD__ANY__9(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_9(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9)
#define lcfu_iec61131__ADD__ANY__10(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_10(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10)
#define lcfu_iec61131__ADD__ANY__11(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_11(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11)
#define lcfu_iec61131__ADD__ANY__12(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_12(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12)
#define lcfu_iec61131__ADD__ANY__13(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_13(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13)
#define lcfu_iec61131__ADD__ANY__14(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_14(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14)
#define lcfu_iec61131__ADD__ANY__15(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14,IN15,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_15(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14,IN15)
#define lcfu_iec61131__ADD__ANY__16(LC_this, IN1, IN2, IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14,IN15,IN16,pEPDB) \
(LC_this)->LC_VD_ADD = LC_MF_ADD_ANY_16(IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,IN9,IN10,IN11,IN12,IN13,IN14,IN15,IN16)
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION_BLOCK RS { vNameAlignment := "center"; ... }
VAR_INPUT
S : BOOL;
R1 : BOOL;
END_VAR
...
END_FUNCTION_BLOCK
#define lcfu_iec61131__RS(LC_this, pEPDB) \
(LC_this)->LC_VD_Q1 = (!(LC_this)->LC_VD_R1) && ((LC_this)->LC_VD_S || (LC_this)->LC_VD_Q1
Example with/without 'passConcreteTypeParameter'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION PACK : ANY_ELEMENTARY { minInputs := 2; ... }
{ ImplementationProperties ( allowedTypeWhitelist:="ANY_ELEMENTARY"; allowedTypeBlacklist:="ANY_CHARS"; expandable; passConcreteTypeParameter; functionHasCFile; untypedCFunctionNameWhitelist:="ANY_ELEMENTARY"; untypedCFunctionNameBlacklist:="ANY_CHARS,BOOL"; ) }
VAR_INPUT
IN0 : BYTE;
...
IN7 : BYTE;
END_VAR
END_FUNCTION
#define lcfu_iec61131__PACK__ANY__2(TYPE,LC_this, v1,v2,pEPDB) lcfu_iec61131__PACK__ANY(sizeof(TYPE),&((LC_this)->LC_VD_PACK),2,v1,v2)
...
Example with 'untypedCFunctionNameWhitelist' and without 'untypedCFunctionNameBlacklist' and with both of them
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION SUB : ANY_MAGNITUDE { hideIONames; ... }
{ ImplementationProperties ( untypedCFunctionNameWhitelist:="ANY_NUM,ANY_DURATION"; ) }
VAR_INPUT
...
END_FUNCTION
The following list of concrete data types emerges for SUB:
Concrete data types because of white list |
Concrete data types after of black list |
REAL, LREAL, USINT, UINT, UDINT, ULINT, SINT, INT, DINT, LINT – due to ANY_NUM TIME – due to ANY_DURATION (Currently, LTIME is not supported in logi.CAD 3.) |
identical because there is no black list |
The code generation requires that __ANY (instead of __REAL, __LREAL, __USINT etc.) is used within the implementation (e.g. in the H-file).
/* Implementation of helper macros (inlined) */
#define LC_MF_SUB_ANY(IN1,IN2) ((IN1)-(IN2))
#define lcfu_iec61131__SUB__ANY(LC_this, IN1, IN2, pEPDB) \
(LC_this)->LC_VD_SUB = LC_MF_SUB_ANY(IN1,IN2)
Compare the following system block that is using the white list and the black list:
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION OR : ANY_BIT { minInputs := 2; ... }
{ ImplementationProperties ( expandable; untypedCFunctionNameWhitelist:="ANY_BIT"; untypedCFunctionNameBlacklist:="BOOL"; ) }
VAR_INPUT
...
END_FUNCTION
The following list of concrete data types emerges for OR:
Concrete data types because of white list |
Concrete data types after of black list |
BOOL, BYTE, WORD, DWORD, LWORD – due to ANY_BIT |
BYTE, WORD, DWORD, LWORD – BOOL is removed |
The code generation requires that __ANY (instead of __BYTE, __WORD, __DWORD and __LWORD) is used within the implementation (e.g. in the H-file) but not for the concrete data type BOOL.
#define lcfu_iec61131__OR__BOOL__2(LC_this, IN1, IN2, pEPDB) \
(LC_this)->LC_VD_OR = LC_MF_OR_BOOL_2(IN1,IN2)
#define lcfu_iec61131__OR__BOOL__3(LC_this, IN1, IN2, IN3,pEPDB) \
(LC_this)->LC_VD_OR = LC_MF_OR_BOOL_3(IN1,IN2,IN3)
...
#define lcfu_iec61131__OR__ANY__2(LC_this, IN1, IN2, pEPDB) \
(LC_this)->LC_VD_OR = LC_MF_OR_ANY_2(IN1,IN2)
#define lcfu_iec61131__OR__ANY__3(LC_this, IN1, IN2, IN3,pEPDB) \
(LC_this)->LC_VD_OR = LC_MF_OR_ANY_3(IN1,IN2,IN3)
...
Example with 'useUntypedTypeStructure'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION MUL_TIME : TIME { hideIONames; ... }
{ ImplementationProperties ( useUntypedTypeStructure; ) }
VAR_INPUT
IN1 : TIME;
IN2 : ANY_NUM;
END_VAR
END_FUNCTION
Usually, the generic data type ANY_NUM of the 2nd input would require that the concrete data types are added for the name of the typedef structure. This is not necessary because of the implementation itself. So useUntypedTypeStructure is used in the interface.
typedef struct _LC_TD_Function_MUL_TIME
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_TIME LC_VD_MUL_TIME;
} LCCG_StructAttrib LC_TD_Function_MUL_TIME;
Compare the following copy of the system block that has been slightly modified: MUL_TIME_Copy is specified without useUntypedTypeStructure.
{ CustomImplementation}
NAMESPACE Copies
FUNCTION MUL_TIME_Copy : TIME { hideIONames; }
VAR_INPUT
IN1 : TIME;
IN2 : ANY_NUM;
END_VAR
END_FUNCTION
The code generation requires that the concrete data types are added for the name of the typedef structures. Hence, the names for the structures are:
MUL_TIME_REAL
MUL_TIME_LREAL
MUL_TIME_USINT
MUL_TIME_UINT
MUL_TIME_UDINT
MUL_TIME_ULINT
MUL_TIME_SINT
MUL_TIME_INT
MUL_TIME_DINT
MUL_TIME_LINT
typedef struct _LC_TD_Function_MUL_TIME_REAL
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_TIME LC_VD_MUL_TIME;
} LCCG_StructAttrib LC_TD_Function_MUL_TIME_REAL;
typedef struct _LC_TD_Function_MUL_TIME_LREAL
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_TIME LC_VD_MUL_TIME;
} LCCG_StructAttrib LC_TD_Function_MUL_TIME_LREAL;
typedef struct _LC_TD_Function_MUL_TIME_USINT
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_TIME LC_VD_MUL_TIME;
} LCCG_StructAttrib LC_TD_Function_MUL_TIME_USINT;
/* and more blocks according to the data type */
Examples affecting the validation when the vendor block is called
Example with 'allowedTypeWhitelist' and without 'allowedTypeBlacklist' and with both of them
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION SHL : ANY_ELEMENTARY { vNameAlignment := "center"; width := 100; bgColor := "dodgerblue"; }
{ ImplementationProperties ( allowedTypeWhitelist:="ANY_BIT,ANY_INT"; ) }
VAR_INPUT
IN : ANY_ELEMENTARY;
N : INT;
END_VAR
END_FUNCTION
The following list of concrete data types emerges for SHL:
Concrete data types because of white list |
Concrete data types after of black list |
BOOL, BYTE, WORD, DWORD, LWORD – due to ANY_BIT USINT, UINT, UDINT, ULINT, SINT, INT, DINT, LINT – due to ANY_INT |
identical because there is no black list |
These concrete data types are supported when the input IN of a SHL block call is connected.
PROGRAM Test1
VAR
result1 : INT;
result2 : REAL;
END_VAR
result1 := SHL(IN := INT#40, N := 1); (* allowed *)
result2 := SHL(IN := REAL#40.0, N := 1); (* NOT allowed *)
END_PROGRAM
Compare the following system block that is using the white list and the black list:
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION LIMIT : ANY_ELEMENTARY { LIMIT { altName := ""}; ... }
{ ImplementationProperties ( allowedTypeWhitelist:="ANY_ELEMENTARY"; allowedTypeBlacklist:="ANY_CHARS"; untypedCFunctionNameWhitelist:="ANY_ELEMENTARY"; untypedCFunctionNameBlacklist:="ANY_CHARS"; ) }
VAR_INPUT
MN : ANY_ELEMENTARY;
IN : ANY_ELEMENTARY;
MX : ANY_ELEMENTARY;
END_VAR
END_FUNCTION
The following list of concrete data types emerges for LIMIT:
Concrete data types because of white list – due to ANY_ELEMENTARY |
Concrete data types after of black list – due to ANY_CHARS |
REAL, LREAL USINT, UINT, UDINT, ULINT SINT, INT, DINT, LINT TIME BOOL, BYTE, WORD, DWORD, LWORD STRING CHAR DATE_AND_TIME, DATE, TIME_OF_DAY, LDATE |
REAL, LREAL USINT, UINT, UDINT, ULINT SINT, INT, DINT, LINT TIME BOOL, BYTE, WORD, DWORD, LWORD DATE_AND_TIME, DATE, TIME_OF_DAY, LDATE |
These concrete data types are supported when the inputs of LIMIT call is connected. This is valid for all 3 inputs MN, IN and MX.
Observe: logi.CAD 3 does not support some of the concrete data types (e.g. LTIME). Otherwise these data types would be contained due to ANY_ELEMENTARY.
PROGRAM Test1
VAR
result1 : INT;
result2 : STRING[10];
END_VAR
result1 := LIMIT(MN := 5, IN := 99, MX := 100); (* allowed *)
result2 := LIMIT(MN := "a", IN := "aa", MX := "aaa"); (* NOT allowed *)
END_PROGRAM
Example with/without 'returnValueMustBeAssigned'
...
{ CustomImplementation , CustomNamespace := iec61131}
...
FUNCTION GET_NAMED_MEMORY : ANY
{ altName := ""; ... }
{ ImplementationProperties ( ...; functionHasCFile; returnValueMustBeAssigned;) }
VAR_INPUT
...
END_FUNCTION
Compare the following copy of the system block that has been slightly modified:
{ CustomImplementation}
NAMESPACE Copies
FUNCTION GET_NAMED_MEMORY_Copy : INT
{ ImplementationProperties ( functionHasCFile;) }
END_FUNCTION
END_NAMESPACE
PROGRAM Test1
VAR
Var1 : REF_TO INT;
END_VAR
GET_NAMED_MEMORY(); (* NOT allowed because of 'returnValueMustBeAssigned' in the vendor block interface *)
Var1 := GET_NAMED_MEMORY(); (* allowed *)
GET_NAMED_MEMORY_Copy(); (* allowed *)
Var1 := GET_NAMED_MEMORY_Copy(); (* allowed *)
END_PROGRAM
Function references
The pragma { FunctionReferences } must be used in a vendor block when f
unctions of a library
are called in the C-code of the vendor block. This pragma is needed so that
logi.CAD 3
gets sufficient information on the called functions when building the application that is using the vendor block.
Compare:
You do not need to insert this pragma, when only function blocks are called in the C-code of the vendor block.
You do not need to insert this pragma for ST/FBD/LD POUs that are calling functions. This pragma is automatically inserted by logi.CAD 3 when you are specifying these POUs with value INTERFACE or DEPLOY to be part of a library.
Complete the pragma { FunctionReferences } by the names of the called functions. Separate the function names by the character ",".
{ CustomImplementation }
FUNCTION_BLOCK TestVendorFB
USING logicals.standard.util.schedule;
{ ImplementationProperties (functionHasCFile; ) }
{ FunctionReferences TO_INT, TO_SINT, MUL_TIME, AND }
(* The functions "TO_INT", "TO_SINT", "MUL_TIME" and "AND" are called in the C-code of the vendor block "TestVendorFB". *)
(* variable declarations *)
END_FUNCTION_BLOCK
Definitions for variables
It is possible to add some special definitions for declared variables – in addition to the statements/definitions already described under " Supported ST-syntax " .
{CustomImplementation}
NAMESPACE com.oem1.lib1
FUNCTION_BLOCK name | FUNCTION name : data-type
USING Namespace_1; (* possible statement, if a namespace should be used *)
{ list of interface statements; }
{ ImplementationProperties (...) };
VAR_IN_OUT
name_1 : data-type := initial-value { REQUIRES_NON_TEMP_VALUE };
...
END_VAR
VAR | VAR_INPUT | VAR_OUTPUT | VAR_IN_OUT | VAR_GLOBAL | VAR_EXTERNAL
name_1, name_2, ..., name_n : data-type := initial-value {
description := "string";
comment := "string";
customDataJson := 'Json-String';
concreteType := data-type;
};
...
END_VAR
END_FUNCTION_BLOCK | END_FUNCTION
END_NAMESPACE
Definition for variable |
Purpose |
{REQUIRES_NON_TEMP_VALUE} |
defines that temporary values must not be connected to the appropriate in-out |
{ |
specifies the following pieces of additional data (= data elements) for the variable:
See " Defining description, comment, JSON string or type for variables or data types " for details. |
Example with '{REQUIRES_NON_TEMP_VALUE}'
{CustomImplementation}
NAMESPACE com.oem1.lib1
FUNCTION myFUN_noTV
VAR_IN_OUT
IO1 : INT {REQUIRES_NON_TEMP_VALUE} ;
END_VAR
END_FUNCTION
END_NAMESPACE
PROGRAM Test1
USING com.oem1.lib1;
VAR_TEMP
tempVar1 : INT;
END_VAR
myFUN_noTV(IO1:=tempVar1);
(* not allowed because of '{REQUIRES_NON_TEMP_VALUE}' in the vendor block interface and
because 'tempVar1' is a temporary variable. *)
END_PROGRAM
Additional statements not to be used
The following statements are only included for reference. Do not use these statements for your manually created interfaces.
{ DoNotValidateThisFile ('') }
{CustomImplementation}
{ AccessLevel := Private|Public }
{suppressWarning modelRuleNamespace.modelRuleId('reason for suppression'), scope:=element|file}
FUNCTION_BLOCK name | FUNCTION name : data-type
USING Namespace_1; (* possible statement, if a namespace should be used *)
...
END_FUNCTION_BLOCK | END_FUNCTION
Statement |
Purpose |
{ DoNotValidateThisFile ('') } |
ignores the entire contents of the current ST-object See " Statement to ignore ST-objects " for details on this statement. |
{ AccessLevel := Private|Public } |
At present, this statement is not supported to be used within vendor blocks. |
{suppressWarning modelRuleNamespace.modelRuleId('reason for suppression'), scope:=element|file} |
At present, this statement is not supported to be used within vendor blocks. See " Statement to suppress warnings " for details on this statement. |