|
|
@@ -0,0 +1,168 @@
|
|
|
+#ifndef _ESPNOW_SERIAL_H_
|
|
|
+#define _ESPNOW_SERIAL_H_
|
|
|
+
|
|
|
+#include <Stream.h>
|
|
|
+#include <WiFi.h>
|
|
|
+#include <esp_wifi.h>
|
|
|
+#include <esp_now.h>
|
|
|
+#include "defines.h"
|
|
|
+#include "IoQueue/IoQueue.h"
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief MAC address type used by ESP-NOW.
|
|
|
+ */
|
|
|
+typedef uint8_t EspMacAddress[ESP_NOW_ETH_ALEN];
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief CCMP key type (used for PMK or LMK).
|
|
|
+ */
|
|
|
+typedef uint8_t CcmpMasterKey[ESP_NOW_KEY_LEN];
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief Stream-like interface over ESP-NOW communication.
|
|
|
+ *
|
|
|
+ * This class wraps ESP-NOW into an Arduino-compatible Stream interface,
|
|
|
+ * allowing ESP-NOW packets to be read and written similarly to a serial port.
|
|
|
+ */
|
|
|
+class EspNowSerial : public Stream
|
|
|
+{
|
|
|
+public:
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Construct a new EspNowSerial object.
|
|
|
+ *
|
|
|
+ * @param mode WiFi mode to operate in (default: WIFI_MODE_STA)
|
|
|
+ */
|
|
|
+ explicit EspNowSerial(wifi_mode_t mode = WIFI_MODE_STA);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Initialize ESP-NOW communication.
|
|
|
+ *
|
|
|
+ * @param channel WiFi channel to use (1–14)
|
|
|
+ * @param broadcast Enable broadcast mode if true
|
|
|
+ * @param pmk Primary Master Key (PMK) for encrypted communication
|
|
|
+ *
|
|
|
+ * @attention
|
|
|
+ * - When broadcast mode is enabled:
|
|
|
+ * - Do NOT add peers
|
|
|
+ * - Do NOT set a PMK
|
|
|
+ * - When broadcast mode is disabled:
|
|
|
+ * - Add peers explicitly
|
|
|
+ * - Set a PMK if encrypted peers are used
|
|
|
+ *
|
|
|
+ * @return esp_err_t ESP_OK on success, error code otherwise
|
|
|
+ */
|
|
|
+ esp_err_t begin(uint8_t channel, bool broadcast, CcmpMasterKey pmk = nullptr);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Deinitialize ESP-NOW and release resources.
|
|
|
+ */
|
|
|
+ void end();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Add an unencrypted peer.
|
|
|
+ *
|
|
|
+ * @param peer_address MAC address of the RX peer
|
|
|
+ * @return esp_err_t ESP_OK on success, error code otherwise
|
|
|
+ *
|
|
|
+ * @see esp_now_add_peer()
|
|
|
+ */
|
|
|
+ esp_err_t add_peer(EspMacAddress peer_address);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Add an encrypted peer.
|
|
|
+ *
|
|
|
+ * @param peer_address MAC address of the RX peer
|
|
|
+ * @param lmk Local Master Key (LMK) used for encryption
|
|
|
+ * @return esp_err_t ESP_OK on success, error code otherwise
|
|
|
+ *
|
|
|
+ * @see esp_now_add_peer()
|
|
|
+ */
|
|
|
+ esp_err_t add_peer_encrypted(EspMacAddress peer_address, CcmpMasterKey lmk);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Get the number of bytes available for reading.
|
|
|
+ *
|
|
|
+ * @return Number of bytes currently available in the RX buffer
|
|
|
+ */
|
|
|
+ int available() override;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Read a single byte from the stream.
|
|
|
+ *
|
|
|
+ * @return Byte value (0–255) or -1 if no data is available
|
|
|
+ */
|
|
|
+ int read() override;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Read multiple bytes from the stream.
|
|
|
+ *
|
|
|
+ * @param buffer Destination buffer
|
|
|
+ * @param length Maximum number of bytes to read
|
|
|
+ * @return Number of bytes actually read
|
|
|
+ */
|
|
|
+ size_t readBytes(uint8_t *buffer, size_t length) override;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Peek the next byte in the stream without removing it.
|
|
|
+ *
|
|
|
+ * @return Byte value (0–255) or -1 if no data is available
|
|
|
+ */
|
|
|
+ int peek() override;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Write a single byte to the stream.
|
|
|
+ *
|
|
|
+ * @note This method is not recommended for high-throughput transfers.
|
|
|
+ *
|
|
|
+ * @param value Byte to send
|
|
|
+ * @return Number of bytes written (1 on success, 0 on failure)
|
|
|
+ */
|
|
|
+ size_t write(uint8_t value) override;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Write multiple bytes to the stream.
|
|
|
+ *
|
|
|
+ * @param buffer Source buffer
|
|
|
+ * @param size Number of bytes to send
|
|
|
+ * @return Number of bytes successfully written
|
|
|
+ */
|
|
|
+ size_t write(const uint8_t *buffer, size_t size) override;
|
|
|
+
|
|
|
+private:
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief ESP-NOW send-complete callback.
|
|
|
+ *
|
|
|
+ * @param mac_addr MAC address of the destination peer
|
|
|
+ * @param status Transmission status
|
|
|
+ */
|
|
|
+ static void _on_data_sent(const uint8_t *mac_addr,
|
|
|
+ esp_now_send_status_t status);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief ESP-NOW receive callback.
|
|
|
+ *
|
|
|
+ * @param mac_addr MAC address of the sender
|
|
|
+ * @param data Pointer to received data
|
|
|
+ * @param len Length of received data in bytes
|
|
|
+ */
|
|
|
+ static void _on_data_recv(const uint8_t *mac_addr,
|
|
|
+ const uint8_t *data,
|
|
|
+ int len);
|
|
|
+
|
|
|
+ wifi_mode_t _wifi_mode; ///< Configured WiFi mode
|
|
|
+ wifi_interface_t _wifi_if; ///< WiFi interface in use
|
|
|
+
|
|
|
+ bool _has_pmk{false}; ///< Indicates whether PMK is set
|
|
|
+ bool _broadcast{false}; ///< Broadcast mode flag
|
|
|
+
|
|
|
+ static EspNowSerial *_instance; ///< Singleton instance for callbacks
|
|
|
+
|
|
|
+ uint8_t _data_sent{1}; ///< TX completion flag
|
|
|
+
|
|
|
+ IoQueue<ESP_NOW_MAX_DATA_LEN> _rx_queue; ///< Internal RX buffer
|
|
|
+};
|
|
|
+
|
|
|
+#endif // _ESPNOW_SERIAL_H_
|