Skip to content

BLE Protocol

BLE Protocol

This document specifies the Bluetooth Low Energy (BLE) communication between ESP32 child modules and the Raspberry Pi parent hub.

Overview

Each ESP32 child module runs a BLE GATT server that:

  1. Advertises its presence
  2. Accepts connections from the parent hub
  3. Sends button state updates via notifications

GATT Service Structure

OpenArcade Input Service
├── UUID: 666f7065-6e41-7263-6164-65000000000
├── Input State Characteristic
│ ├── UUID: 666f7065-6e41-7263-6164-65000000001
│ ├── Properties: Read, Notify
│ └── Value: 4-byte state packet
└── Device Info Characteristic (optional)
├── UUID: 666f7065-6e41-7263-6164-65000000002
├── Properties: Read
└── Value: Device metadata

Connection Parameters

ParameterValueNotes
Advertising interval20-40msFast discovery
Connection interval7.5-15msLow latency
Slave latency0No skipped events
Supervision timeout2000msReasonable disconnect detection

Button State Packet Format

The ESP32 sends a 4-byte packet on every state change:

┌─────────────────────────────────────────────────────────────────────────────┐
│ Byte 0 │ Byte 1 │ Byte 2 │ Byte 3 │
├─────────────────────────────────────────────────────────────────────────────┤
│ [b8][b7][b6][b5]│ [jD][jU][jR][jL]│ [--][--][PA][ST]│ [reserved] │
│ [b4][b3][b2][b1]│ [--][--][--][--]│ [--][--][--][SE]│ │
└─────────────────────────────────────────────────────────────────────────────┘

Byte 0: Action Buttons

BitButton
0Button 1
1Button 2
2Button 3
3Button 4
4Button 5
5Button 6
6Button 7
7Button 8

Byte 1: Joystick Directions

BitDirection
0Left
1Right
2Up
3Down

Byte 2: System Buttons

BitButton
0Select
1Start
2Pair

Byte 3

Reserved for future use (always 0x00).

Communication Flow

Discovery Phase

┌──────────┐ ┌──────────┐
│ ESP32 │ │ RPi │
└────┬─────┘ └────┬─────┘
│ │
│──── BLE Advertisement ────────────────►│
│ "NimBLE_GATT" │
│ │
│◄──────── Connection Request ───────────│
│ │
│──── Connection Established ───────────►│
│ │
│◄──────── GATT Discovery ───────────────│
│ │
│──── Service/Char UUIDs ───────────────►│
│ │
│◄──────── Subscribe to Notifications ───│
│ │

Input Phase

┌──────────┐ ┌──────────┐
│ ESP32 │ │ RPi │
└────┬─────┘ └────┬─────┘
│ │
│ [Button Press Detected] │
│ │
│──── GATT Notification (4 bytes) ──────►│
│ │
│ [Update State Map] │
│ │
│ [Button Release Detected] │
│ │
│──── GATT Notification (4 bytes) ──────►│
│ │

High-Level Protocol (Future)

The protocol also defines higher-level packet types for future features:

ValueNameDirectionPurpose
0x01HELLOChild→ParentAnnounce capabilities on boot
0x02CONFIGParent→ChildAssign offset, debounce, rate
0x03CONFIG_ACKChild→ParentAccept/reject config
0x04INPUTChild→ParentRegular bitfield packet
0x05HEARTBEATChild→ParentKeepalive if no INPUT sent
0x06INFOBidirectionalDiagnostics, version info

HELLO Payload (Future)

struct hello_payload {
uint8_t version; // Protocol minor version
uint8_t reserved; // Alignment
uint8_t num_buttons; // Local button count (1-64)
uint8_t capability_flags; // ANALOG(1), ENCODER(2), etc
uint32_t unique_id; // Hardware ID (0 if not present)
uint16_t fw_ver; // Firmware version
};

Error Handling

EventBehavior
DisconnectionReconnect with exponential backoff
No notifications for 5sSend heartbeat
Invalid packetLog and ignore
CRC mismatchDrop packet, continue

Next Steps