# `LIS3DH.Sampler`

GenServer that drains the LIS3DH's FIFO and dispatches frames to a
subscriber process.

## Why this exists

Polling raw `OUT_*` registers from the BEAM is fine at low ODRs, but at
100 Hz+ the chip's 32-level FIFO and watermark interrupt let the host
off-load buffering to silicon and only intervene on a chosen watermark
threshold.

## Modes

Set the `:mode` option to one of:

  * `:stream` (default) — overwrites the oldest sample when full. Best for
    continuous streaming at the watermark interval. Recommended.
  * `:fifo` — fills to 32 samples and stops. Use when you want a fixed
    snapshot triggered by external timing.
  * `:stream_to_fifo` — starts in Stream and switches to FIFO when an
    interrupt fires on the configured trigger pin. Use to capture history
    around an event (motion, free-fall, click).

The sampler only routes the FIFO watermark interrupt to **INT1** —
`CTRL_REG3.I1_WTM`. The chip has no equivalent INT2 bit, so external
wiring must use INT1 for FIFO.

## Frame format

Each FIFO sample is one X/Y/Z accelerometer reading. Frames are dispatched
as `{LIS3DH.Sampler, sampler_pid, [%{x: float, y: float, z: float}, ...]}`
messages where each map contains values in m/s² scaled from the cached
operating mode and range on the `LIS3DH` struct.

## Usage

    {:ok, i2c} = Wafer.Driver.Circuits.I2C.acquire(bus_name: "i2c-1", address: 0x18)
    {:ok, acc} = LIS3DH.acquire(conn: i2c)
    {:ok, acc} = LIS3DH.configure_accelerometer(acc,
      mode: :high_resolution, odr: 200, range: 2)

    {:ok, int1} = Wafer.Driver.Circuits.GPIO.acquire(pin: 17, direction: :in)

    {:ok, _sampler} =
      LIS3DH.Sampler.start_link(acc: acc, int1: int1, mode: :stream, watermark: 16)

    receive do
      {LIS3DH.Sampler, _pid, frames} -> IO.inspect(frames)
    end

# `option`

```elixir
@type option() ::
  {:acc, LIS3DH.t()}
  | {:int1, Wafer.Conn.t() | nil}
  | {:subscriber, pid()}
  | {:mode, LIS3DH.Fifo.mode()}
  | {:watermark, LIS3DH.Fifo.watermark()}
  | {:trigger, LIS3DH.Fifo.trigger()}
  | {:name, GenServer.name()}
```

Options accepted by `start_link/1`.

# `t`

```elixir
@type t() :: %LIS3DH.Sampler{
  acc: LIS3DH.t(),
  int1: Wafer.Conn.t() | nil,
  mode: LIS3DH.Fifo.mode(),
  subscriber: pid(),
  watermark: LIS3DH.Fifo.watermark()
}
```

Internal sampler state.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `drain`

```elixir
@spec drain(GenServer.server()) :: {:ok, [LIS3DH.axes()]} | {:error, term()}
```

Synchronously drain the FIFO and return any complete frames. Used in
pull-only mode or for on-demand reads.

# `start_link`

```elixir
@spec start_link([option()]) :: GenServer.on_start()
```

Start a FIFO sampler.

## Options

  * `:acc` (required) — an `LIS3DH` struct with `:operating_mode` and
    `:range` cached (e.g. via `LIS3DH.configure_accelerometer/2`).
  * `:int1` (optional) — a `Wafer.GPIO`-implementing connection wired to
    the device's INT1 pin. Without it the sampler runs pull-only.
  * `:subscriber` (default `self()`) — process that receives frame messages.
  * `:mode` (default `:stream`) — `t:LIS3DH.Fifo.mode/0`.
  * `:watermark` (default `16`) — `t:LIS3DH.Fifo.watermark/0`.
  * `:trigger` (default `:int1`) — Stream-to-FIFO trigger pin
    (`t:LIS3DH.Fifo.trigger/0`); ignored in other modes.
  * `:name` — optional GenServer registration name.

---

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