All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.5.0] - 2026-10-05
Breaking changes
- Host applications must now supervise
EtherCAT.Runtime; the package no longer starts the runtime automatically.EtherCAT.start/1returns{:ok, session}, and runtime, provisioning, diagnostics, signal, and capture operations require that%EtherCAT.Session{}. Stopped or replaced sessions return{:error, :stale_session}rather than addressing a newer runtime (6bb51d3,b5ae7bd). - Master and simulator transport configuration now uses explicit
backend:values normalized byEtherCAT.Backend. For raw Ethernet, replaceinterface: "eth0"withbackend: {:raw, %{interface: "eth0"}}(2d77d36). - Replace
await_runningwithEtherCAT.await_ready/2,read_inputwithEtherCAT.read/3, andwrite_outputwithEtherCAT.write/4. Provisioning, SDO transfers, and DC lock waits move toEtherCAT.Provisioning; diagnostic queries move toEtherCAT.Diagnostics; individual signal/latch subscriptions move toEtherCAT.Signals. All take the session first (f15d37b,3798e47). EtherCAT.slaves/1returns configured names. UseEtherCAT.Diagnostics.slaves/1for detailed slave summaries (f15d37b,b5ae7bd).- Custom drivers must implement
EtherCAT.Driverinstead ofEtherCAT.Slave.Driver.signal_model/2receives publicEtherCAT.Driver.PDOvalues and returns namedEtherCAT.Driver.Signalstructs, not integer PDO shortcuts. Codecs return{:ok, value}or{:error, reason}and are required only for registered input/output directions (f15d37b,1360779). - Driver mailbox and sync setup now use
EtherCAT.Driver.Provisioning.mailbox_steps/2. Inline lifecycle and latch callbacks are removed; consume protocol notifications andEtherCAT.Signalssubscriptions instead. Machine commands, state projection, and semantic events belong in the consuming application (f15d37b,da97385,1360779). - Simulator companions now implement
EtherCAT.Simulator.Adapterinstead ofEtherCAT.Simulator.DriverAdapterand supply an explicit profile throughdefinition_options/1; simulator process-data definitions are no longer inferred from driver mappings (7830f13,1360779). - Slave configuration rejects unknown options. Signal references and endpoint
metadata use canonical driver signal names without slave-local aliases
(
a79e14c).
Added
- Coherent per-domain
%EtherCAT.Sample{}observations throughsample/3andsamples/2, with per-signal decoding errors rather than substitute values (da97385,1360779). - Protocol subscriptions atomically return
{:ok, ref, status, samples}, then deliver{:ethercat, ref, payload}messages carrying%EtherCAT.Sample{}or%EtherCAT.Notification{}values for slave/domain changes. Cancel a registration withEtherCAT.unsubscribe/3(eda0e72,3798e47). - Static slave descriptions through
EtherCAT.describe/2andEtherCAT.inventory/1. Optional driver metadata is independent of discovery and live values; device drivers remain application-owned (ec6336a,d5497a7,3798e47,1360779). - Structured master, simulator, and scan observations through
%EtherCAT.Master.Status{},%EtherCAT.Simulator.Status{}, and%EtherCAT.Scan.Result{}(2d77d36).
Fixed
- Invalid codec results, output widths, and nonzero padding fail before staging
writes; input decoding failures remain visible in reads, samples, and signal
subscriptions (
1360779). - Stale worker lifecycle notifications cannot mutate the active session.
Diagnostic collection uses a bounded timeout, explicit query failures, and a
final session check without blocking the master on worker queries. DC waits
remain bound to their original process/session, and activation lock timeouts
return
:dc_lock_timeoutwithout an additional query (8653d87,3798e47). - Standalone scans refuse backends owned by the local master, preventing station
reassignment on a live session. Simulator status identifies transport-only
starts and reports detached runs as
backend: nil(3ebdedc). - Initial PREOP-only provisioning suppresses background health polling, including
after configuration updates that keep slaves in PREOP (
473e224,1e10075). - PREOP-first activation restores health polling and converges to
:operational. Slaves intentionally held in PREOP remain monitored during operational sessions and recover to their configured target; live polling changes apply immediately (8521af7,d126047,c2a27ea). - Explicit subscriber pids are honored, malformed SII EEPROM categories return
structured errors, and capture/simulator name generation is bounded before atom
interning. Generated-source formatting failures return explicit errors
(
263204d).
[0.4.2] - 2026-03-19
Fixed
- The release workflow now runs on OTP
28.1somix hex.publish --dry-runand release publishing no longer crash inside Hex's regex import path on GitHub runners (e6fde6f).
[0.4.1] - 2026-03-19
Fixed
- The release workflow now reads the package version without triggering a fresh
compile during the tag check, so clean GitHub runners no longer fail
v*.*.*releases with a false version mismatch (b2de6f5).
[0.4.0] - 2026-03-19
Added
EtherCAT.Simulatornow supports raw-socket transport, redundant dual-ingress raw topologies, and shared UDP/raw fixtures for integration and hardware bring-up (36ed6b8,eee9d1e,a4b947b).- Integration coverage now includes event-triggered reconnect/disconnect mixes,
clustered recovery chains, and split-domain EL3202 reconnect scenarios
(
c4a6621,1f2b526,b12eec5). - Bus and hardware tooling now expose richer diagnostics plus loopback and
hardening knobs for real-hardware bring-up (
80dc840,c42b0c9). - GitHub Actions now cover CI and release automation, including raw-capable
runners, raw simulator setup, and tag-build verification (
93c864d,6516c23,4a3321b,8eff41c).
Changed
- Public master/domain/slave queries are more consistent, and synchronous calls
now return
{:error, {:server_exit, reason}}instead of exiting the caller when a local runtime dies mid-call (4ae4392,0248012,8eff41c). - Simulator and helper guidance was consolidated into maintained source-adjacent
docs, and generated capture snapshots now use portable data-only
.capturefiles instead of executable Elixir (04b2c5f,072119d,9b3b4ba,dad947e,8eff41c). - Version tags now publish the Hex package and HexDocs directly from CI instead
of only creating a draft GitHub release (
29dcbd2). - Telemetry and structured logging are stricter and less noisy: invalid domain
cycles are separated from transport misses, lifecycle decisions emit bounded
machine-readable events, and long-lived processes stamp consistent metadata on
high-signal logs (
b57763a,af5192e). EtherCAT.Master,EtherCAT.Slave,EtherCAT.Domain, andEtherCAT.DCnow own the public API directly, with internal*.FSMmodules handling state transitions behind that boundary (9f1342a).- Redundant-link timeout detail now emits bounded telemetry and recovery logs
instead of warning on every repeated timeout pattern (
2d97faf). - Redundant-link
no_arrivalstimeout detail now stays in telemetry and generic frame-timeout warnings instead of emitting one-shot warning/cleared log pairs for transient blips (cf4a90c). - Input reads now fail closed on stale cached PDO data, and simulator transport
ownership is split cleanly under
EtherCAT.Simulator.Transport.*(11d1af2). - Raw AF_PACKET transport now suppresses local TX delivery with
PACKET_IGNORE_OUTGOING; redundant links are raw-only in production, and degraded-port health no longer suppresses later send attempts on either leg. Reverse-path cross copies no longer complete exchanges ahead of the authoritative forward-path data, and completed exchanges now drain both legs before dispatching the next request to cut late-frameidx_mismatchdrops (cf4a90c). - Slave reconnect ownership is now simpler:
:downslaves probe their stored scan position, reclaim an anonymous fixed station locally, and rebuild to PREOP themselves instead of waiting for master reconnect authorization or rediscovery fallback (efbc8da).
Fixed
- DC recovery and configuration validation are stricter, catching bad setup
earlier and reducing invalid recovery paths (
95f343d). - Raw simulator EEPROM reads now zero-pad out-of-range windows instead of
crashing startup, which restores the healthy raw transport matrix path
(
35ebde7). - Redundant transport now merges split logical replies correctly and reports
degraded send failures as visible topology and link-health state
(
c937d53,4b1ac0f). - Bus transaction aging, built-in circuit execution, and topology assessment are
more explicit; the legacy
Bus.Linkexecution path is gone and carrier state no longer drives bus correctness (d852fd4,68f6c20). - Raw socket transport no longer drops legitimate replies on idx-mismatch rearm,
and redundant rejoin now drains and reproves a restored leg before promoting
it back into cyclic traffic (
7055878,1b2211f). - Failed activation now rolls back partially started DC/domain runtime,
Slave.subscribe/3rejects unknown signal/latch names, andDomain.write/read/sampleuse explicit ETS lookup instead of exception-driven control flow (4a9a4ad). - Default simulator/master runs no longer flap the whole session on isolated
single-cycle misses: domains now escalate to master recovery only after a
short unhealthy streak, while timeout tuning keeps a wider
5msfloor on both the UDP simulator path and raw startup/activation traffic (cf4a90c). - Redundant links now keep degraded one-sided bounce exchanges within the
original frame-time budget instead of resetting them to a fresh fixed
25msmerge timeout, so a10mscyclic ring can keep running after secondary-port disconnect (fea9d52). - Raw receive errors now surface through the bus transport boundary instead of
being silently ignored, so a broken leg cannot leave single or redundant
links stuck in
:awaitingbehind repeated socket-error chatter (fea9d52). - Redundant realtime exchanges now complete immediately on a single processed
bounce instead of waiting for merge-time timeout fallback, so
1mscyclic domains can stay healthy after backup-port disconnect (52c4ae8). - Redundant realtime logical exchanges now keep a bounded merge window for
complementary bounce replies before accepting a single processed bounce, so
split-ring raw topology breaks merge back to full WKC instead of triggering
false domain recovery (
1a80d39). - Redundant links now complete late degraded reliable one-sided bounces within
the original frame budget, domain timeout-class misses stay stable even when
queued realtime work expires, and the maintained redundant replug watcher now
matches the current
Bus.info/1link/topology surface (7bfdb68). - Slaves held in
:preopor:safeopnow keep health polling active and still transition into recovery on disconnect or lower-state regressions instead of staying stranded in stale held states (efbc8da).
Docs
ARCHITECTURE.md,README.md,RELEASE.md, and simulator guidance were aligned to the current public/runtime boundaries, Hex publish workflow, and raw test interface ownership expectations (b014f5d).- README, hardware playbooks, simulator docs, and API guidance were rewritten
to better explain transport boundaries, bring-up workflow, release metadata,
and fault/recovery scenarios (
8f773d6,c42b0c9,0248012,04b2c5f,072119d,9b3b4ba,ee210fa,8eff41c). - Public master, slave, domain, and DC moduledocs now live inline with their
runtime modules, and the simulator integration README now reflects the
current scenario set and fault-builder surface (
4a9a4ad,11d1af2).
[0.3.1] - 2026-03-12
Added
mix docs.freshnow forces recompilation before docs generation so external moduledoc source files are picked up reliablyEtherCAT.Capturenow supports an interactive slave capture workflow and can generate richer integration support drivers from captured SDO and PDO data- Real-hardware scripts and helpers now live under
test/integration/hardware/, alongside shared hardware support and a captured EL3202 support driver
Changed
- Generated capture drivers now include mailbox startup configuration and device-specific templates such as the EL3202 typed decode path when captured data is available
- Simulator scenario helpers now support deterministic event-triggered follow-up faults, and simulator docs now explain fixture tiers, real-vs-virtual hardware use, and the UDP transport boundary more directly
- Hardware examples were folded into the maintained integration suite so the old
examples/tree could be removed
Fixed
- Master recovery now replaces stale critical disconnect faults with reconnect-time PREOP configuration failures for PDO-participating slaves, allowing later recovery retries to return the master to
:operational - Telemetry-triggered scenario faults now inject synchronously, which makes event-driven simulator scenarios deterministic instead of eventually consistent
- Generated docs no longer warn about public moduledocs referencing hidden internal helper modules
Docs
- Simulator moduledocs and README now explain that the UDP simulator is a virtual slave segment for testing, not a raw-wire EtherCAT NIC replacement
- Root project guidance now points hardware-script users at
MIX_ENV=test, and markdown guidance drift around release/dev docs was cleaned up
[0.3.0] - 2026-03-12
Changed
- Bus link monitoring now uses the internal netlink/sysfs implementation instead of an external interface-management dependency
- Master recovery now gates stopped-domain restart on live carrier state and logs explicit carrier loss/restore events
- Runtime state-machine modules (
Master,Slave,Domain,DC) were further reduced to state-machine boundaries with helper facades EtherCAT.Slave.Drivernow usessignal_model/1,2, and simulator-specific authoring moved out of the real driver behaviour into optionalMyDriver.Simulatorcompanions viaEtherCAT.Simulator.DriverAdapterEtherCAT.Simulatornow exposes builder-style runtime fault injection with queued, delayed, and milestone-triggered scripts plus richer signal/snapshot surfaces for tooling
Fixed
- Public
MasterAPI calls now return{:error, :timeout}when the local master call itself times out instead of exiting the caller - Real carrier loss now stops domains immediately on confirmed
:down, without domain restart churn while the cable is still unplugged - Maintained hardware scripts were refreshed for the current runtime and bus/link-monitor implementation
await_running/1andawait_operational/1now tolerate a small local reply grace window so terminal startup results do not get masked by near-boundary call timeouts- Activation now blocks immediately on PREOP configuration failures instead of starting OP activation work for unrelated slaves
Docs
- The README driver example now matches the current
signal_model/1callback, and the project landing page uses the Kino smart-cell setup screenshot - Simulator docs and integration scenario notes now cover the current fault builder API, mailbox protocol fault coverage, and delayed/milestone scheduling
[0.2.0] - 2026-03-09
Added
- Dynamic PREOP-first startup and configuration flow for discovered slaves
- Master-owned logical window allocation for high-level domain configs
- Split
{domain, SyncManager}attachment support, including split-SM diagnostics - Explicit runtime fault recovery with
:recoveringstate and targeted slave fault tracking - Input freshness timestamps via
read_input/2 -> {:ok, {value, updated_at_us}} - Public telemetry event enumeration via
EtherCAT.Telemetry.events/0 - Richer runtime diagnostics for slaves, domains, and DC status
Changed
- Public lifecycle was exposed through EtherCAT.state/0
EtherCAT.Domain.Configno longer acceptslogical_base; the master allocates it- Master, Slave, Domain, and DC runtime boundaries were decomposed into smaller internal modules
- Slave internals are grouped under clearer runtime, process-data, mailbox, and ESC namespaces
- Automatic bus frame-timeout tuning now uses a safer host-jitter floor on slower cycles
Fixed
- Reconnect and recovery paths now preserve split attachment semantics and restart stopped domains
test/integration/hardware/scripts/el3202.exsandtest/integration/hardware/scripts/sdo_debug.exsnow work against the current driver/runtime contract- Hardware fault-tolerance examples now match the current recovery model
- Polling callers regain access to cached PDO freshness metadata
Docs
- README and moduledocs now reflect the actual runtime state machines and current API
- Completed refactor and spec-alignment plans were closed and moved out of active execution
[0.1.0] - 2026-03-07
Added
- Pure-Elixir EtherCAT master runtime over standard Ethernet (raw socket + UDP transport)
- Declarative bus configuration via
EtherCAT.start/1withSlave.ConfigandDomain.Config - Cyclic process data exchange — self-timed LRW domain cycling with drift-compensated scheduling
- CoE SDO transfers (expedited and segmented) for mailbox-based slave configuration
- Distributed clocks support (
EtherCAT.DC.Config) with automatic reference clock selection - Subscribe-on-change signal API:
subscribe/2,read_input/2,write_output/3 EtherCAT.Slave.Driverbehaviour for custom PDO encode/decode per device type- Default auto-discovery driver for unknown slaves via SII EEPROM PDO scan
slave_info/1,domain_info/1,slaves/0,domains/0introspection API- Telemetry events for domain cycle done/missed
- Bus redundancy link support