CANopen device-driver codegen¶
This page captures the requirements for the CANopen device-driver
codegen toolchain: a layered set of crates that translates CANopen
Electronic Data Sheet (EDS, CiA 306) files into strongly-typed Rust
driver modules at build time, with zero runtime INI parsing and no
dependency on the taktora-connector-can runtime.
The decomposition is the peer of Device-driver codegen for CANopen, executing the lift foreseen by Future CANopen support via ... (ADR_0073) (now closed by Lift OD IR to fieldbus-od-c... (ADR_0078)):
Top-level umbrella feature — CANopen device-driver codeg... (FEAT_0060) — peer to Device-driver codegen toolc... (FEAT_0050) (EtherCAT codegen). The umbrella is build-time only and orthogonal to CAN (SocketCAN) reference c... (FEAT_0046) “CAN reference connector”; the runtime adapter that wires generated devices into the connector is a follow-on spec.
Shared OD core — Shared OD core (FEAT_0061) lifts the OD IR (Identity, DictEntry, DataType, PdoEntry, PdoMap, AccessRights) out of
ethercat-esiinto a newfieldbus-od-corecrate so both parsers share it.Capability-cluster sub-features — one per crate-layer concern, each
:satisfies:CANopen device-driver codeg... (FEAT_0060).Requirements — concrete shall-clauses that
:satisfies:a capability-cluster feature.
This round covers EDS only. DCF (Device Configuration File) support and a live-bus verifier are explicitly out of scope; the architecture preserves the option to add either later (see anti-goals).
Top-level umbrella¶
A layered set of Rust crates that consumes CANopen EDS files (CiA 306) and emits strongly-typed driver modules at build time. The toolchain is organised as five layers that depend only leftwards:
The |
Capability clusters¶
The umbrella decomposes into eight capability clusters. Each cluster
is a sub-feature :satisfies: CANopen device-driver codeg... (FEAT_0060), with concrete
shall-clauses underneath.
EDS parser¶
A pure parser crate. Reads CiA 306 INI, emits a typed IR rooted in Shared OD core (FEAT_0061) types. Knows nothing about codegen, transports, or taktora-internal crates. 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 a serde INI
deserialiser ( |
|
Unknown EDS sections shall be retained in the IR as
|
The parser shall be liberal on common EDS formatting quirks:
BOM, CRLF/LF mix, trailing whitespace on values, comments after
values ( |
The IR shall represent, per device: |
Codegen IR and 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 EDS files share |
When two or more devices’ PDOs include structurally identical entry layouts (same bit-len + data-type tuple list), the codegen layer shall emit one shared PDO entry struct referenced by both devices rather than two duplicated structs. Structural equality is the dedup key; field names do not need to match. |
The codegen layer shall produce |
The codegen layer shall treat one EDS file as one device.
|
taktora-connector-can backend¶
The opinionated, concrete backend that emits per-device structs
implementing the runtime traits in Runtime trait surface (FEAT_0065). The only
crate in the toolchain that depends on |
|
For each parsed EDS file (per One EDS file equals one device (REQ_0735)), the backend
shall emit exactly one Rust struct named per the sanitised
product ident (per Naming policy is owned by c... (REQ_0731) and Revision collision handled ... (REQ_0732)),
deriving |
For each generated device struct, the backend shall emit an
accompanying |
For each declared PDO mapping in the EDS, the backend shall
emit one variant of |
For each PDO mapping, the backend shall skip CANopen |
The module root emitted by |
|
Emission of the full OD table per device (as a sorted
|
The emitted device modules shall compile under |
Runtime trait surface¶
The minimal trait pair the generated devices implement and any
downstream CAN adapter consumes. Lives in a tiny
|
The crate shall define a |
The crate shall define
|
|
|
|
|
Generated code shall reject |
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
|
Parser warnings raised under Liberal parsing — warn and ... (REQ_0725) shall surface as
|
CLI inspection¶
A |
|
|
The CLI shall depend on |
EDS ↔ SDO-dump verification¶
A CI-friendly cross-check: parse an EDS file and a captured SDO-upload JSON dump from a real node, then diff the two on identity, declared PDO maps, and PDO communication parameters. Catches the “vendor shipped a buggy EDS” failure class at build time rather than during cyclic operation. Offline-only this round — live-bus verification is out of scope per NO live-bus verifier this r... (REQ_0797). |
|
When a verification fails, the |
The verifier shall consume the same |
When invoked as a binary
( |
The SDO-dump file format shall be versioned via a top-level
|
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:
CANopen device-driver codeg... (FEAT_0060) to keep the umbrella’s traceability complete.
The toolchain shall not parse DCF (Device Configuration File) inputs this round. EDS describes a device’s shape; DCF describes per-node configuration (chosen RPDO/TPDO mapping, node-id, SDO-write-at-bringup values). DCF support is a follow-on spec; adding it later does not require an IR break because the EDS IR already carries the shape DCF references. |
|
The toolchain shall not offer a
|
|
The toolchain shall not parse EDS files at application
runtime. All EDS parsing happens at build time in
|
This spec shall not require any change to the runtime
contracts of CAN (SocketCAN) reference c... (FEAT_0046) “CAN reference connector”. A
thin adapter that maps any |
The toolchain shall not download, scrape, or otherwise
fetch EDS files from vendor websites or update servers. EDS
files are inputs the user drops into an |
|
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: CANopen device-driver codeg... (FEAT_0060). Architectural
specifications refining these requirements are emitted in
CANopen device-driver codegen — architecture (arc42). Verification artefacts are
emitted in CANopen device-driver codegen — verification.
ID |
Title |
Status |
Satisfies |
|---|---|---|---|
CANopen device-driver codegen toolchain |
open |
||
Shared OD core |
open |
||
EDS parser |
open |
||
Codegen IR and backend trait |
open |
||
taktora-connector-can codegen backend |
open |
||
Runtime trait surface |
open |
||
Build helper (build.rs glue) |
open |
||
CLI inspection (cargo subcommand) |
open |
||
EDS ↔ SDO-dump verification |
open |
ID |
Title |
Status |
Satisfies |
|---|---|---|---|
No transport-specific types in fieldbus-od-core |
open |
||
no_std + alloc, no mandatory serde |
open |
||
OD type surface |
open |
||
ethercat-esi re-exports lifted types |
open |
||
canopen-eds uses fieldbus-od-core types |
open |
||
Pure parse function with no I/O |
open |
||
no_std + alloc, no upstream coupling |
open |
||
serde-derive INI backend |
open |
||
Parse errors carry line and column |
open |
||
Unknown sections captured as RawSection |
open |
||
Liberal parsing — warn and continue on quirks |
open |
||
IR carries identity, OD, PDO comm + maps |
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 |
||
One EDS file equals one device |
open |
||
Backend crate is the sole canopen-eds-rt dependency |
open |
||
One device struct per EDS file |
open |
||
Identity const emitted per device |
open |
||
PDO declarations emitted as sum types |
open |
||
Dummy entries skipped in PDO payload structs |
open |
||
Generated module root exposes a registry |
open |
||
Bring-up SDO writes emitted from EDS |
open |
||
Object dictionary emission is a default-off cargo feature |
open |
||
Generated code compiles under no_std + alloc |
open |
||
CanOpenDevice trait shape |
open |
||
CanOpenConfigurable trait shape for bring-up |
open |
||
Traits live in canopen-eds-rt, not taktora-connector-can |
open |
||
Frame payloads use heapless::Vec<u8, 8> |
open |
||
Frame-per-PDO dispatch shape |
open |
||
CanOpenError variant surface |
open |
||
RPDO rejected outside Operational state |
open |
||
Builder API shape |
open |
||
Output written to OUT_DIR |
open |
||
Cargo rerun-if directives emitted per EDS input |
open |
||
Generated output passes through prettyplease |
open |
||
Parser warnings surface as cargo warnings |
open |
||
cargo eds expand emits one device's generated code |
open |
||
cargo eds list enumerates devices in a glob |
open |
||
CLI shares the parser and codegen crates |
open |
||
Verifier ingests EDS plus JSON SDO-dump |
open |
||
Diagnostic output names the differing field |
open |
||
Verifier reuses the parser |
open |
||
Verifier exits non-zero on mismatch |
open |
||
SDO-dump JSON schema versioned |
open |
||
NO DCF support this round |
rejected |
||
NO CAN-FD payload support in PdoOut |
rejected |
||
NO proc-macro front-end |
rejected |
||
NO unification of EtherCAT and CANopen runtime traits |
rejected |
||
NO runtime EDS parsing |
rejected |
||
NO modification of taktora-connector-can runtime |
rejected |
||
NO automatic vendor library scraping |
rejected |
||
NO live-bus verifier this round |
rejected |