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)):

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

Feature: CANopen device-driver codegen toolchain FEAT_0060

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:

  1. Shared OD corefieldbus-od-core: OD IR lifted from ethercat-esi. no_std + alloc. Knows no XML, no INI, no transport.

  2. Parse layercanopen-eds: CiA 306 INI → typed IR. Depends on fieldbus-od-core. No codegen, no transport dep.

  3. Codegen layercanopen-eds-codegen (IR → TokenStream via CodegenBackend trait) plus canopen-eds-codegen-taktora (the one concrete backend this round, targeting the CanOpenDevice trait surface).

  4. Runtime trait cratecanopen-eds-rt: the CanOpenDevice / CanOpenConfigurable traits the generated drivers implement. Frame-per-PDO dispatch — no cyclic process-image model (per NO unification of EtherCAT ... (REQ_0592)).

  5. Tooling layercanopen-eds-build (build.rs glue), canopen-eds-cli (cargo eds expand / cargo eds list one-shot tools), and canopen-eds-verify (offline diff of EDS XML against a captured SDO-upload JSON dump).

The taktora-connector-can crate (see CAN (SocketCAN) reference c... (FEAT_0046)) is not part of this toolchain. A thin adapter that maps any CanOpenDevice into the connector’s frame plumbing is a follow-on spec; this umbrella does not require changes to CAN (SocketCAN) reference c... (FEAT_0046)’s runtime contracts (see NO modification of taktora-... (REQ_0795)).


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.

Shared OD core

Feature: Shared OD core FEAT_0061
status: open
satisfies: FEAT_0060
is implemented by: BB_0080

A new crate fieldbus-od-core carrying the OD types both ESI and EDS parsers need (CiA 301 semantics). Lifted out of ethercat-esi so both fieldbuses parse against the same IR. Executes the lift foreseen by Future CANopen support via ... (ADR_0073).

Requirement: No transport-specific types in fieldbus-od-core REQ_0700
status: open
satisfies: FEAT_0061
is verified by: TEST_0601

fieldbus-od-core shall declare no transport-specific types. The crate shall not name ethercrab, socketcan, taktora_connector_*, or any I/O-bearing crate as a dependency.

Requirement: no_std + alloc, no mandatory serde REQ_0701
status: open
satisfies: FEAT_0061
is verified by: TEST_0602

The crate shall be #![no_std] with an alloc dependency. No serde, no quick-xml, no serde-ini in the default feature set. Type derives (Serialize, Deserialize, Hash) shall sit behind opt-in cargo features so embedded consumers do not pay for them.

Requirement: OD type surface REQ_0702
status: open
satisfies: FEAT_0061
is verified by: TEST_0600

The crate shall carry Identity (vendor_id, product_code, revision — all u32), DataType (enumerating the CiA 301 data-type table), AccessRights (Const / ReadOnly / WriteOnly / ReadWrite), DictEntry (index, sub_index, name, data_type, access, default/min/max bytes), PdoEntry (index, sub_index, bit_len, optional name), and PdoMap (assigned-to OD index plus entry list).

Requirement: ethercat-esi re-exports lifted types REQ_0703
status: open
satisfies: FEAT_0061
is verified by: TEST_0603

ethercat-esi shall re-export Identity, DataType, AccessRights, DictEntry, PdoEntry, and PdoMap from fieldbus-od-core so existing Device-driver codegen toolc... (FEAT_0050)-era consumers compile source-unchanged. The re-export façade shall stay in place permanently — it is not deprecated.

Requirement: canopen-eds uses fieldbus-od-core types REQ_0704
status: open
satisfies: FEAT_0061
is verified by: TEST_0603

canopen-eds shall use fieldbus-od-core types for every OD-shaped field in its IR. The crate shall not redefine Identity, DictEntry, PdoEntry, or PdoMap locally.

EDS parser

