Architecture¶
Detailed-design specifications. Pages under this section follow the
arc42 template (12 sections) encoded with sphinx-needs using the
useblocks “x-as-code” arc42 directive types — arch-decision,
building-block, architecture, constraint, quality-goal,
risk, glossary. Legacy spec directives may also appear for
detailed-design notes that predate the arc42 adoption.
- Connector framework — architecture (arc42)
- PLC runtime — architecture
- Bounded global allocator — architecture
- Device-driver codegen — architecture (arc42)
- CANopen device-driver codegen — architecture (arc42)
- Logging — architecture (arc42)
- EtherCAT network-config codegen — architecture (arc42)
- Motion — trajectory core architecture
- Runtime diagnostics (medkit)
- Message-plane interface-description codegen — architecture (arc42)
- Workspace tooling — architecture
- Safety architecture decisions
Building blocks¶
ID |
Title |
Status |
Implements |
|---|---|---|---|
taktora-connector-core |
open |
||
taktora-connector-transport-iox |
open |
||
taktora-connector-codec |
open |
||
taktora-connector-mqtt |
open |
||
taktora-connector-host |
open |
||
ConnectorEnvelope (sub-block of BB_0002) |
open |
||
ServiceFactory (sub-block of BB_0002) |
open |
||
MqttConnector (sub-block of BB_0004, plugin side) |
open |
||
MqttGateway (sub-block of BB_0004, gateway side) |
open |
||
Tokio bridge (sub-block of BB_0021) |
open |
||
Dispatch scratch (pre-allocated) |
open |
||
taktora-bounded-alloc crate |
open |
||
Cyclic scan trigger and dispatch |
implemented |
||
Iceoryx2 channel surface (Channel / Publisher / Subscriber) |
implemented |
||
Chain and DAG sequencing primitives |
implemented |
||
Deadline trigger and timing monitor |
implemented |
||
ThreadAttributes (worker affinity and priority) |
implemented |
||
taktora-connector-ethercat |
open |
||
EthercatConnector (sub-block of BB_0030, plugin side) |
open |
||
EthercatGateway (sub-block of BB_0030, gateway side) |
open |
||
PDO mapping (sub-block of BB_0030) |
open |
||
Tokio bridge for ethercrab (sub-block of BB_0030) |
open |
||
Cooperative shutdown (Stoppable + WaitSet stop wakeup) |
implemented |
||
taktora-connector-zenoh |
open |
||
ZenohConnector (sub-block of BB_0040, plugin side) |
open |
||
ZenohGateway (sub-block of BB_0040, gateway side) |
open |
||
Zenoh query handles (sub-block of BB_0041) |
open |
||
Tokio bridge for zenoh (sub-block of BB_0042) |
open |
||
taktora-connector-ui-contract crate |
open |
||
taktora-connector-ui crate (server) |
open |
REQ_0855; REQ_0856; REQ_0857; REQ_0860; REQ_0861; REQ_0862; REQ_0863; REQ_0865; REQ_0866; REQ_0867; REQ_0870; REQ_0871; REQ_0872; REQ_0879; REQ_0883; REQ_0884 |
|
taktora-connector-ui-derive crate |
open |
||
taktora-connector-ui-client crate |
open |
||
Per-task cycle statistics |
open |
||
Statistics snapshot view |
open |
||
xtask-preempt-rt harness |
open |
||
taktora-stats crate |
open |
||
Connector cycle telemetry |
open |
||
ethercat-esi (parser crate) |
open |
||
ethercat-esi-codegen (IR + backend trait) |
open |
||
ethercat-esi-codegen-ethercrab (concrete backend) |
open |
||
ethercat-esi-rt (runtime trait crate) |
open |
||
ethercat-esi-build (build.rs glue) |
open |
||
ethercat-esi-cli (cargo subcommand) |
open |
||
ethercat-esi-verify (EEPROM diff tool) |
open |
||
taktora-connector-ethercat EsiDevice adapter |
open |
||
taktora-connector-can crate |
open |
||
CanConnector (sub-block of BB_0070, plugin side) |
open |
||
CanGateway (sub-block of BB_0070, gateway side) |
open |
REQ_0613; REQ_0614; REQ_0620; REQ_0624; REQ_0625; REQ_0630; REQ_0631 |
|
Tokio bridge for CAN (sub-block of BB_0072) |
open |
||
Per-iface filter compiler (sub-block of BB_0072) |
open |
||
MockCanInterface (sub-block of BB_0070) |
open |
||
fieldbus-od-core |
open |
||
canopen-eds parser crate |
open |
||
canopen-eds-codegen |
open |
||
canopen-eds-codegen-taktora |
open |
||
canopen-eds-rt |
open |
||
canopen-eds-build |
open |
||
canopen-eds-cli |
open |
||
canopen-eds-verify |
open |
||
taktora-connector-can adapter (follow-on) |
open |
||
taktora-log facade crate |
open |
||
taktora-log-dlt DLT-backend crate |
open |
||
DLT daemon client (within taktora-log-dlt) |
open |
||
Cycle-overrun fault primitive surface |
implemented |
||
Framework fail-fast boundary |
open |
||
Absolute-grid timer and cyclic scheduling clock |
implemented |
||
ethercat-netcfg SM-watchdog resolution and validation |
open |
||
Large-payload slice channel (transport-iox) |
implemented |
||
taktora-connector-j1939 crate |
implemented |
||
J1939Connector (sub-block of BB_0098, plugin side) |
implemented |
||
J1939Gateway (sub-block of BB_0098, gateway side) |
implemented |
||
J1939 transport-protocol state machine (sub-block of BB_0100) |
implemented |
||
J1939 address-claim state machine (sub-block of BB_0100) |
implemented |
||
MockJ1939Interface (sub-block of BB_0098) |
implemented |
||
taktora-medkit-model |
open |
||
taktora-medkit-provider |
open |
||
taktora-medkit-gateway |
open |
||
taktora-medkit-gateway-axum |
open |
||
taktora-medkit-binding-executor |
implemented |
||
taktora-medkit-binding-connector |
implemented |
||
taktora-medkit-manifest |
implemented |
||
triggers + SSE event stream |
implemented |
||
Authenticator seam (auth-light) |
implemented |
||
diagnostic lock registry |
implemented |
||
taktora-idl-codegen |
implemented |
||
taktora-idl-codegen-can |
implemented |
||
taktora-idl-codegen-can-tests |
implemented |
||
taktora-idl-core |
implemented |
||
taktora-idl-wire |
implemented |
||
taktora-idl-dbc |
implemented |
||
SSE replay ring + keep-alive |
open |
||
ActionSink write seam + operations surface |
open |
REQ_0969; REQ_0970; REQ_0971; REQ_0972; REQ_0973; REQ_0974; REQ_0975 |
|
Read-family completion |
open |
||
Build identity — capture crate + injection seam |
open |
Architecture views (context, runtime, deployment, crosscutting)¶
ID |
Title |
Status |
Refines |
|---|---|---|---|
System context |
open |
||
Level-1 building block decomposition |
open |
BB_0001; BB_0002; BB_0003; BB_0004; BB_0005; BB_0030; BB_0040 |
|
Send path (app → broker) |
open |
||
Receive path (broker → app) |
open |
||
Health and reconnect lifecycle |
open |
||
Shutdown coordination |
open |
||
In-process gateway deployment |
open |
||
Separate-process gateway deployment |
open |
||
Codec — compile-time generic |
open |
||
Error handling — single error type, explicit origins |
open |
||
Observability — Observer + ExecutionMonitor adapter |
open |
||
Back-pressure — explicit at every bounded buffer |
open |
||
EtherCAT bus bring-up sequence |
open |
||
Cyclic process-data exchange and working-counter health |
open |
||
Optional Distributed Clocks bring-up |
open |
||
Zenoh query request/response flow |
open |
||
Toolchain layering (crate dependency graph) |
open |
||
Build-time vs runtime separation |
open |
||
Build-time generation flow |
open |
||
Preop bring-up flow (per device) |
open |
||
Toolchain crate placement in workspace |
open |
||
CAN frame send path (app → bus) |
open |
||
CAN receive path with multi-iface demux |
open |
||
CAN bus health and bus-off recovery |
open |
||
Toolchain layering (crate dependency graph) |
open |
||
Build-time vs runtime separation |
open |
||
Logging runtime data flow |
open |
||
Logging control-plane (runtime level changes) |
open |
||
medkit crate decomposition |
open |
BB_0104; BB_0105; BB_0106; BB_0107; BB_0108; BB_0109; BB_0110 |
|
Toolchain layering (crate dependency graph) |
implemented |
||
Build-time vs runtime separation |
implemented |
Architecture decisions¶
ID |
Title |
Status |
Refines |
|---|---|---|---|
Spec scope — framework core + MQTT reference |
open |
||
Umbrella feature is a peer of FEAT_0010 |
open |
||
Both deployment shapes supported |
open |
||
Per-channel envelope size, declared in descriptor |
open |
||
Codec is a generic parameter on the connector |
open |
||
Explicit-builder plugin discovery |
open |
||
Plugin and gateway are both taktora-executor consumers |
open |
||
Routing carried as a typed struct |
open |
||
Lifecycle = ReconnectPolicy + ConnectorHealth |
open |
||
MQTT scope — realistic but bounded |
open |
||
Pre-allocate dispatch scratch at Executor::build time |
open |
||
Compile-time caps + hand-rolled fixed-block bitmap |
open |
||
ethercrab as the EtherCAT MainDevice library |
open |
||
Single MainDevice per gateway |
open |
||
Static PDO mapping declared at build time |
open |
||
Distributed Clocks bring-up is opt-in |
open |
||
Linux raw socket only in first cut |
open |
||
``taktora-connector-ethercat`` module decomposition |
open |
||
Tokio runtime owned by ``EthercatGateway``, joined on Drop |
open |
||
``EthercatConnectorOptions`` is a typed builder; PDO map declared as ``&'static [SubDeviceMap]`` |
open |
||
Verification harness — pure-logic unit tests + env-gated bus tests |
open |
||
Zenoh queries live on a concrete handle type, not the Connector trait |
open |
||
Stack-internal reconnect for Zenoh — no ReconnectPolicy |
open |
||
One ZenohRouting struct carries pub/sub QoS; query knobs on options |
open |
||
Reply framing uses a Zenoh-private 1-byte payload prefix |
open |
||
Process boundary as spatial isolation context |
open |
||
Bounded allocator as spatial-determinism anchor |
open |
||
Fixed-bucket histogram for percentile estimation |
open |
||
Harness as xtask, not CI gate |
open |
||
Shared no_std taktora-stats crate |
open |
||
Hybrid two-layer timing measurement |
open |
||
Motion-flavored adapted reference workload |
open |
||
Abort on framework-invariant violation; watchdog drives outputs safe |
open |
||
Parser separated from codegen (strict layering) |
open |
||
Two-trait runtime split (EsiDevice + EsiConfigurable) |
open |
||
PDO assignment alternatives as sum types |
open |
||
Future CANopen support via shared OD IR |
accepted |
||
Vendor extensions captured as opaque blobs |
open |
||
Object dictionary as static table, feature-gated |
open |
||
Use prettyplease, not rustfmt, for emit formatting |
open |
||
cargo subcommand for inspection, not proc-macro |
open |
||
Lift OD IR to fieldbus-od-core now |
open |
||
fieldbus-od-core stays data-only |
open |
||
Re-export from ethercat-esi, do not break it |
open |
||
INI backend choice — serde-derive façade |
open |
||
PDO entry dedup is structural, name-blind |
open |
||
Dummy entries skip into bit offsets, not padding fields |
open |
||
heapless::Vec<u8, 8> for PdoOut payload |
open |
||
Async only on configure, sync on frame path |
open |
||
JSON SDO-dump format with versioned schema |
open |
||
Adopt the log crate as workspace logging facade |
accepted |
||
Pure-Rust DLT via dlt-core; no libdlt FFI |
accepted |
||
Two-crate split (facade vs DLT backend) |
accepted |
||
Bridge existing tracing emitters via tracing-log |
accepted |
||
Console dev fallback when no daemon configured |
accepted |
||
Build-time codegen over runtime parsing |
open |
||
Positional addressing; alias and identity as bring-up assertions |
open |
||
Local-only ESI resolution; URLs are a vendor-and-pin step |
open |
||
Working-counter expectation derived only, never overridden |
open |
||
One file, one bus; multi-bus distribution deferred |
open |
||
std/POSIX baseline for the parser and OD-core crates |
accepted |
||
Object-safe EsiDevice, identity reuse, ethercrab behind SdoWrite |
accepted |
||
f64 + libm in the trajectory core; integer increments at the drive |
accepted |
||
Absolute-grid cyclic dispatch via Linux timerfd; self-computed epoll timeout fails on ms-rounding |
accepted |
||
Lateness grid anchored on scan count plus dispatcher skip signal |
accepted |
||
The ESI parser emits a faithful IR and never resolves configuration |
accepted |
||
Startup SDOs as a typed SubDeviceMap field |
accepted |
||
Joint per-device OpMode enum supersedes per-direction PDO-assignment alternatives |
accepted |
||
Per-phase dispatch dedup via the existing pending_cycle token |
accepted |
||
AttachmentMap — sorted-Vec O(log n) attachment-to-task resolution with lazy-learn dual identity |
accepted |
||
UI connector is a passive, MVVM-shaped, language-neutral transport |
accepted |
||
Reuse the CAN driver layer; own a userspace J1939 dispatcher |
draft |
||
Two-tier delivery; ETP over a bounded growable slice channel |
draft |
||
Full J1939-81 address claiming in the first cut |
draft |
||
Off-path diagnostics boundary + extractable-core layout |
open |
||
Snapshot/merge read seam + shape-diff contract verification |
accepted |
||
Mandatory grouping manifest, applied in the merge pipeline |
accepted |
||
Per-task atomic sink for the executor hook write path |
accepted |
||
Connector health → DTC mapping and last-sample freeze-frame |
accepted |
||
Additive freeze-frame seam through the snapshot (fault_environments) |
accepted |
||
Diff-derived event vocabulary over the golden frame shape |
accepted |
||
Auth-light seam before real JWT/RBAC enforcement |
accepted |
||
Diagnostic write surface gated by Freedom-From-Interference; only QM-scoped families are v1 |
accepted |
||
Locks are diagnostic-coordination-only QM metadata |
accepted |
||
Two planes: a message-plane IR mirroring the device plane |
accepted |
||
Split the serde-free wire runtime from host-side codegen |
accepted |
||
DBC as the first frontend (bounded by construction) |
accepted |
||
Plane-generic codegen with a backend trait; CAN is one backend |
accepted |
||
Tier-A wire-compatibility parity pass |
accepted |
||
Write plane as a port/adapter seam with a deferred safety gate |
accepted |
||
Read-family completion — seam choices |
accepted |
||
rumqttc EventLoop owns MQTT reconnection |
draft |
||
Wildcard inbound demux via a gateway-local matcher |
draft |
||
Clean session with SUBSCRIBE replay on reconnect |
draft |
||
JSON default codec; MsgPackCodec built as a prerequisite |
draft |
||
Compile-time build identity, captured in a leaf crate and injected as data |
accepted |
||
Zero-alloc test enforcement scoped to executor + connector pre-1.0 |
accepted |
||
Coverage measured with cargo-llvm-cov |
accepted |
Quality goals and constraints¶
ID |
Title |
Status |
Refines |
|---|---|---|---|
Fault isolation between protocol stack and app |
open |
||
Compile-time type safety end-to-end |
open |
||
Zero-copy data flow on the publish path |
open |
||
Uniform observable health across connectors |
open |
||
Build-time determinism (same ESI in → same code out) |
open |
||
Layering integrity (strict left-to-right deps) |
open |
||
Zero runtime cost of codegen presence |
open |
||
Trait stability for ecosystem adoption |
open |
||
Build-time determinism (same EDS in → same code out) |
open |
||
Layering integrity (strict left-to-right deps) |
open |
||
Zero runtime cost of codegen presence |
open |
||
Trait stability for ecosystem adoption |
open |
||
Backend decoupling (single facade, replaceable backend) |
open |
||
DLT-ecosystem observability |
open |
||
Low-overhead, non-blocking hot path |
open |
||
Dev-friendly fallback (no daemon required) |
open |
||
Boundedness by construction |
accepted |
||
Auditable runtime (serde-free, no_std, no-heap) |
accepted |
||
Layering integrity (strict left-to-right deps) |
accepted |
ID |
Title |
Status |
Refines |
|---|---|---|---|
Built on taktora-executor's WaitSet |
open |
||
iceoryx2 0.8.x as the IPC layer |
open |
||
Rust 2024 edition / MSRV 1.85 |
open |
||
Single-threaded test discipline |
open |
||
Tokio sidecar contained per connector crate |
open |
||
cargo build-script semantics |
open |
||
ethercrab API surface as upstream |
open |
||
bitvec for process-image access |
open |
||
no_std + alloc baseline for parser and runtime trait |
open |
||
ETG owns the ESI XML schema |
open |
||
cargo build-script semantics |
open |
||
CiA 301 / 306 own the EDS schema |
open |
||
no_std + alloc baseline for OD core, parser, runtime |
open |
||
heapless 0.8 surface for fixed-capacity buffers |
open |
||
log crate as workspace logging facade |
open |
||
No build-time dependency on libdlt |
open |
||
std required, no_std out of scope |
open |
||
Logging is QM |
open |
||
no_std + no-deps baseline for the wire runtime |
accepted |
Risks¶
ID |
Title |
Status |
Links |
|---|---|---|---|
rumqttc API stability before 1.0 |
open |
||
iceoryx2 0.8 pre-1.0 churn |
open |
||
Const-generic monomorphisation cost |
open |
||
Tokio bridge latency |
open |
||
Wildcard demux pathological topic patterns |
open |
||
OD table size blow-up on coupling modules |
open |
||
Beckhoff vendor extensions churn the IR |
open |
||
ethercrab API churn breaking the backend |
open |
||
ESI XML schema drift across vendors |
open |
||
Generated code becomes load-bearing without migration path |
open |
||
EDS files in the wild are inconsistent |
open |
||
serde-ini ecosystem thinness |
open |
||
CiA 301 OD blow-up on profile-rich devices |
open |
||
COB-ID base assumptions in generated code |
open |
||
Unbounded-rejection path unexercised until a second frontend |
open |
||
bool/float CAN fields are rejected, not yet supported |
open |
Glossary¶
ID |
Title |
Status |
|---|---|---|
Connector |
open |
|
Plugin |
open |
|
Gateway |
open |
|
ConnectorEnvelope |
open |
|
Codec |
open |
|
Routing |
open |
|
Bridge |
open |
|
Health |
open |
|
Reconnect policy |
open |
|
Channel |
open |
|
ASIL |
open |
|
ESI |
open |
|
SII |
open |
|
PDO |
open |
|
CoE |
open |
|
OD (Object Dictionary) |
open |
|
InitCmd |
open |
Legacy detailed-design specifications¶
No needs passed the filters