# Hardware bring-up status

Last updated: 2026-05-10

## Boards

Two Seeed XIAO nRF52840 Sense boards are in use.

| Role | Latest firmware | Stack |
|---|---|---|
| Bridge | `firmware/bridge-zephyr` | Zephyr / nRF Connect SDK + MPSL timeslots |
| Dongle | `firmware/bringup/xiao-nrf52840-radio-ack-dongle-test` | Arduino + Adafruit nRF52 + USB HID |

UF2 bootloader volume after a double-tap reset on either board:

```text
/Volumes/XIAO-SENSE
```

UF2 family:

```text
0x28860045
```

## Current state

End-to-end live BLE keyboard works:

```text
Mac/iPhone client → BLE → Tybe Zephyr Dev → MPSL timeslot →
raw 2.4 GHz TX → dongle USB HID → typed text on target
```

Validated:

- Live keyboard typing from the Mac GUI client (`tybe-client`) over BLE.
- Modifier combos (⌘ ⌃ ⌥ ⇧), arrow keys, enter / tab / esc / backspace.
- Caps Lock on the Mac forwards a `TOGGLE_INPUT_SOURCE` opcode.
- Compose mode (full string) over BLE: Korean and English.
- Per-frame BLE Status notification round-trips back to the client; the
  GUI surfaces it as the Bridge pill.
- Multi-frame chunking for long strings.
- Dongle duplicate-seq suppression so retries do not double-type.

Known limitations:

- Bridge currently treats radio TX completion as success
  (`WAIT_FOR_DONGLE_ACK = 0`). Dongle ACK reception inside the same MPSL
  timeslot is not yet wired in.
- No retry on ACK loss yet.
- Protocol still uses single-pulse `KEY` opcodes; rolling key
  (`KEY_DOWN`/`KEY_UP`/`MODIFIER_STATE`) is a planned protocol extension.

## Validated milestones

### 1. USB / UF2 bring-up

Validated:

- macOS detects the XIAO boards.
- UF2 bootloader works.
- Firmware can be built and copied to `/Volumes/XIAO-SENSE`.
- USB CDC serial works.

(Original probe firmware: `legacy/firmware/bringup/xiao-nrf52840-serial`.)

### 2. BLE bridge opcode sink

Validated:

```text
Mac BLE central → bridge BLE GATT → Status ACK
```

(Original ArduinoBLE prototype: `legacy/firmware/bringup/xiao-nrf52840-ble-opcode-sink`.)

### 3. USB HID dongle opcode executor

Validated:

```text
serial Tybe frame → dongle opcode executor → USB HID → typed output
```

(Original USB-only dongle: `legacy/firmware/bringup/xiao-nrf52840-usb-hid-dongle-test`.
Replaced by `firmware/bringup/xiao-nrf52840-radio-ack-dongle-test`, which
is the current production dongle.)

### 4. Raw radio bridge → dongle HID

Validated:

```text
bridge → nRF 2.4 GHz radio → dongle → USB HID → typed output
```

Validated targets:

- Mac TextEdit
- Android phone
- iPhone

(Original probes: `legacy/firmware/bringup/xiao-nrf52840-radio-tx-test`,
`legacy/firmware/bringup/xiao-nrf52840-radio-rx-dongle-test`.)

### 5. Raw radio dongle ACK

Validated:

```text
bridge radio TX → dongle radio RX → USB HID → dongle radio ACK(seq) → bridge radio RX ACK
```

(Original ACK probe: `legacy/firmware/bringup/xiao-nrf52840-radio-ack-bridge-test`.)

### 6. ArduinoBLE bridge → radio dongle HID

Validated, but with a coexistence caveat: ArduinoBLE owns the radio
peripheral, so the bridge had to disconnect/reset between BLE writes.

(`legacy/firmware/bringup/xiao-nrf52840-ble-to-radio-bridge-test`.)

### 7. Bluefruit/SoftDevice timeslot bridge

Validated TX-only path. Bridge-side dongle ACK reception inside the
SoftDevice timeslot proved unreliable.

(`legacy/firmware/bringup/xiao-nrf52840-bluefruit-timeslot-bridge-test`.)

### 8. Zephyr / NCS bridge with MPSL timeslot (current)

Validated:

```text
Mac/iPhone BLE central → bridge BLE GATT → MPSL timeslot →
raw radio TX → dongle USB HID → Status notify back to client
```

BLE connection stays alive across keystrokes. Bridge advertises as:

```text
Tybe Zephyr Dev
```

Active firmware:

```text
firmware/bridge-zephyr
firmware/bringup/xiao-nrf52840-radio-ack-dongle-test
```

## Current radio settings

```text
mode:       Nordic proprietary 2 Mbps
channel:    76
address:    E7 E7 E7 E7 E7
crc:        16-bit, poly 0x11021, init 0xFFFF
packet:     8-bit length + up to 255 bytes payload
```

## Useful commands

Build the active firmware:

```sh
firmware/bridge-zephyr/build.sh
firmware/bringup/xiao-nrf52840-radio-ack-dongle-test/build.sh
```

Flash via UF2 (after double-tap reset):

```sh
cp firmware/bridge-zephyr/build/zephyr/zephyr.uf2 /Volumes/XIAO-SENSE/
cp build/.../xiao-nrf52840-radio-ack-dongle-test.ino.uf2 /Volumes/XIAO-SENSE/
```

Send a Tybe text from the Mac CLI over BLE:

```sh
cd clients/swift-shared
swift run tybe-send "tybe"
swift run tybe-send "안녕하세요"
```

Run the Mac GUI:

```sh
swift run tybe-client
```

The GUI defaults to live keyboard over BLE against the bridge advertising
as `Tybe Zephyr Dev`.

## Next steps

1. Bridge-side dongle ACK in a follow-up MPSL timeslot, then wire retries.
2. Promote the dongle to a Zephyr target (`firmware/dongle-zephyr/`) for
   a unified build, or freeze the Arduino dongle and document its
   limitations.
3. Extend the protocol with `KEY_DOWN` / `KEY_UP` / `MODIFIER_STATE` for
   true rolling-key live input.
4. Port `TybeBLE` to iOS (Core Bluetooth code is identical) and ship a
   minimal iOS Tybe client.
5. Once iOS works, port the same GATT contract to an Android client.

Older bring-up notes referencing ArduinoBLE, the serial-relay path, and
the Bluefruit timeslot prototype are preserved in `legacy/` and described
under each milestone above.
