ST25R100 (st25r100 v0.1.0)

Copy Markdown View Source

An Elixir driver for the ST25R100 NFC reader chip.

Supports resolving NFC-A tag UIDs (4-byte and 7-byte) and reading the full memory of Type 2 Tags (NTAG21x, Mifare Ultralight, etc) via a simple, pure functional API. Driver state is a struct passed to and returned from each function; no GenServer is used.

Summary

Functions

Closes the reset GPIO pin if it was opened.

Sends a REQA (Request Command, 0x26) to detect any NFC-A tag in the field. Returns {:ok, atqa} containing the 2-byte ATQA response on success, or {:error, :timeout} if no tag responded.

Initializes the ST25R100 chip. If a reset_pin was supplied in new/2, it opens the pin, cycles it, and holds it LOW to keep the chip powered. Then, resets registers to default, verifies IC type, turns on the oscillator, waits for stable status, and applies base analog and protocol configurations.

Initializes a new driver state with the given SPI bus handle and optional options.

Reads a Type 2 Tag's full memory, starting at block 0 and repeating READ commands until a NAK (end of memory) or the read cap is reached.

Resolves a tag's UID via anti-collision and SELECT (Cascade Level 1, and Level 2 if needed for a 7-byte UID).

Enables or disables the RF transmitter field.

Types

t()

@type t() :: %ST25R100{
  field_on: boolean(),
  osc_stable: boolean(),
  reset_gpio: any() | nil,
  reset_pin: any() | nil,
  spi: any()
}

Functions

close(st25_r100)

@spec close(t()) :: :ok

Closes the reset GPIO pin if it was opened.

detect_tag(st25_r100)

@spec detect_tag(t()) :: {:ok, binary()} | {:error, any()}

Sends a REQA (Request Command, 0x26) to detect any NFC-A tag in the field. Returns {:ok, atqa} containing the 2-byte ATQA response on success, or {:error, :timeout} if no tag responded.

init(state)

@spec init(t()) :: {:ok, t()} | {:error, any()}

Initializes the ST25R100 chip. If a reset_pin was supplied in new/2, it opens the pin, cycles it, and holds it LOW to keep the chip powered. Then, resets registers to default, verifies IC type, turns on the oscillator, waits for stable status, and applies base analog and protocol configurations.

new(spi_bus, opts \\ [])

@spec new(
  any(),
  keyword()
) :: t()

Initializes a new driver state with the given SPI bus handle and optional options.

Options

  • :reset_pin - A GPIO pin number/string (e.g. "GPIO25" or 25) that is connected to the chip's Enable/Reset line. If provided, the GPIO will be opened and held LOW to activate the chip during init/1.

read_data(st25_r100, opts \\ [])

@spec read_data(
  t(),
  keyword()
) :: {:ok, binary()} | {:error, any()}

Reads a Type 2 Tag's full memory, starting at block 0 and repeating READ commands until a NAK (end of memory) or the read cap is reached.

Must be called after a read_uid/1 call that returned {:ok, uid} on the same driver state.

Options

  • :max_reads - number of READ commands to attempt before giving up (default 64, 1024 bytes). The T2T block address is a single byte, so values above 64 will wrap the address instead of erroring.

read_uid(st25_r100)

@spec read_uid(t()) :: {:ok, binary()} | {:error, :unsupported_tag} | {:error, any()}

Resolves a tag's UID via anti-collision and SELECT (Cascade Level 1, and Level 2 if needed for a 7-byte UID).

Only Type 2 Tags are currently supported; returns {:error, :unsupported_tag} for any other tag type. A successful {:ok, uid} means it's safe to call read_data/2 next.

set_field(state, bool)

@spec set_field(t(), boolean()) :: {:ok, t()} | {:error, any()}

Enables or disables the RF transmitter field.