An open-source arcade control panel: 16 buttons, 11 dimmable LEDs, an OLED menu, and a desktop app to configure all of it.
Download · Features · Quick start · BLAST protocol · Building · Contributing
B.L.A.S.T. is the button box that sits next to your lightgun or arcade cabinet. It presents itself to the PC as a plain USB keyboard, so every game and emulator understands it without drivers. Each game gets its own profile of key bindings, which you pick on the built-in OLED or let your frontend switch automatically. The button LEDs can be driven live by the game (blink the coin button, breathe the start button, flash on a hit) over a simple text protocol.
It's a full stack in one repo:
| Component | Stack | |
|---|---|---|
| 🧠 | Firmware | C++ / Arduino on a Raspberry Pi Pico (RP2040 / RP2350) |
| 🖥️ | Config app | Rust + Slint, native on Linux, Windows and macOS |
| 🔌 | PCB | KiCad schematic, layout and production files |
|
|
|
|
-
Grab the latest release from the Releases page:
File What it is blast-firmware-X.Y.Z.uf2Firmware for the controller blast-app-X.Y.Z-linux-x86_64.tar.gzConfig app for Linux blast-app-X.Y.Z-windows-x86_64.zipConfig app for Windows blast-app-X.Y.Z-macos-universal.tar.gzConfig app for macOS (Apple Silicon + Intel) -
Flash the firmware: hold BOOTSEL while plugging in the Pico and drop the
.uf2onto theRPI-RP2drive that shows up. -
Run the app, pick the B.L.A.S.T. port (it's preselected), and create your first profile.
-
Play. Choose the profile on the OLED, or let your frontend switch to it.
Tip
Use the app and firmware from the same release. The app shows a warning in the status bar when they differ. Builds labeled 0.0.0+<commit> are unofficial development builds.
Out of the box the serial port speaks the BLAST protocol: one line of plain ASCII per command, with no handshake and no replies. Anything that can write to a serial port can drive the LEDs.
stty -F /dev/ttyACM0 115200 raw -echo
printf 'B1\n' > /dev/ttyACM0 # host started: all LEDs off
printf 'BLxtcrisis\n' > /dev/ttyACM0 # load the profile for "tcrisis"
printf 'B4x0x2x200\n' > /dev/ttyACM0 # both coin buttons blink fast
printf 'B3x1x4x1500\n' > /dev/ttyACM0 # P1 start breathes with a 3 s cycle
printf 'B5x2x3x5\n' > /dev/ttyACM0 # P2 action A flashes 5 timesThe full spec is in firmware/BLAST_PROTOCOL.md.
flowchart LR
subgraph PC["🖥️ PC"]
game["Game / emulator"]
hook["LED output tool<br/>(e.g. MAMEHooker)"]
app["B.L.A.S.T. config app"]
end
subgraph Pico["🧠 RP2040 / RP2350"]
fw["Firmware"]
end
fw -- "USB HID keystrokes" --> game
hook -- "BLAST text protocol<br/>(USB serial)" --> fw
app <-- "SLIP binary protocol<br/>(same USB serial)" --> fw
fw --- mcp["MCP23017<br/>16 buttons"]
fw --- tlc["TLC59711<br/>12 LED channels"]
fw --- oled["SSD1306<br/>128×64 OLED"]
One USB cable carries both the keyboard and the serial port. The serial port runs one of two protocols at a time: the BLAST text protocol for games (the default), or the binary SLIP protocol that the config app switches to while it's connected. The OLED shows which one is active (B or S).
🔩 Hardware bill of materials
| Part | Role | Interface |
|---|---|---|
| Raspberry Pi Pico (W) / RP2350 | Main MCU | – |
| MCP23017 | 16 button inputs, active-low with pull-ups | I²C 0x20 + interrupt |
| TLC59711 | 12-channel 16-bit PWM LED driver | Bit-banged SPI (GP6 / GP7) |
| SSD1306 | 128×64 OLED | I²C 0x3C |
| RGB LED | Status indicator | GPIO |
KiCad sources and fabrication outputs (BOM, positions, netlist) are in pcb/blast/.
🗂️ Repository layout
blast/
├── firmware/ # Arduino/C++ firmware for RP2040/RP2350
│ ├── firmware.ino # Entry point, pin map, button + LED handling
│ ├── blast_protocol.* # BLAST text protocol (host LED control)
│ ├── serializer.* # SLIP binary protocol (config app)
│ ├── menu.* # OLED menu state machine
│ ├── debounce_mcp.* # MCP23017 debouncing
│ ├── storage.* # Profile persistence and migrations
│ └── flash.sh # One-shot flashing via picotool
├── app/ # Rust/Slint configuration tool
│ ├── ui/app.slint # UI definition
│ └── src/ # ui.rs, protocol.rs, slip.rs, types.rs, keymap.rs
├── pcb/blast/ # KiCad project + production files
├── scripts/ # version.sh, changelog.sh, test.sh
└── .github/workflows/ # CI, release-start, release-finish
🖥️ Config app (Rust)
Requirements: Rust 1.92+ (needed by Slint 1.18). On Linux you also need libudev-dev, libfontconfig-dev and pkg-config.
cd app
cargo run --release # build and launch
cargo test # unit tests
cargo clippy # lint (warnings fail CI)
cargo fmt --check # formatting check🧠 Firmware (Arduino-Pico)
Requirements:
-
Arduino-Pico core by Earle F. Philhower, III, version 6.1.1
Boards Manager URL:https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json -
Libraries:
Library Version Adafruit MCP23017 Arduino Library 2.3.2 Adafruit SSD1306 2.5.16 Adafruit GFX Library 1.12.4 Adafruit BusIO 1.17.4 Wire, SPI, EEPROM, Keyboard, HID_Keyboard and tusb-hid ship with the Arduino-Pico core.
With arduino-cli (from the repo root, same as CI):
arduino-cli compile \
--fqbn "$(jq -r '.board + ":" + .configuration' .vscode/arduino.json)" \
--output-dir _build firmware/firmware.ino
cd firmware && ./flash.sh # finds the controller by VID/PID, reboots it into the bootloader, flashes it[!IMPORTANT] Always build with the full FQBN from
.vscode/arduino.json. It selects the Pico W boot stage and the 128 KB filesystem layout. With another flash layout the stored profiles are lost.
With the Arduino IDE: open firmware/firmware.ino, select the Raspberry Pi Pico W board (Arduino-Pico core) with a 128 KB filesystem and the Pico SDK USB stack, then upload.
Contributions are welcome! The project uses GitFlow: branch feature/* off develop and open a PR back to develop. CI builds the app on all three platforms, builds the firmware and runs the linters on every push.
- 📖 GITFLOW.md: branching, versioning and releases
- ⚙️ .github/WORKFLOWS.md: the CI/CD pipelines
- 📝 CHANGELOG.md: add your change under
## [Unreleased]
B.L.A.S.T. is released under the MIT License.
The configuration tool's user interface is built with Slint, used under the Slint Royalty-free Desktop, Mobile, and Web Applications License 2.0. The app also shows the Slint attribution under Help → About B.L.A.S.T.
🪙 INSERT COIN TO CONTINUE 🪙
Made with 🔥 for light gun fans.
USE AT YOUR OWN RISK
This software and firmware are provided "AS IS" without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement.
Important Notes:
- The developers and contributors of this project assume no liability for any damages, losses, or issues arising from the use, misuse, or inability to use this software or hardware
- This includes, but is not limited to: hardware damage, data loss, system malfunction, or any other direct or indirect consequences
- By using this software, you acknowledge that you do so at your own risk
- Users are responsible for ensuring compatibility with their systems and compliance with local regulations
- This project is an independent effort and is not affiliated with or endorsed by any hardware manufacturer unless explicitly stated
For Hobbyist and Educational Use:
This project is intended for personal, educational, and hobbyist use. Users modifying firmware or hardware configurations should have appropriate technical knowledge and accept full responsibility for their modifications.
If you're unsure about any aspect of installation or use, please consult the documentation or seek assistance from knowledgeable individuals before proceeding.