Skip to content

Drive the bit-banged boards on macOS - #2

Merged
Boernsman merged 1 commit into
mainfrom
macos-bitbang-support
Sep 9, 2026
Merged

Boernsman merged 1 commit into
mainfrom
macos-bitbang-support

Conversation

@Boernsman

@Boernsman Boernsman commented Sep 9, 2026

Copy link
Copy Markdown

The 4 and 8 relay boards hang their relays off the data lines of the board's FTDI
chip, and the relay library reaches those lines through a backend it picks by
platform. It has one for Windows and one for Linux, so on macOS it ends up with no
backend at all and those boards could only be refused.

A backend for macOS

bitbang.py is a backend of the same shape, written against pylibftdi — the
library the Linux one uses, which works just as well on macOS. It is put in place of
the library's own on everything but Windows, which keeps its D2XX DLL. Two things it
does differently:

  • it finds libftdi and libusb where Homebrew and MacPorts put them, which is
    outside the paths ctypes searches, and where find_library can otherwise turn up a
    dylib built for the wrong architecture;
  • it opens a board by its whole serial number rather than by a prefix, so the board
    that --serial picked is the board that gets driven. The library's Linux backend
    matches serial + ".+", which cannot match a serial number in full, so that path
    is replaced as well.

The serial number is also what now gets passed to the library's initialise. A
bit-banged board is not reached through its serial port at all, so the port name it
was given before was never going to find it.

Nothing has to be unloaded or disabled on macOS: the board can be bit-banged while
the system's FTDI serial driver still offers it as /dev/cu.usbserial-*.

pylibftdi is picked up as a dependency on macOS and Linux. It needs the libftdi
C library, which pip cannot supply; the README says how to install it.

Correction: the probe change here did not work

This section originally claimed that probing no longer disturbs the relays. That was
wrong, and #3 fixes it — read that one for what actually happens.

The check added here made a bit-banged board give itself away by handing over bytes
with nothing asked of it. It passed in testing only because a libftdi session had
just run against the board, which is what wakes the read side of an FT245's FIFO. On
a fresh port the board stays silent, so the probe still wrote ask//, still left the
relays holding a /, and still reported an 8 relay board as a type16 with sixteen
relays that are not there.

Testing

Against an 8 relay board (FT245, serial DAE00745) on macOS 26: list, status,
on, off, toggle, set, pulse, watch, --json, selection by serial, the
error when the board is already claimed, and relay state surviving between commands.
All of that holds; only the probe claim above was wrong.

21 new tests stub out the FTDI chip and the serial port, so they need no hardware and
run on every platform in CI. Only the macOS half of the backend has been exercised
against a board; Windows is untouched.

The 4 and 8 relay boards hang their relays off the data lines of the
board's FTDI chip, and the relay library reaches those lines through a
backend it picks by platform. It has one for Windows and one for Linux,
so on macOS it ends up with no backend at all and those boards could
only be refused.

Add a backend of the same shape written against pylibftdi, the library
the Linux one uses, which works just as well on macOS. It is put in
place of the library's own on everything but Windows, and differs from
it in two ways: it finds libftdi where Homebrew and MacPorts put it,
which is outside the paths ctypes searches, and it opens a board by its
whole serial number rather than by a prefix, so the board that --serial
picked is the board that gets driven.

Pass that serial number to the library instead of the port name. A
bit-banged board is not reached through its serial port at all, so the
port it was opened with was never going to find it.

Stop probing from writing to a board that must not be written to. A
bit-banged board is a FIFO wearing a serial port's clothes: 'ask//' left
the relays holding a '/', and the stream of zeroes that came back read
as a valid two byte reply, so the board was reported as a type16 with
sixteen relays that were not there. It gives itself away by handing over
bytes with nothing asked of it, which a board that answers a protocol
never does, so the port is now listened to first and only a port that
stays quiet is spoken to.

Tested against an 8 relay board (FT245) on macOS 26.
@Boernsman
Boernsman merged commit 1a00f84 into main Sep 9, 2026
11 checks passed
@Boernsman
Boernsman deleted the macos-bitbang-support branch September 9, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant