An EtherCAT PDU, called a datagram here: one command to the SubDevices, with its address, its data and the working counter they increment (ETG.1000.4, 5.4).
A datagram to send is given as a tuple, named for its command:
| Request | Does |
|---|---|
{:aprd, position, register, length} | reads at the SubDevice at that position from the MainDevice, 0 the first |
{:apwr, position, register, data} | writes there |
{:aprw, position, register, data} | writes there and reads what was there |
{:fprd, station, register, length} | reads at the SubDevice with that configured station address or alias |
{:fpwr, station, register, data} | writes there |
{:fprw, station, register, data} | writes there and reads what was there |
{:brd, register, length} | reads at every SubDevice, the bitwise or of them all |
{:bwr, register, data} | writes at every SubDevice |
{:brw, register, data} | writes at every SubDevice and reads the bitwise or |
{:lrd, address, length} | reads in the logical memory that the FMMUs map |
{:lwr, address, data} | writes there |
{:lrw, address, data} | writes there and reads, each FMMU doing what it is set up for |
{:armw, position, register, length} | reads at one SubDevice and writes what it read at all the others after it |
{:frmw, station, register, length} | likewise, by station address |
A register is an address in a SubDevice's own memory, 0 to 65535, its registers and the RAM behind them alike. Lengths are in bytes, and multi-byte values are little-endian, as everything in EtherCAT.
Each SubDevice that does what a datagram asks increments its working counter: by one for a read, by one for a write, and by three for a read and write that does both (two for the write).
iex> datagram = EtherCAT.Datagram.new({:fprd, 0x1001, 0x0130, 2})
iex> datagram.address
{0x1001, 0x0130}
iex> datagram.data
<<0, 0>>
Summary
Types
The name of an EtherCAT command.
A datagram to send, as in the table above.
A datagram as it is on the wire. address is {adp, ado} for the physical commands, the position
or station address and the register, as the spec calls them, and a 32-bit logical address for
:lrd, :lwr and :lrw. A position is sent as its negative, which each SubDevice increments on
the way, so adp is that in a datagram that came back.
Functions
Whether a command addresses a SubDevice by its position.
The datagrams of a frame, after its header, in order, or why they aren't: :invalid_command for a
command the spec doesn't define, and :invalid_length when they run past the end, or end before
it.
A datagram on the wire, with next set when another follows it in the frame.
Whether a command addresses the logical memory, rather than a SubDevice's own.
A request as a datagram to send, with index 0. A read is sent with zeros, which a broadcast read ors
with what it reads. Raises ArgumentError for a request that isn't one, or whose data can't fit an
Ethernet frame.
The bytes a datagram takes in a frame: its data and twelve.
Types
@type command() ::
:aprd
| :apwr
| :aprw
| :fprd
| :fpwr
| :fprw
| :brd
| :bwr
| :brw
| :lrd
| :lwr
| :lrw
| :armw
| :frmw
The name of an EtherCAT command.
@type request() :: {:aprd | :fprd | :armw | :frmw, 0..65535, 0..65535, pos_integer()} | {:apwr | :aprw | :fpwr | :fprw, 0..65535, 0..65535, binary()} | {:brd, 0..65535, pos_integer()} | {:bwr | :brw, 0..65535, binary()} | {:lrd, 0..4_294_967_295, pos_integer()} | {:lwr | :lrw, 0..4_294_967_295, binary()}
A datagram to send, as in the table above.
@type t() :: %EtherCAT.Datagram{ address: {0..65535, 0..65535} | 0..4_294_967_295, circulating: boolean(), command: command(), data: binary(), index: 0..255, irq: 0..65535, wkc: 0..65535 }
A datagram as it is on the wire. address is {adp, ado} for the physical commands, the position
or station address and the register, as the spec calls them, and a 32-bit logical address for
:lrd, :lwr and :lrw. A position is sent as its negative, which each SubDevice increments on
the way, so adp is that in a datagram that came back.
Functions
Whether a command addresses a SubDevice by its position.
The datagrams of a frame, after its header, in order, or why they aren't: :invalid_command for a
command the spec doesn't define, and :invalid_length when they run past the end, or end before
it.
iex> EtherCAT.Datagram.decode_all(<<0x07, 7, 3, 0, 0, 0, 1, 0, 0, 0, 0x11, 3, 0>>)
{:ok, [%EtherCAT.Datagram{command: :brd, index: 7, address: {3, 0}, data: <<0x11>>, wkc: 3}]}
A datagram on the wire, with next set when another follows it in the frame.
iex> EtherCAT.Datagram.encode(%{EtherCAT.Datagram.new({:brd, 0x0000, 1}) | index: 7}, false)
<<0x07, 7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0>>
Whether a command addresses the logical memory, rather than a SubDevice's own.
A request as a datagram to send, with index 0. A read is sent with zeros, which a broadcast read ors
with what it reads. Raises ArgumentError for a request that isn't one, or whose data can't fit an
Ethernet frame.
@spec size(t()) :: pos_integer()
The bytes a datagram takes in a frame: its data and twelve.