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.

Bound Checks (POU CheckBounds) 1:

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:

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: