From 755bdd92d71f4bd215c2985d5ab431c06653116b Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 18 May 2026 22:44:57 +0200 Subject: [PATCH] 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 --- Makefile | 5 + main/CMakeLists.txt | 3 + main/README.md | 40 +++----- main/esp_now_comm.c | 159 ++++++++++++++++-------------- main/esp_now_proto.c | 94 ++++++++++++++++++ main/esp_now_proto.h | 26 +++++ main/proto/esp_now_messages.pb.c | 20 ++++ main/proto/esp_now_messages.pb.h | 126 +++++++++++++++++++++++ main/proto/esp_now_messages.proto | 32 ++++++ 9 files changed, 405 insertions(+), 100 deletions(-) create mode 100644 main/esp_now_proto.c create mode 100644 main/esp_now_proto.h create mode 100644 main/proto/esp_now_messages.pb.c create mode 100644 main/proto/esp_now_messages.pb.h create mode 100644 main/proto/esp_now_messages.proto diff --git a/Makefile b/Makefile index eebe970..3f2f1bd 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,8 @@ default: proto_generate_uart: python libs/nanopb/generator/nanopb_generator.py main/proto/uart_messages.proto + +proto_generate_espnow: + python libs/nanopb/generator/nanopb_generator.py main/proto/esp_now_messages.proto + +proto_generate: proto_generate_uart proto_generate_espnow diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2da29eb..590f4f2 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -18,8 +18,11 @@ idf_component_register( "cmd_client_info.c" "client_registry.c" "esp_now_comm.c" + "esp_now_proto.c" "proto/uart_messages.pb.c" + "proto/esp_now_messages.pb.c" "proto/pb_encode.c" + "proto/pb_decode.c" "proto/pb_common.c" INCLUDE_DIRS "." diff --git a/main/README.md b/main/README.md index eb4a295..4967471 100644 --- a/main/README.md +++ b/main/README.md @@ -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 1–13). -### 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 0–2): - -| 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 | diff --git a/main/esp_now_comm.c b/main/esp_now_comm.c index 37acc47..b3ec608 100644 --- a/main/esp_now_comm.c +++ b/main/esp_now_comm.c @@ -1,5 +1,6 @@ #include "client_registry.h" #include "esp_now_comm.h" +#include "esp_now_proto.h" #include "esp_err.h" #include "esp_event.h" #include "esp_log.h" @@ -17,10 +18,6 @@ #define POWERPOD_FW_VERSION 1u #endif -#define ESPNOW_MAGIC 0xA1 -#define ESPNOW_MSG_DISCOVER 1 -#define ESPNOW_MSG_SLAVE_INFO 2 -#define ESPNOW_MSG_HEARTBEAT 3 #define ESPNOW_DISCOVER_INTERVAL_MS 500 #define ESPNOW_HEARTBEAT_INTERVAL_MS 1000 #define ESPNOW_HEARTBEAT_MISS_COUNT 3 @@ -33,24 +30,6 @@ static const uint8_t ESPNOW_BCAST[ESP_NOW_ETH_ALEN] = {0xff, 0xff, 0xff, static const char *TAG = "[ESPNOW]"; -typedef struct __attribute__((packed)) { - uint8_t magic; - uint8_t type; - uint8_t network; - uint8_t reserved; -} espnow_discover_packet_t; - -typedef struct __attribute__((packed)) { - uint8_t magic; - uint8_t type; - uint8_t network; - uint8_t mac[ESP_NOW_ETH_ALEN]; - uint32_t version; - uint32_t slave_id; - uint8_t available; - uint8_t used; -} espnow_slave_packet_t; - static app_config_t s_config; static uint8_t s_wifi_channel; static uint8_t s_own_mac[ESP_NOW_ETH_ALEN]; @@ -98,30 +77,54 @@ static esp_err_t ensure_peer(const uint8_t *mac) { static esp_err_t ensure_broadcast_peer(void) { return ensure_peer(ESPNOW_BCAST); } -static void build_slave_packet(espnow_slave_packet_t *pkt, uint8_t type) { - pkt->magic = ESPNOW_MAGIC; - pkt->type = type; - pkt->network = s_config.network; - memcpy(pkt->mac, s_own_mac, ESP_NOW_ETH_ALEN); - pkt->version = POWERPOD_FW_VERSION; - pkt->slave_id = s_own_mac[5]; - pkt->available = 1; - pkt->used = 0; +static void fill_presence(alox_EspNowSlavePresence *presence) { + presence->network = s_config.network; + presence->version = POWERPOD_FW_VERSION; + presence->slave_id = s_own_mac[5]; + presence->available = true; + presence->used = false; + esp_now_proto_setup_presence_encode(presence, s_own_mac); } -static void send_slave_packet(const uint8_t *dest_mac, uint8_t type) { - espnow_slave_packet_t pkt; - build_slave_packet(&pkt, type); +static esp_err_t send_message(const uint8_t *dest_mac, + const alox_EspNowMessage *msg) { + uint8_t buf[ESPNOW_PB_MAX_SIZE]; + size_t len = 0; + + esp_err_t err = esp_now_proto_encode(msg, buf, sizeof(buf), &len); + if (err != ESP_OK) { + ESP_LOGW(TAG, "encode failed"); + return err; + } if (ensure_peer(dest_mac) != ESP_OK) { - return; + return ESP_FAIL; } - esp_err_t err = esp_now_send(dest_mac, (const uint8_t *)&pkt, sizeof(pkt)); + err = esp_now_send(dest_mac, buf, len); if (err != ESP_OK) { - ESP_LOGW(TAG, "send type=%u failed: %s", (unsigned)type, + ESP_LOGW(TAG, "send type=%u failed: %s", (unsigned)msg->type, esp_err_to_name(err)); } + return err; +} + +static void send_presence(const uint8_t *dest_mac, + alox_EspNowMessageType type) { + alox_EspNowMessage msg = alox_EspNowMessage_init_zero; + alox_EspNowSlavePresence *presence = NULL; + + msg.type = type; + if (type == alox_EspNowMessageType_ESPNOW_SLAVE_INFO) { + msg.which_payload = alox_EspNowMessage_slave_info_tag; + presence = &msg.payload.slave_info; + } else { + msg.which_payload = alox_EspNowMessage_heartbeat_tag; + presence = &msg.payload.heartbeat; + } + + fill_presence(presence); + send_message(dest_mac, &msg); } static void slave_reset_join(void) { @@ -130,15 +133,16 @@ static void slave_reset_join(void) { s_last_discover_ms = 0; } -static void handle_client_packet(const espnow_slave_packet_t *pkt) { - if (pkt->network != s_config.network) { +static void handle_client_presence(const alox_EspNowSlavePresence *presence, + const uint8_t mac[CLIENT_MAC_LEN]) { + if (presence->network != s_config.network) { return; } bool is_new = false; bool reactivated = false; esp_err_t err = client_registry_heartbeat( - pkt->mac, pkt->slave_id, pkt->version, pkt->used != 0, &is_new, + mac, presence->slave_id, presence->version, presence->used, &is_new, &reactivated); if (err != ESP_OK) { ESP_LOGW(TAG, "client registry full"); @@ -146,20 +150,20 @@ static void handle_client_packet(const espnow_slave_packet_t *pkt) { } char mac_str[18]; - mac_to_str(pkt->mac, mac_str, sizeof(mac_str)); + mac_to_str(mac, mac_str, sizeof(mac_str)); if (is_new) { ESP_LOGI(TAG, "client registered id=%lu mac=%s ver=%lu", - (unsigned long)pkt->slave_id, mac_str, - (unsigned long)pkt->version); + (unsigned long)presence->slave_id, mac_str, + (unsigned long)presence->version); } else if (reactivated) { ESP_LOGI(TAG, "client reconnected id=%lu mac=%s", - (unsigned long)pkt->slave_id, mac_str); + (unsigned long)presence->slave_id, mac_str); } } static void handle_discover(const uint8_t *sender_mac, - const espnow_discover_packet_t *pkt) { - if (pkt->network != s_config.network) { + const alox_EspNowDiscover *discover) { + if (discover->network != s_config.network) { return; } @@ -183,9 +187,10 @@ static void handle_discover(const uint8_t *sender_mac, char mac_str[18]; mac_to_str(sender_mac, mac_str, sizeof(mac_str)); - ESP_LOGI(TAG, "joined network %u, master %s", (unsigned)pkt->network, mac_str); + ESP_LOGI(TAG, "joined network %u, master %s", (unsigned)discover->network, + mac_str); - send_slave_packet(sender_mac, ESPNOW_MSG_SLAVE_INFO); + send_presence(sender_mac, alox_EspNowMessageType_ESPNOW_SLAVE_INFO); } static void slave_check_master_timeout(void) { @@ -220,7 +225,7 @@ static void slave_heartbeat_task(void *param) { continue; } - send_slave_packet(s_master_mac, ESPNOW_MSG_HEARTBEAT); + send_presence(s_master_mac, alox_EspNowMessageType_ESPNOW_HEARTBEAT); } } @@ -238,51 +243,53 @@ static void master_monitor_task(void *param) { static void espnow_recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) { - if (info == NULL || data == NULL || len < 3) { + if (info == NULL || data == NULL || len <= 0) { return; } - if (data[0] != ESPNOW_MAGIC) { + alox_EspNowMessage msg = alox_EspNowMessage_init_zero; + uint8_t peer_mac[CLIENT_MAC_LEN]; + + esp_now_proto_setup_message_decode(&msg, peer_mac); + if (esp_now_proto_decode(data, (size_t)len, &msg) != ESP_OK) { return; } - switch (data[1]) { - case ESPNOW_MSG_DISCOVER: - if (!s_config.master && len >= (int)sizeof(espnow_discover_packet_t)) { - handle_discover(info->src_addr, - (const espnow_discover_packet_t *)data); + if (!s_config.master) { + if (msg.type != alox_EspNowMessageType_ESPNOW_DISCOVER || + msg.which_payload != alox_EspNowMessage_discover_tag) { + return; } - break; - case ESPNOW_MSG_SLAVE_INFO: - case ESPNOW_MSG_HEARTBEAT: - if (s_config.master && len >= (int)sizeof(espnow_slave_packet_t)) { - handle_client_packet((const espnow_slave_packet_t *)data); - } - break; - default: - break; + handle_discover(info->src_addr, &msg.payload.discover); + return; } + + const alox_EspNowSlavePresence *presence = esp_now_proto_get_presence(&msg); + if (presence == NULL) { + return; + } + + if (msg.type != alox_EspNowMessageType_ESPNOW_SLAVE_INFO && + msg.type != alox_EspNowMessageType_ESPNOW_HEARTBEAT) { + return; + } + + handle_client_presence(presence, peer_mac); } static void master_discover_task(void *param) { (void)param; - espnow_discover_packet_t pkt = { - .magic = ESPNOW_MAGIC, - .type = ESPNOW_MSG_DISCOVER, - .network = s_config.network, - .reserved = 0, - }; + alox_EspNowMessage msg = alox_EspNowMessage_init_zero; + msg.type = alox_EspNowMessageType_ESPNOW_DISCOVER; + msg.which_payload = alox_EspNowMessage_discover_tag; + msg.payload.discover.network = s_config.network; ESP_LOGI(TAG, "master discover task on network %u ch %u", (unsigned)s_config.network, (unsigned)s_wifi_channel); while (1) { - esp_err_t err = - esp_now_send(ESPNOW_BCAST, (const uint8_t *)&pkt, sizeof(pkt)); - if (err != ESP_OK) { - ESP_LOGW(TAG, "discover broadcast failed: %s", esp_err_to_name(err)); - } + send_message(ESPNOW_BCAST, &msg); vTaskDelay(pdMS_TO_TICKS(ESPNOW_DISCOVER_INTERVAL_MS)); } } diff --git a/main/esp_now_proto.c b/main/esp_now_proto.c new file mode 100644 index 0000000..53940aa --- /dev/null +++ b/main/esp_now_proto.c @@ -0,0 +1,94 @@ +#include "esp_now_proto.h" +#include "client_registry.h" +#include "pb_decode.h" +#include "pb_encode.h" +#include + +static bool encode_mac(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + const uint8_t *mac = (const uint8_t *)*arg; + if (mac == NULL) { + return true; + } + if (!pb_encode_tag_for_field(stream, field)) { + return false; + } + return pb_encode_string(stream, mac, CLIENT_MAC_LEN); +} + +static bool decode_mac(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + (void)field; + uint8_t *mac = (uint8_t *)*arg; + if (mac == NULL) { + return false; + } + if (stream->bytes_left > CLIENT_MAC_LEN) { + return false; + } + return pb_read(stream, mac, stream->bytes_left); +} + +esp_err_t esp_now_proto_encode(const alox_EspNowMessage *msg, uint8_t *buf, + size_t buf_size, size_t *out_len) { + if (msg == NULL || buf == NULL || out_len == NULL || buf_size == 0) { + return ESP_ERR_INVALID_ARG; + } + + pb_ostream_t stream = pb_ostream_from_buffer(buf, buf_size); + if (!pb_encode(&stream, alox_EspNowMessage_fields, msg)) { + return ESP_FAIL; + } + + *out_len = stream.bytes_written; + return ESP_OK; +} + +void esp_now_proto_setup_presence_encode(alox_EspNowSlavePresence *presence, + const uint8_t mac[6]) { + if (presence == NULL) { + return; + } + presence->mac.funcs.encode = encode_mac; + presence->mac.arg = (void *)mac; +} + +void esp_now_proto_setup_message_decode(alox_EspNowMessage *msg, + uint8_t mac_out[6]) { + if (msg == NULL || mac_out == NULL) { + return; + } + msg->payload.slave_info.mac.funcs.decode = decode_mac; + msg->payload.slave_info.mac.arg = mac_out; + msg->payload.heartbeat.mac.funcs.decode = decode_mac; + msg->payload.heartbeat.mac.arg = mac_out; +} + +esp_err_t esp_now_proto_decode(const uint8_t *data, size_t len, + alox_EspNowMessage *msg) { + if (data == NULL || msg == NULL || len == 0) { + return ESP_ERR_INVALID_ARG; + } + + pb_istream_t stream = pb_istream_from_buffer(data, len); + if (!pb_decode(&stream, alox_EspNowMessage_fields, msg)) { + return ESP_FAIL; + } + return ESP_OK; +} + +const alox_EspNowSlavePresence * +esp_now_proto_get_presence(const alox_EspNowMessage *msg) { + if (msg == NULL) { + return NULL; + } + + switch (msg->which_payload) { + case alox_EspNowMessage_slave_info_tag: + return &msg->payload.slave_info; + case alox_EspNowMessage_heartbeat_tag: + return &msg->payload.heartbeat; + default: + return NULL; + } +} diff --git a/main/esp_now_proto.h b/main/esp_now_proto.h new file mode 100644 index 0000000..1f4da48 --- /dev/null +++ b/main/esp_now_proto.h @@ -0,0 +1,26 @@ +#ifndef ESP_NOW_PROTO_H +#define ESP_NOW_PROTO_H + +#include "esp_err.h" +#include "esp_now_messages.pb.h" +#include +#include + +#define ESPNOW_PB_MAX_SIZE 250 + +esp_err_t esp_now_proto_encode(const alox_EspNowMessage *msg, uint8_t *buf, + size_t buf_size, size_t *out_len); + +esp_err_t esp_now_proto_decode(const uint8_t *data, size_t len, + alox_EspNowMessage *msg); + +void esp_now_proto_setup_presence_encode(alox_EspNowSlavePresence *presence, + const uint8_t mac[6]); + +void esp_now_proto_setup_message_decode(alox_EspNowMessage *msg, + uint8_t mac_out[6]); + +const alox_EspNowSlavePresence * +esp_now_proto_get_presence(const alox_EspNowMessage *msg); + +#endif diff --git a/main/proto/esp_now_messages.pb.c b/main/proto/esp_now_messages.pb.c new file mode 100644 index 0000000..939f833 --- /dev/null +++ b/main/proto/esp_now_messages.pb.c @@ -0,0 +1,20 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-1.0.0-dev */ + +#include "esp_now_messages.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(alox_EspNowDiscover, alox_EspNowDiscover, AUTO) + + +PB_BIND(alox_EspNowSlavePresence, alox_EspNowSlavePresence, AUTO) + + +PB_BIND(alox_EspNowMessage, alox_EspNowMessage, AUTO) + + + + + diff --git a/main/proto/esp_now_messages.pb.h b/main/proto/esp_now_messages.pb.h new file mode 100644 index 0000000..2eb3257 --- /dev/null +++ b/main/proto/esp_now_messages.pb.h @@ -0,0 +1,126 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-1.0.0-dev */ + +#ifndef PB_ALOX_MAIN_PROTO_ESP_NOW_MESSAGES_PB_H_INCLUDED +#define PB_ALOX_MAIN_PROTO_ESP_NOW_MESSAGES_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _alox_EspNowMessageType { + alox_EspNowMessageType_ESPNOW_UNKNOWN = 0, + alox_EspNowMessageType_ESPNOW_DISCOVER = 1, + alox_EspNowMessageType_ESPNOW_SLAVE_INFO = 2, + alox_EspNowMessageType_ESPNOW_HEARTBEAT = 3 +} alox_EspNowMessageType; + +/* Struct definitions */ +typedef struct _alox_EspNowDiscover { + uint32_t network; +} alox_EspNowDiscover; + +typedef struct _alox_EspNowSlavePresence { + uint32_t network; + pb_callback_t mac; + uint32_t version; + uint32_t slave_id; + bool available; + bool used; +} alox_EspNowSlavePresence; + +typedef struct _alox_EspNowMessage { + alox_EspNowMessageType type; + pb_size_t which_payload; + union _alox_EspNowMessage_payload { + alox_EspNowDiscover discover; + alox_EspNowSlavePresence slave_info; + alox_EspNowSlavePresence heartbeat; + } payload; +} alox_EspNowMessage; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN +#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_HEARTBEAT +#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_HEARTBEAT+1)) + + + +#define alox_EspNowMessage_type_ENUMTYPE alox_EspNowMessageType + + +/* Initializer values for message structs */ +#define alox_EspNowDiscover_init_default {0} +#define alox_EspNowSlavePresence_init_default {0, {{NULL}, NULL}, 0, 0, 0, 0} +#define alox_EspNowMessage_init_default {_alox_EspNowMessageType_MIN, 0, {alox_EspNowDiscover_init_default}} +#define alox_EspNowDiscover_init_zero {0} +#define alox_EspNowSlavePresence_init_zero {0, {{NULL}, NULL}, 0, 0, 0, 0} +#define alox_EspNowMessage_init_zero {_alox_EspNowMessageType_MIN, 0, {alox_EspNowDiscover_init_zero}} + +/* Field tags (for use in manual encoding/decoding) */ +#define alox_EspNowDiscover_network_tag 1 +#define alox_EspNowSlavePresence_network_tag 1 +#define alox_EspNowSlavePresence_mac_tag 2 +#define alox_EspNowSlavePresence_version_tag 3 +#define alox_EspNowSlavePresence_slave_id_tag 4 +#define alox_EspNowSlavePresence_available_tag 5 +#define alox_EspNowSlavePresence_used_tag 6 +#define alox_EspNowMessage_type_tag 1 +#define alox_EspNowMessage_discover_tag 2 +#define alox_EspNowMessage_slave_info_tag 3 +#define alox_EspNowMessage_heartbeat_tag 4 + +/* Struct field encoding specification for nanopb */ +#define alox_EspNowDiscover_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, network, 1) +#define alox_EspNowDiscover_CALLBACK NULL +#define alox_EspNowDiscover_DEFAULT NULL + +#define alox_EspNowSlavePresence_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, network, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, mac, 2) \ +X(a, STATIC, SINGULAR, UINT32, version, 3) \ +X(a, STATIC, SINGULAR, UINT32, slave_id, 4) \ +X(a, STATIC, SINGULAR, BOOL, available, 5) \ +X(a, STATIC, SINGULAR, BOOL, used, 6) +#define alox_EspNowSlavePresence_CALLBACK pb_default_field_callback +#define alox_EspNowSlavePresence_DEFAULT NULL + +#define alox_EspNowMessage_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,discover,payload.discover), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,slave_info,payload.slave_info), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,heartbeat,payload.heartbeat), 4) +#define alox_EspNowMessage_CALLBACK NULL +#define alox_EspNowMessage_DEFAULT NULL +#define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover +#define alox_EspNowMessage_payload_slave_info_MSGTYPE alox_EspNowSlavePresence +#define alox_EspNowMessage_payload_heartbeat_MSGTYPE alox_EspNowSlavePresence + +extern const pb_msgdesc_t alox_EspNowDiscover_msg; +extern const pb_msgdesc_t alox_EspNowSlavePresence_msg; +extern const pb_msgdesc_t alox_EspNowMessage_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define alox_EspNowDiscover_fields &alox_EspNowDiscover_msg +#define alox_EspNowSlavePresence_fields &alox_EspNowSlavePresence_msg +#define alox_EspNowMessage_fields &alox_EspNowMessage_msg + +/* Maximum encoded size of messages (where known) */ +/* alox_EspNowSlavePresence_size depends on runtime parameters */ +/* alox_EspNowMessage_size depends on runtime parameters */ +#define ALOX_MAIN_PROTO_ESP_NOW_MESSAGES_PB_H_MAX_SIZE alox_EspNowDiscover_size +#define alox_EspNowDiscover_size 6 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/main/proto/esp_now_messages.proto b/main/proto/esp_now_messages.proto new file mode 100644 index 0000000..cc0019d --- /dev/null +++ b/main/proto/esp_now_messages.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package alox; + +enum EspNowMessageType { + ESPNOW_UNKNOWN = 0; + ESPNOW_DISCOVER = 1; + ESPNOW_SLAVE_INFO = 2; + ESPNOW_HEARTBEAT = 3; +} + +message EspNowDiscover { + uint32 network = 1; +} + +message EspNowSlavePresence { + uint32 network = 1; + bytes mac = 2; + uint32 version = 3; + uint32 slave_id = 4; + bool available = 5; + bool used = 6; +} + +message EspNowMessage { + EspNowMessageType type = 1; + oneof payload { + EspNowDiscover discover = 2; + EspNowSlavePresence slave_info = 3; + EspNowSlavePresence heartbeat = 4; + } +}