Subrange Types

Overview

A subrange type is a user-defined type whose range of values is only a subset of that of the basic data type. You can also use implicit range boundary checks.

You can do the declaration in a DUT object but you can also declare a variable directly with a subrange type.

Syntax

Syntax for the declaration as a DUT object:

TYPE <name>: <Inttype> (<ug>..<og>) END_TYPE;

<name>

a valid IEC identifier

<inttype>

one of the data types SINT, USINT, INT, UINT, DINT, UDINT, BYTE, WORD, DWORD (LINT, ULINT, LWORD)

<ug>

a constant compatible with the basic type, setting the lower boundary of the range types

The lower boundary itself is included in this range.

<og>

a constant compatible with the basic type, setting the upper boundary of the range types.

The upper boundary itself is included in this basic type.

Example

TYPE
 SubInt : INT (-4095..4095);
END_TYPE

Direct Declaration of a Variable with a Subrange Type

VAR
 i : INT (-4095..4095);
 ui : UINT (0..10000);
END_VAR

If a value is assigned to a subrange type (in the declaration or in the implementation) but does not match this range (for example, i:=5000 in the upper shown declaration example), a message will be issued.

Check Functions for Range Bounds

In order to observe the range bounds of subrange types during runtime, the functions CheckRangeSigned, CheckLRangeSigned or CheckRangeUnsigned, CheckLRangeUnsigned have to be added to the application. For information on inserting the function, refer to the description of the POUs for implicit checks function.

The purpose of this check function is the proper treatment of violations of the subrange (for example, by setting an error flag or changing the value). The function is called implicitly as soon as a variable of subrange type is assigned.

 WARNING
UNINTENDED EQUIPMENT OPERATION
Do not change the declaration part of an implicit check function.
Failure to follow these instructions can result in death, serious injury, or equipment damage.

Example

The assignment of a variable belonging to a signed subrange type entails an implicit call to CheckRangeSigned. The default implementation of that function trimming a value to the permissible range is provided as follows:

Declaration part:

// Implicitly generated code : DO NOT EDIT
FUNCTION CheckRangeSigned : DINT
VAR_INPUT
value, lower, upper: DINT;
END_VAR

Implementation part:

// Implicitly generated code : Only an Implementation suggestion
IF (value < lower) THEN
CheckRangeSigned := lower;
ELSIF(value > upper) THEN
CheckRangeSigned := upper;
ELSE
CheckRangeSigned := value;
END_IF

When called, the function gets the following input parameters:

  • value: the value to be assigned to the range type

  • lower: the lower boundary of the range

  • upper: the upper boundary of the range

As long as the assigned value is within the valid range, it will be used as return value of the function. Otherwise, in correspondence to the range violation, either the upper or the lower boundary of the range will be returned.

The assignment i:=10*y will now be replaced implicitly by

i := CheckRangeSigned(10*y, -4095, 4095);

If y, for example, has the value 1000, the variable i will not be assigned to 10*1000=10000 (as provided by the original implementation), but to the upper boundary of the range that is 4095.

The same applies to function CheckRangeUnsigned.

NOTE: If neither of the functions is available, no type checking of subrange types occurs during runtime. In this case, you can assign any DINT/UDINT value to a variable of subrange type DINT/UDINT. You can assign any LINT/ULINT value to a variable of a subrange type LINT/ULINT.