EtherCAT.Datagram (yaethercat v0.1.0)

Copy Markdown View Source

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:

RequestDoes
{: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.

t()

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

command()

@type command() ::
  :aprd
  | :apwr
  | :aprw
  | :fprd
  | :fpwr
  | :fprw
  | :brd
  | :bwr
  | :brw
  | :lrd
  | :lwr
  | :lrw
  | :armw
  | :frmw

The name of an EtherCAT command.

request()

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

t()

@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

auto_increment?(command)

@spec auto_increment?(command()) :: boolean()

Whether a command addresses a SubDevice by its position.

decode_all(binary)

@spec decode_all(binary()) ::
  {:ok, [t()]} | {:error, :invalid_command | :invalid_length}

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}]}

encode(d, next)

@spec encode(t(), boolean()) :: binary()

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

logical?(command)

@spec logical?(command()) :: boolean()

Whether a command addresses the logical memory, rather than a SubDevice's own.

new(request)

@spec new(request()) :: t()

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.

size(datagram)

@spec size(t()) :: pos_integer()

The bytes a datagram takes in a frame: its data and twelve.