Device-driver codegen¶
This page captures the requirements for the device-driver codegen
toolchain: a layered set of crates that translates EtherCAT ESI XML
device descriptions into strongly-typed Rust driver modules at build
time, with zero runtime XML parsing and no dependency on the
taktora-connector-ethercat runtime.
The decomposition mirrors the convention established in Connector framework and Soft-RT PLC runtime heart:
Top-level umbrella feature — Device-driver codegen toolc... (FEAT_0050) — peer to PLC runtime heart on iceoryx2 (FEAT_0010) (PLC runtime heart), Connector framework (FEAT_0030) (Connector framework), and Bounded global allocator (FEAT_0040) (Bounded global allocator). The codegen toolchain is a build-time concern orthogonal to the runtime connector framework; it is not bound to taktora-executor or taktora-connector and could be consumed by any ethercrab user.
Capability-cluster sub-features — one per crate-layer concern, each
:satisfies:Device-driver codegen toolc... (FEAT_0050).Requirements — concrete shall-clauses that
:satisfies:a capability-cluster feature.
This round covers EtherCAT only (ESI XML → typed driver structs). CANopen / EDS support is explicitly out of scope; the architecture preserves the option to extract a shared object-dictionary IR later (see Future CANopen support via ... (ADR_0073)).
Top-level umbrella¶
A layered set of Rust crates that consumes EtherCAT Slave Information (ESI) XML files and emits strongly-typed driver modules at build time. The toolchain is organised as four layers that depend only leftwards:
The |
Capability clusters¶
The umbrella decomposes into seven capability clusters. Each cluster
is a sub-feature :satisfies: Device-driver codegen toolc... (FEAT_0050), with concrete
shall-clauses underneath.
ESI parser¶
A pure parser crate. Reads ESI XML, emits a typed in-memory IR. Knows nothing about codegen, ethercrab, or taktora-executor. Suitable for any downstream tool — codegen, network configurator, simulator, verifier. |
The crate shall expose |
The crate shall be |
The crate shall implement parsing on top of |
The |
The IR shall represent, per device: |
Vendor-specific ESI extensions (e.g. Beckhoff |
|
IR and codegen backend trait¶
The codegen-side IR (an extension of the parser IR with naming /
collision policy applied) and the |
The crate shall define a |
The |
When two devices in the input set share a product name but differ
in revision (e.g. |
When two or more devices’ PDOs include structurally identical entry layouts (same field order, same bit lengths, same data types), the codegen layer shall emit one shared PDO entry struct referenced by both devices rather than two duplicated structs. Structural equality is the deduplication key — names do not need to match. |
The codegen layer shall produce |
ethercrab backend¶
The opinionated, concrete backend that emits per-device structs
implementing the runtime traits in Runtime trait surface (FEAT_0054). This is the
only crate in the toolchain that depends on |
|
For each |
For each generated device struct, the backend shall emit an
accompanying |
When an ESI device declares multiple PDO assignment alternatives
(typically “Standard” / “Compact”), the backend shall emit a
|
For each variant of |
The module root emitted by |
The emitted device modules shall compile under |
Runtime trait surface¶
The minimal trait pair the generated devices implement and the
|
The crate shall define an |
The crate shall define |
|
Emission of the full object-dictionary table per device (as a
|
|
Build helper¶
A trivial helper crate so downstream consumers run codegen with
one |
|
The helper shall write the generated module to
|
The helper shall print |
Before writing the output, the helper shall format the
|
CLI inspection¶
A |
|
|
The CLI shall depend on |
EEPROM diff verification¶
A CI-friendly cross-check: parse an ESI XML file and the matching
captured SII EEPROM |
|
When a verification fails, the |
The verifier shall consume the same |
When invoked as a binary ( |
Anti-goals¶
The following requirements are explicitly rejected — captured for
the record so future readers see what the toolchain deliberately does
not do, and why. Each rejected requirement :satisfies:
Device-driver codegen toolc... (FEAT_0050) to keep the umbrella’s traceability complete.
The toolchain shall not include a CAN parser, a CANopen
runtime trait, an EDS / XDD reader, or a SocketCAN backend.
CANopen and EtherCAT’s CoE share the Object Dictionary
semantics, but transport semantics diverge (cyclic PDI vs
event-driven frames). A follow-on spec extracts a shared
|
The toolchain shall not offer an |
When CANopen support is added in a follow-on spec, the runtime
trait family shall not be merged with |
The toolchain shall not parse ESI XML at application
runtime. All XML parsing happens at build time in
|
This spec shall not require any change to the runtime
contracts of EtherCAT reference connector (FEAT_0041) “EtherCAT reference connector”.
The connector consumes |
The toolchain shall not download, scrape, or otherwise
fetch ESI XML from vendor websites or update servers. ESI files
are inputs the user drops into a |
Cross-cutting traceability¶
Every requirement on this page (excluding rejected anti-goals)
carries a :satisfies: link to its capability-cluster feat; every
cluster feat :satisfies: Device-driver codegen toolc... (FEAT_0050). Architectural
specifications refining these requirements are emitted in
Device-driver codegen — architecture (arc42). Verification artefacts are
emitted in Device-driver codegen — verification.
ID |
Title |
Status |
Satisfies |
|---|---|---|---|
Device-driver codegen toolchain |
open |
||
ESI parser |
open |
||
IR and codegen backend trait |
open |
||
ethercrab codegen backend |
open |
||
Runtime trait surface |
open |
||
Build helper (build.rs glue) |
open |
||
CLI inspection (cargo subcommand) |
open |
||
EEPROM diff verification |
open |
ID |
Title |
Status |
Satisfies |
|---|---|---|---|
Pure parse function with no I/O |
open |
||
no_std + alloc compatible |
open |
||
quick-xml + serde backend |
open |
||
Parser does not depend on ethercrab or codegen |
open |
||
IR carries identity, PDO maps, mailbox, DC, and OD |
open |
||
Vendor-specific extensions captured as opaque blobs |
open |
||
Parse errors carry line and column |
open |
||
CodegenBackend trait shape |
open |
||
Naming policy is owned by codegen, not the backend |
open |
||
Revision collision handled deterministically |
open |
||
Common PDO entry types deduplicated |
open |
||
Emission target is proc_macro2 TokenStream |
open |
||
Backend crate is the sole ethercrab dependency |
open |
||
One device struct per ESI device entry |
open |
||
SubDeviceIdentity const emitted per device |
open |
||
PDO assignment alternatives emitted as sum type |
open |
||
One PDO struct per assignment alternative |
open |
||
Generated module root exposes a registry |
open |
||
Generated code compiles under no_std + alloc |
open |
||
EsiDevice trait shape |
open |
||
EsiConfigurable trait shape for preop bring-up |
open |
||
Traits live in ethercat-esi-rt, not taktora-connector |
open |
||
Object dictionary emission is a default-off cargo feature |
open |
||
Process image access via bitvec BitSlice |
open |
||
Builder API shape |
open |
||
Output written to OUT_DIR |
open |
||
Cargo rerun-if directives emitted per ESI input |
open |
||
Generated output passes through prettyplease |
open |
||
cargo esi expand emits one device's generated code |
open |
||
cargo esi list enumerates devices in a glob |
open |
||
CLI shares the parser and codegen crates |
open |
||
Verifier ingests ESI XML plus SII binary |
open |
||
Diagnostic output names the differing field |
open |
||
Verifier reuses the parser |
open |
||
Verifier exits non-zero on mismatch |
open |
||
NO CAN / CANopen / EDS support in this round |
rejected |
||
NO proc-macro front-end |
rejected |
||
NO unification of EtherCAT and CANopen runtime traits |
rejected |
||
NO runtime XML parsing |
rejected |
||
NO modification of taktora-connector-ethercat runtime |
rejected |
||
NO automatic vendor library scraping |
rejected |