🔍
v1.3.8

Arrays

Arrays are the primary way to work with ordered collections of data in TSharkRex. They are used extensively for CAN data buffers, UDS request payloads, signal lookup tables, and any scenario where you need to store multiple values of the same type. TSharkRex supports both one-dimensional and two-dimensional arrays with compile-time fixed sizes.

Because TSharkRex uses static memory allocation, all array sizes must be known at compile time. There are no dynamically sized arrays, no resizing, and no heap allocation. This guarantees deterministic memory usage on the embedded device.

One-Dimensional Arrays

A one-dimensional array is declared using the ARRAY[low..high] OF type syntax inside a VAR block. The index range is inclusive on both ends.

VAR
    buffer : ARRAY[0..7] OF BYTE;
    flags : ARRAY[0..3] OF BOOL;
    values : ARRAY[0..15] OF DINT;
END_VAR;

In this example:

Array indices always start from the lower bound you specify. While 0 is the conventional starting index, the language allows any non-negative lower bound:

VAR
    sensors : ARRAY[1..4] OF INT;   // Indices 1, 2, 3, 4
END_VAR;
By convention, almost all TSharkRex arrays start at index 0. Stick with this convention unless you have a specific reason to do otherwise - it makes your code more readable and consistent with CAN data indexing.

Two-Dimensional Arrays

Two-dimensional arrays are declared by specifying two index ranges separated by a comma. They are particularly useful for storing multiple CAN frame payloads or UDS DID request sequences.

VAR
    payload : ARRAY[0..3, 0..7] OF BYTE := [
        0x03, 0x22, 0x42, 0x1B, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x52, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x22, 0x00, 0x00, 0x00, 0x00
    ];
END_VAR;

This declares a 4×8 array - four rows of eight bytes each. Each row represents a complete UDS DID request payload:

The first byte 0x03 in each row is the UDS payload length, 0x22 is the “Read Data By Identifier” service ID, and the next two bytes form the DID number. The remaining bytes are padding.

This pattern of storing multiple DID request payloads in a 2D array is one of the most common uses of arrays in TSharkRex. It allows you to iterate over requests using a single loop or index variable, rather than duplicating code for each DID.

Array Initialization

Arrays can be initialized at declaration time using square bracket syntax with comma-separated values:

VAR
    data : ARRAY[0..3] OF BYTE := [0x03, 0x22, 0x45, 0x55];
END_VAR;

For larger arrays, you can spread the initializer across multiple lines for readability:

VAR
    lookup : ARRAY[0..7] OF INT := [
        0, 100, 200, 400,
        800, 1000, 500, 250
    ];
END_VAR;

Two-dimensional arrays are initialized in row-major order - all elements of row 0 first, then row 1, and so on (as shown in the 2D array example above).

You Must Initialize ALL Elements

When initializing an array, you must provide exactly as many values as the array has elements. The compiler will report an error if the count does not match. For example, ARRAY[0..7] has 8 elements, so you must provide exactly 8 values.

Padding with Zeros

When only the first few bytes carry data and the rest should be zero, you still need to write out all elements explicitly:

VAR
    // UDS request: only first 3 bytes matter, but all 8 must be provided
    request : ARRAY[0..7] OF BYTE := [0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00];
END_VAR;
Note

If you do not provide any initializer at all (just request : ARRAY[0..7] OF BYTE;), the array elements default to zero. Only use the := [...] syntax when you need specific starting values.

Array Access

Individual array elements are accessed using square bracket notation with an index expression:

VAR
    buffer : ARRAY[0..7] OF BYTE;
    value : BYTE;
END_VAR;

// Read an element
value := buffer[3];

// Write an element
buffer[0] := 0xFF;

For two-dimensional arrays, provide both indices separated by a comma:

VAR
    payload : ARRAY[0..3, 0..7] OF BYTE;
    row : BYTE := 2;
    col : BYTE := 1;
    value : BYTE;
END_VAR;

// Read from 2D array
value := payload[row, col];

// Write to 2D array
payload[row, col] := value;

The index can be any integer expression - a literal, a variable, or a computed value:

buffer[i] := buffer[i + 1];        // Copy next element
value := payload[row * 2, offset]; // Computed indices
Out-of-bounds access is undefined behavior. TSharkRex does not perform runtime bounds checking - accessing an index outside the declared range may read or write arbitrary memory. Always ensure your indices are within the valid range.

