Max — Firmware Data Flows

ESP32-S3 (V3/V4) — FreeRTOS task architecture and message routing

Segment 1: 4-Phase Boot Sequence (Splash Within 500ms)

Phase 1 HAL Init GPIO, UART Phase 2 Managers Power, NVS Phase 3 Radio Init LoRa, WiFi Phase 4 + OLED Splash User sees ✓ 0ms 100ms 250ms 500ms SPLASH
Boot flow: ESP32 ROM bootloader → Arduino Setup → Phase 1 (GPIO, UART ready) → Phase 2 (Power manager, NVS init, settle) → Phase 3 (Radio subsystems: LoRa, WiFi, BLE) → Phase 4 (remaining services) + OLED splash visible within 500ms window. User sees proof of life before any RF touches power rail.

Segment 2: FreeRTOS Task Scheduling (4 Concurrent Tasks)

Core 0 Radio Task Priority 3 Mesh Task Priority 2 Probe Task Priority 1 Display Task Priority 1 Message Router Active Managers • CommandManager • LoRaManager • WiFiManager • ScheduleManager • Heartbeat (2s/5m) • PowerManager • BLETransport loop() { /* idle */ FreeRTOS scheduler runs all tasks }
Task architecture: Four FreeRTOS tasks (Radio, Mesh, Probe, Display) run concurrently on Core 0. Each task can block on events (DIO1 ISR, timer, socket). Message Router is singleton — all inter-task communication flows through it. No polling loops; all wake via ISR/event. Heartbeat is event-driven via `kick()` calls, not periodic ticks. Arduino `loop()` stays empty — FreeRTOS scheduler owns the CPU.
void loop() { /* empty — FreeRTOS manages everything */ } // Tasks wake on: // - ISR (DIO1 LoRa, button GPIO) // - Socket ready (WiFi, BLE, MQTT) // - Semaphore/event flag (CommandManager, etc.)

Segment 3: Incoming Data — Commands & Sensor Readings

Data Sources LoRa BLE WiFi MQTT Serial GPIO Command Manager (Any→Any Router) Execution Execute (Relay, GPIO) Collect (Telemetry)
Data ingress: Commands arrive from six transport layers (LoRa, BLE GATT, WiFi HTTP API, MQTT subscribe, Serial CLI, GPIO button) → CommandManager deserialized them (converts bytes → ControlPacket) → Routes to correct handler (RelayManager, ScheduleManager, etc.) → Handler executes action (relay state, schedule task) or publishes telemetry. All transport handlers are bidirectional; responses flow back out same transport.

Segment 4: Outgoing Data — Telemetry & Status Broadcasting

Telemetry Builders StatusBuilder HeartbeatBuilder ConfigSnapshot (JSON) Message Serializer (MsgPack) Broadcast LoRa TX BLE Adv WiFi MQTT Pub HTTP /api Serial UART
Data egress: StatusBuilder, HeartbeatBuilder, ConfigSnapshot construct JSON/MessagePack telemetry snapshots → Message Serializer encodes per-transport format → Broadcasts simultaneously to all active transports (LoRa TX, BLE advertising, WiFi `/api/status`, MQTT publish, Serial output). Broadcast happens every heartbeat interval (2s when active, 5min idle). If a transport is down (WiFi disconnected, BLE not connected), that path is skipped — no error.

Segment 5: Complete Firmware Cycle — Command → Execute → Telemetry

User sends BLE RX Deserialize Command Manager Execute Relay/GPIO Build Status LoRa BLE Adv WiFi MQTT T+0ms: RX T+5ms: Route T+10ms: Execute T+20ms: Broadcast ✓
Complete cycle (latency ~20ms): User command arrives via BLE (or any transport) → BLE layer deserializes → CommandManager routes to handler (RelayManager, ScheduleManager, etc.) → Handler executes action (set relay GPIO, schedule task) → Parallel: StatusBuilder captures new state → Message Serializer broadcasts new status to all transports (LoRa, BLE advertising, WiFi `/api/status`, MQTT, Serial) within ~20ms. User sees state change reflected immediately in app, dashboard, or third-party systems listening on MQTT.