# `Sml.Transport`
[🔗](https://github.com/emischorr/sml_ex/blob/v0.1.0/lib/sml/transport.ex#L1)

SML transport protocol version 1 (framing of SML files).

A telegram on the wire looks like this:

    1B 1B 1B 1B  01 01 01 01   start sequence
    ...                        SML messages, padded with 00 to a multiple of 4
    1B 1B 1B 1B  1A PP CC CC   end sequence, PP = padding bytes, CCCC = CRC

Inside the payload a literal `1B 1B 1B 1B` block is escaped by doubling it.
The CRC (see `Sml.CRC16`) covers everything from the start
sequence up to and including the padding count byte.

Use `unwrap/2` to get the raw message bytes out of one telegram and
`extract/1` to split a byte stream (e.g. read from a serial IR head) into
complete telegrams.

# `unwrap_error`

```elixir
@type unwrap_error() ::
  :no_start_sequence
  | :incomplete
  | :invalid_escape
  | :invalid_padding
  | :invalid_crc
```

# `extract`

```elixir
@spec extract(binary()) :: {[binary()], binary()}
```

Splits a byte stream into complete telegrams.

Returns the complete telegrams found (still framed, ready for
`Sml.decode/2`) and the remaining bytes, which should be prepended to the
next chunk read from the stream. Garbage between telegrams and frames that
are interrupted by a new start sequence are dropped.

    {telegrams, buffer} = Sml.Transport.extract(buffer <> chunk)

# `framed?`

```elixir
@spec framed?(binary()) :: boolean()
```

Returns `true` if `data` contains an SML transport start sequence.

# `unwrap`

```elixir
@spec unwrap(binary(), keyword()) :: {:ok, binary()} | {:error, unwrap_error()}
```

Extracts the payload (the SML messages) from the first telegram in `data`.

Bytes before the start sequence are ignored. Escaped sequences are
unescaped and padding is removed.

## Options

  * `:crc` - checksum algorithm to verify: `:auto` (default, X-25 or
    Kermit), `:x25`, `:kermit`, or `false` to skip the check

---

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