In case of nested string blocks: How can the return value be entirely mapped ?

If you are using nested blocks with STRING values without a maximum length (e.g. string blocks) within the application, the available memory is restricted. This restriction depends on the used target system (see "Properties and restrictions specific to the target system"). Subsequently, it is possible that:

  • a return value cannot be completely mapped in the available memory

and

  • a return value of a different length is created when a different target system is used.

If you want to avoid both consequences, do not nest blocks with STRING values without a maximum length. In case of user-defined blocks, both consequences cannot occur because the STRING variables must be declared with a maximum length.
images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Even if you do not nest the blocks, it is possible anyway that the STRING return value cannot be mapped in the available memory. In this case, the output ENO of the block is set to value FALSE (or an equivalent) (see also section "Internal error diagnostic for block" in the block descriptions how the block behaves).

The following examples calling the CONCAT block provide a better understanding of the possible usages and their consequences. The CONCAT block has been selected for the examples because this block has inputs as well as a return value of data type STRING without a maximum length. The calculated values are evaluated by using the Assert block .

Observe: The larger a STRING value is, the more RAM is required on the target system. If there is not sufficient RAM on the target system, it is likely that the application cannot be successfully loaded onto the target system at all.

Example 1: CONCAT without nesting, ENO=TRUE

The return value is completely mapped because resultString1 is declared with a length of 300 characters. The behavior on different target systems is identical because CONCAT is not nested (the restriction of the memory is not applied).

FUNCTION_BLOCK ConcatSample1
VAR
resultString1 : STRING[300];
length1 : INT;
eno1 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 3 inputs amount to 300 characters. This is OK because 'resultString1' has a length of 300 characters. So 'eno1' evaluates to 'TRUE'. *)
resultString1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>eno1);
length1 := LEN(resultString1);
ASSERT(length1=300);
ASSERT(eno1);
END_FUNCTION_BLOCK

Example 2: CONCAT without nesting, ENO=FALSE (because return value is too long)

The return value is not completely mapped because resultString2 is declared with a length of 200 characters. However, the behavior on different target systems is identical because CONCAT is not nested (the restriction of the memory is not applied).

FUNCTION_BLOCK ConcatSample2
VAR
resultString2 : STRING[200];
length2 : INT;
eno2 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 3 inputs amount to 300 characters. But 'resultString2' has a length of 200 characters. So 'eno2' evaluates to 'FALSE'. *)
resultString2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>eno2);
length2 := LEN(resultString2);
ASSERT(length2=200);
ASSERT(NOT eno2);
END_FUNCTION_BLOCK

Example 3: CONCAT without nesting, ENO=TRUE – no restriction to 1,024 characters

The return value is completely mapped because resultString3 is declared with a length of 1,500 characters. The behavior on different target systems is identical because CONCAT is not nested. Here, the restriction of the memory is not applied as well. This becomes obvious as the return value of 1,100 characters can be mapped completely (actually, it would exceed the limit of 1,024 bytes that is valid when using the runtime system for Windows).

FUNCTION_BLOCK ConcatSample3
VAR
resultString3 : STRING[1500];
length3 : INT;
eno3 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 11 inputs amount to 1100 characters. This is OK again because 'resultString3' has a length of 1500 characters. So 'eno3' evaluates to 'TRUE'. *)
resultString3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, IN4 := stringLength100, IN5 := stringLength100, IN6 := stringLength100, IN7 := stringLength100, IN8 := stringLength100, IN9 := stringLength100, IN10 := stringLength100, IN11 := stringLength100, ENO=>eno3);
length3 := LEN(resultString3);
ASSERT(length3=1100);
ASSERT(eno3);
END_FUNCTION_BLOCK

Example 4: CONCAT with nesting, ENO of some inner CONCATs=FALSE – restriction to 1,024 characters

The combined return value is not completely mapped although resultString4 is declared with a length of 1,500 characters. The behavior on different target systems is not identical because CONCAT is nested. Hence, the restriction of the memory is applied – this is 1,024 bytes when using the runtime system for Windows. Observe that 1 byte of the memory is used for each CONCAT call for internal purpose. If there is a different restriction for the target system (e.g. for Controllinos), a different value is returned.

