Refactor ESP-NOW air protocol to nanopb protobuf.

Add esp_now_messages.proto with EspNowMessage types, encode/decode helpers,
and Makefile targets to regenerate firmware and UART schemas together.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-18 22:44:57 +02:00
co-authored by Cursor
parent 6cdca4f3ad
commit 755bdd92d7
9 changed files with 405 additions and 100 deletions
+16 -24
View File
@@ -64,30 +64,17 @@ Implementation: `esp_now_comm.c` / `esp_now_comm.h`.
WiFi is brought up in STA mode (no AP association). Channel = `app_config.network` (clamped to 113).
### Air protocol (compact binary, not protobuf)
### Air protocol (nanopb)
| Byte | Field |
|------|--------|
| 0 | Magic `0xA1` |
| 1 | Message type |
| 2 | Network ID (must match local config) |
| 3+ | Type-specific |
Schema: `proto/esp_now_messages.proto`. Encode/decode: `esp_now_proto.c`. The ESP-NOW payload is a single encoded `EspNowMessage` (no extra framing).
| Type | Value | Direction | Purpose |
|------|-------|-----------|---------|
| `DISCOVER` | 1 | Master → broadcast `FF:FF:FF:FF:FF:FF` | Master is searching for slaves |
| `SLAVE_INFO` | 2 | Slave → master | Slave registration |
| `HEARTBEAT` | 3 | Slave → master | Keep-alive (header only, no extra payload) |
| `EspNowMessageType` | Direction | `oneof` payload |
|---------------------|-----------|-----------------|
| `ESPNOW_DISCOVER` | Master → broadcast `FF:FF:FF:FF:FF:FF` | `EspNowDiscover` (`network`) |
| `ESPNOW_SLAVE_INFO` | Slave → master | `EspNowSlavePresence` |
| `ESPNOW_HEARTBEAT` | Slave → master | `EspNowSlavePresence` (same fields) |
`SLAVE_INFO` payload (after header bytes 02):
| Field | Type | Description |
|-------|------|-------------|
| `mac` | 6 bytes | Slave WiFi MAC |
| `version` | uint32 | `POWERPOD_FW_VERSION` (default 1) |
| `slave_id` | uint32 | Currently last byte of MAC |
| `available` | uint8 | 1 = available |
| `used` | uint8 | 0 = unused |
`EspNowSlavePresence`: `network`, `mac` (6 bytes), `version`, `slave_id`, `available`, `used`.
**Master:** task `espnow_disc` sends `DISCOVER` every **500 ms** on the configured network. Logs `slave joined id=… mac=… ver=…` when a new slave is seen (up to 16 entries). Task `espnow_mon` runs every **1 s** and marks a client **inactive** (`available = false`) if no `SLAVE_INFO` or `HEARTBEAT` was received for **3 s** (three missed 1 s heartbeats). A later heartbeat sets `available` true again and logs reactivation.
@@ -164,11 +151,14 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
Regenerate C code:
```bash
make proto_generate
# or individually:
make proto_generate_uart
# or:
python libs/nanopb/generator/nanopb_generator.py main/proto/uart_messages.proto
make proto_generate_espnow
```
After generation, ensure `main/proto/*.pb.c` includes use `#include "…pb.h"` (not `main/proto/…`).
Build embeds `POWERPOD_GIT_HASH` via `git rev-parse` in `main/CMakeLists.txt`.
### VERSION command
@@ -260,7 +250,9 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
| `cmd_client_info.c/h` | CLIENT_INFO handler |
| `client_registry.c/h` | Registered slave table |
| `led_ring.c/h` | LED digit display |
| `proto/uart_messages.proto` | Protocol schema |
| `proto/uart_messages.proto` | UART protocol schema |
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
| `esp_now_proto.c/h` | Encode/decode `EspNowMessage` |
| `proto/*.pb.c/h` | Generated nanopb |
| `CMakeLists.txt` | Sources, `esp_wifi`, drivers, git hash |