Przejdź do głównej zawartości

Operations Logic Programming Reference

Ta treść nie jest jeszcze dostępna w Twoim języku.

After running, Overvis MC251 starts execution of the operations logic program, if it was placed earlier in the internal memory.

If there is no program in the internal memory, and a memory card is present (formatted as FAT or FAT32), MC251 may load the taskfiles automatically. Such a reading runs once after startup or after installing a new memory card, but only if the internal memory does not contain a program. MC251 searches for and checks the taskfiles placed in the folder TASKS on the memory card. The found correct files are read into the internal memory and they form the operations logic program.

The internal logic memory can be cleared along with the settings reset to factory defaults. To preserve the settings and clear the internal logic memory via Modbus, you should enter setup mode and write command 40959 to register 120.

The Modbus registers (see Modbus Register Map, registers 2020-2023) indicate the result of reading the folder TASKS, including the number of read files and the amount of used memory. If during reading and verifying the program errors were detected, then the type of error and line number are indicated. If the program consisted of several files in the folder “TASKS”, then the internal memory will read all files except those in which errors are detected. Therefore, during error correction you should check the number of read files. After corrections were made, the internal memory should be cleared so that the program would be re-read. Files can have arbitrary names and extensions (except .OBJ, .MAP, .CNF) and placed in subfolders of the folder “TASKS”.

Taskfile describes set of actions repeated at a specified time interval. The actions can include gathering data, processing and comparing the values and special actions after fulfillment of the preset conditions (according to the processing results).

File consists of lines. Each line can be one of the following:

  • empty;
  • option;
  • definition;
  • action.

Lines can include comments preceded by ; or #. The text after these symbols is ignored. Lines can start from labels, followed by :. Labels are used for action references (e.g. CALL function1function1: RETURN). Line parts are separated by or TAB symbols.

Options configure taskfile compilation or execution.

Options start with @ followed by option kind. Then comes the option value.

Checked at compile time. If version is out of compiler supported versions range, taskfile compilation error occurs.

Examples:

Terminal window
@PROTOCOLVERSION 10

Sets the variable type size. Greater values allow for more available parameter cast types, and handle correctly bigger values, but take more memory.

  • 32 - use 32 bit (4 bytes) signed integer variables.
  • 64 - use 64 bit (8 bytes) signed integer variables.

Examples:

Terminal window
@VARBITS 64

This option is a set interval between two consequtive runs of the task. Actual interval depends on the controller load and overall taskfiles complexity (some actions such as parameter read/write or SMS sends can prolong the run execution). If the next run time comes before the other run has been finished, the new one is delayed and will be executed as soon as possible.

Option value is seconds integer in range 0..2000000.

0 - no interval, immediate re-runs.

Default is 60.

Examples:

Terminal window
@UPDATE 10 ; rerun task every 10 seconds

This options is a modifier for the set interval between two consequtive runs of the task. If set to non-zero value, set interval is managed with subsecond precision and equals ‘UPDATE’ / ‘UPDATEDIVISOR’.

Option value is hertz integer in range 0..500.

0 - intervals calculation precision in seconds.

Default is 0.

Examples:

Terminal window
@UPDATE 2
@UPDATEDIVISOR 3 ; the interval between runs will be 2/3 or about 667 ms

This option defines forced wait delays between device parameter read/write operations (this does not affect memory parameters, see Parameter definition below). This allows more time for the other clients requests processing. The delay is proportional to the time taken by the previous parameter operation.

Option value is percents integer in range 0..100.

  • 100 - no forced delays.
  • 50 - delay time equals the previous operation time.
  • 25 - delay time is 3 times greater than the operation time.

Default is 25.

Examples:

Terminal window
@PARAMLOADRATIO 50 ; parameters operations are separated with delays of equal length

Wait limit for device parameter read/write operations (this does not affect memory parameters, see Parameter definition below). After timeout expires, operation results in error.

Option value is milliseconds integer in range 0..5000.

Default is 5000.

Examples:

Terminal window
@PARAMTIMEOUT 1000 ; wait no more than 1 second for the parameter operation completion

Determines whether task holding items (variables and conditions) are reset before each run.

  • 0 - variables and conditions retain their values in RAM, and are reset at powerdowns or controller reset.
  • 1 - variables and conditions are reset before each run.

Default is 0.

Examples:

Terminal window
@RESETDATA 1 ; holding items values left after the run are not used in the subsequent runs

Definitions declare logical links, strings and Modbus register mapping, or holding items types.

Definition lines start with DEF followed by new defined name. Then comes the definition type which can be one of the following groups:

  • string;
  • Modbus device;
  • parameter;
  • variable(s);
  • condition(s).

String definition is marked by " pair, with the string inside. String can include special references, enclosed in * (the escape character * should be doubled to be included into the string itself).

