# `Wafer.Registers`
[🔗](https://harton.dev/james/wafer/src/branch/main/lib/wafer/registers.ex#L1)

This module provides helpful macros for specifying the registers used to
communicate with your device.

This can be a massive time saver, and means you can basically just copy them
straight out of the datasheet.

See the documentation for `defregister/4` for more information.

# `access_mode`

```elixir
@type access_mode() :: :ro | :rw | :wo
```

# `bytes`

```elixir
@type bytes() :: non_neg_integer()
```

# `register_name`

```elixir
@type register_name() :: atom()
```

# `defregister`
*macro* 

```elixir
@spec defregister(atom(), non_neg_integer(), :ro | :rw | :wo | non_neg_integer()) ::
  Macro.t()
```

Define functions for interacting with a device register with common defaults.

## Examples

When specified with an access mode, assumes a 1 byte register:

    iex> defregister(:status, 0x03, :ro)

When specified with a byte size, assumes a `:rw` register:

    iex> defregister(:config, 0x02, 2)

# `defregister`
*macro* 

```elixir
@spec defregister(atom(), non_neg_integer(), :ro | :rw | :wo, non_neg_integer()) ::
  Macro.t()
```

Define functions for interacting with a device register.

## Parameters
  - `name` - name of the register.
  - `register_address` - the address of the register.
  - `mode` the access mode of the register.
  - `bytes` the number of bytes in the register.

## Examples

### Read-only registers

Define a read-only register named `status` at address `0x03` which is a single
byte wide:

    iex> defregister(:status, 0x03, :ro, 1)

This will define the following function along with documentation and
typespecs:

```elixir
def read_status(conn), do: Chip.read_register(conn, 0x03, 1)
```

### Write-only registers

Define a write-only register named `int_en` at address `0x02` which is 2 bytes
wide:

    iex> defregister(:int_en, 0x02, :wo, 2)

This will define the following functions along with documentation and
typespecs:

```elixir
def write_int_en(conn, data)
    when is_binary(data) and byte_size(data) == 2,
    do: Chip.write_register(conn, 0x2, data)

def write_int_en(_conn, data),
    do: {:error, "Argument error: #{inspect(data)}"}
```

### Read-write registers.

Define a read-write register named `config` at address `0x01`.

    iex> defregister(:config, 0x01, :rw, 1)

In addition to defining `read_config/1` and `write_config/2` as per the
examples above it will also generate the following functions along with
documentation and typespecs:

```elixir
def swap_config(conn, data)
    when is_binary(data) and byte_size(data) == 1,
    do: Chip.swap_register(conn, 0x01, data)

def swap_config(_conn, data),
    do: {:error, "Argument error: #{inspect(data)}"}

def update_config(conn, callback)
    when is_function(callback, 1) do
      with {:ok, data} <- Chip.read_register(conn, 0x01, 1),
           new_data when is_binary(new_data) and byte_size(new_data) == 1 <- callback.(data),
           {:ok, conn} <- Chip.write_register(conn, 0x01, new_data),
           do: {:ok, conn}
    end

def update_config(_conn, _callback),
    do: {:error, "Argument error: callback should be an arity 1 function"}
```

---

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