Skip to content
Agentmart
Submit a tool

cyton-dongle

Connect and stream from OpenBCI Cyton/Daisy via USB dongle, including first-time radio channel pairing

Skill by plurigrid

IndexedMIT★ 70
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/plurigrid-cyton-dongle

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Connect and stream from OpenBCI Cyton/Daisy via USB dongle, including first-time radio channel pairing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/cyton-dongle

What's inside

Skill name
cyton-dongle
Description
Connect and stream from OpenBCI Cyton/Daisy via USB dongle, including first-time radio channel pairing
License
MIT
Instructions
256 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Cyton Dongle

USB wireless receiver (RFD22301/RFDuino) for OpenBCI Cyton 8/16-channel EEG board.

## Hardware

- **Dongle**: FTDI FT231X USB-UART → RFDuino 2.4 GHz radio
- **Serial**: 115200 baud, 8N1
- **Device**: `/dev/cu.usbserial-*` (macOS) or `/dev/ttyUSB*` (Linux)
- **Sample Rate**: 250 Hz
- **Channels**: 8 (Cyton) or 16 (Cyton + Daisy)
- **Packet**: 33 bytes (0xA0 start, 24 bytes channel data, 6 bytes aux, 1 byte counter, 0xC0 stop)

## First-Time Pairing (Critical)

A new dongle and board are typically on **different radio channels**. The standard `0xF0 0x01` channel-set command requires both sides to handshake — it **fails when they're on different channels**.

Use `0xF0 0x02` (CHANNEL_SET_OVERRIDE) to force the dongle to each channel without requiring board response, then check system status:

```python
import serial, time

ser = serial.Serial('/dev/cu.usbserial-XXXXX', 115200, timeout=2)
time.sleep(2)

for chan in range(26):
    ser.reset_input_buffer()
    ser.write(bytes([0xF0, 0x02, chan]))  # override dongle (no handshake)
    time.sleep(0.5)
    ser.read(ser.in_waiting or 512)

    ser.reset_input_buffer()
    ser.write(bytes([0xF0, 0x07]))        # system status query
    time.sleep(0.5)
    resp = ser.read(ser.in_waiting or 512).decode('utf-8', errors='ignore')

    if 'System is Up' in resp:
        print(f'FOUND BOARD ON CHANNEL {chan}')
        break
    else:
        print(f'Ch {chan}: Down')

ser.close()
```

## Radio Commands (0xF0 prefix)

| Bytes | Command | Notes |
|-------|---------|-------|
| `0xF0 0x00` | CHANNEL_GET | Returns current dongle channel |
| `0xF0 0x01 <ch>` | CHANNEL_SET | Coordinated change, **requires board online** |
| `0xF0 0x02 <ch>` | CHANNEL_OVERRIDE | **Dongle-only, no handshake** — use for pairing |
| `0xF0 0x03` | POLL_TIME_GET | Current poll time |
| `0xF0 0x04 <t>` | POLL_TIME_SET | Set poll time |
| `0xF0 0x05` | BAUD_DEFAULT | 115200 |
| `0xF0 0x06` | BAUD_FAST | 230400 |
| `0xF0 0x07` | SYS_STATUS | "System is Up" or "System is Down" |
| `0xF0 0x0A` | BAUD_HYPER | 921600 |

Channels are 0-25. Default for new boards is usually 1.

## Serial Commands

| Cmd | Action |
|-----|--------|
| `v` | Firmware version + board info |
| `b` | Start binary streaming |
| `s` | Stop streaming |
| `C` | Enable Daisy (16ch mode) |
| `D` | Query Daisy module |
| `?` | Print ADS1299 registers |
| `1`-`8` | Default channel settings (ch 1-8) |
| `!`-`*` | Default channel settings (ch 9-16, Daisy) |
| `d` | Reset all channel defaults |

## Parsing Binary Packets

```python
SCALE_UV = 4.5 / (24 * (2**23 - 1)) * 1e6  # ~0.02235 uV/count

def parse_24bit(b0, b1, b2):
    val = (b0 << 16) | (b1 << 8) | b2
    return val - 0x1000000 if val >= 0x800000 else val
```

**33-byte packet**: `0xA0 | sample_num | 8×3-byte channels | 6-byte aux | 0xC0`

With Daisy: odd sample numbers = channels 1-8, even = channels 9-16.

## Streaming and Channel Quality Check

```python
import serial, time, math

ser = serial.Serial('/dev/cu.usbserial-XXXXX', 115200, timeout=5)
time.sleep(2)
ser.reset_input_buffer()

# Override to known channel
ser.write(bytes([0xF0, 0x02, CHANNEL]))
time.sleep(1)
ser.read(ser.in_waiting or 512)

# Reset board
ser.write(b'v')
time.sleep(3)
ser.read(ser.in_waiting or 4096)
ser.reset_input_buffer()

SCALE_UV = 4.5 / (24 * (2**23 - 1)) * 1e6

def p24(b0, b1, b2):
    v = (b0 << 16) | (b1 << 8) | b2
    return v - 0x1000000 if v >= 0x800000 else v

# Start stream
ser.write(b'b')
time.sleep(1.5)
ser.read(ser.in_waiting or 2048)  # drain text

From plurigrid/asi, MIT.

More from plurigrid/asi

Signals

Stars
70
Forks
13
Open issues
3
Last commit (this folder)
Mar 28, 2026 (7 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from plurigrid

Cite this page

cyton-dongle skill. Agent Mart. https://agentmart.dev/skills/plurigrid-cyton-dongle (last updated 2026-10-24)