arb-ex

DocsHex.pm

An Elixir NIF for controlling the ABACOM CH341A relay board (documentation).

Getting started

Requirements

None. A precompiled NIF with libusb linked into it is downloaded at build time, so neither the Rust toolchain nor libusb-1.0-0-dev has to be installed. Artifacts are published for:

Anywhere else, Windows included, the NIF is compiled from source instead, which needs Rust and a C compiler — still not libusb, which is built from the copy vendored in the crate. ARB_BUILD=true forces a source build on a supported target too.

Installation

Add :arb to your list of dependencies:

def deps do
[
{:arb, "~> 0.20"}
]
end

Usage

Open a libusb context once and hold it — initialising one is by far the most expensive part of talking to a board, and Arb.Usb has the figures. Naming a board through it is free and resolves nothing until an operation runs.

iex> {:ok, usb} = Arb.open()
iex> board = Arb.board(usb)
iex> Arb.set_relays(board, [1, 4, 7])
:ok
iex> Arb.relays(board)
{:ok, [1, 4, 7]}
iex> Arb.set_relays(board, [])
:ok

Arb.relays/1 is a plain read. Arb.self_test/1 is the separate health check — it moves no relay, so it is safe on a board driving live outputs.

With more than one board attached, Arb.list_boards/1 enumerates them and names each unambiguously:

iex> {:ok, boards} = Arb.list_boards(usb)
iex> Enum.map(boards, &inspect/1)
["#Arb.Board<port 1 (1-1)>", "#Arb.Board<port 5 (1-5)>"]

These boards report no serial number and no product strings, so where a board is plugged in is the only thing telling two of them apart — the 1-1 notation is the one lsusb -t uses, so the two can be read side by side. Label the cables if the relays drive anything that must not be actuated by mistake.

Migrating from 0.19 — where the three functions took a :port option and built a context per call — is covered in the changelog.

Development

Rust is the only prerequisite. config/config.exs forces a source build in this repo, so a clean clone works without setting anything:

mix test

Tests tagged :libusb exercise the real NIF and need a USB bus — not a relay board. They run by default and are excluded only in CI, which has no bus at all (see .github/workflows/ci.yml).

Releasing

The precompiled artifacts have to exist before the package is published, because the checksum file that pins them is built from what the release actually holds.

  1. Bump @version in mix.exs and land it.
  2. git tag v<version> && git push origin master --tags — this runs .github/workflows/release.yml, which builds every target and attaches the artifacts to the GitHub release.
  3. Wait for all of them. A partial release yields a checksum file missing those targets, and users on them get a download error at compile time.
  4. mix rustler_precompiled.download Arb.Native --all --print, which writes checksum-Elixir.Arb.Native.exs.
  5. mix hex.publish. It refuses to build without that file.

See also