Behaviour for EtherCAT frame transports.
Modelled after :gen_udp's {active, once} pattern:
arm once, receive one message containing the EtherCAT payload, repeat.
Implementations
EtherCAT.Bus.Transport.RawSocket— AF_PACKET raw EthernetEtherCAT.Bus.Transport.UdpSocket— UDP/IP encapsulation (spec §2.6)
Async receive flow
# After sending a frame, arm for one delivery:
transport_mod.set_active_once(transport)
# In gen_statem handle_event(:info, msg, :awaiting, data):
case transport_mod.match(transport, msg) do
{:ok, ecat_payload, rx_at, _src_mac} -> # process response
{:error, reason} -> # transport-level receive failure
:ignore -> :keep_state_and_data
end
Summary
Callbacks
Close the transport. Returns the struct with the socket set to nil.
Drain buffered frames and cancel any pending select/active registration.
Returns the network interface name, or nil if not applicable.
Decode one process mailbox message from this transport.
Returns a human-readable transport identifier for telemetry and logging.
Open a transport from keyword options.
Returns true when the transport is open.
Re-arm for the next async delivery without draining buffered frames.
Send an EtherCAT payload. Returns monotonic tx timestamp on success.
Arm for exactly one async delivery — analogous to inet:setopts([{active, once}]).
Returns the transport's own source MAC address (6 bytes), or nil.
Types
@type t() :: struct()
Callbacks
Close the transport. Returns the struct with the socket set to nil.
@callback drain(t()) :: :ok
Drain buffered frames and cancel any pending select/active registration.
Returns the network interface name, or nil if not applicable.
Used by the internal bus link monitor. Returns nil for transports that
don't rely on a named OS interface (e.g. UdpSocket).
@callback match(t(), msg :: term()) :: {:ok, ecat_payload :: binary(), rx_at :: integer(), frame_src_mac :: binary() | nil} | {:error, reason :: term()} | :ignore
Decode one process mailbox message from this transport.
Returns {:ok, ecat_payload, rx_at, frame_src_mac} when the message belongs
to this transport and data is ready; {:error, reason} when the message
belongs to this transport but receive processing failed; :ignore for all
other messages.
frame_src_mac is the 6-byte source MAC address from the Ethernet header
of the received frame, or nil for transports that don't expose it (UDP).
The redundant link uses this to distinguish cross-over frames (sent by the
other port's NIC) from own-port loopback frames.
RawSocket: matches{:"$socket", raw, :select, _}, callsrecvmsginternally, strips Ethernet headers. The two-step select dance is hidden.UdpSocket: matches{:udp, raw, _ip, _port, data}and returns data inline.
Returns a human-readable transport identifier for telemetry and logging.
RawSocket: returns the interface name (e.g."eth0")UdpSocket: returns"host:port"(e.g."192.168.1.1:34980")
Open a transport from keyword options.
Returns true when the transport is open.
@callback rearm(t()) :: :ok
Re-arm for the next async delivery without draining buffered frames.
Unlike set_active_once/1, this preserves any frames already in the
socket buffer. Used by the bus after an idx-mismatch so that a
legitimate response sitting behind a rogue frame is not lost.
RawSocket: self-sends a synthetic select notification somatch/2re-enters and reads the next buffered frame.UdpSocket: delegates toset_active_once/1(no drain issue).
Send an EtherCAT payload. Returns monotonic tx timestamp on success.
The transport is responsible for any outer framing (Ethernet headers,
UDP/IP headers). The payload is the output of Bus.Frame.encode/1.
@callback set_active_once(t()) :: :ok
Arm for exactly one async delivery — analogous to inet:setopts([{active, once}]).
After calling this, the next received frame will be delivered as a message
to the calling process. Use match/2 to decode it.
RawSocket: calls:socket.recvmsg(:nowait)to register the kernel selectUdpSocket: calls:inet.setopts([{:active, :once}])
@callback src_mac(t()) :: <<_::48>> | nil
Returns the transport's own source MAC address (6 bytes), or nil.
Used by the redundant link to identify whether a received frame
originated from this port's NIC or crossed over from the other port.
Returns nil for transports without MAC addresses (e.g. UDP).