# `Meshcore.Commands.Base`
[🔗](https://github.com/nyannus/meshcore_ex/blob/v0.1.0/lib/meshcore/commands/base.ex#L1)

Shared plumbing for the command modules.

All commands share these conventions:

  * the first argument is the connection (`mc`, the pid or registered name of
    a `Meshcore.Client`);
  * timeouts are **milliseconds** (Python uses seconds);
  * a command returns `{:ok, %Meshcore.Event{}}` or `{:error, %Meshcore.Event{}}`.
    The error event has `type: :error` and a payload with either
    `:reason` (`:timeout`, `:not_connected`, `:disconnected`, …) or
    `:error_code`/`:code_string` when the device rejected the command;
  * a *destination* (`t:Meshcore.Util.destination/0`) is a contact map, a hex
    public key or a raw public key;
  * programmer errors (malformed destination, wrong key size…) raise
    `ArgumentError`, like Python's `ValueError`.

# `mc`

```elixir
@type mc() :: GenServer.server()
```

# `result`

```elixir
@type result() :: {:ok, Meshcore.Event.t()} | {:error, Meshcore.Event.t()}
```

# `encode_reply_path`

```elixir
@spec encode_reply_path(integer(), String.t(), integer()) :: binary()
```

Encodes the reply path a server should use when answering us.

The first byte packs `hop_count | hash_mode << 6`; the path is reversed **by
hop** (multi-byte hashes stay intact). Paths are truncated to what the
server's 64 byte buffer can hold.

# `send_anon_req`

```elixir
@spec send_anon_req(mc(), Meshcore.Util.destination(), atom(), keyword()) :: result()
```

Sends an anonymous request (command `0x39`) to `dst`.

`dst` need not be a known contact. When it is, the contact's out path is used
as the reply path; otherwise a zero-hop direct reply is requested. A contact
that is currently flooded is temporarily pinned to a zero-hop path (the
servers gate these requests behind direct routing) and reset afterwards.

# `send_binary_req`

```elixir
@spec send_binary_req(
  mc(),
  Meshcore.Util.destination(),
  atom(),
  binary() | nil,
  keyword()
) :: result()
```

Sends a binary request (command `0x32`) to `dst`.

The pending request is registered with the reader *atomically* when the
`:msg_sent` acknowledgement arrives, so a response can never overtake the
registration. Options: `:timeout` and `:min_timeout` (ms, `nil`/`0` = use the
device's suggestion), `:context`, `:then` (see `Meshcore.Client.command/4`).

# `send_command`

```elixir
@spec send_command(mc(), iodata(), [Meshcore.Event.type()], keyword()) :: result()
```

Sends raw command bytes and waits for one of the `expected` event types.

See `Meshcore.Client.command/4` for the options. With no expected events the
command is fire-and-forget.

---

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