Feature: EDS parser FEAT_0062
status: open
satisfies: FEAT_0060
is refined by: CON_0021, ADR_0081
is implemented by: BB_0081

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.

Requirement: Pure parse function with no I/O REQ_0720
status: open
satisfies: FEAT_0062
is verified by: TEST_0610

The crate shall expose parse(text: &str) -> Result<EdsFile, EdsError>. The function shall perform no filesystem or network I/O; the caller is responsible for reading the EDS bytes.

Requirement: no_std + alloc, no upstream coupling REQ_0721
status: open
satisfies: FEAT_0062
is verified by: TEST_0611, TEST_0612, TEST_0682

The crate shall be #![no_std] with alloc, and shall not depend on ethercrab, canopen-eds-codegen, taktora-connector-can, or any transport crate. A downstream tool that only needs the IR shall not be forced to compile the codegen layer.

Requirement: serde-derive INI backend REQ_0722
status: open
satisfies: FEAT_0062
is verified by: TEST_0610
links incoming: RISK_0021

The crate shall implement parsing on top of a serde INI deserialiser (serde_ini is the primary candidate; the alternative rust-ini is acceptable behind the same façade). Hand-written line parsing is rejected — schema maintenance lives in the serde derives.

Requirement: Parse errors carry line and column REQ_0723
status: open
satisfies: FEAT_0062
is verified by: TEST_0614

EdsError variants raised during parsing shall carry the source line and byte column of the offending construct so build-time diagnostics point at the failing EDS file location.

Requirement: Unknown sections captured as RawSection REQ_0724
status: open
satisfies: FEAT_0062
is verified by: TEST_0613

Unknown EDS sections shall be retained in the IR as RawSection { name, keys: Vec<(String, String)> }. The parser shall not hard-fail on unknown sections — direct CANopen analogue of the EtherCAT RawXml policy (Vendor extensions captured ... (ADR_0074)).

Requirement: Liberal parsing — warn and continue on quirks REQ_0725
status: open
satisfies: FEAT_0062
is verified by: TEST_0615
links incoming: RISK_0020

The parser shall be liberal on common EDS formatting quirks: BOM, CRLF/LF mix, trailing whitespace on values, comments after values (; ...), redundant whitespace around =, and EDS exporter-quirk keys (e.g. LineFeed). Quirks shall surface as EdsFile::warnings: Vec<EdsWarning> carrying { line, kind } so build-time logs can print them without failing the parse. A strict mode is not provided in this round.

Requirement: IR carries identity, OD, PDO comm + maps REQ_0726
status: open
satisfies: FEAT_0062
is verified by: TEST_0610

The IR shall represent, per device: Identity (lifted from the [Identity] block / OD index 0x1018), DeviceInfo (vendor / product names, baud-rate flags, NMT-boot-slave flag), the OD as Vec<DictEntry>, Vec<PdoMap> for declared RPDOs / TPDOs, and parallel Vec<RPdoComm> / Vec<TPdoComm> for PDO communication parameters (transmission type, cob-id, inhibit time, event timer).

Codegen IR and backend trait

Feature: Codegen IR and backend trait FEAT_0063
status: open
satisfies: FEAT_0060
is refined by: ADR_0082
is implemented by: BB_0082

The codegen-side IR (an extension of the parser IR with naming / collision policy applied) and the CodegenBackend trait that lets multiple emitters share that IR. This crate (canopen-eds-codegen) knows nothing about INI and nothing about taktora-connector-can.

Requirement: CodegenBackend trait shape REQ_0730
status: open
satisfies: FEAT_0063
is verified by: TEST_0623

The crate shall define a CodegenBackend trait with fn emit_device(&self, device: &eds::Device) -> Result<TokenStream, CodegenError> and fn emit_module_root(&self, devices: &[eds::Device]) -> Result<TokenStream, CodegenError>. The top-level entry point shall be fn generate<B: CodegenBackend>(eds: &EdsFile, backend: &B) -> Result<TokenStream, CodegenError>.