Special references include:

  • VAR(variable) - for a numeric value out of a variable. lasterror variable may be also used here;
  • ERR(variable) - for a literal representation of an error code name out of a variable. lasterror variable may be also used here;
  • PHONE(index) - for a number out of a list of GSM abonents in the device settings. Index is a number in range 0 to 4.

Examples:

Terminal window
DEF my_string1 "2 ** 2 = *VAR(var_mul_result)*" ; this string template may produce a "2 * 2 = 4" string
DEF e_msg "Handled error #*VAR(lasterror)*: *ERR(lasterror)*" ; this string template may produce a "Handled error #1: FUNCTION_ILLEGAL" string

Modbus device can be used as a parameter source or storage.

Modbus device is defined by one of the following types:

  • MBWRDENIED - only reading functions may be used;
  • MBWRSINGLE - single register/coil write functions can be used;
  • MBWRMULTI - multiple register/coil write functions can be used;
  • MBWRANY - both single/multiple register/coil write functions can be used.

The type is followed by 2 or 3 arguments:

  1. Modbus unit address - one of the following: fixed ID in range 1..255, own Controller virtual device ID as *, or indirect ID as a variable plus integer value (e.g. some_variable+10);
  2. read registers/coils per one Modbus request limit, in range 1..125;
  3. the argument is present only for MBWRMULTI, MBWRANY types - write registers/coils per one Modbus request limit, in range 1..125.

Examples:

Terminal window
DEF mc_252 WRHANY * 125 125 ; own controller virtual device

Parameters are used to access external data: get data to or from variables.

Parameter is defined by one of the data types.

Table 1 - Parameter types available for any variable type size

No.TypeDescription
0UINT16unsigned (non-negative) 16-bit (2 bytes) integer, serialized as Big Endian (most significant byte first, e.g. 258 is stored as 0x01, 0x02);
1INT16signed 16-bit (2 bytes) integer, serialized as Big Endian;
2INT16BLEsigned 16-bit (2 bytes) integer, serialized as Little Endian (least significant byte first, e.g. 258 is stored as 0x02, 0x01);
3INT32signed 32-bit (4 bytes) integer, serialized as Big Endian (most significant byte first, e.g. 66051 is stored as 0x00, 0x01, 0x02, 0x03);
4INT32BLEsigned 32-bit (4 bytes) integer, with bytes serialized as Little Endian (least significant byte first, e.g. 66051 is stored as 0x03, 0x02, 0x01, 0x00);
5INT32WLEsigned 32-bit (4 bytes) integer, with words serialized as Little Endian (least significant word first, e.g. 66051 is stored as 0x02, 0x03, 0x00, 0x01);
6BIT1-bit integer (used for example to access Modbus coils and discrete inputs);
7INT32BEsame as INT32
8F32EP0RIEEE 754 single precision (4 bytes) floating-point, serialized as Big Endian;
9F32BLEEP0RIEEE 754 single precision (4 bytes) floating-point, with bytes serialized as Little Endian;
10F32WLEEP0RIEEE 754 single precision (4 bytes) floating-point, with words serialized as Little Endian;
11F32EP1Rsingle precision (4 bytes) floating-point, serialized as divided by 10 Big Endian;
12F32BLEEP1Rsame as F32BLEEP0R, but divided by 10 before serializing;
13F32WLEEP1Rsame as F32WLEEP0R, but divided by 10 before serializing;
14F32EP2Rsingle precision (4 bytes) floating-point, serialized as divided by 100 Big Endian;
15F32BLEEP2Rsame as F32BLEEP0R, but divided by 100 before serializing;
16F32WLEEP2Rsame as F32WLEEP0R, but divided by 100 before serializing;
17F32EP3Rsingle precision (4 bytes) floating-point, serialized as divided by 1000 Big Endian;
18F32BLEEP3Rsame as F32BLEEP0R, but divided by 1000 before serializing;
19F32WLEEP3Rsame as F32WLEEP0R, but divided by 1000 before serializing;
20UINT16BLEunsigned (non-negative) 16-bit (2 bytes) integer, serialized as Little Endian;
21UINT8unsigned (non-negative) 8-bit (1 byte) integer;
22INT8signed 8-bit (1 byte) integer;

Table 2 - Parameter types available for 64-bit variable type