Common Patterns

CAN Data Buffers

The most ubiquitous use of arrays is as CAN frame data buffers. A standard CAN frame carries up to 8 bytes of payload:

VAR
    SENDDATA : ARRAY[0..7] OF BYTE;
    RECVDATA : ARRAY[0..7] OF BYTE;
END_VAR;

CAN-FD (Flexible Data-rate) frames can carry up to 64 bytes:

VAR
    FDDATA : ARRAY[0..63] OF BYTE;
END_VAR;

DID Module Data Buffers

When using the DID_EXT function block for UDS communication, each DID module needs a data buffer to receive the response. These buffers are typically 64 bytes:

VAR
    MODULE_0_DATA : ARRAY[0..63] OF BYTE;
    MODULE_1_DATA : ARRAY[0..63] OF BYTE;
    MODULE_2_DATA : ARRAY[0..63] OF BYTE;
END_VAR;

Filling an Array with a FOR Loop

A FOR loop is the standard way to initialize or process array elements programmatically:

VAR
    buffer : ARRAY[0..7] OF BYTE;
    i : BYTE;
END_VAR;

// Clear the buffer
FOR i := 0 TO 7 DO
    buffer[i] := 0x00;
END_FOR;

// Fill with incrementing values
FOR i := 0 TO 7 DO
    buffer[i] := i * 10;
END_FOR;

Copying Between Arrays

To copy data from one array to another, iterate over the elements:

VAR
    source : ARRAY[0..7] OF BYTE;
    dest : ARRAY[0..7] OF BYTE;
    i : BYTE;
END_VAR;

FOR i := 0 TO 7 DO
    dest[i] := source[i];
END_FOR;

Building a CAN Frame Payload

A typical pattern is to construct a CAN frame payload byte-by-byte and then send it:

VAR
    CANSEND : CAN_TX;
    SENDDATA : ARRAY[0..7] OF BYTE;
    hastighet : INT;    // Speed value to send
END_VAR;

// Build the payload
SENDDATA[0] := 0x03;                              // UDS length
SENDDATA[1] := 0x22;                              // Read By ID service
SENDDATA[2] := SHR(hastighet, 8) BAND 0xFF;       // Speed high byte
SENDDATA[3] := hastighet BAND 0xFF;               // Speed low byte
SENDDATA[4] := 0x00;                              // Padding
SENDDATA[5] := 0x00;
SENDDATA[6] := 0x00;
SENDDATA[7] := 0x00;

// Send the frame
CANSEND(ENABLE := TRUE, ID := 0x7DF, EXT := FALSE,
        DATALENGTH := 8, DATA := SENDDATA);

Iterating Over 2D Payloads

When you have multiple DID requests stored in a 2D array, you can iterate over them using a row index:

VAR
    payload : ARRAY[0..3, 0..7] OF BYTE := [
        0x03, 0x22, 0x42, 0x1B, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x52, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x22, 0x42, 0x22, 0x00, 0x00, 0x00, 0x00
    ];
    SENDDATA : ARRAY[0..7] OF BYTE;
    current_row : BYTE := 0;
    i : BYTE;
END_VAR;

// Copy current row to send buffer
FOR i := 0 TO 7 DO
    SENDDATA[i] := payload[current_row, i];
END_FOR;

// Advance to next row (wrap around)
current_row := current_row + 1;
IF current_row > 3 THEN
    current_row := 0;
END_IF;

Arrays and Pointers

Arrays work closely with pointers in TSharkRex. You can take the address of an array element using the @ operator and pass it to function blocks that expect pointer parameters. This is covered in detail in the next chapter, Pointers.

VAR
    data : ARRAY[0..7] OF BYTE;
    pData : POINTER TO BYTE;
END_VAR;

pData := @data[0];   // Point to first element of the array

Size Considerations

Remember that TSharkRex runs on embedded hardware with limited memory. While the compiler will reject programs that exceed available memory, it is good practice to keep arrays as small as necessary:

The most common array sizes in practice are ARRAY[0..7] OF BYTE (standard CAN payload) and ARRAY[0..63] OF BYTE (CAN-FD payload or DID response buffer). If you are unsure what size to use, start with one of these.