CircuitsFT232H. Device
(circuits_ft232h v0.1.0)
Copy Markdown
A GenServer that owns the USB handle to one FT232H and serialises all traffic with it.
Started once per physical chip and registered in CircuitsFT232H.Registry
by the device's id (currently "<bus>:<address>" — once we read FTDI
serial numbers this becomes the serial). All MPSSE traffic flows through
transaction/4, so the chip sees commands from at most one process at a
time.
The Device enforces two kinds of allocation:
- I2C/SPI mutual-exclusion lock — at most one of
:i2cor:spimay be active on a chip at once.claim_mode/2returns{:error, {:mode_busy, current}}for a conflicting claim. - GPIO pin allocation — individual pins may be opened by GPIO consumers, and the Device tracks which pins are claimed in which direction. Pin claims are checked against the active protocol's reserved pin set so the two don't fight over the same wires.
Summary
Types
Canonical identifier for a physical FT232H.
Protocol modes a chip can be locked into.
Linear pin index. 0..7 map to ADBUS0..ADBUS7 ("AD0".."AD7"); 8..15
map to ACBUS0..ACBUS7 ("AC0".."AC7").
Direction of a GPIO pin.
Internal GenServer state.
Functions
Claims pin for GPIO use in the given direction. Fails if the pin is
already claimed, if it's reserved by the active protocol, or if pin is
out of range.
Claims one of the mutually-exclusive protocol modes for the chip.
Starts a Device under CircuitsFT232H.DeviceSupervisor if one isn't
already running for the descriptor's id.
Returns the direction currently configured for pin, or nil if the pin
isn't open.
Returns the canonical id for a USB descriptor.
Returns the current protocol mode the chip is locked into.
Returns the list of pins reserved by the given protocol mode. Pins outside this list are available for GPIO use.
Reads the current state of the low-byte (ADBUS0..7) and high-byte (ACBUS0..7) ports in a single USB round-trip. Used by the GPIO poller to detect edges across many pins without paying per-pin latency.
Reads the current logic level of a previously-opened GPIO pin.
Releases a previously-claimed GPIO pin and switches it back to input.
Releases whichever mode the chip is currently locked into.
Changes the direction of an already-opened GPIO pin. The pin keeps its current driven value when switching to output.
Starts a Device server for the FT232H described by :descriptor.
Stops the Device server for the given id.
Sends command (an MPSSE byte stream) to the chip and optionally reads
response_length bytes back.
Verifies the chip is in MPSSE mode and responding to commands by issuing
an unrecognised opcode and checking for the standard 0xFA <opcode> echo.
Finds the pid of the Device server with the given id, if one is running.
Writes value (0 or 1) to a previously-opened GPIO output pin.
Types
@type id() :: String.t()
Canonical identifier for a physical FT232H.
Prefers the chip's FTDI-programmed serial number string when one is
available (so the id is stable across replugs). Falls back to
"<bus>:<address>" if the chip has no serial or it couldn't be read
(e.g. permission denied).
@type mode() :: :none | :i2c | :spi
Protocol modes a chip can be locked into.
@type pin() :: 0..15
Linear pin index. 0..7 map to ADBUS0..ADBUS7 ("AD0".."AD7"); 8..15
map to ACBUS0..ACBUS7 ("AC0".."AC7").
@type pin_direction() :: :input | :output
Direction of a GPIO pin.
@type t() :: %CircuitsFT232H.Device{ acbus_dir: byte(), acbus_value: byte(), adbus_dir: byte(), adbus_value: byte(), extra_reserved_pins: [pin()], gpio_pins: %{optional(pin()) => pin_direction()}, id: id() | nil, mode: mode(), usb: CircuitsFT232H.USB.t() | nil }
Internal GenServer state.
Functions
@spec claim_gpio_pin(id(), pin(), pin_direction(), 0..1) :: :ok | {:error, term()}
Claims pin for GPIO use in the given direction. Fails if the pin is
already claimed, if it's reserved by the active protocol, or if pin is
out of range.
On success the pin is initialised — direction set, and for outputs the initial value driven.
@spec claim_mode(id(), :i2c | :spi, [pin()]) :: :ok | {:error, {:mode_busy, mode()} | {:pin_busy, pin()}}
Claims one of the mutually-exclusive protocol modes for the chip.
Returns :ok if the chip is currently unclaimed (or already claimed in
the requested mode), or {:error, {:mode_busy, current_mode}} otherwise.
Also fails with {:error, {:pin_busy, pin}} if any currently-open GPIO
pin would conflict with the new mode.
extra_pins lets a backend reserve additional pins beyond the protocol's
defaults — e.g. the I2C backend reserves AD7 when clock stretching is
enabled, so a GPIO consumer can't grab the SCL-feedback pin.
@spec find_or_start( CircuitsFT232H.USB.Descriptor.t(), keyword() ) :: {:ok, pid()} | {:error, term()}
Starts a Device under CircuitsFT232H.DeviceSupervisor if one isn't
already running for the descriptor's id.
Returns the existing pid if one is found. Use this from the I2C/SPI/GPIO backends — multiple buses may map to the same physical chip.
@spec gpio_pin_direction(id(), pin()) :: pin_direction() | nil
Returns the direction currently configured for pin, or nil if the pin
isn't open.
@spec id_for(CircuitsFT232H.USB.Descriptor.t()) :: id()
Returns the canonical id for a USB descriptor.
Returns the current protocol mode the chip is locked into.
Returns the list of pins reserved by the given protocol mode. Pins outside this list are available for GPIO use.
Reads the current state of the low-byte (ADBUS0..7) and high-byte (ACBUS0..7) ports in a single USB round-trip. Used by the GPIO poller to detect edges across many pins without paying per-pin latency.
Reads the current logic level of a previously-opened GPIO pin.
Releases a previously-claimed GPIO pin and switches it back to input.
@spec release_mode(id()) :: :ok
Releases whichever mode the chip is currently locked into.
@spec set_gpio_pin_direction(id(), pin(), pin_direction()) :: :ok | {:error, term()}
Changes the direction of an already-opened GPIO pin. The pin keeps its current driven value when switching to output.
@spec start_link(keyword()) :: GenServer.on_start()
Starts a Device server for the FT232H described by :descriptor.
Registers under the device's id in CircuitsFT232H.Registry. Subsequent
callers can locate the server via whereis/1 or by referring to it by
id in any of the public functions on this module.
Options:
:descriptor(required) — theCircuitsFT232H.USB.Descriptorfor the chip.:latency_ms(default16) — USB latency timer.
@spec stop(id()) :: :ok
Stops the Device server for the given id.
@spec transaction(id(), iodata(), non_neg_integer(), timeout()) :: :ok | {:ok, binary()} | {:error, term()}
Sends command (an MPSSE byte stream) to the chip and optionally reads
response_length bytes back.
command may be any iodata. If response_length is 0 the call
returns :ok once the bytes have been queued to the chip. Otherwise it
returns {:ok, binary} of exactly response_length payload bytes (the
USB status prefix is stripped).
Use this for protocol-level MPSSE sequences. For pin-level operations,
prefer write_gpio_pin/3, read_gpio_pin/2, and friends — they share
the Device's pin-state tracking so GPIO and protocol traffic don't
trample each other's bytes.
Verifies the chip is in MPSSE mode and responding to commands by issuing
an unrecognised opcode and checking for the standard 0xFA <opcode> echo.
Finds the pid of the Device server with the given id, if one is running.
Writes value (0 or 1) to a previously-opened GPIO output pin.