No.TypeDescription
23UINT32unsigned (non-negative) 32-bit (4 bytes) integer, serialized as Big Endian (most significant byte first, e.g. 66051 is stored as 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03);
24UINT32BLEunsigned (non-negative) 32-bit (4 bytes) integer, with bytes serialized as Little Endian (least significant byte first, e.g. 66051 is stored as 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);
25UINT32WLEunsigned (non-negative) 32-bit (4 bytes) integer, with words serialized as Little Endian (least significant word first, e.g. 66051 is stored as 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
26INT64signed 64-bit (8 bytes) integer, serialized as Big Endian (most significant byte first, e.g. 66051 is stored as 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03);
27INT64BLEsigned 64-bit (8 bytes) integer, with bytes serialized as Little Endian (least significant byte first, e.g. 66051 is stored as 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);
28INT64WLEsigned 64-bit (8 bytes) integer, with words serialized as Little Endian (least significant word first, e.g. 66051 is stored as 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
29F64EP0RIEEE 754 double precision (8 bytes) floating-point, serialized as Big Endian;
30F64BLEEP0RIEEE 754 double precision (8 bytes) floating-point, with bytes serialized as Little Endian;
31F64WLEEP0RIEEE 754 double precision (8 bytes) floating-point, with words serialized as Little Endian;
32F64EP1Rdouble precision (8 bytes) floating-point, serialized as divided by 10 Big Endian;
33F64BLEEP1Rsame as F64BLEEP0R, but divided by 10 before serializing;
34F64WLEEP1Rsame as F64WLEEP0R, but divided by 10 before serializing;
35F64EP2Rdouble precision (8 bytes) floating-point, serialized as divided by 100 Big Endian;
36F64BLEEP2Rsame as F64BLEEP0R, but divided by 100 before serializing;
37F64WLEEP2Rsame as F64WLEEP0R, but divided by 100 before serializing;
38F64EP3Rdouble precision (8 bytes) floating-point, serialized as divided by 1000 Big Endian;
39F64BLEEP3Rsame as F64BLEEP0R, but divided by 1000 before serializing;
40F64WLEEP3Rsame as F64WLEEP0R, but divided by 1000 before serializing;
41F64EP4Rdouble precision (8 bytes) floating-point, serialized as divided by 10000 Big Endian;
42F64BLEEP4Rsame as F64BLEEP0R, but divided by 10000 before serializing;
43F64WLEEP4Rsame as F64WLEEP0R, but divided by 10000 before serializing;
44F64EP5Rdouble precision (8 bytes) floating-point, serialized as divided by 100000 Big Endian;
45F64BLEEP5Rsame as F64BLEEP0R, but divided by 100000 before serializing;
46F64WLEEP5Rsame as F64WLEEP0R, but divided by 100000 before serializing;
47F64EP6Rdouble precision (8 bytes) floating-point, serialized as divided by 1000000 Big Endian;
48F64BLEEP6Rsame as F64BLEEP0R, but divided by 1000000 before serializing;
49F64WLEEP6Rsame as F64WLEEP0R, but divided by 1000000 before serializing;

The type is followed by 1 or 3 arguments:

  1. source - one of the following: MEMTEMP, MEMBAT, MEMFILE, MEMFLASH (for memory areas) or a Modbus device defined earlier.
  2. For Modbus device source it is the Modbus data table: one of the following C, D, H, I for coils, discrete inputs, holding registers or input registers respectively. For memory sources it is optional - if specified, it maps the memory parameter to own controller virtual device addresses.
  3. For Modbus device source it is the starting address (either fixed in range 0..65535, or indirect as a variable plus integer value, e.g. some_variable+0). For memory sources it is optional - if specified, it maps the memory parameter to own controller virtual device addresses. Parameter may occupy several addresses depending on its type and size.

Memory sources for the parameters allow to read presets or store settings and temporary values to be processed at consequtive runs.

  • MEMTEMP - RAM space, data is lost at powerdown or controller reset, small area size but excellent write speed;
  • MEMBAT - memory area powered by internal clock battery, very limited size but good write speed;
  • MEMFLASH - controller settings area, data retains at reset, small size and usually read-only;
  • MEMFILE - extendable file area, requires memory card with the taskfiles to be present, average speed but excellent area size.

Examples:

Terminal window
DEF local_time UINT32 mc_251 H 170 ; own controller registers 170..171
DEF alg_mode UINT32 MEMTEMP H 5000 ; RAM value, mapped to own holding register 5000

Variables are used to operate integer values. All variables have the same type, which is set in taskfile options.

Variables can be mostly defined automatically when first mentioned. Some operations though (like ‘ISKNOWN’, copying, or array items assignment) require the variable to be defined earlier.

Variables are defined with VAR type. Variable arrays are defined with VARS type followed by array size in range 1..65535 (array of a single variable is effectively the same as a simple variable).

There is one pre-defined variable: lasterror. Error occurances write the error code to it. It cannot be written like the other variables, but RAISE command effectively writes to it. This variable can be used in error handlers for error-specific actions.

Examples:

Terminal window
DEF variable_1 VAR
DEF array_with_5_items VARS 5

Conditions are used to operate boolean values.

Conditions can be mostly defined automatically when first mentioned. Some operations though (like ‘ISKNOWN’, copying or array items assignment) require the condition to be defined earlier.

Conditions are defined with COND type. Condition arrays are defined with CONDS type followed by array size in range 1..65535 (array of a single condition is effectively the same as a simple condtion).

Examples:

Terminal window
DEF is_temperature_high COND

Actions form iterative logic algorythm. Actions can be one of the following:

  • assertion;
  • check;
  • command.

Actions are executed consequtively with these exceptions:

  • check actions would skip a single action, if their condition is not TRUE;
  • command actions like GO, CALL, RETURN would jump to a label or return from the function call;
  • command action RAISE or any error occurance would either jump to the error handler or stop this execution run due to an unhandled error;
  • command action EXIT stops this execution run.

There are 2 labels used as the main taskfile function definition:

  • run - each time the taskfile run is executed, the action labelled run is performed first (if there is no such label, the first action in the taskfile is the first to be performed);
  • onerror - if an error occurs with no other handlers specified, a handler labelled onerror is used (if there is no such label, the error would be unhandled, see Error handling below).

The action may in some cases reference the other items which were not defined earlier in the taskfile:

  • variable arrays and condition arrays should be defined before they are referenced;
  • evalutions which can take arguments of different types (like direct copying), require arguments to be defined earlier;
  • ohter variables and conditions can be referenced without pre-definition;
  • labels can be referenced by CALL, TRYCALL or GO before they are defined;
  • strings can be referenced by SENDSMS, SMSRCVD, NOSMSRCVD, SYSLOG or PARAMCOMMENT before they are defined;
  • in all the other cases the referenced item should be defined earlier in the taskfile.

Assertions are actions producing some result data, which they store in one of the holding items (variable or condition).

Assertions start with a PUT followed by result target item name. Then comes the function with the proper result type for this target (see Variable evalution, Condition evalution below). If no function is specified, the argument is directly copied into target (this can also be used to get the items from the array indexed by the variable, or put them back).

Examples:

Terminal window
DEF numbers VARS 3
PUT numbers[0] 0
PUT numbers[1] 1
PUT numbers[2] 2 ; numbers contains [0, 1, 2]
PUT index 2
PUT x numbers[index] ; x contains 2
PUT var_mul_result MUL x 2 ; var_mul_result contains 4

Checks are actions used for branching. They skip the next action if their function (with condition result, that is boolean) produces FALSE or an unknown value.

Checks start with IF followed by the function with the condition result type (see Condition evalution below). If no function specified, the argument should be a condition name.

Examples:

Terminal window
PUT lesser 5
PUT greater 3
IF LE lesser greater ; LE 5 3 produces FALSE, for 5 <= 3 is not true
GO then_section ; this command will not be executed
; else section
PUT tmp lesser ; lesser and greater variables values exchange
PUT lesser greater
PUT greater tmp
GO endif_section
then_section:
; two variables already sorted, nothing to do
endif_section:
; two variables are sorted now, lesser <= greater

Commands are actions producing no result data or discarding it.

Commands are one of the following:

  • EXIT - stops taskfile execution. Has 1 argument: error name, OK (if no error) or lasterror.
  • RAISE - forces an error occurance. Has 1 argument: error name, or lasterror (for raising the same error higher).
  • GO - next action will not be performed, execution will continue from the specified label. Has 1 argument: label name.
  • CALL - starts some user function execution. Next action execution is postponed, execution will now continue from the specified label. Has 1 argument - function entry label name.
  • TRYCALL - starts some user function with its own error handling. Next action execution is postponed, execution will now continue from the specified label. Has 2 arguments - function entry label label name and error handler label name.
  • RETURN - ends user function execution. Next action will not be performed, execution will continue from the previously postponed action (by the previously met ‘CALL’).
  • WRITE - outputs data to the parameter. Has 2 arguments: parameter name, then variable name or an integer value.
  • PARAMLOG - writes the parameter to the data log. Has 1 argument: parameter name. The parameter must be in Modbus registers or otherwise mapped to Modbus, as its address is used in logs.
  • PARAMCOMMENT - writes the parameter to the data log with a comment. Has 2 arguments: parameter name, then string name. The parameter must be in Modbus registers or otherwise mapped to Modbus, as its address is used in logs.
  • SYSLOG - writes the string to the system log. Has 1 argument: the string name.
  • SENDSMS - sends the string as an SMS. Has 2 arguments: the addressee string, then the SMS text string name. If the addressee strings results in no other characters than 0, the SMS would not be sent.

Examples:

Terminal window
WRITE param_hysteresis 5
EXIT OK

Variable evalution functions are used in assertion action (PUT) to calculate a new variable value.

They can produce numeric value or an unknown result (see Unknown values below).

Most of the following functions take 2 arguments (e.g. a and b) and perform an operation.

  • ADD - addition (a + b). The first argument is variable, the second can be either variable or an integer value.

  • SUB - subtraction (a - b). The first argument is variable, the second can be either variable or an integer value.

  • MUL - multiplication (a * b). The first argument is variable, the second can be either variable or an integer value.

  • DIV - division (a / b, integer result). The first argument is variable, the second can be either variable or an integer value.

  • MOD - remainder of division (a - (a / b * b)). The first argument is variable, the second can be either variable or an integer value.

  • SQRT - square root (integer). Takes a single variable or an integer value argument.

  • VAL - direct copy. Takes a single argument: variable or an integer value. As with the other direct copying evalutions, function name VAL can be omitted.

Most of the following functions take 2 arguments (e.g. a and b) and perform an operation.

  • BITSAND - logical AND of every bit of a with the corresponding bit of b. The first argument is variable, the second can be either variable or an integer value.

  • BITSOR - logical OR of every bit of a with the corresponding bit of b. The first argument is variable, the second can be either variable or an integer value.

  • SHR - arithmetic shift to the right of the bits of a, b times right. The first argument is variable, the second can be either variable or an integer value.

  • SHL - shift to the left of the bits of a, b times left. The first argument is variable, the second can be either variable or an integer value.

  • BITSBIT - bit b copy out of the bits of a. Is equivalent to SHR a b followed by BITSAND a 1. The first argument is variable, the second can be either variable or integer value.

  • BITSNOT - bits inversion. Takes a single variable or an integer value argument.

  • READ - takes parameter as an argument, and reads then casts its value to the variable default type.
  • MAX - maximal item of the array. Takes a single argument: array of variables.
  • MAXIDX - index of the maximal item of the array in range of 0 to array size minus 1. Takes a single argument: array of variables.
  • MIN - minimal item of the array. Takes a single argument: array of variables.
  • MINIDX - index of the minimal item of the array in range of 0 to array size minus 1. Takes a single argument: array of variables.
  • SUM - sum of the array items. Takes a single argument: array of variables.
  • SELECTBY - takes 2 arguments: array of variables and array of conditions of the same size, and selects the variable corresponding to the first condition which is TRUE.

Examples:

Terminal window
PUT square MUL x x

Condition evalution functions are used in either assertions (PUT actions) or checks (IF actions) to determine a condition value.

They can produce TRUE, FALSE or an unknown result (if referring the other unknown item values, see Unknown values below).

All functions come in direct or inversed form, which differ only in result being inverted or not before use. The functions are listed in both forms, e.g. ‘EQ’ / ‘NE’ for equality and non-equality (inverted EQ) checks.

  • EQ / NE - equal / non-equal (a = b / a != b). The first argument is variable, the second can be either variable or an integer value.
  • GE / LS - greater-or-equal / lesser (a >= b / a < b). The first argument is variable, the second can be either variable or an integer value.
  • GR / LE - greater / lesser-or-equal (a > b / a <= b). The first argument is variable, the second can be either variable or an integer value.
  • AND / NAND - logical AND / inverted logical AND (a && b / !(a && b)). Takes 2 condition arguments.
  • OR / NOR - logical OR / inverted logical OR (a || b / !(a || b)). Takes 2 condition arguments.
  • VAL / NOT - direct copy / inverted copy (a / !a). Takes a single argument: condition or boolean value (TRUE or FALSE). As with the other direct copying evalutions, function name VAL can be omitted.
  • SMSRCVD / NOSMSRCVD - checks whether a new SMS starting with a specified text came from a number starting with specified digits. The first argument is a phone number start, the second is an SMS text start. If the phone number is an empty string, SMS from any abonents are checked.
  • ISKNOWN / ISNOTKNOWN - checks whether the holding item value is known. Takes a single argument: variable or condition (the values are unknown if they are read from an uninitialized parameters or evaluted from the other unknown items, see Unknown values below).

Examples:

Terminal window
PUT c_equal EQ x 5
IF c_equal
EXIT OK
; the same function can be used in check directly
IF EQ x 5
EXIT OK

Fractional values and fixed point calculations

Section titled “Fractional values and fixed point calculations”

Data processing is performed by variable evalutions which store values of integer type.

However, parameters read and write can cast data types from and to fractional values of single and double precision as defined in IEEE 754 standard. This casting can be done with a multiplier (depending on the parameter type used), to preserve a certain number of decimal digits of the value fractional part. Some connected devices may also have integer parameters representing a fractional value (pre-multiplied in a similar way as above).

This allows to operate fractional values as integers.

A care should be taken using operations like multiplication, division or square root.

For example, MUL 2 2 = 4, but if the first argument represents 0.2 value multiplied by 10, and the second - 0.02 value multiplied by 100 (fixed point values with 1 and 2 digit precision respectively), the result represents 0.004 multiplied by 1000 (10*100, as the multipliers were also multiplied).

A square root of the previous value (4 standing for a value 0.004 multiplied by 1000), SQRT 4 produces 2, which is a wrong result, because of the multiplier 1000. For SQRT 1000 is not an integer. To get a correct result, this value multiplier should be adjusted to a nearest multiplier with even number of zeroes, that is 10000. So 4 should be pre-multiplied by 10 (producing 40 for 0.004 multiplied by 10000). Then the SQRT 40 produces 6 which is a correct result (standing for 0.06 multiplied by 100).

Holding items can be organized in arrays of fixed size. Arrays should be defined before referencing them in evalutions (e.g. DEF some_array VARS 5 or DEF the_other_array CONDS 2).

There are 3 ways of using the arrays:

  • array items with an integer value index can be used in most of the functions and assertions instead of a single item name as an argument (or an assertion result, e.g. PUT some_array[3] MUL some_array[2] some_array[1]).
  • array items with variable index can be used: a) either in assertions as a result for a direct copying or a single-argument functions (e.g. PUT some_array[ar_idx] SQRT distance), b) or as an argument for a direct copying (including NOT function which is just an inverted copying of a condition, e.g. IF NOT c_array[counter]).
  • certain array evalution functions take arrays as arguments, performing searching or digesting and producing a single variable result.

Errors can occur during actions execution.

Some commands like CALL or RETURN result in error due to misusage, which requires program correction. The other commands or functions result in error due to either wrong argument values (square root of a negative variable) or external reasons (e.g. parameter could not be read or written).

Error occurance in the function causes execution to interrupt and jump to the function error handler. This can happen once per function call: if no handler has been provided, or another error occurs in the error handler itself, the execution continues at the caller function handler. For the main taskfile function, onerror label is used as a default taskfile error handler.

A pre-defined variable lasterror can be used to read error code and perform error-specific actions.

If no caller handler is availbale, the error is considered unhandled - the default handler is performed similar to this:

Terminal window
SYSLOG default_err_msg
EXIT lasterror
;
DEF default_err_msg "Unhandled error #*VAR(lasterror)*: *ERR(lasterror)*"

Error during the assertion usually causes the result target to have an unknown value. Unknown values can also appear without an actual error, e.g. when reading an unitialized parameter or using the variable which has not been asserted.

Unknown values tend to spread, as most functions referring an unknown variable or condition value will result in an unknown value themselves. Some functions may still determine the result, notwithstanding of unknown items in their arguments. SELECTBY array function can get the result early (before reaching any of the unknown items later). AND logical check can result in FALSE if any of its arguments is FALSE (while the other one can have any value), OR can likewise result in TRUE, etc.

Critical commands may require additional checks (ISKNOWN / ISNOTKNOWN) and direct variable assertions, or parameter initializations, to guard against unknown states.

IF check action treat unknown function result as FALSE, and would skip the next command. This allows to choose between direct and inverted check function to guard the branch against executing in unknown states.

Below there are examples of finished programs, each consists of a single task file. To run the sample on the MC251 it is necessary to:

  1. Create a text file (e.g. having the .txt extension) with program text.
  2. Put the file in the folder TASKS.
  3. Put the prepared folder onto the microSD memory card, formatted as FAT or FAT32.
  4. Put the memory card into the MC251.

This example describes a program that, in the event of fault of the device, will send SMS with warning.

In the taskfile text:

  • 3 is Modbus ID of the device OM-310;
  • 240 is the register address which is monitored for the fault.
Terminal window
# SMS sending when bit 0 of register 240 of device 3 is set
#10th version of Protocol
@PROTOCOLVERSION 10
#task rerun interval will be every 3 seconds
@UPDATE 3
#limit of response waiting for Modbus query is 1000 msec = 1 sec
@PARAMTIMEOUT 1000
#after each query the delay is added, equal to the response waiting time,
#so the other clients can perform their queries
@PARAMLOADRATIO 50
#MC251 can read and write no less than 120 registers per one query
#note the * character - it is Modbus ID of the MC251 own virtual Modbus device
DEF mc251 MBWRANY * 120 120
#ОМ-310 has Modbus ID equal to 3 and allows reading 4 registers per one query,
#but writing of only one register per one query
DEF om310 MBWRSINGLE 3 4
#during each update, it is required to read
#the holding register with address 240 from OM-310
#UINT16 – means that the 16-bit value is unsigned (it can’t be less than 0)
DEF alarms UINT16 om310 H 240
#each run starts here
PUT alarm READ alarms
#copy zero bit of the register 240
PUT alarm BITSBIT alarm 0
#now the variable holds the parameter 240.0 value 0 or 1
#variable is compared with 1, the condition produces `TRUE`, if alarm = 1
PUT is_alarm EQ alarm 1
#condition is met, if the previous condition is not fulfilled, and vice versa
PUT no_alarm NOT is_alarm
#if the condition is_alarm is met (if 240.0 = 1), then send one SMS
IF is_alarm
SENDSMS technician_number alarm_msg
#program end
EXIT OK
#SMS text
DEF alarm_msg "OM-310 (3) – avaria"
#the phone to receive the SMS can be specified below
DEF technician_number "01234567"

In this example, the program controls the hysteresis value on the second channel of the TR-101 device, depending on the temperature of the sensor on the first channel.

The program uses clock battery-powered memory as a storage of the temperature limits and corresponding hysteresis parameters. These parameters are mapped to the MC251 own registers to simplify program configuration.

In the taskfile text:

  • 16 is Modbus ID of the device TR-101;
  • 4 is the address of the channel 1 temperature register;
  • 47 is the address of the channel 2 hysteresis reguster;
  • 5500 is the address for the lower temperature limit;
  • 5501 is the address for the upper temperature limit;
  • 5502 is the address for the hysteresis at crossing the lower temperature limit;
  • 5503 is the address for the hysteresis at crossing the upper temperature limit.
Terminal window
@PROTOCOLVERSION 10
@UPDATE 20 #program will run every 20 seconds
@PARAMLOADRATIO 50
DEF mc251 MBWRANY * 120 120
#TR-101 has Modbus ID 16 and can read no less than 100 registers per a query,
#but write one register per one query
DEF tr101 MBWRSINGLE 16 100
#INT16 – registers with signed integers, as the temperature can be less than 0
DEF t_lower INT16 MEMBAT H 5500
DEF t_upper INT16 MEMBAT H 5501
DEF t_chan1 INT16 tr101 H 4
#UINT16 – as the hysteresis is no less than 0
DEF h_at_lower UINT16 MEMBAT H 5502
DEF h_at_upper UINT16 MEMBAT H 5503
DEF h_chan2 UINT16 tr101 H 47
DEF temperatures VARS 3
DEF hysteresi VARS 3
DEF checks CONDS 3
#program start
run:
#lower and upper temperature limits, as well as its current value
PUT temperatures[0] READ t_lower
PUT temperatures[1] READ t_upper
PUT temperatures[2] READ t_chan1
# hysteresis for temperatures that are below (or above) than the limits
PUT hysteresi[0] READ h_at_lower
PUT hysteresi[1] READ h_at_upper
# current hysteresis value
PUT hysteresi[2] READ h_chan2
# was the temperature out of the limits?
PUT checks[0] LE temperatures[2] temperatures[0]
PUT checks[1] GE temperatures[2] temperatures[1]
# in other cases - do not change the hysteresis (current value)
PUT checks[2] TRUE
# the desired hysteresis is selected from hysteresi array
# according to the conditions of checks array
PUT hysteresis SELECTBY hysteresi checks
# is hysteresis not set to the desired value yet?
IF NE hysteresis hysteresi[2]
# write a new hysteresis to TR-101
WRITE h_chan2 hysteresis
EXIT OK

In this example, a program is described that monitors the temperature measured by OB-215. When the temperature exceeds -15 degrees for more than 10 minutes, it sends an SMS and starts logging the temperature values.

In the taskfile text:

  • 11 is Modbus ID of the OB-215 device;
  • 6 is the address of the register from which the temperature is read.
Terminal window
@PROTOCOLVERSION 10
# the program will run every 15 seconds
@UPDATE 15
DEF controller MBWRANY * 120 120
DEF ob215 MBWRSINGLE 11 4
DEF temperature INT16 ob215 H 6
# alarm flag - temperature rise for more than 10 minutes
DEF alarm_temp_high UINT16 MEMTEMP H 5000
# counter for a delay of 10 minutes (600 seconds)
DEF counter UINT16 MEMTEMP
PUT v_temp READ temperature
PUT v_alarm READ alarm_temp_high
# v_alarm is auto-defined above as a variable
# (by a PUT v_alarm READ construction)
IF ISNOTKNOWN v_alarm
PUT v_alarm 0
PUT v_counter READ counter
IF ISNOTKNOWN v_counter
PUT v_counter 0
PUT temp_limit -150
run:
IF GR v_temp temp_limit
GO noticed_temp_high
WRITE alarm_temp_high 0
WRITE counter 0
EXIT OK
noticed_temp_high:
PUT counter_limit MUL 60 10
IF GE v_counter counter_limit
GO temp_high_too_long
PUT v_counter ADD v_counter 15
WRITE counter v_counter
EXIT OK
temp_high_too_long:
# SMS should be send only once -
# (the flag v_alarm will become 1 at the next run)
IF EQ v_alarm 0
SENDSMS phone1 txt
WRITE alarm_temp_high 1
PARAMCOMMENT temperature txt
EXIT OK
DEF txt "OB-215 (11) – avaria, tmp *VAR(v_temp)* > *VAR(temp_limit)*"
DEF phone1 "01234567" ; phone number for the SMS can be specified here

Q: Where should I place my taskfiles on the SD card?

A: Place your taskfiles in the TASKS folder in the root of the SD card. The SD card must be formatted as FAT or FAT32. Files can have any name and extension except .OBJ, .MAP, .CNF (e.g., task.txt), and can also be organized in subfolders.

