Affects: ForgeIEC Studio tongs-* Anvil server (anvild)

What is a device?

A bus device is a single device inside a segment β€” Modbus TCP slave (I/O block, drive), EtherCAT slave (servo axis, I/O coupler), Profibus DP slave or EtherNet/IP adapter. The bridge daemon maintains one logical connection per device, polls the configured registers and publishes the data via Anvil zero-copy IPC to the PLC runtime.

A device can be modular: a bus coupler (slot 0) carries 1..N I/O modules in slots 1..N. Compact devices without expansion slots have an empty modules list β€” variables then sit at slot 0.


FDD integration

Instead of describing every device manually, you import a manufacturer FDD at creation. ForgeIEC Studio:

  1. Reads <Identification>, <DiagnosticDecode>, <ModuleProtocol>, <Document> from the FDD
  2. Shows the embedded PDF data sheet in the documents tab of the properties panel
  3. Populates status variables from the diagnostic-bit definitions
  4. Filters the module picker to show only compatible modules (matched via <ModuleProtocol>)

The catalogRef field of the device points to the FDD used. You can swap an FDD (e.g. weidmueller/UR20-FBC-PN-IRT-V2 β†’ -V3) and keep all I/O variable bindings β€” identity hangs on the deviceId UUID, not the manufacturer entry.

Create your own FDDs via File β†’ New FDD (diagnostics tab + documents tab in the FDD editor).

More on the FDD system: news post.


Device fields

The struct definition lives in editor/include/model/FBusSegmentConfig.h. A device is persisted in the .forge project as <fi:device> under <fi:segment> (see bus configuration).

Identity + addressing

FieldTypeMeaning
deviceIdUUIDStable primary key β€” generated on creation, survives hostname rename and IP change. Keeps all variable bindings stable.
hostnameStringUser-visible label ("Stachelbeere", "Maibeere"). Is part of the IEC namespace (anvil.<Segment>.Stachelbeere.<...>). DHCP-safe, but not a primary key.
ipAddressString (IP)IP address (Modbus TCP / EtherNet/IP). Empty for devices without an IP (EtherCAT slaves identify via bus position).
portIntTCP port. Default 502 (Modbus TCP).
slaveIdIntModbus slave ID (1..247). For TCP usually 1.
catalogRefStringReference to the FDD catalog entry, e.g. "weidmueller/UR20-FBC-PN-IRT-V2". Drives the module picker + diagnostic-bit resolution.
descriptionStringFree text ("Irrigation valve south").

Modules (slots)

FieldTypeMeaning
modulesList of FBusModuleConfigI/O modules of the device. Slot 0 = coupler / compact device, slots 1..N = expansion modules. Per module: slotIndex, catalogRef, name, baseAddress, settings.

For modular couplers, each module ships with its own FDD file β€” again with diagnostic bits + data sheet. The picker shows only modules that the coupler understands according to its <ModuleProtocol>.

Per-device overrides

Override β€” for this device only β€” the corresponding values of the segment. 0 or empty string means inherit from segment. In the properties panel usually collapsed under Advanced Overrides.

FieldTypeMeaning
macString AA:BB:CC:DD:EE:FFMAC address for static ARP / identity check. Protects against IP hijacking for DHCP devices.
endiannessEnum"ABCD" (big-endian, IEC default), "DCBA" (word swap), "BADC" (byte swap), "CDAB" (both). Empty = inherit from segment.
timeoutOverrideMsInt (ms)Per-device timeout. 0 = segment timeout.
retryCountIntRetries per request. 0 = segment default.
connectionModeEnum"always" (keep TCP open) or "on_demand" (reconnect per transaction). Empty = segment default.
gatewayOverrideString (IP)Own gateway if the device is in a different subnet than the bind NIC.

Device-specific settings

The settings map (key/value) carries values that only make sense for this device or its device type β€” e.g. a frequency-converter threshold or a preferred Modbus function code.


Edit path in ForgeIEC Studio

ActionEffect
Single click on a device nodeFPropertiesPanel shows all fields as inline editors β€” general, override block, diagnostic bits with live values, status table.
Double clickModal dialog FBusDeviceDialog. In edit mode the “Import from catalog” button is locked so that a later FDD import does not overwrite existing I/O bindings.

Status variables (read-only)

Every device publishes a status struct at runtime. Properties panel shows them as a read-only table β€” the bridge writes them, the ST code reads them. On the ST side, they are accessible under anvil.<Segment>.<Device>.Status.<Var>:

Status variableTypeMeaning
xOnlineBOOLDevice currently reachable (last request was answered)
eStateINTState enum: 0=offline, 1=connecting, 2=online, 3=error
wErrorCountWORDFailed requests since bridge start
sLastErrorMsgSTRINGLast error message (timeout, Modbus exception, …)

Additionally, all bits from the FDD <DiagnosticDecode> section appear as type-safe status members β€” e.g. WireBreak, ShortCircuit, OverTemperature. Properties panel shows meaning

  • severity multilingually (DE/EN) from the FDD.

ST example:

IF anvil.Halle1.Maibeere.Status.xOnline AND
   anvil.Halle1.Maibeere.Status.wErrorCount < 10 AND
   NOT anvil.Halle1.Maibeere.Status.WireBreak THEN
    bSensor_OK := TRUE;
END_IF;

AI-assistant diagnostic loop via MCP catalog.diag_bits returns the resolved meaning of these bits in plain text.


Example: Weidmueller UR20 coupler with two modules

A ProfiNet IRT coupler (UR20-FBC-PN-IRT-V2) with an 8-DI module and an 8-DO module:

[[bus_segments.devices]]
device_id    = "0e5d5537-e328-44e6-8214-78d529b18ebd"
hostname     = "Stachelbeere"
ip_address   = "192.168.24.25"
port         = 502
slave_id     = 1
catalog_ref  = "weidmueller/UR20-FBC-PN-IRT-V2"
description  = "Bus coupler hall 1, row A"

[[bus_segments.devices.modules]]
slot_index   = 0
catalog_ref  = "weidmueller/UR20-FBC-PN-IRT-V2"
name         = "Coupler"
base_address = 0

[[bus_segments.devices.modules]]
slot_index   = 1
catalog_ref  = "weidmueller/UR20-8DI-P"
name         = "8 DI slot 1"
base_address = 0

[[bus_segments.devices.modules]]
slot_index   = 2
catalog_ref  = "weidmueller/UR20-8DO-P"
name         = "8 DO slot 2"
base_address = 0

Effect:

  • The 8 inputs appear in the address pool as %IX0.0..%IX0.7 with deviceId=0e5d5537-..., moduleSlot=1, modbusAddress=0..7
  • The 8 outputs similarly with moduleSlot=2
  • ST access: anvil.Halle1.Stachelbeere.IO.DI_1 / anvil.Halle1.Stachelbeere.IO.DO_1
  • Diagnostic bits from the FDD: Status.WireBreak, Status.ShortCircuit, etc. β€” type-safe, multilingual descriptions

See also