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:

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

Feature: Device-driver codegen toolchain FEAT_0050

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:

  1. Parse layerethercat-esi: XML → typed IR, no_std + alloc. No knowledge of codegen or ethercrab.

  2. Codegen layerethercat-esi-codegen (IR → TokenStream via a CodegenBackend trait) plus ethercat-esi-codegen-ethercrab (the one concrete backend shipped in this round).

  3. Tooling layerethercat-esi-build (build.rs glue), ethercat-esi-cli (cargo esi expand / cargo esi list one-shot tools), and ethercat-esi-verify (diff ESI XML against captured SII EEPROM .bin dumps).

  4. Runtime trait crateethercat-esi-rt: the EsiDevice / EsiConfigurable traits the generated drivers implement.

The taktora-connector-ethercat crate (see EtherCAT reference connector (FEAT_0041)) is not part of this toolchain. It sits one layer above as a thin adapter that maps any EsiDevice into the ethercat_hal::EthercatDevice trait it already consumes. No change to EtherCAT reference connector (FEAT_0041)’s runtime contracts is required by this spec.


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

Feature: ESI parser FEAT_0051
status: open
satisfies: FEAT_0050
is refined by: CON_0013, CON_0014, ADR_0074
is implemented by: BB_0060

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.

Requirement: Pure parse function with no I/O REQ_0500
status: open
satisfies: FEAT_0051
is verified by: TEST_0400

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

Requirement: no_std + alloc compatible REQ_0501
status: open
satisfies: FEAT_0051
is verified by: TEST_0401

The crate shall be #![no_std] with an alloc dependency so it can run inside proc-macro, build.rs, embedded build tooling, or a hosted CLI without pulling in a default-features std surface.

Requirement: quick-xml + serde backend REQ_0502
status: open
satisfies: FEAT_0051
is verified by: TEST_0512

The crate shall implement parsing on top of quick-xml with serde deserialisation. Hand-written Read-based parsing is rejected — schema maintenance lives in the serde derives.

Requirement: Parser does not depend on ethercrab or codegen REQ_0503
status: open
satisfies: FEAT_0051
is verified by: TEST_0402, TEST_0472

The ethercat-esi crate shall not declare ethercrab or any codegen crate as a dependency. A downstream tool that only needs the IR shall not be forced to compile the codegen layer.

Requirement: IR carries identity, PDO maps, mailbox, DC, and OD REQ_0504
status: open
satisfies: FEAT_0051
is verified by: TEST_0400

The IR shall represent, per device: Identity (vendor id, product code, revision), Vec<SyncManager>, Vec<Pdo> for TxPDOs and RxPDOs, Option<Mailbox> capturing CoE/EoE/FoE support and InitCmds, Option<DistributedClock>, and a Vec<DictEntry> for the object dictionary. The OD field shall be present in the IR unconditionally so non-codegen consumers can inspect it; codegen-side emission of OD tables is feature-gated per Object dictionary emission ... (REQ_0533).

Requirement: Vendor-specific extensions captured as opaque blobs REQ_0505
status: open
satisfies: FEAT_0051
is verified by: TEST_0403
links incoming: RISK_0011, RISK_0013

Vendor-specific ESI extensions (e.g. Beckhoff <Vendor:...> elements) shall be retained in the IR as opaque RawXml blobs carrying the element name, attributes, and inner text/children. The parser shall not hard-fail on unknown vendor elements; downstream tools may inspect or ignore them.

Requirement: Parse errors carry line and column REQ_0506
status: open
satisfies: FEAT_0051
is verified by: TEST_0404

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

IR and codegen backend trait

Feature: IR and codegen backend trait FEAT_0052
status: open
satisfies: FEAT_0050
is implemented by: BB_0061

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 (ethercat-esi-codegen) knows nothing about XML and nothing about ethercrab.

Requirement: CodegenBackend trait shape REQ_0510
status: open
satisfies: FEAT_0052

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

Requirement: Naming policy is owned by codegen, not the backend REQ_0511
status: open
satisfies: FEAT_0052
is verified by: TEST_0410

The ethercat-esi-codegen crate shall sanitise ESI product names into valid Rust identifiers (e.g. EL3001-0000EL3001_0000) before invoking the backend. Backends shall receive idents pre-validated; they shall not be expected to re-implement sanitisation.

Requirement: Revision collision handled deterministically REQ_0512
status: open
satisfies: FEAT_0052
is verified by: TEST_0411, TEST_0471

When two devices in the input set share a product name but differ in revision (e.g. EL3204 rev 0x00100000 vs rev 0x00110000), the codegen layer shall disambiguate them using a deterministic suffix derived from the revision, producing distinct Rust idents (EL3204_REV0010 vs EL3204_REV0011). Ordering of input files shall not affect the generated idents.

Requirement: Common PDO entry types deduplicated REQ_0513
status: open
satisfies: FEAT_0052
is verified by: TEST_0412, TEST_0471

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.

Requirement: Emission target is proc_macro2 TokenStream REQ_0514
status: open
satisfies: FEAT_0052
is verified by: TEST_0413

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.

ethercrab backend

Feature: ethercrab codegen backend FEAT_0053
status: open
satisfies: FEAT_0050
is refined by: CON_0011, ADR_0072
is implemented by: BB_0062

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

Requirement: Backend crate is the sole ethercrab dependency REQ_0520
status: open
satisfies: FEAT_0053
is verified by: TEST_0423, TEST_0472

ethercat-esi-codegen-ethercrab shall be the only crate in the toolchain that declares ethercrab (any version) as a dependency. Neither ethercat-esi, ethercat-esi-codegen, ethercat-esi-build, nor ethercat-esi-verify shall depend on ethercrab.

Requirement: One device struct per ESI device entry REQ_0521
status: open
satisfies: FEAT_0053
is verified by: TEST_0420

For each <Device> element parsed from the input ESI files, the backend shall emit exactly one Rust struct named per the sanitised product ident (per Naming policy is owned by c... (REQ_0511) and Revision collision handled ... (REQ_0512)), deriving Debug + Default + Clone.

Requirement: SubDeviceIdentity const emitted per device REQ_0522
status: open
satisfies: FEAT_0053
is verified by: TEST_0420

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

Requirement: PDO assignment alternatives emitted as sum type REQ_0523
status: open
satisfies: FEAT_0053
is verified by: TEST_0420

When an ESI device declares multiple PDO assignment alternatives (typically “Standard” / “Compact”), the backend shall emit a <IDENT>PdoAssignment enum with one variant per alternative. Modelling alternatives with Option<…> fields on the device struct is rejected — every alternative is a closed, named choice.

Requirement: One PDO struct per assignment alternative REQ_0524
status: open
satisfies: FEAT_0053
is verified by: TEST_0420

For each variant of <IDENT>PdoAssignment, the backend shall emit a corresponding <IDENT>Pdo<Variant> struct that holds the typed PDO entries for that variant. The device struct’s pdo field shall be a sum type whose variants embed these per-alternative structs.

Requirement: Generated module root exposes a registry REQ_0525
status: open
satisfies: FEAT_0053
is verified by: TEST_0421

The module root emitted by emit_module_root shall expose a registry!() declarative macro (or equivalent generated static table) that maps each emitted device’s SubDeviceIdentity to a factory closure returning Box<dyn EsiDevice>. Identity-based dispatch in downstream code (e.g. taktora-connector-ethercat) shall be reducible to a HashMap lookup against this table.

Requirement: Generated code compiles under no_std + alloc REQ_0526
status: open
satisfies: FEAT_0053
is verified by: TEST_0422

The emitted device modules shall compile under #![no_std] + alloc so generated drivers are usable from embedded contexts. The backend shall not emit std::-qualified paths in generated code.

Runtime trait surface

Feature: Runtime trait surface FEAT_0054
status: open
satisfies: FEAT_0050
is implemented by: BB_0063

The minimal trait pair the generated devices implement and the taktora-connector-ethercat adapter consumes. Lives in a tiny ethercat-esi-rt crate so the runtime contract is not coupled to either the codegen or the connector.

Requirement: EsiDevice trait shape REQ_0530
status: open
satisfies: FEAT_0054
is verified by: TEST_0430

The crate shall define an EsiDevice trait with const IDENTITY: SubDeviceIdentity, fn input_len(&self) -> usize, fn output_len(&self) -> usize, fn decode_inputs(&mut self, bits: &BitSlice<u8, Lsb0>) -> Result<(), EsiError>, and fn encode_outputs(&self, bits: &mut BitSlice<u8, Lsb0>) -> Result<(), EsiError>. The trait shall add no async methods — the cyclic hot path stays synchronous.

Requirement: EsiConfigurable trait shape for preop bring-up REQ_0531
status: open
satisfies: FEAT_0054
is verified by: TEST_0431

The crate shall define EsiConfigurable: EsiDevice with type Assignment and async fn configure<'a>(&mut self, sub: &SubDevicePreOperational<'a>, a: Self::Assignment) -> Result<(), EsiError>. Bring-up SDO writes (InitCmds, 0x1C12 / 0x1C13 PDO assignment writes) live inside the generated body of this method.

Requirement: Traits live in ethercat-esi-rt, not taktora-connector REQ_0532
status: open
satisfies: FEAT_0054
is verified by: TEST_0432

EsiDevice and EsiConfigurable shall live in a dedicated ethercat-esi-rt crate. They shall not live in taktora-connector-ethercat, ethercat-hal, or any other taktora-internal crate, so any ethercrab user can adopt the generated drivers without depending on taktora.

Requirement: Object dictionary emission is a default-off cargo feature REQ_0533
status: open
satisfies: FEAT_0054
is verified by: TEST_0424
links incoming: RISK_0010

Emission of the full object-dictionary table per device (as a static &[(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 InitCmd writes shall remain unconditional; only the OD table is gated. With the feature off, generated code shall not pay for OD blow-up (which can reach 10–50× for OD-heavy devices per OD table size blow-up on co... (RISK_0010)).

Requirement: Process image access via bitvec BitSlice REQ_0534
status: open
satisfies: FEAT_0054

decode_inputs and encode_outputs shall operate on bitvec::slice::BitSlice<u8, Lsb0> references covering the device’s portion of the EtherCAT cycle PDI. The trait shall not embed an opinion on how the surrounding application acquires those slices.

Build helper

Feature: Build helper (build.rs glue) FEAT_0055
status: open
satisfies: FEAT_0050
is satisfied by: REQ_0540, REQ_0541, REQ_0542, REQ_0543
is refined by: CON_0010, ADR_0076, ARCH_0052
is implemented by: BB_0064

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

Requirement: Builder API shape REQ_0540
status: open
satisfies: FEAT_0055
is verified by: TEST_0440

ethercat-esi-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_0510).

Requirement: Output written to OUT_DIR REQ_0541
status: open
satisfies: FEAT_0055
is verified by: TEST_0440

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 ESI input REQ_0542
status: open
satisfies: FEAT_0055
is verified by: TEST_0441

The helper shall print cargo:rerun-if-changed=<path> for each ESI 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_0543
status: open
satisfies: FEAT_0055
is verified by: TEST_0442, TEST_0470

Before writing the output, the helper shall format the TokenStream via prettyplease::unparse so the file is human-readable when diffed or inspected through cargo expand.

CLI inspection

Feature: CLI inspection (cargo subcommand) FEAT_0056
status: open
satisfies: FEAT_0050
is satisfied by: REQ_0550, REQ_0551, REQ_0552
is refined by: ADR_0077
is implemented by: BB_0065

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

Requirement: cargo esi expand emits one device's generated code REQ_0550
status: open
satisfies: FEAT_0056
is verified by: TEST_0450

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

Requirement: cargo esi list enumerates devices in a glob REQ_0551
status: open
satisfies: FEAT_0056
is verified by: TEST_0451

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

Requirement: CLI shares the parser and codegen crates REQ_0552
status: open
satisfies: FEAT_0056
is verified by: TEST_0452

The CLI shall depend on ethercat-esi and ethercat-esi-codegen-ethercrab 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 ethercat-esi-build for the same input and formatter settings (Generated output passes thr... (REQ_0543)).

EEPROM diff verification

Feature: EEPROM diff verification FEAT_0057
status: open
satisfies: FEAT_0050
is satisfied by: REQ_0560, REQ_0561, REQ_0562, REQ_0563
is implemented by: BB_0066

A CI-friendly cross-check: parse an ESI XML file and the matching captured SII EEPROM .bin dump from a real device, then diff the two on identity, PDO map, and mailbox configuration. Catches the “vendor shipped a buggy ESI file” failure class at build time rather than during cyclic operation.

Requirement: Verifier ingests ESI XML plus SII binary REQ_0560
status: open
satisfies: FEAT_0057
is verified by: TEST_0460

ethercat-esi-verify shall expose fn verify(xml: &str, sii: &[u8]) -> Result<VerifyReport, VerifyError> that parses both inputs and compares them on: Identity (vendor / product / revision), the assigned PDO index list per direction, and the mailbox bootstrap configuration (CoE/EoE/FoE supported sets).

Requirement: Diagnostic output names the differing field REQ_0561
status: open
satisfies: FEAT_0057
is verified by: TEST_0461

When a verification fails, the VerifyReport shall name each differing field with both the ESI-side and SII-side values (e.g. Identity.revision: esi=0x00100000 sii=0x00110000) rather than reporting only “mismatch”.

Requirement: Verifier reuses the parser REQ_0562
status: open
satisfies: FEAT_0057
is verified by: TEST_0462

The verifier shall consume the same EsiFile IR produced by ESI parser (FEAT_0051) and shall not maintain a second parse path. SII binary decoding lives inside the verifier crate (no reuse from ethercrab — the verifier shall not depend on ethercrab per Backend crate is the sole e... (REQ_0520)).

Requirement: Verifier exits non-zero on mismatch REQ_0563
status: open
satisfies: FEAT_0057
is verified by: TEST_0463

When invoked as a binary (ethercat-esi-verify <xml> <sii>), 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 ethercat-esi-verify -- ... as a pre-merge check.


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.

Requirement: NO CAN / CANopen / EDS support in this round REQ_0590
status: rejected
satisfies: FEAT_0050

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 fieldbus-od-core IR once a concrete CANopen device is in scope; see Future CANopen support via ... (ADR_0073).

Requirement: NO proc-macro front-end REQ_0591
status: rejected
satisfies: FEAT_0050

The toolchain shall not offer an esi_device!("EL3001.xml") proc-macro form. The IDE-discoverability gain does not justify the doubled codegen surface or the worse compile-time profile for what is effectively a one-time generation step per device set. cargo esi expand (cargo esi expand emits one ... (REQ_0550)) covers the inspection use case.

Requirement: NO unification of EtherCAT and CANopen runtime traits REQ_0592
status: rejected
satisfies: FEAT_0050

When CANopen support is added in a follow-on spec, the runtime trait family 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.

Requirement: NO runtime XML parsing REQ_0593
status: rejected
satisfies: FEAT_0050

The toolchain shall not parse ESI XML at application runtime. All XML parsing happens at build time in ethercat-esi-build or in the CLI tools. Consumers of the generated modules shall not need to ship XML files alongside their binary.

Requirement: NO modification of taktora-connector-ethercat runtime REQ_0594
status: rejected
satisfies: FEAT_0050

This spec shall not require any change to the runtime contracts of EtherCAT reference connector (FEAT_0041) “EtherCAT reference connector”. The connector consumes EsiDevice through a thin adapter (see ethercat-esi-verify (EEPROM... (BB_0066)); it does not become aware of XML or codegen.

Requirement: NO automatic vendor library scraping REQ_0595
status: rejected
satisfies: FEAT_0050

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 esi/ directory; provenance is the user’s responsibility.


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.

Used filter: types(feat)

ID

Title

Status

Satisfies

FEAT_0050

Device-driver codegen toolchain

open

FEAT_0051

ESI parser

open

FEAT_0050

FEAT_0052

IR and codegen backend trait

open

FEAT_0050

FEAT_0053

ethercrab codegen backend

open

FEAT_0050

FEAT_0054

Runtime trait surface

open

FEAT_0050

FEAT_0055

Build helper (build.rs glue)

open

FEAT_0050

FEAT_0056

CLI inspection (cargo subcommand)

open

FEAT_0050

FEAT_0057

EEPROM diff verification

open

FEAT_0050

Used filter: types(req)

ID

Title

Status

Satisfies

REQ_0500

Pure parse function with no I/O

open

FEAT_0051

REQ_0501

no_std + alloc compatible

open

FEAT_0051

REQ_0502

quick-xml + serde backend

open

FEAT_0051

REQ_0503

Parser does not depend on ethercrab or codegen

open

FEAT_0051

REQ_0504

IR carries identity, PDO maps, mailbox, DC, and OD

open

FEAT_0051

REQ_0505

Vendor-specific extensions captured as opaque blobs

open

FEAT_0051

REQ_0506

Parse errors carry line and column

open

FEAT_0051

REQ_0510

CodegenBackend trait shape

open

FEAT_0052

REQ_0511

Naming policy is owned by codegen, not the backend

open

FEAT_0052

REQ_0512

Revision collision handled deterministically

open

FEAT_0052

REQ_0513

Common PDO entry types deduplicated

open

FEAT_0052

REQ_0514

Emission target is proc_macro2 TokenStream

open

FEAT_0052

REQ_0520

Backend crate is the sole ethercrab dependency

open

FEAT_0053

REQ_0521

One device struct per ESI device entry

open

FEAT_0053

REQ_0522

SubDeviceIdentity const emitted per device

open

FEAT_0053

REQ_0523

PDO assignment alternatives emitted as sum type

open

FEAT_0053

REQ_0524

One PDO struct per assignment alternative

open

FEAT_0053

REQ_0525

Generated module root exposes a registry

open

FEAT_0053

REQ_0526

Generated code compiles under no_std + alloc

open

FEAT_0053

REQ_0530

EsiDevice trait shape

open

FEAT_0054

REQ_0531

EsiConfigurable trait shape for preop bring-up

open

FEAT_0054

REQ_0532

Traits live in ethercat-esi-rt, not taktora-connector

open

FEAT_0054

REQ_0533

Object dictionary emission is a default-off cargo feature

open

FEAT_0054

REQ_0534

Process image access via bitvec BitSlice

open

FEAT_0054

REQ_0540

Builder API shape

open

FEAT_0055

REQ_0541

Output written to OUT_DIR

open

FEAT_0055

REQ_0542

Cargo rerun-if directives emitted per ESI input

open

FEAT_0055

REQ_0543

Generated output passes through prettyplease

open

FEAT_0055

REQ_0550

cargo esi expand emits one device's generated code

open

FEAT_0056

REQ_0551

cargo esi list enumerates devices in a glob

open

FEAT_0056

REQ_0552

CLI shares the parser and codegen crates

open

FEAT_0056

REQ_0560

Verifier ingests ESI XML plus SII binary

open

FEAT_0057

REQ_0561

Diagnostic output names the differing field

open

FEAT_0057

REQ_0562

Verifier reuses the parser

open

FEAT_0057

REQ_0563

Verifier exits non-zero on mismatch

open

FEAT_0057

REQ_0590

NO CAN / CANopen / EDS support in this round

rejected

FEAT_0050

REQ_0591

NO proc-macro front-end

rejected

FEAT_0050

REQ_0592

NO unification of EtherCAT and CANopen runtime traits

rejected

FEAT_0050

REQ_0593

NO runtime XML parsing

rejected

FEAT_0050

REQ_0594

NO modification of taktora-connector-ethercat runtime

rejected

FEAT_0050

REQ_0595

NO automatic vendor library scraping

rejected

FEAT_0050