ANY and ANY_<type>
When implementing a function, a method or a function block (from build 4026), you can declare inputs (VAR_INPUT) as variables with generic IEC date type ANY
or ANY_<type>
. Consequently you can implement calls whose call parameters differ by their data type.
At runtime you can query the value transferred and its data type via a predefined structure within the programming block for the input variable.
The compiler internally replaces the type of the input variable with the data structure described below, but the value is not directly transferred. Instead, a pointer to the actual value is transferred, for which reason only one variable can be transferred. Therefore, the data type is only concretized at the call. Calls of such programming blocks can therefore take place with arguments that each have different data types.
An input of the data type ANY
or ANY_<type>
can neither be assigned any constants nor any property when calling the function, the function block or the method. Conversely, a property cannot be assigned any variable of the data type ANY
or ANY_<type>
.
The generic IEC data types shown below are supported. The table shows which generic data types allow which elementary data types.
Generic data types | Elementary data types | ||
---|---|---|---|
ANY | ANY_BIT |
|
|
ANY_DATE |
|
| |
ANY_NUM | ANY_REAL |
| |
ANY_INT |
| ||
ANY_STRING |
|
|
Internal data structure with 'ANY' and 'ANY_<type>'
When compiling the code, the input variables with ANY data type are replaced internally with the following structure. The structure elements are assigned to the actual call parameter at runtime.
TYPE AnyType :
STRUCT
// the type of the actual parameter
typeclass : __SYSTEM.TYPE_CLASS ;
// the pointer to the actual parameter
pvalue : POINTER TO BYTE;
// the size of the data, to which the pointer points
diSize : DINT;
END_STRUCT
END_TYPE
Via this structure you can access the input variable inside the programming block and, for example, query the transferred value. |
Declaration
The syntax descriptions refer to a programming block with precisely one parameter (one input parameter).
Syntax
FUNCTION | FUNCTION_BLOCK | METHOD <POU name>
( : <return data type> )?
VAR_INPUT
<input variable name> : <generic data type>;
END_VAR
<generic data type> = ANY | ANY_BIT | ANY_DATE |
ANY_NUM | ANY_REAL | ANY_INT | ANY_STRING
Call
The syntax descriptions refer to a programming block with precisely one parameter, to which an argument is transferred. The data type of the argument concretizes the generic data type of the input variable. For example, arguments of the type BYTE
, WORD
, DWORD
, LWORD
can be transferred to a ANY_BIT
input variable.
Function call syntax
<variable name> := <function name> ( <argument name> );
<argument name> : variable with valid data type
Function block call syntax
<function block name> ( <input variable name> := <argument name> );
Method call syntax
<function block name> . <method name> ( <input variable name> := <argument name> );
Sample 1: transfer of elementary data types to inputs with generic data type
FUNCTION F_ComputeAny : BOOL
VAR_INPUT
anyInput1 : ANY; // valid data type see table
END_VAR
FUNCTION_BLOCK FB_ComputeAny
VAR_INPUT
anyInput1 : ANY;
END_VAR
FUNCTION_BLOCK FB_ComputeMethod
METHOD ComputeAny : BOOL
VAR_INPUT
anyInput1 : ANY_INT; // valid data types are SINT, INT, DINT,INT, USINT, UINT, UDINT, ULINT
END_VAR
PROGRAM PLC_PRG
VAR
fbComputeAnyByte : FB_ComputeAny;
fbComputeAnyInt : FB_ComputeAny;
fbComputeM1 : FB_ComputeMethod;
fbComputeM2 : FB_ComputeMethod;
nByte : BYTE := 16#AB;
nInt : INT := -1234;
bResultByte : BOOL;
bResultInt : BOOL;
END_VAR
bResultByte := F_ComputeAny(nByte);
bResultInt := F_ComputeAny(nInt);
fbComputeAnyByte(anyInput1 := nByte);
fbComputeAnyInt(anyInput1 := nInt);
fbComputeM1.methComputeAny(anyInput1 := nByte);
fbComputeM2.methComputeAny(anyInput1 := nInt);
Sample 2: transfer of elementary data types to inputs with generic data type
The transfer parameters of the function calls have different data types.
FUNCTION F_AnyBitFunc : BOOL
VAR_INPUT
value : ANY_BIT;
END_VAR
FUNCTION F_AnyDateFunc : BOOL
VAR_INPUT
value : ANY_DATE;
END_VAR
FUNCTION F_AnyFunc : BOOL
VAR_INPUT
value : ANY;
END_VAR
FUNCTION F_AnyIntFunc : BOOL
VAR_INPUT
value : ANY_INT;
END_VAR
FUNCTION F_AnyNumFunc : BOOL
VAR_INPUT
value : ANY_NUM;
END_VAR
FUNCTION F_AnyRealFunc : BOOL
VAR_INPUT
value : ANY_REAL;
END_VAR
FUNCTION F_AnyStringFunc : BOOL
VAR_INPUT
value : ANY_STRING;
END_VAR
PROGRAM MAIN
VAR
bBOOL : BOOL := TRUE;
nBYTE : BYTE := 16#AB;
nWORD : WORD := 16#1234;
nDWORD : DWORD := 16#6789ABCD;
nLWORD : LWORD := 16#0123456789ABCDEF;
sSTRING : STRING := 'xyz';
wsWSTRING : WSTRING := "abc";
dtDATEANDTIME : DATE_AND_TIME := DT#2017-02-20-11:07:00;
dDATE : DATE := D#2017-02-20;
tdTIMEOFDAY : TIME_OF_DAY := TOD#11:07:00;
fREAL : REAL := 42.24;
fLREAL : LREAL := 24.42;
nUSINT : USINT := 12;
nUINT : UINT := 1234;
nUDINT : UDINT := 12345;
nULINT : ULINT := 123456;
nSINT : SINT := -12;
nINT : INT := -1234;
nDINT : DINT := -12345;
nLINT : LINT := -123456;
END_VAR
F_AnyFunc(bBOOL);
F_AnyFunc(nBYTE);
F_AnyFunc(nWORD);
F_AnyFunc(nDWORD);
F_AnyFunc(nLWORD);
F_AnyFunc(sSTRING);
F_AnyFunc(wsWSTRING);
F_AnyFunc(dtDATEANDTIME);
F_AnyFunc(tdTIMEOFDAY);
F_AnyFunc(fREAL);
F_AnyFunc(fLREAL);
F_AnyFunc(nUSINT);
F_AnyFunc(nUINT);
F_AnyFunc(nUDINT);
F_AnyFunc(nULINT);
F_AnyFunc(nSINT);
F_AnyFunc(nINT);
F_AnyFunc(nDINT);
F_AnyFunc(nLINT);
F_AnyBitFunc(nBYTE);
F_AnyBitFunc(nWORD);
F_AnyBitFunc(nDWORD);
F_AnyBitFunc(nLWORD);
F_AnyStringFunc(sSTRING);
F_AnyStringFunc(wsWSTRING);
F_AnyDateFunc(dtDATEANDTIME);
F_AnyDateFunc(dDATE);
F_AnyDateFunc(tdTIMEOFDAY);
F_AnyNumFunc(fREAL);
F_AnyNumFunc(fLREAL);
F_AnyNumFunc(nUSINT);
F_AnyNumFunc(nUINT);
F_AnyNumFunc(nUDINT);
F_AnyNumFunc(nULINT);
F_AnyNumFunc(nSINT);
F_AnyNumFunc(nINT);
F_AnyNumFunc(nDINT);
F_AnyNumFunc(nLINT);
F_AnyRealFunc(fREAL);
F_AnyRealFunc(fLREAL);
F_AnyIntFunc(nUSINT);
F_AnyIntFunc(nUINT);
F_AnyIntFunc(nUDINT);
F_AnyIntFunc(nULINT);
F_AnyIntFunc(nSINT);
F_AnyIntFunc(nINT);
F_AnyIntFunc(nDINT);
F_AnyIntFunc(nLINT);
Sample 3: comparison of two transferred variables
The function compares the two variables transferred to determine whether they are of the same type and have the same value.
FUNCTION F_GenericCompare : BOOL
VAR_INPUT
any1 : ANY;
any2 : ANY;
END_VAR
VAR
nCount: DINT;
END_VAR
IF any1.typeclass <> any2.typeclass THEN
RETURN;
END_IF
IF any1.diSize <> any2.diSize THEN
RETURN;
END_IF
// Byte comparison
FOR nCount := 0 TO any1.diSize-1 DO
IF any1.pvalue[nCount] <> any2.pvalue[nCount] THEN
RETURN;
END_IF
END_FOR
F_GenericCompare := TRUE;
Sample 4: determination of the transferred data type
The function checks whether the transferred variable is of the type REAL
or LREAL
. If this is the case, the value of the variable is rounded.
// function to round transfer parameters of the type REAl and LREAL (other types are detected as invalid)
FUNCTION F_RoundFloatingValue : INT
VAR_INPUT
anyIn : ANY; // input variable of the type ANY
END_VAR
VAR
pAnyReal : POINTER TO REAL; // pointer to a variable of the type REAL
pAnyLReal : POINTER TO LREAL; // pointer to a variable of the type LREAL
END_VAR
VAR_OUTPUT
bInvalidType : BOOL; // output variable with value TRUE if the transferred parameter has an invalid type
END_VAR
// round floating value for a transfer parameter of the type REAL
IF (anyIn.TypeClass = __SYSTEM.TYPE_CLASS.TYPE_REAL) THEN
pAnyReal := anyIn.pValue;
F_RoundFloatingValue := REAL_TO_INT(pAnyReal^);
// round floating value for a transfer parameter of the type LREAL
ELSIF (anyIn.TypeClass = __SYSTEM.TYPE_CLASS.TYPE_LREAL) THEN
pAnyLReal := anyIn.pValue;
F_RoundFloatingValue := LREAL_TO_INT(pAnyLReal^);
// inform about invalid type if the transfer parameter is not of the type REAL or LREAL
ELSE
bInvalidType := TRUE;
END_IF