Bound Checks (POU CheckBounds)
Functions for checking the field boundaries: CheckBounds
The purpose of this monitoring function is to deal with field bound violations as appropriate. A response to a violation may be setting of an error flag or changing the array index, for example. The check is only performed with a variable array index. A consistently faulty array index results in a compiler error. TwinCAT calls the function implicitly as soon as an ARRAY variable is assigned values.
After inserting the function, automatically generated code appears in the declaration part and the implementation part.
Do not change the declaration part To maintain the functionality of the monitoring functions, the declaration part must not be modified. The only exception is to add local variables. |
Standard implementation
Declaration part:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
Implementation part:
// Implicitly generated code : Only an Implementation suggestion
{noflow}
IF index < lower THEN
CheckBounds := lower;
ELSIF index > upper THEN
CheckBounds := upper;
ELSE
CheckBounds := index;
END_IF
{flow}
When the function is called it is assigned the following input parameters:
- index: Index of the array element
- lower: Lower bound of the array range
- upper: Upper bound of the array range
The return value is the index of the array element, provided it is in the valid range. Otherwise TwinCAT returns the upper or lower bound, depending on which bound was exceeded.
Sample implementation
Declaration part:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
// User defined local variables
VAR
sMessageLow : STRING := 'CheckBounds: Index too low (%d)';
sMessageHigh : STRING := 'CheckBounds: Index too high (%d)';
END_VAR
Implementation part:
{noflow}
// Index too low
IF index < lower THEN
CheckBounds := lower;
// Increase global counter
GVL_CheckBounds.nTooLow := GVL_CheckBounds.nTooLow + 1;
// Log message
ADSLOGDINT(msgCtrlMask := ADSLOG_MSGTYPE_WARN,
msgFmtStr := sMessageLow,
dintArg := index);
// Index too high
ELSIF index > upper THEN
CheckBounds := upper;
// Increase global counter
GVL_CheckBounds.nTooHigh := GVL_CheckBounds.nTooHigh + 1;
// Log message
ADSLOGDINT(msgCtrlMask := ADSLOG_MSGTYPE_WARN,
msgFmtStr := sMessageHigh,
dintArg := index);
// Index OK
ELSE
CheckBounds := index;
END_IF
{flow}
Like in the standard implementation, in this sample implementation a violation of the array range is corrected by returning the upper or lower bound. In addition a global counter is incremented, if the array is accessed outside the defined array range. The global counters therefore represent the number of upper or lower bound violations for entire project. In addition, the function ADSLOGDINT from the Tc2_System library is used to issue a violation of the array bounds as a warning in the message window.
Application example
In the program listed below, the index exceeds the defined upper bound of the field aSample. The CheckBounds function corrects this access to the array, which takes place outside the defined array bounds.
PROGRAM MAIN
VAR
aSample : ARRAY[0..7] OF BOOL;
nIndex : INT := 10;
END_VAR
aSample[nIndex] := TRUE;
In this example, the function CheckBounds causes index 10 to be changed to the upper bound of the array range of aSample (7). The element aSample[7] is assigned the value TRUE. In this way, the function corrects array accesses outside the valid field range. However, it is essential that the cause of the error, namely the access to the element in position 10, is also corrected. So that this automatically corrected faulty access does not remain undiscovered, a warning is displayed in the message window in this example, as described above.
Implementation example for the classification of errors/exceptions
Global variable list "GVL_Exc":
VAR_GLOBAL
nCheckBounds : INT;
nCheckBounds_OutOfBounds : INT;
myException : __SYSTEM.ExceptionCode;
END_VAR
Function "CheckBounds":
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper : DINT;
END_VAR
// Only an implementation suggestion
{noflow}
GVL_Exc.nCheckBounds := GVL_Exc.nCheckBounds + 1;
// Index too low
IF index < lower THEN
CheckBounds := lower;
GVL_Exc.myException := __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS;
GVL_Exc.nCheckBounds_OutOfBounds := GVL_Exc.nCheckBounds_OutOfBounds + 1;
// Index too high
ELSIF index > upper THEN
CheckBounds := upper;
GVL_Exc.myException := __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS;
GVL_Exc.nCheckBounds_OutOfBounds := GVL_Exc.nCheckBounds_OutOfBounds + 1;
// Index OK
ELSE
CheckBounds := index;
END_IF
See also: