REXLANG – User Programmable Block

Block SymbolLicensing group: REXLANG
PIC

Function Description
The REXYGEN system’s standard function blocks address most typical control application requirements. However, there are scenarios where a user-defined function is necessary or more efficient. The REXLANG block is designed for these situations. It allows the implementation of a user-defined algorithm using a scripting language that closely resembles C (or Java).

Scripting Language
The scripting language employed in REXLANG is akin to C, but there are notable differences and limitations:

  • Supported data types include double, long and string. Types like int, short, and bool are internally converted to long. The float type is converted to double. The typedef type is not available.
  • Pointers and structures are not implemented. Arrays can be defined and indexing is possible using the [ ] operator. Inputs, outputs, and parameters of the block cannot be arrays.
  • The ’,’ operator is not implemented.
  • The preprocessor supports commands like #include, #define, #ifdef .. [#else .. ] #endif, and #ifndef .. [#else .. ] #endif. However, #pragma and #if .. [#else .. ] #endif are not supported.
  • While standard ANSI C libraries are not implemented, many mathematical functions from math.h and other functions are available (detailed below).
  • Keywords input, output, and parameter are used to reference the REXLANG block’s inputs, outputs, and parameters. System functions for execution control and diagnostics are implemented.
  • The main() function is executed periodically during runtime. Other functions like init() (executed once at startup), exit() (executed upon control algorithm stop), and parchange() (executed upon parameter changes) are also available.
  • Functions and procedures without parameters must declare void explicitly.
  • Overloading of identifiers is not allowed, i.e., keywords and built-in functions cannot share names with identifiers. Local and global variables must have distinct names.
  • Array initializers are not supported for both local and global arrays.
  • User-defined return values from main(), init(), and exit() are written to the iE output. Values < -99 will stop algorithm execution (requiring a RESET input for further execution). Return values are categorized as follows:
    iE >= 0

    indicates no errors.

    0 > iE >= -99

    signifies a warning, without affecting function block execution.

    iE < -99

    implies an error, halting the function block execution.

Scripting Language Syntax
The syntax of the scripting language is rooted in C, but with some modifications:

  • <type> input(<input number>) <variable name>; for input variables.
  • <type> output(<output number>) <variable name>; for output variables.
  • <type> parameter(<parameter number>) <variable name>; for parameter variables.

The input and parameter variables are read-only, whereas output variables are write-only.

Example:

double input(1) input_signal; /* declaration of a variable of type  
                                  double, which corresponds with the  
                                  u1 input of the block */  
long output(2) output_signal; /* declaration of a variable of type  
                                  long, which corresponds with the y2  
                                  output of the block */  
 
input_signal = 3;               //not allowed, inputs are read-only  
sum = output_signal + 1;        //not allowed, outputs are write-only  
if (input_signal>1) output_signal = 3 + input_signal;  //correct

Available Functions
The scripting language encompasses a broad spectrum of functions, including those for mathematical calculations, vector operations, string handling, and system-level commands. The functions are categorized and described in detail as follows:

  • Mathematical Functions (aligned with ANSI C’s math.h library):
    This category includes functions like atan, sin, cos, exp, log, sqrt, tan, asin, acos, fabs, fmod, sinh, cosh, tanh, pow, atan2, ceil, floor, and abs. Note that abs is specifically designed for integer values, while the rest operate with double type variables. The fabs function is used to calculate the absolute value of a decimal number.
  • Vector Functions (not part of ANSI C):
    This set includes specialized functions for vector manipulation:
    double max([n,] val1, …, valn)

    Returns the maximum value among the provided elements. The first parameter, indicating the number of items, is optional.

    double max(n, vec)

    Finds the maximum value in the vec vector.

    double min([n,] val1, …, valn)

    Similar to max, but returns the minimum value.

    double min(n, vec)

    Finds the minimum value in the vec vector.

    double poly([n,] x, an, …, a1, a0)

    Calculates the value of a polynomial y = anxn + + a1x + a0. The first parameter is optional.

    double poly(n, x, vec)

    Computes the polynomial value y = vec[n]xn + + vec[1]x + vec[0].

    double scal(n, vec1, vec2)

    Calculates the scalar product of two vectors: y = vec1[0]vec2[0] + + vec1[n-1]vec2[n-1].

    double scal(n, vec1, vec2, skip1, skip2)

    A variant of scal that allows skipping elements: y = vec1[0]vec2[0]+vec1[skip1]vec2[skip2]++vec1[(n-1)*skip1]vec2[(n-1)*skip2]. This is well suited for multiplication of matrices, which are stored as vectors (line by line or column by column).

    double conv(n, vec1, vec2)

    Computes the convolution of two vectors: y = vec1[0]vec2[n-1] + vec1[1]vec2[n-2] + + vec1[n-1]vec2[0].

    double sum(n, vec)

    Sums the elements of a vector: y = vec[0] + vec[1] + + vec[n-1].

    double sum([n,] val1, ..., valn)

    Sums the provided values. The count parameter is optional.

    []array([n,] an-1, ..., a1, a0)

    Creates an array/vector with specified elements. The count parameter n is optional. The type of the returned value is chosen automatically to fit the type of parameters (all must be of the same type).

    []subarray(idx, vec)

    Returns a subarray of vec starting from index idx. The type of the returned value is chosen automatically according to the vec array.

    copyarray(count, vecSource, idxSource, vecTarget, idxTarget)

    Copies count items of the vecSource array, starting at idxSource index, to the vecTarget array, starting at idxTarget index. Both arrays must be of the same type.

    void fillarray(vector, value, count)

    Copies value to count items of the vector array (always starting from index 0).

    Note: The functions max, min, poly, scal, conv, and sum are overloaded, meaning they have multiple variants based on the parameters. Parameters are strictly type-checked, requiring casting for non-double types. For instance:
    double res = max(dVal, (double)iVal, 1.0, (double)2);
    casts iVal to double. If a parameter is not a double, an error stating "no function of this prototype was found" is reported.

  • String Functions (This section covers functions analogous to those found in ANSI C’s string.h library, providing a range of operations for string manipulation and analysis:)
    string strsub(str, idx, len)

    Extracts a substring from str, starting at index idx and spanning len characters.

    long strlen(str)

    Returns the length of the string str, measured in characters.

    long strfind(str, substr[, offset])

    Finds the first occurrence of substr within str and returns its position. The search starts from the character with index offset (if not specified, then from the beginning). The parameter substr can also be a character.

    long strrfind(str, substr)

    Identifies the last occurrence of substr within str and provides its index.

    strreplace(str, pattern, substr)

    Replaces all instances of pattern in str with substr. This modification is done in-place, directly altering str.

    strupr(str)

    Converts all characters in str to uppercase.

    strlwr(str)

    Transforms str to all lowercase characters.

    strtrim(str)

    Removes leading and trailing whitespace from str.

    long str2long(str[, default])

    Converts str to an integer. If conversion fails, the optional second parameter (default value) is returned, or 0 if not provided.

    double str2double(str[, default])

    Turns str into a decimal number. Similar to str2long, it returns an optional default value or 0 on failure.

    string long2str(num[, radix])

    Converts an integer num to a string, with an optional radix parameter specifying the base (default is 10). The output string does not indicate the numeral system (no prefixes like 0x for hexadecimal).

    string double2str(num)

    Converts a decimal number num to a string representation.

    strcpy(dest, src)

    Copies the content of src into dest. For ANSI C compatibility, dest = src achieves the same result.

    strcat(dest, src)

    Appends src to the end of dest. As in ANSI C, dest = dest + src performs the same operation.

    strcmp(str1, str2)

    Compares two strings str1 and str2. The construction str1 == str2 can be used for the same purpose, providing ANSI C compatibility.

    float2buf(buf, x[,endian])

    Converts the real number x into an array buf of four elements, each representing an octet of the number in IEEE 754 single precision format (known as float). The function is useful for filling communication buffers. Optional 3rd parameter has the following meaning:

    0

    processor native endian (default),

    1

    little endian,

    2

    big endian.

    double2buf(buf, x[,endian])

    Similar to float2buf, but for double precision, storing eight elements (double type).

    double buf2float(buf[, endian])

    The inverse of float2buf.

    double buf2double(buf[, endian])

    The inverse of double2buf.

    long RegExp(str, regexp, capture[])

    Matches str against the regular expression regexp, storing captured groups in capture. Returns the number of captures or a negative error code. The regular expression syntax includes standard constructs like:

    (?i)

    Must be at the beginning of the regular expression. Makes the matching case-insensitive.

    ̂

    Match beginning of a string

    $

    Match end of a string

    ()

    Grouping and substring capturing

    \s

    Match whitespace

    \S

    Match non-whitespace

    \d

    Match decimal digit

    \n

    Match new line character

    \r

    Match line feed character

    \f

    Match vertical tab character

    \v

    Match horizontal tab character

    \t

    Match horizontal tab character

    \b

    Match backspace character

    +

    Match one or more times (greedy)

    +?

    Match one or more times (non-greedy)

    *

    Match zero or more times (greedy)

    *?

    Match zero or more times (non-greedy)

    ?

    Match zero or once (non-greedy)

    x|y

    Match x or y (alternation operator)

    \meta

    Match one of the meta characters: ^$().[]*+?|\

    \xHH

    Match byte with hex value 0xHH, e.g. \x4a.

    [...]

    Match any character from the set. Ranges like [a-z] are supported.

    [^...]

    Match any character but the ones from the set.


    Example:
    RegExp("48,string1,string2","̂(\\d+),([̂,]+),",capture);
    Result: capture=["48,string1","48","string1"]
    long ParseJson(json, cnt, names[], values[])

    This function processes a json string, extracting the values of specified objects. The names array should list the properties of interest (access subitems with . and array indices with [], for instance, "cars[1].model"). Corresponding values are then populated in the values array. The cnt parameter determines the number of objects to be parsed, which should match the length of both the names and values arrays. This function returns the total number of successfully parsed values, or a negative value if an error occurs during parsing.

    Note: String variables are declared as in ANSI C (char <variable name>[<max chars>];). For function arguments, use char <variable name>[] or string <variable name>.

  • System functions (not part of ANSI C)
    Archive(arc, type, id, lvl_cnt, value)

    This function archives a value into the system’s archival subsystem. arc serves as a bitmask to specify the target archives (e.g., for archives 3 and 5, set arc = 20, which is 10100 in binary or 20 in decimal). Archive numbering starts from 1, with a maximum of 15 archives (archive 0 is reserved for internal system logs). The type parameter defines the data type, with options:

    1

    Bool

    2

    Byte (U8)

    3

    Short (I16)

    4

    Long (I32)

    5

    Word (U16)

    6

    DWord (U32)

    7

    Float (F32)

    8

    Double (F64)

    9

    Time

    10

    Large (I64)

    11

    Error

    12

    String

    17

    Bool Group

    18

    Byte Group (U8)

    19

    Short Group (I16)

    20

    Long Group (I32)

    21

    Word Group (U16)

    22

    DWord Group (U32)

    23

    Float Group (F32)

    24

    Double Group (F64)

    25

    Time Group

    26

    Large Group (I64)

    27

    Error Group


    id represents a unique archive item ID, lvl_cnt denotes an alarm level or the number of elements for Group types, and value is the data to be archived.
    Trace(id, val)

    Displays both the id and val values, mainly used for debugging purposes. id is a user-defined constant ranging from 0 to 9999 for easy message identification. val can be any data type, including strings. Output appears in the system log of REXYGEN.. In order to view these debugging messages in System log it is necessary to enable them. Go to the menu
    Target Diagnostic messages and tick the Information checkbox in the Function block messages box. Logging has to be also enabled for the particular block by ticking the Enable logging checkbox in the Runtime tab of the block parameters dialog. By default, this is enabled after placing a new block from library. Only then are the messages displayed in the System log.

    TraceError(id, val) TraceWarning(id, val) TraceVerbose(id, val)

    Similar to Trace, these commands categorize the output into Error, Warning, or Verbose logging groups. Error messages are always logged. For Warning and Verbose messages, enable the respective message groups in the Diagnostic messages menu.

    Suspend(sec)

    Suspends script execution if it exceeds the specified time in sec during a sampling period. The script resumes from the suspension point upon the next block execution. Use Suspend(0) to pause the script immediately.

    double GetPeriod()

    Returns the block’s sampling period in seconds.

    double CurrentTime()

    Function provides the current time in an internal format, often used with ElapsedTime().

    double ElapsedTime(new_time, old_time)

    Calculates elapsed time between new_time and old_time in seconds. Function CurrentTime() is typically used for new_time.

    double Random()

    Generates a pseudo-random number from the 0,1) interval. The generator is initialized before the init() function, ensuring a consistent sequence.

    long QGet(var)

    Returns the quality of the var variable (see the QFC, QFD, VIN, VOUT blocks). The function is intended for use with the inputs, outputs and parameters. It always returns 0 for internal variables.

    void QSet(var, value)

    Sets the quality of the var variable (see the QFC, QFD, VIN, VOUT blocks). The function is intended for use with the inputs, outputs and parameters. It has no meaning for internal variables.

    long QPropag([n, ]val1, …, valn)

    Returns the quality resulting from merging of qualities of val1,…,valn. The basic rule for merging is that the resulting quality correspond with the worst quality of val1,…,valn. To obtain the same behavior as in other blocks of the REXYGEN system, use this function to set the quality of output, use all the signals influencing the output as parameters.

    double LoadValue(fileid, idx)

    Reads a value from a file. Supports both binary files (with double values) and text files (values on separate lines). The file is identified by fileid, and idx indicates the index (for binary files) or line number (for text files). At present the following values are supported:

    0

    file on a disk identified by the p0 parameter,

    1

    file on disk identified by name of the REXLANG block and extension .dat,

    2

    file on a disk identified by the srcname parameter, but the extension is changed to .dat,

    3

    rexlang.dat file in the current directory,

    4-7

    same like 0-3, but format is text file. Each line contains one number. The index idx is the line number and starts at zero. Value idx=-1 means next line (e.g. sequential writing).

    void SaveValue(fileid, idx, value)

    Stores a value in a file, with parameters functioning similarly to LoadValue.

    void GetSystemTime(time)

    Returns the system time in UTC (modifiable via OS settings). The time parameter must be an array of at least 8 long items. The function fills the array with the following values in the given order: year, month, day (in the month), day of week, hours, minutes, seconds, milliseconds. On some platforms the milliseconds value has a limited precision or is not available at all (the function returns 0 ms).

    void Sleep(seconds)

    Halts the block’s algorithm (and whole task) for the defined time. Use this block with extreme caution and only if there is no other possibility to achieve the desired behaviour of your algorithm. The sleep interval should not exceed 900 milliseconds. The shortest interval is about 0.01s, the precise value depends on the target platform.

    long GetExtInt(ItemID)

    Returns the value of input/output/parameter of arbitrary block in REXYGEN algorithm. Such an external data item is referenced by the ItemID parameter. The structure of the string parameter ItemID is the same as in e.g. the sc parameter of the GETPI function block. If the value cannot be obtained (e.g. invalid or non-existing ItemID, data type conflict, etc.), the REXLANG block issues an error and must be reset.

    long GetExtLong(ItemID)

    See GetExtInt(ItemID).

    double GetExtReal(ItemID)

    Similar to GetExtInt(ItemID) but for decimal numbers.

    double GetExtDouble(ItemID)

    See GetExtReal(ItemID).

    string GetExtString(ItemID)

    Similar to GetExtInt(ItemID) but for strings.

    void SetExt(ItemID, value)

    Sets the input/output/parameter of arbitrary block in REXYGEN algorithm to value. Such an external data item is referenced by the ItemID parameter. The structure of the string parameter ItemID is the same as in e.g. the sc parameter of the SETPI function block. The type of the external data item (long/double/string) must correspond with the type of the value parameter. If the value cannot be set (e.g. invalid or non-existing ItemID, data type conflict, etc.), the REXLANG block issues an error and must be reset.

    int BrowseExt(ItemID, first_subitem_index, max_count, subitems, kinds)

    Function browses task address space. If ItemID is a block identifier (block path), subitems string array will contain names of all inputs, outputs, parameters and internal states. Function returns number of subitems or negative error code. kinds values: executive = 0, module = 1, driver = 2, archive = 3, level = 4, task = 5, quicktask = 6, subsystem = 7, block = 8, input = 9, output = 10, internal state = 11, parameter or state array = 12, special = 13.

    long CallExt(ItemID)

    Executes a single step of any block within the REXYGEN algorithm, identified by ItemID. The structure of the string parameter ItemID is the same as in e.g. the sc parameter of the GETPI function block. It’s recommended to call only halted blocks (set checkbox Halt on the property page Runtime in the parameters dialog of the block), which should be in the same task as the REXLANG block. The function returns result code of the calling block (see REXYGEN error codes).

    long GetInArrRows(input)

    Returns the number of rows of the array that is attached to the input with index input of the REXLANG block.

    long GetInArrCols(input)

    Returns the number of columns of the array that is attached to the input with index input of the REXLANG block.

    long GetInArrMax(input)

    Returns the maximum (allocated) size of the array that is attached to the input with index input of the REXLANG block.

    double GetInArrDouble(input, row, col)

    Returns the member of the array that is attached to the input with index input of the REXLANG block.

    long GetInArrLong(input, row, col)

    Similar to GetInArrDouble(...), but the value is of type long.

    Void SetInArrValue(input, row, col, value)

    Sets the member of the array that is attached to the input with index input of the REXLANG block.

    Void SetInArrDim(input, row, col)

    Sets the dimension of the array that is attached to the input with index input of the REXLANG block.

    long memrd32(hMem, offset)

    Reading physical memory. Get the handle by
    Open(72,"/dev/mem",<physical address>,<area size>).

    long memwr32(hMem, offset, value)

    Writing to physical memory. Get the handle by
    OpenMemory("/dev/mem",<physical address>,<area size>).

  • Communication Functions (not part of ANSI C)

    This suite of functions facilitates communication over various channels including TCP/IP, UDP/IP, serial lines (RS-232 or RS-485), SPI bus, and I2C bus. Below is a concise list of these functions. For comprehensive details, refer to the example projects in the REXYGEN system.

    long OpenFile(string filename)

    This function opens a file and returns an identification number (handle) of the file. If the function returns a negative value, the file opening was unsuccessful.

    long OpenCom(string comname, long baudrate, long parity)

    Opens a serial line and returns its handle. From REXYGEN version 3.0 onwards, virtual ports can be specified as comname. For detailed information about virtual ports, see the UART block description. If a negative value is returned, the opening failed. The parity setting options are 0 for none, 1 for odd, and 2 for even.

    long OpenUDP(string localname, long lclPort, string remotename, long remPort)

    Opens a UDP socket and returns its handle. If the function returns a negative value, the socket opening was unsuccessful. The function can open either an IPv4 or IPv6 socket based on the remotename, localname, or operating system settings if a DNS name is used. Optional settings include an empty localname (any interface), an empty remotename or 0 for remPort (unused), and 0 for lclPort (assigned by the UDP/IP stack).

    long OpenTCPsvr(string localname, long lclPort)

    This function opens a TCP socket in server (listening) mode. It returns a handle for the socket, and a negative return value indicates an unsuccessful opening. The function can open either IPv4 or IPv6 sockets depending on remotename, localname, or operating system settings if a DNS name is used. You can set an empty localname to mean any interface.

    long OpenTCPcli(string remotename, long remPort)

    Opens a TCP socket in client mode and returns its handle. A negative return value indicates failure to open the socket. The function opens either an IPv4 or IPv6 socket based on remotename, localname, or operating system settings if a DNS name is used. Note that this function does not wait for the connection to be established, which might take a few milliseconds on a local network or a few seconds for remote locations. If Write() or Read() are called before the connection is established, an error code -307 (file open error) is returned.

    long OpenI2C(string devicename)

    Opens the I2C bus and returns its handle. If the function returns a negative value, the opening was not successful.

    long OpenSPI(string devicename)

    Opens the SPI bus and returns its handle. A negative return value indicates an unsuccessful opening.

    long OpenDevice(string filename)

    Similar to OpenFile(), but the functions Write() and Read() are non-blocking. If data cannot be read or written, the function immediately returns a -1 error code.

    long OpenMemory(string devicename, long baseaddr, long size)

    Maps physical memory and returns the associated handle. If a negative value is returned, the operation was unsuccessful.

    long OpenSHM(string devicename, long deviceid, long size, long flags)

    Maps shared memory (Linux only, using ftok() and shmget()) and returns the associated handle. The first and second parameters serve to identify the memory area (they must be the same for all cooperating entities). The size parameter specifies the size of the shared memory area in bytes. The flags parameter represents standard Linux flags and permissions (if set to 0, which is the default value, the following rights are set: create the area if it does not exist, and allow everyone to read and write).

    void Close(long handle)

    Closes a socket, serial line, file, or any device opened with the Open... functions.

    void SetOptions(long handle, long params[])

    Configures the parameters of a socket or serial line. The array size must be at least:

    22

    for serial line (on Windows parameters for SetCommState() and SetCommTimeouts() in following order: BaudRate, fParity, Parity, StopBits, ByteSize, fDtrControl, fRtsControl, fAbortOnError, fBinary, fErrorChar, fNull, fDsrSensitivity, fInX, fOutX, fOutxCtsFlow, fOutxDsrFlow, fTXContinueOnXoff, ReadIntervalTimeout, ReadTotalTimeoutConstant, ReadTotalTimeoutMultiplier, WriteTotalTimeoutConstant, WriteTotalTimeoutMultiplier; linux use different function, but meaning of the parameters is as same as possible),

    2

    for file (1st item is mode: 1=seek begin, 2=seek current, 3=seek end, 4=set file end, 2nd item is offset for seek),

    3

    for SPI (1st item is SPI mode, 2nd item is bits per word, 3rd item is max speed in Hz),

    5

    for I2C (1st item is slave address, 2nd item is 10-bit address flag, 3rd item is Packet Error Checking flag, 4th item is number of retries, 5th item is timeout),

    other

    handle types are not supported

    void GetOptions(long handle, long params[])

    Reads the parameters of a socket or serial line and stores them in the params array. The array size must accommodate the specific device requirements (see SetOptions).

    long Accept(long hListen)

    Accepts a connection on a listening socket, returning a communication socket handle or an error code.

    long Read(long handle, long buffer[], long count[, offset])

    Receives data from a serial line or socket, returning the number of bytes read or an error code. The count parameter defines the maximum number of bytes to read. Each byte of incoming data is put to the buffer array of type long in the corresponding order. The function has one more (optional) offset parameter that can be used when reading data from memory when the handle is created using the OpenSHM() or OpenMemory().

    It is also possible to use the form
    long Read(long handle, string data[], long count) (i.e. a string is used instead of a data array; one byte in the input file corresponds to one character; not applicable to binary files).
    The error codes are:

    -1

    it is necessary to wait for the operation to finish (the function is "non-blocking")

    -309

    reading failed; the operating system error code appears in the log (when function block logging is enabled)

    -307

    file/socket is not open

    long Write(long handle, long buffer[], long count[, offset])

    Sends data over a serial line or socket. The count parameter defines the number of bytes to send. The count of bytes or en error code sent is returned. Each byte of outgoing data is read from the buffer array of type long in the corresponding order. The function has one more (optional) offset parameter that can be used to write data to memory when the handle is created using the OpenSHM() or OpenMemory().

    It is also possible to use the form
    long Write(long handle, string data) (i.e. a string is used instead of a data array; one byte in the output file corresponds to one character; not applicable to binary files).
    The error codes are:

    -1

    it is necessary to wait for the operation to finish (the function is "non-blocking")

    -310

    write failed; the operating system error code appears in the log (when function block logging is enabled)

    -307

    file/socket is not open

    long ReadLine(long handle, string data)

    Reads a line from a (text) file, serial line, or socket, storing the characters in data up to its allocated size. The function returns the actual size of the line or an error code.

    long DeleteFile(string filename)

    Deletes a file, returning 0 on success or a negative error code on failure.

    long RenameFile(string filename, string newfilename)

    Renames a file, returning 0 on success or a negative error code on failure.

    bool ExistFile(string filename)

    Checks if a file or device exists (can be opened for reading), returning true or false.

    long I2C(long handle, long addr, long bufW[], long cntW, long bufR[], long cntR)

    Handles communication over the I2C bus, particularly on Linux systems with I2C capabilities (e.g., Raspberry Pi). The function sends and receives data to/from a slave device using addr. The parameter handle is returned by the OpenI2C function, whose parameter defines the device name (according to the operating system). The parameter bufW is a buffer (an array) for the data which is sent out, cntW is the number of bytes to send out, bufR is a buffer (an array) for the data which comes in and cntR is the number of bytes to receive. The function returns 0 or an error code.

    long SPI(long handle, 0, long bufW[], long cntW, long bufR[], long cntR)

    Executes a transaction over the SPI bus, particularly on Linux systems with SPI capabilities. The parameter handle is returned by the OpenSPI function, whose parameter defines the device name (according to the operating system). The second parameter is always 0 (reserved for internal use). The parameter bufW is a buffer (an array) for the data which is sent out, cntW is the number of bytes to send out, bufR is a buffer (an array) for the data which comes in and cntR is the number of bytes to receive. Note that SPI communication is full-duplex, therefore the resulting length of the SPI transaction is given by maximum of the cntW and cntR parameters, not their sum. The function returns 0 or an error code.

    long Seek(long handle, long mode[], long offset)

    Sets the position for Read/Write commands. Parameter mode means:

    1

    offset from begin of the file,

    2

    offset from current position,

    3

    offset from end of the file.

    long Recv(long handle, long buffer[], long count)

    Obsolete function. Use Read instead.

    long Send(long handle, long buffer[], long count)

    Obsolete function. Use Write instead.

    long crc16(data, length, init, poly, flags, offset)

    Computes a 16-bit Cyclic Redundancy Code (CRC), commonly used as a checksum or hash in various communication protocols.

    data
    A byte array (represented by a long array) or a string for which the hash is computed.
    length
    The number of bytes in the input array or text. Use -1 to process the entire string.
    init
    The initial vector for the CRC computation.
    poly
    The control polynomial used in the computation.
    flags
    Configuration flags
    1

    Reverses the bit order in both the input bytes and the resulting CRC.

    2

    The resulting CRC is XORed with 0xFFFF.

    4

    If data is a long array, all 4 bytes in a long are processed (LSB first).

    8

    Similar to flag 4, but processes MSB first.

    offset
    The index of the first byte to be processed in the data array (usually 0).

    Note: Similar functions exist for computing 32-bit and 8-bit CRCs: long crc32(data, length, init, poly, flags, offset) and long crc8(data, length, init, poly, flags, offset). The initial vector, control polynomial, and flags for various protocols can be found at https://crccalc.com/

    Examples:

    • MODBUS: crc16("123456789", -1, 0xFFFF, 0x8005, 1, 0)
    • DECT-X: crc16("123456789", -1, 0, 0x0589, 0, 0)

    Additional Note: The crc8(...) and crc32(...) functions also exist, supporting 8-bit and 32-bit CRC calculations with the same parameter structure.

Remarks

  • Data types of inputs u0..u15, outputs y0..y15, and parameters p0..p15 are determined during the source code compilation.
  • Error codes < -99 require a RESET input for restarting the REXLANG block after addressing the cause of the error.
  • ATTENTION!!! It is possible to read inputs in the init() function, but since other blocks usually do not set outputs in the init phase, there will always be 0. Outputs can be set, but usually this is not done.
  • The srcname parameter can be specified with an absolute path. Otherwise, the file is searched for in the current directory and the specified directories (see the LibraryPath parameter of the PARAM block).
  • Vector function parameters are primarily of type double, with the exception of the n parameter, which is of type long. Note that the functions with one vector parameter exist in three variants:
    double function(val1,…,valn)

    Vector is defined as a sequence of values of type double.

    double function(n,val1,…,valn)

    Vector is defined as in the first case, only the first parameter defines the number of values – the size of the vector. This variant is compatible with the C compiler. The n (The optional parameter n of the vector functions must be specified if the compatibility with C/C++ compiler is required. In such a case all the nonstandard functions must be implemented as well and the functions with variable number of parameters need to know the parameter count.) parameter must be a number, not the so-called const variable and it must correspond with the number of the following elements defining the vector.

    double function(n,vec)

    The n parameter is an arbitrary expression of type long and defines the number of elements the function takes into account.

  • It’s crucial to remember that arrays in the scripting language behave similarly to arrays in C: indexing begins at 0 and there is no automatic boundary checking. For instance, if you declare double vec[10], x;, the array vec will have elements indexed from 0 to 9. Accessing vec[10] does not trigger a syntax or runtime error, but the returned value is undefined since it’s beyond the array bounds. Additionally, assigning a value to vec[11] (e.g., vec[11] = x;) can be particularly dangerous, as it may inadvertently overwrite adjacent memory locations. This could lead to unpredictable behavior or cause the program to crash.
  • During the compilation process, if there are syntax errors, the compiler reports a parser error along with the line number where the error occurred. These reports specifically indicate issues with syntax. However, if the syntax appears correct and an error is still reported, it’s advisable to check for conflicts involving identifiers, keywords, or function names, as these can also cause errors not immediately evident as syntax-related.
  • All jumps are translated as relative, i.e. the corresponding code is restricted to 32767 instructions (in portable format for various platforms).
  • All valid variables and the results of temporary computations are stored in the stack, which includes:
    • Global and local static variables are permanently located at the stack’s base.
    • Return addresses for function calls.
    • Function parameters.
    • Variables local to functions.
    • The return value of a function.
    • Temporary computational results. For example, in the expression a = b + c;, b and c are first pushed onto the stack. Their sum is then calculated, the operands are popped off the stack, and the result is pushed onto the stack.

    Simple variables such as long or double occupy one stack slot each. For arrays, the total occupied size matters, irrespective of the element type.

  • When arrays are passed to functions, they are referenced rather than copied. This means only one stack slot is used for the reference, and the function operates directly on the original array.
  • If the allocated stack size is insufficient (less than the space needed for global variables plus 10), it is automatically doubled, with an additional 100 slots for computational needs, function parameters, and local variables, especially when few global variables are defined.
  • With basic debug level, various checks are conducted during script execution. These include the initialization of read values and array index boundary checks. Additionally, a few uninitialized values are inserted at both the start and end of each declared array for boundary checking, and NOP instructions with source file line numbers are added to the *.ill file.
  • At full debug level, an additional check for invalid data range accesses (such as stack overflows) is enabled.
  • In this context, an ’instruction’ refers to a processor-independent mnemonic code. These codes are stored in the *.ill file.
  • The OpenCom() function sets binary non-blocking mode without timeouts, 8 data bits, 1 stop bit, no parity, 19200 Baud. Optionally, the baudrate and parity parameters can be adjusted in the OpenCom() function.
  • Accessing text files is significantly slower than binary files. However, text files offer the advantage of being viewable and editable without specialized software.
  • The block does not automatically invoke the parchange() function. This function must be manually called within the init() function if needed.
  • The OpenFile() function opens files in the data directory of the REXYGEN system (i.e., in Linux by default in \rex\data, on Windows
    C:\ProgramData\REX Controls\REX_<version>\RexCore). Subdirectories are allowed, but .. is not permitted. Links are followed.

Debugging the code
Use the Trace command mentioned above.

Inputs

HLD

Hold – the block code is not executed if the input is set to on

Bool

RESET

Rising edge resets the block. The block gets initialized again (all global variables are cleared and the Init() function is called).

Bool

u0..u15

Input signals which are accessible from the script

Any

Outputs

iE

Runtime error code. For error codes iE < 99 the algorithm is stopped until it is reinitialized by the RESET input or by restarting the executive

Error

0 ....

No error occurred, the whole main() function was executed (also the init() function).

-1 ...

The execution was suspended using the Suspend() command, i.e. the execution will resume as soon as the REXLANG block is executed again

< -1 .

Error code of the REXYGEN system, see Appendix C

> 0 ..

User-defined return values, algorithm execution without any change

y0..y15

Output signals which can be set from within the script

Any

Parameters

srcname

Source file name  srcfile.c

String

srctype

Coding of source file  1

Long (I32)

1: C-like 

Text file respecting the C-like syntax described above

2: STL 

Text file respecting the IEC61131-3 standard. The standard is implemented with the same limitations as the C-like script (i.e. no structures, only INT, REAL and STRING data types, function blocks are global variables VAR_INPUT, outputs are global variables VAR_OUTPUT, parameters are global variables VAR_PARAMETER, standard functions according to specification, system and communication functions are the same as in C-like).

3: RLB 

REXLANG binary file which results from compilation of C-like or STL scripts. Use this option if you do not wish to share the source code of your block.

4: ILL 

Text file with mnemocodes, which can be compared to assembler. This choice is currently not supported.

stack

Stack size defined as number of variables. Default and recommended value is 0, which enables automatic estimation of the necessary stack size.

Long (I32)

debug

Debug level – checking is safer but slows down the execution of the algorithm. Option No check can crash REXYGENapplication on target platform if code is incorrect.  3

Long (I32)

1 ....

No check

2 ....

Basic check

3 ....

Full check

strs

Total size of buffer for strings. Enter the maximum number of characters to allocate memory for. The default value 0 means that the buffer size is determined automatically.

Long (I32)

p0..p15

Parameters which are accessible from the script

Any

Example C-like
The following example shows a simple code to sum two input signals and also sum two user-defined parameters.

double input(0) input_u0;  
double input(2) input_u2;  
 
double parameter(0) param_p0;  
double parameter(1) param_p1;  
 
double output(0) output_y0;  
double output(1) output_y1;  
 
double my_value;  
 
long init(void)  
{  
  my_value = 3.14;  
  return 0;  
}  
 
long main(void)  
{  
  output_y0 = input_u0 + input_u2;  
  output_y1 = param_p0 + param_p1 + my_value;  
  return 0;  
}  
 
long exit(void)  
{  
  return 0;  
}

Example STL
And here is the same example in Structured Text.

VAR_INPUT  
  input_u0:REAL;  
  input_u1:REAL;  
  input_u2:REAL;  
END_VAR  
 
VAR_OUTPUT  
  output_y0:REAL;  
  output_y1:REAL;  
END_VAR  
 
VAR_PARAMETER  
  param_p0:REAL;  
  param_p1:REAL;  
END_VAR  
 
VAR  
  my_value: REAL;  
END_VAR  
 
FUNCTION init : INT;  
  my_value := 3.14;  
  init := 0;  
END_FUNCTION  
 
FUNCTION main : INT;  
  output_y0 := input_u0 + input_u2;  
  output_y1 := param_p0 + param_p1 + my_value;  
  main := 0;  
END_FUNCTION  
 
FUNCTION exit : INT;  
  exit := 0;  
END_FUNCTION

2024 © REX Controls s.r.o., www.rexygen.com