# `Meshcore.Reader`
[🔗](https://github.com/nyannus/meshcore_ex/blob/v0.1.0/lib/meshcore/reader.ex#L1)

Decodes frames received from the device into `Meshcore.Event`s.

The reader is a **pure** state machine (no processes): `handle_rx/2` takes a
frame and returns the events it produced together with the updated reader.
It keeps only the state needed to turn frames into events:

  * the contact list currently being received (`CONTACT_START` … `CONTACT_END`),
  * pending binary requests (so `:binary_response` frames can be decoded into
    `:status_response`, `:telemetry_response`, `:mma_response`,
    `:acl_response` and `:neighbours_response` events),
  * the `Meshcore.PacketParser` used for RX-log decoding and channel-message
    path correlation.

Malformed or truncated frames never raise: they are logged and dropped, as in
the Python implementation.

# `pending`

```elixir
@type pending() :: %{
  request_type: atom(),
  pubkey_prefix: String.t(),
  expires_at: integer(),
  is_anon: boolean(),
  context: map()
}
```

# `t`

```elixir
@type t() :: %Meshcore.Reader{
  contact_nb: non_neg_integer(),
  contacts: %{required(String.t()) =&gt; map()},
  parser: Meshcore.PacketParser.t(),
  pending_binary_requests: %{required(String.t()) =&gt; pending()}
}
```

# `cleanup_expired`

```elixir
@spec cleanup_expired(t()) :: t()
```

Drops expired pending binary requests.

# `decrypt_channels?`

```elixir
@spec decrypt_channels?(t()) :: boolean()
```

Whether channel decryption is enabled.

# `handle_rx`

```elixir
@spec handle_rx(t(), binary()) :: {[Meshcore.Event.t()], t()}
```

Decodes one frame. Returns `{events, reader}`; `events` is in dispatch order.

# `new`

```elixir
@spec new() :: t()
```

Creates a new reader.

# `register_binary_request`

```elixir
@spec register_binary_request(
  t(),
  String.t(),
  String.t(),
  atom(),
  non_neg_integer(),
  keyword()
) :: t()
```

Registers a pending binary request keyed by its expected `tag` (hex), so the
matching `:binary_response` can be decoded. Expired registrations are purged.

Options: `:context` (map copied into the result), `:is_anon` (boolean).

# `set_decrypt_channels`

```elixir
@spec set_decrypt_channels(t(), boolean()) :: t()
```

Enables or disables decryption of group-channel packets in the RX log.

---

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