FUNCTION_BLOCK ConcatSample4
VAR
resultString4a : STRING[1500];
length4a : INT;
eno4a, enoA1, enoB1, enoC1, enoD1 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* Here there is a nested usage of CONCAT. The scenario is as follows:
Unsized strings are assigned to 4 inputs of the outer CONCAT by calling CONCAT blocks again. Let's call them the inner CONCATs.
A string with a length of 100 characters is assigned to the 3 inputs of each inner CONCAT. For the runtime system for Windows, this is valid:
* The 3 inputs of the 1st inner CONCAT amount to 300 characters. 1 byte of the memory is used for internal purpose. As 301 < 1024, 'enoA1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 2nd inner CONCAT ampunt to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 602 < 1024, 'enoB1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 3rd inner CONCAT amount to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 903 < 1024, 'enoC1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 4th inner CONCAT amount to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 1204 > 1024, 'enoD1' evaluates to 'FALSE'. Only 120 characters (of the 300 characters) can be mapped in the available memory.
So a string of 1020 characters is assigned to the outer CONCAT (300 + 300 + 300 + 120). This is OK because 'resultString4a' has a length of 1500 characters. So 'eno4a' evaluates to 'TRUE'. *)
resultString4a := CONCAT(IN1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoA1), IN2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoB1), IN3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoC1), IN4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoD1), ENO=>eno4a);
length4a := LEN(resultString4a);
ASSERT(length4a=1020); (* Valid for: runtime system for Windows. In case of a Controllino Maxi, 'resultString4a' would just have a length of 63 characters. *)
ASSERT(eno4a);
ASSERT(enoA1);
ASSERT(enoB1);
ASSERT(enoC1);
ASSERT(NOT enoD1);
END_FUNCTION_BLOCK

Example 5: Similar to example 4, but without nesting and all ENO=TRUE – no restriction to 1,024 characters

The return value is completely mapped because resultString5 is declared with a length of 1,500 characters. The behavior on different target systems is identical because CONCAT is not nested. Here, the restriction of the memory is not applied as well. This becomes obvious as the return value of 1,500 characters can be mapped completely (actually, it would exceed the limit of 1,024 bytes that is valid when using the runtime system for Windows).

FUNCTION_BLOCK ConcatSample5
VAR
resultString5 : STRING[1500];
length5 : INT;
eno5, enoV1, enoV2, enoV3, enoV4 : BOOL;
VarString1, VarString2, VarString3, VarString4 : STRING[300];
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* Here a workaround to avoid the restriction of 1024 bytes. Assign the result of the previously "inner" CONCAT blocks to STRING variables. Here all ENOs evaluate to 'TRUE'. *)
VarString1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV1);
VarString2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV2);
VarString3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV3);
VarString4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV4);
 
(* Then assign these STRING variables to the inputs of the previously "outer" CONCAT. This makes the code easier to read as well. *)
resultString5 := CONCAT(IN1 := VarString1, IN2 := VarString2, IN3 := VarString3, IN4 := VarString4, ENO=>eno5);
length5 := LEN(resultString5);
ASSERT(length5=1200);
ASSERT(eno5);
ASSERT(enoV1);
ASSERT(enoV2);
ASSERT(enoV3);
ASSERT(enoV4);
END_FUNCTION_BLOCK

Example 6: Example 4 enhanced by one inner CONCAT, ENO of some inner CONCATs=FALSE – restriction to 1,024 characters

The combined return value is also not completely mapped although resultString6 is declared with a length of 1,500 characters. The behavior on different target systems is not identical because CONCAT is nested. Hence, the restriction of the memory is applied – this is 1,024 bytes when using the runtime system for Windows. Observe that 1 byte of the memory is used for each CONCAT call for internal purpose. If there is a different restriction for the target system (e.g. for Controllinos), a different value is returned.

FUNCTION_BLOCK ConcatSample6
VAR
resultString6 : STRING[1500];
length6 : INT;
eno6, enoA2, enoB2, enoC2, enoD2, enoE2: BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* This is identical to example 4, but a 5th inner CONCAT is added. In addition to the behavior of example 4, the 300 characters of the 5th inner CONCAT cannot be mapped at all because there is no available memory left. So 'enoE2' evaluates to 'FALSE' (such as 'enoD2'). *)
resultString6 := CONCAT(IN1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoA2), IN2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoB2), IN3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoC2), IN4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoD2), IN5 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoE2), ENO=>eno6);
length6 := LEN(resultString6);
ASSERT(length6=1020); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'resultString6' would just have a length of 63 characters. *)
ASSERT(eno6);
ASSERT(enoA2); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'enoA2' to 'enoD2' would evaluate to 'FALSE'. *)
ASSERT(enoB2);
ASSERT(enoC2);
ASSERT(NOT enoD2);
ASSERT(NOT enoE2);
END_FUNCTION_BLOCK