I/O Binding¶
Address Examples: %IX0.0, %QX0.0, %IW0, %QW0¶
Use %IX0.0 when you need a concrete boolean input example, %QX0.0 for a
boolean output example, %IW0 for a word input example, and %QW0 for a word
output example.
Symbolic variables bind to physical I/O channels through direct addresses,
VAR_CONFIG, or io.toml.
At this point the problem is signal identity, not transport selection.
Keep one binding path authoritative for each signal so diagnostics and operator views describe the same process image.
Guide¶
This guide explains how to map hardware I/O to Structured Text variables using the Web UI
or io.toml and IEC addresses (%IX, %QX, %MX).
Tip: The Web UI supports driver selection, GPIO pin mapping, Modbus/TCP settings, and safe‑state outputs under I/O → I/O configuration (no manual file editing needed).
1) Addressing Basics¶
Use IEC-style addresses in ST:
VAR_GLOBAL
InSignal AT %IX0.0 : BOOL;
OutSignal AT %QX0.0 : BOOL;
END_VAR
%I= input,%Q= output,%M= memoryX= bit address (use for GPIO and discrete I/O)
Marker (%M) address variants:
%MX<byte>.<bit>(bit, BOOL), example:%MX0.7%MB<byte>(byte), example:%MB12%MW<byte>(word), example:%MW50%MD<byte>(double word), example:%MD200%ML<byte>(long word), example:%ML8%M*(wildcard, resolved byVAR_CONFIG)
Runtime cycle semantics for %M bindings:
- Cycle start:
%Mprocess image is read into bound variables. - Cycle end: bound variable values are written back to
%Mprocess image.
2) io.toml Structure (v1)¶
Single-driver form (legacy + still supported):
[io]
driver = "simulated"
params = {}
Multi-driver form (composed drivers, executed in order):
[io]
drivers = [
{ name = "modbus-tcp", params = { address = "192.168.0.10:502", unit_id = 1, input_start = 0, output_start = 0, timeout_ms = 500, on_error = "fault" } },
{ name = "mqtt", params = { broker = "192.168.0.20:1883", topic_in = "line/in", topic_out = "line/out", reconnect_ms = 500, keep_alive_s = 5, allow_insecure_remote = true } }
]
Rule:
- Use either
io.driver+io.paramsorio.drivers(do not mix both in one file).
Optional safe state outputs:
[[io.safe_state]]
address = "%QX0.0"
value = "FALSE"
If io.toml is missing, the runtime uses system IO config:
- Linux/macOS:
/etc/trust/io.toml - Windows:
C:\\ProgramData\\truST\\io.toml
3) GPIO Example (Raspberry Pi)¶
[io]
driver = "gpio"
[io.params]
backend = "sysfs"
inputs = [
{ address = "%IX0.0", line = 17, debounce_ms = 5 }
]
outputs = [
{ address = "%QX0.0", line = 27, initial = false }
]
[[io.safe_state]]
address = "%QX0.0"
value = "FALSE"
4) Loopback (Local Testing)¶
[io]
driver = "loopback"
params = {}
This copies outputs to inputs for local testing without hardware.
5) Modbus/TCP Example¶
[io]
driver = "modbus-tcp"
[io.params]
address = "192.168.0.10:502"
unit_id = 1
input_start = 0
output_start = 0
timeout_ms = 500
on_error = "fault"
6) MQTT Example¶
[io]
driver = "mqtt"
[io.params]
broker = "192.168.0.20:1883"
topic_in = "line/in"
topic_out = "line/out"
reconnect_ms = 500
keep_alive_s = 5
allow_insecure_remote = true
7) Transport Gating Notes (Critical)¶
EtherCAT hardware transport (non-mock adapter):
- requires build feature
ethercat-wire - supported on unix targets only in this build
adapter = "mock"remains valid for deterministic local/CI validation
OPC UA wire server:
- requires build feature
opcua-wire - if
[runtime.opcua].enabled = truewithoutopcua-wire, runtime startup fails with a feature-disabled error - when enabled, configure either:
allow_anonymous = true(local commissioning only), orallow_anonymous = falseplus bothusernameandpassword
Communication examples with step-by-step commissioning flow:
examples/communication/modbus_tcp/README.mdexamples/communication/mqtt/README.mdexamples/communication/opcua/README.mdexamples/communication/ethercat/README.mdexamples/communication/ethercat_field_validated_es/README.mdexamples/communication/gpio/README.mdexamples/communication/multi_driver/README.md
8) Validate + Inspect¶
EtherCAT backend details (module chain profile, diagnostics, and hardware setup):
docs/guides/ETHERCAT_BACKEND_V1.md.
Validate a project folder:
trust-runtime validate --project <project-folder>
Read current I/O snapshot:
trust-runtime ctl --project <project-folder> io-read
Write output (for testing):
trust-runtime ctl --project <project-folder> io-write %QX0.0 TRUE