# `EtherCAT.Mailbox`
[🔗](https://github.com/tallakt/yaethercat/blob/v0.1.0/lib/ethercat/mailbox.ex#L1)

The mailbox of a SubDevice: two areas of its memory behind sync managers 0 and 1, one the
MainDevice writes and one it reads, each holding one message at a time (ETG.1000.4, 5.6 and 7.2).

A message is a header of six bytes, then its service data:

  * the length of the service data
  * a station address, the MainDevice's own (0) in what it sends
  * a channel and priority, both 0 here
  * the type, as `:coe`, and a counter from 1 to 7 that tells a new message from a repeated one

A write that the SubDevice doesn't take, because it hasn't read the last one yet, comes back with
a working counter of 0 and is sent again. A read of an empty mailbox likewise; so the MainDevice
reads the status of sync manager 1 until it says the mailbox is full, then the mailbox.

Only one exchange goes on with a SubDevice's mailbox at once: `transaction/4` waits its turn for
the mailbox, from the `EtherCAT.MainDevice`, and runs in the caller.

# `t`

```elixir
@type t() :: %{
  station: 0..65535,
  receive: {0..65535, 0..65535},
  send: {0..65535, 0..65535},
  counter: 1..7,
  seen: [{type(), binary()}]
}
```

A SubDevice's mailbox while it's the caller's: its station address, its two areas, an offset and a
size each, and the counter of the next message.

# `type`

```elixir
@type type() :: :error | :aoe | :eoe | :coe | :foe | :soe | :voe | 0..15
```

A mailbox protocol.

# `decode`

```elixir
@spec decode(binary()) ::
  {:ok, {type(), 0..7, 0..65535, binary()}} | {:error, :invalid_length}
```

A message read from a mailbox, its type, counter and service data, the rest of the mailbox passed
over; or `{:error, :invalid_length}` for a length that runs past it.

# `encode`

```elixir
@spec encode(type(), 1..7, binary(), pos_integer()) :: binary()
```

A message, its header and service data, padded with zeros to `size`, the size of the mailbox.

# `error`

```elixir
@spec error(0..65535) :: atom() | 0..65535
```

What an error reply's detail means (ETG.1000.4, Table 30).

# `read`

```elixir
@spec read(EtherCAT.MainDevice.t(), t(), keyword()) ::
  {:ok, {type(), 0..7, 0..65535, binary()}, t()} | {:error, term()}
```

Reads the next message from a SubDevice's mailbox, waiting until there is one: `{:ok, {type,
counter, address, data}, mailbox}`, or `{:error, :timeout}`.

# `transaction`

```elixir
@spec transaction(
  EtherCAT.MainDevice.t(),
  0..65535,
  (t() -&gt; {result, t()}),
  keyword()
) ::
  result | {:error, term()}
when result: term()
```

Runs `fun` with a SubDevice's mailbox once it's the caller's, and gives it back after. `fun` returns
its result with the mailbox as `write/5` and `read/3` left it, so that the counter goes on from
there. The result is that of `fun`, or `{:error, :no_mailbox}` for a SubDevice without one, or one
that wasn't scanned.

# `write`

```elixir
@spec write(EtherCAT.MainDevice.t(), t(), type(), binary(), keyword()) ::
  {:ok, t()} | {:error, term()}
```

Writes a message to a SubDevice's mailbox, waiting until it takes it: the mailbox with its counter
moved on, or why not.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
