Appendix A: Variable Type Reference
Scalar Types
| Type | Rust Type | Size | Range | IEC 61131-3 Equivalent |
|---|---|---|---|---|
bool | bool | 1 byte | true / false | BOOL |
u8 | u8 | 1 byte | 0 to 255 | USINT / BYTE |
i8 | i8 | 1 byte | -128 to 127 | SINT |
u16 | u16 | 2 bytes | 0 to 65,535 | UINT / WORD |
i16 | i16 | 2 bytes | -32,768 to 32,767 | INT |
u32 | u32 | 4 bytes | 0 to 4,294,967,295 | UDINT / DWORD |
i32 | i32 | 4 bytes | -2,147,483,648 to 2,147,483,647 | DINT |
u64 | u64 | 8 bytes | 0 to 2^64 - 1 | ULINT / LWORD |
i64 | i64 | 8 bytes | -2^63 to 2^63 - 1 | LINT |
f32 | f32 | 4 bytes | IEEE 754 single precision | REAL |
f64 | f64 | 8 bytes | IEEE 754 double precision | LREAL |
String Type
| Type | Rust Type | Size | Range |
|---|---|---|---|
string | FixedString<N> | N bytes | UTF-8 text, zero-padded to capacity |
Fixed-length strings are stored as zero-padded byte arrays in shared memory. The max_length field sets the capacity in bytes (default: 64, maximum: 255).
"info_test_id": { "type": "string", "description": "Test identifier" },
"info_specimen_name": { "type": "string", "max_length": 128, "description": "Specimen name" },
"info_notes": { "type": "string", "max_length": 255, "description": "Operator notes" }
In the control program, string variables appear as FixedString<N> fields:
// Read a string
let test_id = ctx.gm.info_test_id.as_str();
log::info!("Test: {}", test_id);
// Write a string
ctx.gm.info_test_id.set("TEST-001");
// Check if empty
if ctx.gm.info_notes.is_empty() {
log::warn!("No notes entered");
}
Strings longer than the capacity are silently truncated at a valid UTF-8 character boundary.
Bit-Mapped Variables
Bool variables can be mapped to individual bits of an integer variable using the source and bit fields. This is useful for EtherCAT devices that pack multiple digital I/O channels into a single word.
"impact67_0_digital_inputs": { "type": "u16", "link": "ethercat.impact67_0.digital_inputs" },
"impact67_0_digital_outputs": { "type": "u16", "link": "ethercat.impact67_0.digital_outputs" },
"ls_centering_neg": { "type": "bool", "source": "impact67_0_digital_inputs", "bit": 0 },
"ls_centering_pos": { "type": "bool", "source": "impact67_0_digital_inputs", "bit": 1 },
"ls_lift_neg": { "type": "bool", "source": "impact67_0_digital_inputs", "bit": 2 },
"cr_lift_brake": { "type": "bool", "source": "impact67_0_digital_outputs", "bit": 0 }
The code generator produces unpack_bits() and pack_bits() methods on GlobalMemory that are called automatically by the framework each cycle:
- After reading shared memory:
unpack_bits()extracts each bool from its source word - Your
process_tick()runs — read and write the individual bools naturally - Before writing shared memory:
pack_bits()inserts each bool back into its source word
Unmapped bits in the source word are preserved.
Rules:
sourcemust name another variable in the same projectsourcemust be an integer type (u8,u16,u32,u64,i8,i16,i32,i64)bitis 0-based (0 = LSB) and must be within the source type’s bit width- The bit-mapped variable must be type
bool sourceandbitmust always be specified together
In the control program, bit-mapped variables are ordinary bools — no special access pattern:
// Read individual digital inputs
if ctx.gm.ls_centering_neg {
log::info!("Centering negative limit reached");
}
// Set individual digital outputs
ctx.gm.cr_lift_brake = true;
Variable Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | Data type (see tables above) |
link | string | no | Hardware FQDN link (e.g., "ethercat.el2004.output1") |
description | string | no | Human-readable description |
initial | any | no | Initial value (as JSON, parsed based on type) |
nonvolatile | bool | no | When true, value persists across restarts |
max_length | number | no | String capacity in bytes (default: 64, max: 255) |
source | string | no | Source variable for bit-mapped bools |
bit | number | no | Bit position in source (0 = LSB) |