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

A protocol for interacting with I2C devices directly.  Most of the time you'll
want to use the `Chip` protocol for working with registers, but this is
provided for consistency's sake.

This API is extremely similar to the `Circuits.I2C` APIs, except that it takes
a `Conn` which implements `I2C` as an argument.

## Deriving

If you're implementing your own `Conn` type that simply delegates to one of
the lower level drivers then you can derive this protocol automatically:

```elixir
defstruct MyI2CDevice do
  @derive Wafer.I2C
  defstruct [:conn]
end
```

If your type uses a key other than `conn` for the inner connection you can
specify it while deriving:

```elixir
defstruct MyI2CDevice do
  @derive {Wafer.I2C, key: :i2c_conn}
  defstruct [:i2c_conn]
end

# `address`

```elixir
@type address() :: 0..127
```

# `data`

```elixir
@type data() :: binary()
```

# `option`

```elixir
@type option() :: any()
```

# `options`

```elixir
@type options() :: [option()]
```

# `t`

```elixir
@type t() :: term()
```

All the types that implement this protocol.

# `detect_devices`

```elixir
@spec detect_devices(Wafer.Conn.t()) :: {:ok, [address()]} | {:error, any()}
```

Detect the devices adjacent to the connection's device on the same I2C bus.

# `read`

```elixir
@spec read(Wafer.Conn.t(), non_neg_integer(), options()) ::
  {:ok, data()} | {:error, reason :: any()}
```

Initiate a read transaction to the connection's I2C device.

# `write`

```elixir
@spec write(Wafer.Conn.t(), data(), options()) ::
  {:ok, Wafer.Conn.t()} | {:error, reason :: any()}
```

Write `data` to the connection's I2C device.

# `write_read`

```elixir
@spec write_read(Wafer.Conn.t(), data(), non_neg_integer(), options()) ::
  {:ok, data(), Wafer.Conn.t()} | {:error, reason :: any()}
```

Write data to an I2C device and then immediately issue a read.

---

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