Firmware Architecture
The firmware runs on ESP32 hardware and is organized around small Process subclasses coordinated by a ProcessManager. A single WebSocketManager shares network connectivity, while CommandRegistry routes incoming commands to handlers.
High-level Diagram
flowchart LR
subgraph Core
PM[ProcessManager]
CR[CommandRegistry]
WS[WebSocketManager]
CFG[Configuration]
end
subgraph Processes
WIFI[WiFiProcess]
BLE[BLEProcess]
IMU[IMUProcess]
LED[LedProcess]
VIB[VibrationProcess]
PUB[PublishProcess]
RX[ReceiveProcess]
CFGP[ConfigurationProcess]
end
PM --> WIFI & BLE & IMU & LED & VIB & PUB & RX & CFGP
RX --> CR
CR --> LED & VIB & CFGP
IMU --> PUB
PUB --> WS
WS --> RX
Lifecycle (src/main.cpp)
sequenceDiagram
participant Main
participant PM as ProcessManager
participant WS as WebSocketManager
participant CR as CommandRegistry
Main->>Main: setup()
Main->>PM: addProcess(...), setupProcesses()
Main->>CR: registerGlobalCommands()
Main->>PM: haltProcess("ble") until WiFi connects
loop loop()
Main->>CFGP: configuration.update()
Main->>WIFI: check WiFi
Main->>PM: start/stop BLE based on WiFi
Main->>LED: set breathing / random color
Main->>WS: update()
Main->>PM: updateProcesses()
end
Key Components
- ProcessManager (
include/ProcessManager.h): holds a map of named processes, handles start/halt/setup/update. All processes must checkisProcessRunning()before doing work. - Processes:
WiFiProcess: manages Wi‑Fi connectivity; gates BLE startup.BLEProcess: scans for beacons; can be halted when offline.IMUProcess: captures accelerometer data.LedProcess: orchestrates LED behaviors (ledsBreathing, random colors on Wi‑Fi connect).VibrationProcess: triggers haptics for commands/events.PublishProcess: packages sensor readings for outbound frames.ReceiveProcess: listens for inbound WebSocket text/bin and forwards commands toCommandRegistry.ConfigurationProcess: handles configuration mode and persistence.- WebSocketManager (
include/WebSocketManager.h): parses thews://host:port/pathURL, reconnects every 5s if needed, and exposessendMessage,hasMessage,getMessage. - CommandRegistry (
include/CommandRegistry.h): maps command strings to handlers; used both globally (registerGlobalCommands) and by specific processes.
Stateful LEDs
When handling commands that change LEDs or vibration, update local state so diagnostics (status command) reflect reality.
Adding Features Safely
- Create a new
Processwhen you need periodic work or lifecycle hooks; avoid bloating existing ones. - Use
commandRegistry.registerCommandfor any external control surface—keep parsing/validation close to the handler. - Keep message formats stable: outbound frames are trimmed to 20 hex characters; if you add fields, update both the client parsers (
HitloopDevice.parseHexData) and the server relay if needed. - Maintain non-blocking
loop(); heavy tasks should be chunked across iterations or offloaded to timers.