Support ESPNow and improve documentation
This commit is contained in:
170
src/helpers/bridges/ESPNowBridge.h
Normal file
170
src/helpers/bridges/ESPNowBridge.h
Normal file
@@ -0,0 +1,170 @@
|
||||
#pragma once
|
||||
|
||||
#include "MeshCore.h"
|
||||
#include "esp_now.h"
|
||||
#include "helpers/AbstractBridge.h"
|
||||
#include "helpers/SimpleMeshTables.h"
|
||||
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
|
||||
#ifndef WITH_ESPNOW_BRIDGE_SECRET
|
||||
#error WITH_ESPNOW_BRIDGE_SECRET must be defined to use ESPNowBridge
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bridge implementation using ESP-NOW protocol for packet transport
|
||||
*
|
||||
* This bridge enables mesh packet transport over ESP-NOW, a connectionless communication
|
||||
* protocol provided by Espressif that allows ESP32 devices to communicate directly
|
||||
* without WiFi router infrastructure.
|
||||
*
|
||||
* Features:
|
||||
* - Broadcast-based communication (all bridges receive all packets)
|
||||
* - Network isolation using XOR encryption with shared secret
|
||||
* - Duplicate packet detection using SimpleMeshTables tracking
|
||||
* - Maximum packet size of 250 bytes (ESP-NOW limitation)
|
||||
*
|
||||
* Packet Structure:
|
||||
* [1 byte] Magic Header (0xAB) - Used to identify ESPNowBridge packets
|
||||
* [2 bytes] Fletcher-16 checksum of encrypted payload (calculated over payload only)
|
||||
* [n bytes] Encrypted payload containing the mesh packet
|
||||
*
|
||||
* The Fletcher-16 checksum is used to validate packet integrity and detect
|
||||
* corrupted or tampered packets. It's calculated over the encrypted payload
|
||||
* and provides a simple but effective way to verify packets are both
|
||||
* uncorrupted and from the same network (since the checksum is calculated
|
||||
* after encryption).
|
||||
*
|
||||
* Configuration:
|
||||
* - Define WITH_ESPNOW_BRIDGE to enable this bridge
|
||||
* - Define WITH_ESPNOW_BRIDGE_SECRET with a string to set the network encryption key
|
||||
*
|
||||
* Network Isolation:
|
||||
* Multiple independent mesh networks can coexist by using different
|
||||
* WITH_ESPNOW_BRIDGE_SECRET values. Packets encrypted with a different key will
|
||||
* fail the checksum validation and be discarded.
|
||||
*/
|
||||
class ESPNowBridge : public AbstractBridge {
|
||||
private:
|
||||
static ESPNowBridge *_instance;
|
||||
static void recv_cb(const uint8_t *mac, const uint8_t *data, int len);
|
||||
static void send_cb(const uint8_t *mac, esp_now_send_status_t status);
|
||||
|
||||
/** Packet manager for allocating and queuing mesh packets */
|
||||
mesh::PacketManager *_mgr;
|
||||
|
||||
/** RTC clock for timestamping debug messages */
|
||||
mesh::RTCClock *_rtc;
|
||||
|
||||
/** Tracks seen packets to prevent loops in broadcast communications */
|
||||
SimpleMeshTables _seen_packets;
|
||||
|
||||
/**
|
||||
* Maximum ESP-NOW packet size (250 bytes)
|
||||
* This is a hardware limitation of ESP-NOW protocol:
|
||||
* - ESP-NOW header: 20 bytes
|
||||
* - Max payload: 250 bytes
|
||||
* Source: ESP-NOW API documentation
|
||||
*/
|
||||
static const size_t MAX_ESPNOW_PACKET_SIZE = 250;
|
||||
|
||||
/**
|
||||
* Magic byte to identify ESPNowBridge packets (0xAB)
|
||||
*/
|
||||
static const uint8_t ESPNOW_HEADER_MAGIC = 0xAB;
|
||||
|
||||
/** Buffer for receiving ESP-NOW packets */
|
||||
uint8_t _rx_buffer[MAX_ESPNOW_PACKET_SIZE];
|
||||
|
||||
/** Current position in receive buffer */
|
||||
size_t _rx_buffer_pos;
|
||||
|
||||
/**
|
||||
* Network encryption key from build define
|
||||
* Must be defined with WITH_ESPNOW_BRIDGE_SECRET
|
||||
* Used for XOR encryption to isolate different mesh networks
|
||||
*/
|
||||
const char *_secret = WITH_ESPNOW_BRIDGE_SECRET;
|
||||
|
||||
/**
|
||||
* Performs XOR encryption/decryption of data
|
||||
*
|
||||
* Uses WITH_ESPNOW_BRIDGE_SECRET as the key in a simple XOR operation.
|
||||
* The same operation is used for both encryption and decryption.
|
||||
* While not cryptographically secure, it provides basic network isolation.
|
||||
*
|
||||
* @param data Pointer to data to encrypt/decrypt
|
||||
* @param len Length of data in bytes
|
||||
*/
|
||||
void xorCrypt(uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* ESP-NOW receive callback
|
||||
* Called by ESP-NOW when a packet is received
|
||||
*
|
||||
* @param mac Source MAC address
|
||||
* @param data Received data
|
||||
* @param len Length of received data
|
||||
*/
|
||||
void onDataRecv(const uint8_t *mac, const uint8_t *data, int len);
|
||||
|
||||
/**
|
||||
* ESP-NOW send callback
|
||||
* Called by ESP-NOW after a transmission attempt
|
||||
*
|
||||
* @param mac_addr Destination MAC address
|
||||
* @param status Transmission status
|
||||
*/
|
||||
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs an ESPNowBridge instance
|
||||
*
|
||||
* @param mgr PacketManager for allocating and queuing packets
|
||||
* @param rtc RTCClock for timestamping debug messages
|
||||
*/
|
||||
ESPNowBridge(mesh::PacketManager *mgr, mesh::RTCClock *rtc);
|
||||
|
||||
/**
|
||||
* Initializes the ESP-NOW bridge
|
||||
*
|
||||
* - Configures WiFi in station mode
|
||||
* - Initializes ESP-NOW protocol
|
||||
* - Registers callbacks
|
||||
* - Sets up broadcast peer
|
||||
*/
|
||||
void begin() override;
|
||||
|
||||
/**
|
||||
* Main loop handler
|
||||
* ESP-NOW is callback-based, so this is currently empty
|
||||
*/
|
||||
void loop() override;
|
||||
|
||||
/**
|
||||
* Called when a packet is received via ESP-NOW
|
||||
* Queues the packet for mesh processing if not seen before
|
||||
*
|
||||
* @param packet The received mesh packet
|
||||
*/
|
||||
void onPacketReceived(mesh::Packet *packet) override;
|
||||
|
||||
/**
|
||||
* Called when a packet needs to be transmitted via ESP-NOW
|
||||
* Encrypts and broadcasts the packet if not seen before
|
||||
*
|
||||
* @param packet The mesh packet to transmit
|
||||
*/
|
||||
void onPacketTransmitted(mesh::Packet *packet) override;
|
||||
|
||||
/**
|
||||
* Gets formatted date/time string for logging
|
||||
* Format: "HH:MM:SS - DD/MM/YYYY U"
|
||||
*
|
||||
* @return Formatted date/time string
|
||||
*/
|
||||
const char *getLogDateTime();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user