Requirement: Naming policy is owned by codegen, not the backend REQ_0731
status: open
satisfies: FEAT_0063
is verified by: TEST_0620

The canopen-eds-codegen crate shall sanitise EDS ProductName strings into valid Rust identifiers (whitespace, hyphens, slashes, dots → _; leading digit prefixed with _) before invoking the backend. Backends shall receive idents pre-validated; they shall not re-implement sanitisation.

Requirement: Revision collision handled deterministically REQ_0732
status: open
satisfies: FEAT_0063
is verified by: TEST_0621, TEST_0681

When two EDS files share ProductName but differ in RevisionNumber (OD index 0x1018:03), the codegen layer shall disambiguate using a deterministic _REV<hex> suffix derived from the raw RevisionNumber. Input file order shall not affect the generated idents.

Requirement: Common PDO entry types deduplicated REQ_0733
status: open
satisfies: FEAT_0063
is verified by: TEST_0622, TEST_0681

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.

Requirement: Emission target is proc_macro2 TokenStream REQ_0734
status: open
satisfies: FEAT_0063
is verified by: TEST_0623

The codegen layer shall produce proc_macro2::TokenStream values and assemble them with quote!. String-templated emission (format! + write) is rejected — token-level construction preserves span / hygiene and yields rustfmt-able output via prettyplease (per Use prettyplease, not rustf... (ADR_0076)).

Requirement: One EDS file equals one device REQ_0735
status: open
satisfies: FEAT_0063
is verified by: TEST_0624

The codegen layer shall treat one EDS file as one device. emit_module_root shall accept &[EdsFile] and emit one device per file plus the shared registry table per Generated module root expos... (REQ_0745).

taktora-connector-can backend

Feature: taktora-connector-can codegen backend FEAT_0064
status: open
satisfies: FEAT_0060
is refined by: ADR_0083
is implemented by: BB_0083

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 canopen-eds-rt.

Requirement: Backend crate is the sole canopen-eds-rt dependency REQ_0740
status: open
satisfies: FEAT_0064
is verified by: TEST_0633, TEST_0682

canopen-eds-codegen-taktora shall be the only crate in the toolchain that declares canopen-eds-rt as a dependency. Neither canopen-eds, canopen-eds-codegen, canopen-eds-build, canopen-eds-cli, nor canopen-eds-verify shall depend on canopen-eds-rt.

Requirement: One device struct per EDS file REQ_0741
status: open
satisfies: FEAT_0064
is verified by: TEST_0630

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 Debug + Default + Clone.

Requirement: Identity const emitted per device REQ_0742
status: open
satisfies: FEAT_0064
is verified by: TEST_0630

For each generated device struct, the backend shall emit an accompanying pub const <IDENT>_IDENTITY: Identity = Identity { vendor_id, product_code, revision }; so identity-driven dispatch (per Generated module root expos... (REQ_0745)) can use a static table.

Requirement: PDO declarations emitted as sum types REQ_0743
status: open
satisfies: FEAT_0064
is verified by: TEST_0630

For each declared PDO mapping in the EDS, the backend shall emit one variant of <IDENT>Rpdo / <IDENT>Tpdo enum plus one payload struct per variant. Modelling PDOs as nullable fields on the device struct is rejected — every declared PDO is a closed, named choice.

Requirement: Dummy entries skipped in PDO payload structs REQ_0744
status: open
satisfies: FEAT_0064
is verified by: TEST_0630, TEST_0635

For each PDO mapping, the backend shall skip CANopen Dummy* data-type entries when emitting payload struct fields — only real mapped objects appear as fields. Bit offsets of real fields shall be threaded through generated decode / encode bodies (not carried as named padding fields). See Dummy entries skip into bit... (ADR_0083).

Requirement: Generated module root exposes a registry REQ_0745
status: open
satisfies: FEAT_0064
is verified by: TEST_0631