Q: How do I know if my taskfile has syntax errors?

A: When MC251 loads taskfiles, it checks them for errors. If errors are detected, the file won’t be loaded. You can check the loading status via Modbus registers (see Modbus Register Map, registers 2020-2023). The system will indicate the error type and line number where the error was found.

Q: Will my program survive a power cycle or firmware update?

A: The program stored in internal memory is retained at power downs or restarts. It may be deleted during firmware updates, due to data formats of the logic execution engine updates. However, if you keep the SD card with taskfiles installed, the program will be automatically reloaded after the update.

Q: How do I clear the program from internal memory without resetting all settings?

A: Enter setup mode via Modbus and write command 40959 to register 120. This clears only the internal logic memory while preserving your device configuration. If the SD card with the taskfiles is installed, the program will be automatically reloaded.

Q: What happens if my task takes longer than the UPDATE interval?

A: If the next run is scheduled before the current one finishes, it will be delayed and executed as soon as possible. If multiple runs are delayed, they will be skipped, which could affect the calculations (like counters). In this case, consider optimizing long operations, splitting the task in two or increasing the UPDATE interval.

Q: Can I share data between multiple taskfiles?

A: Yes. Use memory-sourced parameters (like MEMTEMP or MEMBAT) mapped to the same Modbus address in different taskfiles. Only one taskfile should write to the shared parameter (the “writer”), while others can read from it.

Q: How do I handle decimal/fractional values if variables are integers?

A: Use fixed-point arithmetic by multiplying fractional values by a power of 10. For example, to work with 2 decimal places, multiply values by 100. Parameter types like F32EP2R automatically handle this conversion when reading/writing. However, be careful with multiplication, division and root operations as they affect the decimal point position.

Q: What’s the difference between MEMTEMP, MEMBAT, MEMFLASH, and MEMFILE?

A:

  • MEMTEMP - RAM space, data is lost at powerdown or controller reset, small area size but excellent write speed;
  • MEMBAT - memory area powered by internal clock battery, very limited size but good write speed;
  • MEMFLASH - controller settings area, data retains at reset, small size and usually read-only;
  • MEMFILE - extendable file area, requires memory card with the taskfiles to be present, average speed but excellent area size.

Q: Why does my IF check skip the command even when the condition seems true?

A: The IF check treats unknown values as FALSE. If your variable hasn’t been initialized or a READ operation failed, the value may be unknown. Use ISKNOWN to verify the variable state before checking it.

Q: How do I debug my taskfile program?

A: Use SYSLOG commands to write diagnostic messages to the system log. You can also map intermediate values to Modbus registers using memory parameters (e.g., MEMTEMP H 5000) and read them via Modbus.

Q: Can I use the same Modbus address for different parameter types?

A: Yes, for the parameters of the same size with the same address. Memory-stored parameters in that case will share the same memory area. This is useful for transferring data between taskfiles. However, MEMFILE parameters (stored on SD card) don’t support the sharing feature.

Q: What happens when an error occurs during program execution?

A: Execution jumps to the error handler. If TRYCALL was used, it jumps to the specified handler label. Otherwise, it looks for the nearest upper-level handler, and at last, for the onerror label in the taskfile. If no handler is available, the error is logged and the run exits with the error code.

Q: How do I send SMS only once when an alarm condition is triggered?

A: Use a flag variable stored in persistent memory (like MEMBAT) to track whether the SMS was already sent. Check the flag before sending. Set it after sending and clear the flag after the alarm condition ends. See Example 3 for a working implementation.

Q: How do I check the time interval which the event is active for?

A: Either use a counter (memory-stored parameter to increment at each update period while the event continues and to reset to 0 after the event stops) or a timestamp (variable to store a clock from the MC251 registers at the event start and to be cleared at the event end).

Q: How do I check if the task is run for the first time after reset or after the power-off?

A: A MEMTEMP flag, if checked (and then set to 1 in case it was not set), can tell whether the task run is the first after the power cycle. A MEMBAT or a MEMFILE flag can similarly tell if it is the very first run.

Q: How do I scan an array? How do I make a code part executed a set number of times?

A: Use a variable as a loop index. Check before or after the cycle code. Use 1 or more GO operators to continue the cycle or to end/break it. Do not forget to increment or decrement the index variable inside.

Q: Can I make a repeated code part execution with a complex loop end condition?

A: Yes, using IF and GO. However, it is not recommended without explicit timeouts. The loop which is not limited by a constant can turn infinite or in other way exceed the task configured update time. It could cause this task update skips or other task lags.

Q: Can I call a function from a function? How many nesting levels are there?

A: Yes, you can CALL or TRYCALL a function, which in turn calls some other function. The nesting stack size equals the number of RETURN operators in the taskfile. Because of the limited stack size, the recursion is not recommended.

For technical support and assistance: