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

The Slave Information Interface: the EEPROM of a SubDevice, which describes it (ETG.1000.6, 5.4).

Its first 64 words hold the identity, the station alias and the mailboxes; categories follow from
word 0x40, each a type and a length in words, until the type 0xFFFF:

  * strings, which the others refer to by number from 1, 0 being none
  * general: the device's name and the mailbox protocols it details
  * FMMU: what each FMMU is for
  * SyncM: each sync manager's area, control byte and type
  * TXPDO and RXPDO: the PDOs, their sync manager and their entries

`decode/1` takes the EEPROM's bytes and `read/3` reads them from a SubDevice through its registers.

# `entry`

```elixir
@type entry() :: %{
  index: 0..65535,
  subindex: byte(),
  name: String.t() | nil,
  data_type: byte(),
  bits: byte()
}
```

An entry of a PDO: the object mapped, its name, its CoE data type and its length in bits.

# `mailboxes`

```elixir
@type mailboxes() :: %{receive: {0..65535, 0..65535}, send: {0..65535, 0..65535}}
```

Two mailboxes, from the MainDevice (receive) and to it (send): each an offset and a size in bytes.

# `pdo`

```elixir
@type pdo() :: %{
  index: 0..65535,
  sync_manager: byte(),
  synchronization: byte(),
  name: String.t() | nil,
  entries: [entry()]
}
```

A PDO: its index, its sync manager, its name and entries.

# `sync_manager`

```elixir
@type sync_manager() :: %{
  start: 0..65535,
  length: 0..65535,
  control: byte(),
  enable: byte(),
  type: :unused | :mailbox_out | :mailbox_in | :outputs | :inputs | byte()
}
```

A sync manager as the SII describes it.

# `t`

```elixir
@type t() :: %EtherCAT.SII{
  alias: 0..65535,
  bootstrap_mailbox: mailboxes() | nil,
  categories: [{0..65535, binary()}],
  fmmus: [:outputs | :inputs | :mailbox_status | :unused],
  general: map() | nil,
  mailbox: mailboxes() | nil,
  mailbox_protocols: [:aoe | :eoe | :coe | :foe | :soe | :voe],
  product_code: 0..4_294_967_295,
  revision: 0..4_294_967_295,
  rx_pdos: [pdo()],
  serial: 0..4_294_967_295,
  size: non_neg_integer(),
  strings: [String.t()],
  sync_managers: [sync_manager()],
  tx_pdos: [pdo()],
  vendor_id: 0..4_294_967_295,
  version: 0..65535
}
```

# `decode`

```elixir
@spec decode(binary()) :: {:ok, t()} | {:error, :too_short}
```

The SII from its bytes: the first 128 at least, and as many categories as they hold. A category
cut short ends the decoding there. `categories` keeps every category as it came, by type.

# `read`

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

Reads `words` words of a SubDevice's SII from word `address`, by its station address, through its
SII registers.

The SubDevice reads its EEPROM a few words at a time, 2 or 4 as its control register says, and the
MainDevice waits for each read to finish before it takes the data.

# `read_all`

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

Reads a SubDevice's whole SII: the first 64 words, and its categories until their end, or until
the size the SII says it is, 64 Ki words at most.

# `string`

```elixir
@spec string([String.t()], byte()) :: String.t() | nil
```

String `n` of an SII's strings, counting from 1; nil for 0 or one that isn't there.

---

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