This commit is contained in:
aZholtikov committed 2026-11-01 09:07:02 +03:00
1 parent 036b856a93
commit 384360d2a4
3 files changed
+411 -349

No files matched your search

+105 -99
View File
@@ -30,128 +30,134 @@
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_err.h"
#include "esp_event.h"
#include "driver/spi_master.h"
#include "zh_nrf24_config.h"
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
/** Max entries in the binding table (RAM and NVS). */
#define ZH_NRF_GATEWAY_MAX_BINDINGS 254
extern TaskHandle_t zh_nrf24_gateway;
ESP_EVENT_DECLARE_BASE(ZH_NRF_GATEWAY_EVENTS);
typedef struct
{
spi_host_device_t spi_host; /*!< SPI host (SPI2_HOST / SPI3_HOST) */
int pin_sck; /*!< SCK GPIO */
int pin_miso; /*!< MISO GPIO */
int pin_mosi; /*!< MOSI GPIO */
int pin_csn; /*!< CSN GPIO (chip select, active low) */
int pin_ce; /*!< CE GPIO (chip enable, active high) */
int pin_irq; /*!< IRQ GPIO (open-drain, active low) */
uint8_t channel; /*!< RF channel (0..125) */
uint32_t address; /*!< 24-bit pipe address, transmitted as LE bytes */
uint32_t spi_clock_hz; /*!< SPI clock, 0 → default 4 MHz */
} zh_nrf24_gateway_init_config_t;
typedef enum
{
/** Sensor telemetry (data: zh_nrf24_sensor_transmitted_data_t) */
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
typedef enum
{
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED,
} zh_nrf24_gateway_event_t;
/** Pairing completed (data: zh_nrf_gateway_binding_t) */
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
ESP_EVENT_DECLARE_BASE(ZH_NRF24_GATEWAY_EVENTS);
/** Unknown {id, type} seen in a data packet, auto-added to bindings
* (data: zh_nrf_gateway_binding_t) */
ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED,
} zh_nrf_gateway_event_t;
/** A single {id, type} binding. */
typedef struct
{
uint8_t id; /**< 1..254, 0xFF = unassigned */
uint8_t type; /**< zh_nrf24_sensor_type_t */
} zh_nrf_gateway_binding_t;
typedef struct
{
spi_host_device_t spi_host; /*!< SPI host (SPI2_HOST / SPI3_HOST) */
int pin_sck; /*!< SCK GPIO */
int pin_miso; /*!< MISO GPIO */
int pin_mosi; /*!< MOSI GPIO */
int pin_csn; /*!< CSN GPIO (chip select, active low) */
int pin_ce; /*!< CE GPIO (chip enable, active high) */
int pin_irq; /*!< IRQ GPIO (open-drain, active low) */
uint8_t channel; /*!< RF channel (0..125) */
uint32_t address; /*!< 24-bit pipe address, transmitted as LE bytes */
uint32_t spi_clock_hz; /*!< SPI clock, 0 → default 4 MHz */
} zh_nrf_gateway_config_t;
/**
* @brief Initialize the gateway.
*
* Configures SPI, the IRQ GPIO with falling-edge interrupt, the nRF24L01+
* transceiver (DPL enabled, RX mode) and prepares NVS and the default
* event loop if they are not already initialized.
*
* @param[in] config Gateway configuration (must not be NULL)
*
* @return ESP_OK on success, or an ESP-IDF error code
*/
esp_err_t zh_nrf_gateway_init(const zh_nrf24_gateway_init_config_t *config);
/** A single {id, type} binding. */
typedef struct
{
uint8_t id; /**< 1..254, 0xFF = unassigned */
uint8_t type; /**< zh_nrf24_sensor_type_t */
} zh_nrf_gateway_binding_t;
/**
* @brief Start the receiver task.
*
* The task blocks on the IRQ semaphore (or polls the FIFO as a fallback
* once per second) and dispatches received packets.
*
* @return ESP_OK on success
*/
esp_err_t zh_nrf_gateway_start(void);
/**
* @brief Initialize the gateway.
*
* Configures SPI, the IRQ GPIO with falling-edge interrupt, the nRF24L01+
* transceiver (DPL enabled, RX mode) and prepares NVS and the default
* event loop if they are not already initialized.
*
* @param[in] config Gateway configuration (must not be NULL)
*
* @return ESP_OK on success, or an ESP-IDF error code
*/
esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config);
/* ===================== BINDING TABLE API ===================== */
/**
* @brief Start the receiver task.
*
* The task blocks on the IRQ semaphore (or polls the FIFO as a fallback
* once per second) and dispatches received packets.
*
* @return ESP_OK on success
*/
esp_err_t zh_nrf_gateway_start(void);
/**
* @brief Copy current bindings into @p buf.
*
* Thread-safe. Returns number of entries copied (≤ max_count and ≤
* current table size).
*/
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count);
/* ===================== BINDING TABLE API ===================== */
/** @brief Current number of bindings in the table. */
size_t zh_nrf_gateway_bindings_count(void);
/**
* @brief Copy current bindings into @p buf.
*
* Thread-safe. Returns number of entries copied (≤ max_count and ≤
* current table size).
*/
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count);
/**
* @brief Check whether a {id, type} binding exists.
*
* @return true if the binding is present in the table
*/
bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
/** @brief Current number of bindings in the table. */
size_t zh_nrf_gateway_bindings_count(void);
/**
* @brief Auto-register {id, type} if not present.
*
* Validates both fields, then adds the pair to the table and persists
* to NVS if it is not already there. The id is taken from the packet
* as-is (unlike pairing, which assigns a new id).
*
* @return 1 binding was newly added
* @return 0 binding already existed
* @return negative ESP error (invalid arg, NVS failure, etc.)
*/
int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type);
/**
* @brief Check whether a {id, type} binding exists.
*
* @return true if the binding is present in the table
*/
bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
/**
* @brief Delete a {id, type} binding.
*
* Composite key: both @p id AND @p type must match. If only one matches,
* nothing is deleted and ESP_ERR_NOT_FOUND is returned.
*
* @return ESP_OK / ESP_ERR_NOT_FOUND / ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE / NVS error
*/
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type);
/**
* @brief Auto-register {id, type} if not present.
*
* Validates both fields, then adds the pair to the table and persists
* to NVS if it is not already there. The id is taken from the packet
* as-is (unlike pairing, which assigns a new id).
*
* @return 1 binding was newly added
* @return 0 binding already existed
* @return negative ESP error (invalid arg, NVS failure, etc.)
*/
int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type);
/** Delete every binding whose id equals @p id (any type). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_id(uint8_t id);
/**
* @brief Delete a {id, type} binding.
*
* Composite key: both @p id AND @p type must match. If only one matches,
* nothing is deleted and ESP_ERR_NOT_FOUND is returned.
*
* @return ESP_OK / ESP_ERR_NOT_FOUND / ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE / NVS error
*/
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type);
/** Delete every binding whose type equals @p type (any id). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type);
/** Delete every binding whose id equals @p id (any type). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_id(uint8_t id);
/** Delete every binding whose type equals @p type (any id). Returns count, or -err. */
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type);
/** Remove all bindings (persisted). */
esp_err_t zh_nrf_gateway_binding_clear_all(void);
/** Remove all bindings (persisted). */
esp_err_t zh_nrf_gateway_binding_clear_all(void);
#ifdef __cplusplus
}