The module root emitted by emit_module_root shall expose a registry!() declarative macro (or equivalent generated static table) mapping each emitted device’s Identity to a factory closure returning Box<dyn CanOpenDevice>. Identity-based dispatch in a downstream adapter shall be reducible to a HashMap lookup against this table.

Requirement: Bring-up SDO writes emitted from EDS REQ_0746
status: open
satisfies: FEAT_0064
is verified by: TEST_0636

impl CanOpenConfigurable for <IDENT> shall emit SDO writes for: PDO communication parameters (OD ranges 0x1400..0x14FF and 0x1800..0x18FF), PDO mapping parameters (0x1600..0x17FF and 0x1A00..0x1BFF), and the [DeviceInfo].NMT_BootSlave-driven NMT start request when declared. Values shall come from the EDS — per-bus customisation is DCF territory, out of scope per NO DCF support this round (REQ_0790).

Requirement: Object dictionary emission is a default-off cargo feature REQ_0747
status: open
satisfies: FEAT_0064
is verified by: TEST_0634
links incoming: RISK_0022

Emission of the full OD table per device (as a sorted static OD: &[(u16, u8, DataType, &str)] lookup, per Object dictionary as static... (ADR_0075)) shall be gated behind a default-off object-dictionary cargo feature on the generated module’s parent crate. PDOs and bring-up SDO writes shall remain unconditional; only the OD table is gated.

Requirement: Generated code compiles under no_std + alloc REQ_0748
status: open
satisfies: FEAT_0064
is verified by: TEST_0632

The emitted device modules shall compile under #![no_std] + alloc. The backend shall not emit std::-qualified paths in generated code.

Runtime trait surface

Feature: Runtime trait surface FEAT_0065
status: open
satisfies: FEAT_0060
is refined by: QG_0017, CON_0023, ADR_0084, ADR_0085
is implemented by: BB_0084

The minimal trait pair the generated devices implement and any downstream CAN adapter consumes. Lives in a tiny canopen-eds-rt crate so the runtime contract is not coupled to either the codegen or the connector.

Requirement: CanOpenDevice trait shape REQ_0750
status: open
satisfies: FEAT_0065
is verified by: TEST_0640

The crate shall define a CanOpenDevice trait with const IDENTITY: Identity, fn node_id(&self) -> u8, fn set_node_id(&mut self, id: u8), fn nmt_state(&self) -> NmtState, fn set_nmt_state(&mut self, s: NmtState), fn on_rpdo(&mut self, idx: u8, frame: PdoFrame<'_>) -> Result<(), CanOpenError>, and fn drain_tpdos(&mut self, out: &mut dyn TpdoSink) -> Result<(), CanOpenError>. The trait shall add no async methods on the RPDO/TPDO path — the frame-handling hot path stays synchronous.

Requirement: CanOpenConfigurable trait shape for bring-up REQ_0751
status: open
satisfies: FEAT_0065
is verified by: TEST_0641

The crate shall define CanOpenConfigurable: CanOpenDevice carrying async fn configure<S: SdoClient>(&mut self, sdo: &mut S) -> Result<(), CanOpenError>. Bring-up SDO writes (PDO comm, PDO mapping, optional NMT start) live inside the generated body of this method.

Requirement: Traits live in canopen-eds-rt, not taktora-connector-can REQ_0752
status: open
satisfies: FEAT_0065
is verified by: TEST_0642

CanOpenDevice and CanOpenConfigurable shall live in a dedicated canopen-eds-rt crate. They shall not live in taktora-connector-can, fieldbus-od-core, or any other taktora-internal crate. Any CAN consumer shall be able to adopt the generated drivers without depending on taktora.

Requirement: Frame payloads use heapless::Vec<u8, 8> REQ_0753
status: open
satisfies: FEAT_0065
is verified by: TEST_0643
links incoming: RISK_0023

PdoFrame shall borrow an inbound payload as &[u8]; PdoOut shall carry the outbound payload as heapless::Vec<u8, 8> (classical CAN cap). PdoOut::can_id: u32 shall carry the resolved COB-ID computed by generated code from the current node_id() and the EDS-declared base COB-ID; the consumer forwards it as the CAN frame ID without further resolution. CAN-FD payloads are out of scope this round (see NO CAN-FD payload support i... (REQ_0791)).

Requirement: Frame-per-PDO dispatch shape REQ_0754
status: open
satisfies: FEAT_0065
is verified by: TEST_0640

on_rpdo(idx, frame) shall accept an RPDO enumeration index in 0..=3 (CANopen’s 4-RPDO cap from CiA 301) and route to the right typed decoder in generated code. Caller-side resolution from CAN ID to RPDO enumeration uses the configured 0x1400..0x14FF communication parameters and is the consumer’s responsibility. drain_tpdos(out) shall produce zero or more frames per call into a caller-provided TpdoSink.

Requirement: CanOpenError variant surface REQ_0755
status: open
satisfies: FEAT_0065
is verified by: TEST_0640

CanOpenError shall enumerate CiA 301 SDO abort codes (AbortCode(u32)), payload-length mismatch (PdoLenMismatch { expected: u8, got: u8 }), unknown-index, NmtStateViolation, and a TransportFailed(&'static str) variant for caller-supplied I/O failures.

Requirement: RPDO rejected outside Operational state REQ_0756
status: open
satisfies: FEAT_0065
is verified by: TEST_0644

Generated code shall reject on_rpdo calls when nmt_state() != NmtState::Operational, returning CanOpenError::NmtStateViolation. NMT state is caller-managed; the trait carries getter / setter but no transition methods.

Build helper

Feature: Build helper (build.rs glue) FEAT_0066
status: open
satisfies: FEAT_0060
is refined by: CON_0020
is implemented by: BB_0085

A trivial helper crate so downstream consumers run codegen with one build.rs invocation and one include! line.

Requirement: Builder API shape REQ_0760
status: open
satisfies: FEAT_0066
is verified by: TEST_0650

canopen-eds-build shall expose Builder::new().glob(<pattern>).backend(<backend>).out_file(<name>).build() returning Result<(), BuildError>. The backend parameter shall be generic over CodegenBackend per CodegenBackend trait shape (REQ_0730).

Requirement: Output written to OUT_DIR REQ_0761
status: open
satisfies: FEAT_0066
is verified by: TEST_0650

The helper shall write the generated module to $OUT_DIR/<out_file> so consumers wire it in with include!(concat!(env!("OUT_DIR"), "/<out_file>"));.

Requirement: Cargo rerun-if directives emitted per EDS input REQ_0762
status: open
satisfies: FEAT_0066
is verified by: TEST_0651

The helper shall print cargo:rerun-if-changed=<path> for each EDS file matched by the glob and for the build script itself, so cargo re-runs codegen exactly when an input changes — not on every build.

Requirement: Generated output passes through prettyplease REQ_0763
status: open
satisfies: FEAT_0066
is verified by: TEST_0652, TEST_0680

Before writing the output, the helper shall format the TokenStream via prettyplease::unparse so the file is human-readable when diffed or inspected (per Use prettyplease, not rustf... (ADR_0076)).

Requirement: Parser warnings surface as cargo warnings REQ_0764
status: open
satisfies: FEAT_0066
is verified by: TEST_0653

Parser warnings raised under Liberal parsing — warn and ... (REQ_0725) shall surface as cargo:warning=<line>: <kind> lines so they appear in cargo build output. A strict mode that promotes warnings to errors is not provided in this round.

CLI inspection

Feature: CLI inspection (cargo subcommand) FEAT_0067
status: open
satisfies: FEAT_0060
is satisfied by: REQ_0770, REQ_0771, REQ_0772
is implemented by: BB_0086

A cargo subcommand so users can inspect what was generated for a given EDS file without going through $OUT_DIR / cargo expand. Adds discoverability with one extra crate, no change to the codegen path (per cargo subcommand for inspec... (ADR_0077)).

Requirement: cargo eds expand emits one device's generated code REQ_0770
status: open
satisfies: FEAT_0067
is verified by: TEST_0660

canopen-eds-cli shall expose a cargo eds expand --device <ident> subcommand that parses the matching EDS file(s) and prints the generated module for that device to stdout, formatted per Generated output passes thr... (REQ_0763).

Requirement: cargo eds list enumerates devices in a glob REQ_0771
status: open
satisfies: FEAT_0067
is verified by: TEST_0661

cargo eds list shall accept a glob pattern (defaulting to eds/*.eds when invoked from a crate root) and print the (ident, vendor_id, product_code, revision) tuple for every device found.

Requirement: CLI shares the parser and codegen crates REQ_0772
status: open
satisfies: FEAT_0067
is verified by: TEST_0662

The CLI shall depend on canopen-eds and canopen-eds-codegen-taktora as library dependencies. It shall not duplicate parse or emit logic. Output produced by the CLI for a given input shall be byte-identical to the output produced by canopen-eds-build for the same input and formatter settings (Generated output passes thr... (REQ_0763)).

EDS ↔ SDO-dump verification

Feature: EDS ↔ SDO-dump verification FEAT_0068
status: open
satisfies: FEAT_0060
is refined by: ADR_0086
is implemented by: BB_0087

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).

Requirement: Verifier ingests EDS plus JSON SDO-dump REQ_0780
status: open
satisfies: FEAT_0068
is verified by: TEST_0670

canopen-eds-verify shall expose fn verify(eds: &str, dump: &SdoDump) -> Result<VerifyReport, VerifyError> that parses both inputs and compares them on: Identity (vendor / product / revision from OD index 0x1018:01..03), the declared PDO map index list per direction and the entries within each declared mapping, PDO communication parameters (transmission type, cob-id, event timer), and device-type at OD index 0x1000.

Requirement: Diagnostic output names the differing field REQ_0781
status: open
satisfies: FEAT_0068
is verified by: TEST_0671

When a verification fails, the VerifyReport shall name each differing field with both the EDS-side and dump-side values (e.g. Identity.product_code: eds=0x60900000 dump=0x60910000) rather than reporting only “mismatch”.

Requirement: Verifier reuses the parser REQ_0782
status: open
satisfies: FEAT_0068
is verified by: TEST_0672

The verifier shall consume the same EdsFile IR produced by EDS parser (FEAT_0062) and shall not maintain a second parse path. JSON SDO-dump decoding lives inside the verifier crate. The verifier shall not depend on canopen-eds-codegen, canopen-eds-rt, or taktora-connector-can.

Requirement: Verifier exits non-zero on mismatch REQ_0783
status: open
satisfies: FEAT_0068
is verified by: TEST_0673

When invoked as a binary (canopen-eds-verify <eds> <dump.json>), the verifier shall exit 0 on match, 1 on any field mismatch, and 2 on parse or I/O errors. CI gates may then cargo run -p canopen-eds-verify -- ... as a pre-merge check.

Requirement: SDO-dump JSON schema versioned REQ_0784
status: open
satisfies: FEAT_0068
is verified by: TEST_0674

The SDO-dump file format shall be versioned via a top-level schema field carrying the string taktora.canopen.sdo-dump.v1. Unknown schema strings shall be rejected with a parse error before any field comparison runs (per JSON SDO-dump format with v... (ADR_0086)).


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.

Requirement: NO DCF support this round REQ_0790
status: rejected
satisfies: FEAT_0060

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.

Requirement: NO CAN-FD payload support in PdoOut REQ_0791
status: rejected
satisfies: FEAT_0060

PdoOut::payload shall not support CAN-FD’s 64-byte payload this round. Lifting heapless::Vec<u8, 8> to a const-generic capacity (heapless::Vec<u8, N>) is a follow-on. See heapless::Vec<u8, 8> for Pd... (ADR_0084).

Requirement: NO proc-macro front-end REQ_0792
status: rejected
satisfies: FEAT_0060

The toolchain shall not offer a canopen_device!("foo.eds") proc-macro form. The IDE-discoverability gain does not justify the doubled codegen surface or the worse compile-time profile. cargo eds expand (cargo eds expand emits one ... (REQ_0770)) covers the inspection use case. Mirrors NO proc-macro front-end (REQ_0591).

Requirement: NO unification of EtherCAT and CANopen runtime traits REQ_0793
status: rejected
satisfies: FEAT_0060

CanOpenDevice shall not be merged with EsiDevice / EsiConfigurable. EtherCAT’s cyclic-bit-buffer model and CANopen’s event-driven-frame model are different transport semantics; forcing them into one trait would leak a fake “process image” into CANopen and mis-model event-triggered TPDOs. This requirement closes the loop on NO unification of EtherCAT ... (REQ_0592) by delivering the separate trait family the rejection reserved.

Requirement: NO runtime EDS parsing REQ_0794
status: rejected
satisfies: FEAT_0060

The toolchain shall not parse EDS files at application runtime. All EDS parsing happens at build time in canopen-eds-build or in the CLI tools. Consumers of the generated modules shall not need to ship EDS files alongside their binary. Mirrors NO runtime XML parsing (REQ_0593).

Requirement: NO modification of taktora-connector-can runtime REQ_0795
status: rejected
satisfies: FEAT_0060

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 CanOpenDevice into the connector’s frame plumbing is a follow-on spec; this umbrella stops at producing typed devices that implement canopen-eds-rt traits. Mirrors NO modification of taktora-... (REQ_0594).

Requirement: NO automatic vendor library scraping REQ_0796
status: rejected
satisfies: FEAT_0060

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 eds/ directory; provenance is the user’s responsibility. Mirrors NO automatic vendor library... (REQ_0595).

Requirement: NO live-bus verifier this round REQ_0797
status: rejected
satisfies: FEAT_0060

canopen-eds-verify shall not open a SocketCAN interface, send live SDO upload requests, or otherwise touch a real bus. Verification is strictly offline — EDS file vs. captured JSON dump (Verifier ingests EDS plus J... (REQ_0780)). Live verification belongs in the follow-on taktora-connector-can adapter spec where the bus is already at hand.


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.

Used filter: types(feat)

ID

Title

Status

Satisfies

FEAT_0060

CANopen device-driver codegen toolchain

open

FEAT_0061

Shared OD core

open

FEAT_0060

FEAT_0062

EDS parser

open

FEAT_0060

FEAT_0063

Codegen IR and backend trait

open

FEAT_0060

FEAT_0064

taktora-connector-can codegen backend

open

FEAT_0060

FEAT_0065

Runtime trait surface

open

FEAT_0060

FEAT_0066

Build helper (build.rs glue)

open

FEAT_0060

FEAT_0067

CLI inspection (cargo subcommand)

open

FEAT_0060

FEAT_0068

EDS ↔ SDO-dump verification

open

FEAT_0060

Used filter: types(req)

ID

Title

Status

Satisfies

REQ_0700

No transport-specific types in fieldbus-od-core

open

FEAT_0061

REQ_0701

no_std + alloc, no mandatory serde

open

FEAT_0061

REQ_0702

OD type surface

open

FEAT_0061

REQ_0703

ethercat-esi re-exports lifted types

open

FEAT_0061

REQ_0704

canopen-eds uses fieldbus-od-core types

open

FEAT_0061

REQ_0720

Pure parse function with no I/O

open

FEAT_0062

REQ_0721

no_std + alloc, no upstream coupling

open

FEAT_0062

REQ_0722

serde-derive INI backend

open

FEAT_0062

REQ_0723

Parse errors carry line and column

open

FEAT_0062

REQ_0724

Unknown sections captured as RawSection

open

FEAT_0062

REQ_0725

Liberal parsing — warn and continue on quirks

open

FEAT_0062

REQ_0726

IR carries identity, OD, PDO comm + maps

open

FEAT_0062

REQ_0730

CodegenBackend trait shape

open

FEAT_0063

REQ_0731

Naming policy is owned by codegen, not the backend

open

FEAT_0063

REQ_0732

Revision collision handled deterministically

open

FEAT_0063

REQ_0733

Common PDO entry types deduplicated

open

FEAT_0063

REQ_0734

Emission target is proc_macro2 TokenStream

open

FEAT_0063

REQ_0735

One EDS file equals one device

open

FEAT_0063

REQ_0740

Backend crate is the sole canopen-eds-rt dependency

open

FEAT_0064

REQ_0741

One device struct per EDS file

open

FEAT_0064

REQ_0742

Identity const emitted per device

open

FEAT_0064

REQ_0743

PDO declarations emitted as sum types

open

FEAT_0064

REQ_0744

Dummy entries skipped in PDO payload structs

open

FEAT_0064

REQ_0745

Generated module root exposes a registry

open

FEAT_0064

REQ_0746

Bring-up SDO writes emitted from EDS

open

FEAT_0064

REQ_0747

Object dictionary emission is a default-off cargo feature

open

FEAT_0064

REQ_0748

Generated code compiles under no_std + alloc

open

FEAT_0064

REQ_0750

CanOpenDevice trait shape

open

FEAT_0065

REQ_0751

CanOpenConfigurable trait shape for bring-up

open

FEAT_0065

REQ_0752

Traits live in canopen-eds-rt, not taktora-connector-can

open

FEAT_0065

REQ_0753

Frame payloads use heapless::Vec<u8, 8>

open

FEAT_0065

REQ_0754

Frame-per-PDO dispatch shape

open

FEAT_0065

REQ_0755

CanOpenError variant surface

open

FEAT_0065

REQ_0756

RPDO rejected outside Operational state

open

FEAT_0065

REQ_0760

Builder API shape

open

FEAT_0066

REQ_0761

Output written to OUT_DIR

open

FEAT_0066

REQ_0762

Cargo rerun-if directives emitted per EDS input

open

FEAT_0066

REQ_0763

Generated output passes through prettyplease

open

FEAT_0066

REQ_0764

Parser warnings surface as cargo warnings

open

FEAT_0066

REQ_0770

cargo eds expand emits one device's generated code

open

FEAT_0067

REQ_0771

cargo eds list enumerates devices in a glob

open

FEAT_0067

REQ_0772

CLI shares the parser and codegen crates

open

FEAT_0067

REQ_0780

Verifier ingests EDS plus JSON SDO-dump

open

FEAT_0068

REQ_0781

Diagnostic output names the differing field

open

FEAT_0068

REQ_0782

Verifier reuses the parser

open

FEAT_0068

REQ_0783

Verifier exits non-zero on mismatch

open

FEAT_0068

REQ_0784

SDO-dump JSON schema versioned

open

FEAT_0068

REQ_0790

NO DCF support this round

rejected

FEAT_0060

REQ_0791

NO CAN-FD payload support in PdoOut

rejected

FEAT_0060

REQ_0792

NO proc-macro front-end

rejected

FEAT_0060

REQ_0793

NO unification of EtherCAT and CANopen runtime traits

rejected

FEAT_0060

REQ_0794

NO runtime EDS parsing

rejected

FEAT_0060

REQ_0795

NO modification of taktora-connector-can runtime

rejected

FEAT_0060

REQ_0796

NO automatic vendor library scraping

rejected

FEAT_0060

REQ_0797

NO live-bus verifier this round

rejected

FEAT_0060