From 384360d2a49c790d4eedeacbf4f73a602da62712 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sun, 1 Nov 2026 09:07:02 +0300 Subject: [PATCH] wip: --- README.md | 182 +++++++----------- include/zh_nrf24_gateway.h | 204 ++++++++++---------- zh_nrf24_gateway.c | 374 +++++++++++++++++++++++-------------- 3 files changed, 411 insertions(+), 349 deletions(-) diff --git a/README.md b/README.md index aa3f377..ce18552 100755 --- a/README.md +++ b/README.md @@ -1,122 +1,76 @@ -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_log.h" -#include "esp_event.h" - #include "zh_nrf24_gateway.h" -#include "zh_nrf24_config.h" -static const char *TAG = "MAIN"; +#define GATEWAY_CHANNEL 120 +#define GATEWAY_ADDRESS 0xDDEEFF -#define GW_CHANNEL 120 -#define GW_ADDRESS 0xDDEEFF - -static const zh_nrf_gateway_config_t s_gw_config = { - .spi_host = SPI2_HOST, - .pin_sck = 18, - .pin_miso = 19, - .pin_mosi = 23, - .pin_csn = 17, - .pin_ce = 16, - .pin_irq = 4, - .channel = GW_CHANNEL, - .address = GW_ADDRESS, - .spi_clock_hz = 0, -}; - -static void handle_paired_event(const zh_nrf_gateway_binding_t *b) -{ - ESP_LOGI(TAG, ">>> SENSOR PAIRED: id=%u type=%u (%s)", - b->id, b->type, - zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)b->type)); - - /* Здесь можно добавить: - * - публикацию в MQTT: "sensor/paired" {id, type}; - * - сохранение метаданных во внешнюю БД; - * - запись в журнал / уведомление; - * - поиск пользователя, которому принадлежит новое устройство, - * и т.п. - */ -} - -static void handle_sensor_data_event(const zh_nrf24_sensor_transmitted_data_t *d) -{ - const char *name = zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d->type); - - ESP_LOGI(TAG, "<<< sensor id=%d type=%s battery=%.2fV", - d->id, name, d->battery / 100.0); - - switch (d->type) - { - case ZH_NRF24_SENSOR_TOUCH_SWITCH: - ESP_LOGI(TAG, " button event"); - break; - case ZH_NRF24_SENSOR_WATER_LEAKAGE: - ESP_LOGI(TAG, " status=%s", - d->value_1 == ZH_NRF24_SENSOR_STATUS_ALARM ? "ALARM" : "DRY"); - break; - case ZH_NRF24_SENSOR_OPEN_CLOSE: - ESP_LOGI(TAG, " state=%s", - d->value_1 == ZH_NRF24_SENSOR_STATUS_OPEN ? "OPEN" : "CLOSE"); - break; - case ZH_NRF24_SENSOR_PLANT_HUMIDITY: - ESP_LOGI(TAG, " humidity=%d%%", d->value_1); - break; - case ZH_NRF24_SENSOR_BMP280: - ESP_LOGI(TAG, " T=%d C, P=%d", d->value_1, d->value_2); - break; - case ZH_NRF24_SENSOR_BME280: - ESP_LOGI(TAG, " H=%d%% T=%d C P=%d mmHg", - d->value_1, d->value_2, d->value_3); - break; - case ZH_NRF24_SENSOR_BME680: - ESP_LOGI(TAG, " H=%d%% T=%d C P=%d Q=%d", - d->value_1, d->value_2, d->value_3, d->value_4); - break; - default: - break; - } -} - -static void gateway_event_handler(void *arg, - esp_event_base_t base, - int32_t id, - void *event_data) -{ - if (base != ZH_NRF_GATEWAY_EVENTS) return; - - switch (id) - { - case ZH_NRF_GATEWAY_EVENT_SENSOR_DATA: - handle_sensor_data_event((const zh_nrf24_sensor_transmitted_data_t *)event_data); - break; - - case ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED: - handle_paired_event((const zh_nrf_gateway_binding_t *)event_data); - break; - - default: - break; - } -} +void zh_nrf24_gateway_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); void app_main(void) { - ESP_LOGI(TAG, "Starting nRF24L01+ gateway"); + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ESP_ERROR_CHECK(nvs_flash_init()); + } + esp_event_loop_create_default(); + esp_event_handler_instance_register(ZH_NRF24_GATEWAY_EVENTS, ESP_EVENT_ANY_ID, &zh_nrf24_gateway_event_handler, NULL, NULL); + zh_nrf_gateway_config_t config = { + .spi_host = SPI2_HOST, + .pin_sck = 18, + .pin_miso = 19, + .pin_mosi = 23, + .pin_csn = 17, + .pin_ce = 16, + .pin_irq = 4, + .channel = GATEWAY_CHANNEL, + .address = GATEWAY_ADDRESS, + .spi_clock_hz = 0, + }; + zh_nrf_gateway_init(&config); + zh_nrf_gateway_start(); +} - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(esp_event_handler_instance_register( - ZH_NRF_GATEWAY_EVENTS, - ESP_EVENT_ANY_ID, - &gateway_event_handler, - NULL, NULL)); - - ESP_ERROR_CHECK(zh_nrf_gateway_init(&s_gw_config)); - ESP_ERROR_CHECK(zh_nrf_gateway_start()); - - ESP_LOGI(TAG, "Gateway running: channel=%d, address=0x%06X", - GW_CHANNEL, GW_ADDRESS); +void zh_nrf24_gateway_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + switch (event_id) + { + case ZH_NRF_GATEWAY_EVENT_SENSOR_DATA: + zh_nrf24_sensor_transmitted_data_t *sensor_data = (zh_nrf24_sensor_transmitted_data_t *)event_data; + printf("Data received - id=%d type=%s battery=%.2fV ", sensor_data->id, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)sensor_data->type), sensor_data->battery / 100.0); + switch (sensor_data->type) + { + case ZH_NRF24_SENSOR_TOUCH_SWITCH: + printf("button pressed\n"); + break; + case ZH_NRF24_SENSOR_WATER_LEAKAGE: + printf("status=%s\n", sensor_data->value_1 == ZH_NRF24_SENSOR_STATUS_ALARM ? "ALARM" : "DRY"); + break; + case ZH_NRF24_SENSOR_OPEN_CLOSE: + printf("status=%s\n", sensor_data->value_1 == ZH_NRF24_SENSOR_STATUS_OPEN ? "OPEN" : "CLOSE"); + break; + case ZH_NRF24_SENSOR_PLANT_HUMIDITY: + printf("soil moisture=%.1f%%\n", sensor_data->value_1 / 10.0); + break; + case ZH_NRF24_SENSOR_BMP280: + printf("temperature=%.1fC, atmospheric pressure=%.1fmmHg\n", sensor_data->value_1 / 10.0, sensor_data->value_2 / 10.0); + break; + case ZH_NRF24_SENSOR_BME280: + printf("humidity=%.1f%%, temperature=%.1fC, atmospheric pressure=%.1fmmHg\n", sensor_data->value_1 / 10.0, sensor_data->value_2 / 10.0, sensor_data->value_3 / 10.0); + break; + default: + break; + } + break; + case ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED: + zh_nrf_gateway_binding_t *pairing_data = (zh_nrf_gateway_binding_t *)event_data; + printf("Sensor paired - id=%d type=%s\n", pairing_data->id, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)pairing_data->type)); + break; + case ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED: + zh_nrf_gateway_binding_t *registering_data = (zh_nrf_gateway_binding_t *)event_data; + printf("Sensor registered - id=%d type=%s\n", registering_data->id, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)registering_data->type)); + break; + default: + break; + } } \ No newline at end of file diff --git a/include/zh_nrf24_gateway.h b/include/zh_nrf24_gateway.h index 389221c..c64d826 100644 --- a/include/zh_nrf24_gateway.h +++ b/include/zh_nrf24_gateway.h @@ -30,128 +30,134 @@ #include #include +#include +#include + +#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 } diff --git a/zh_nrf24_gateway.c b/zh_nrf24_gateway.c index 038c1c1..6253403 100644 --- a/zh_nrf24_gateway.c +++ b/zh_nrf24_gateway.c @@ -1,21 +1,22 @@ #include "zh_nrf24_gateway.h" -#include -#include +// #include +// #include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "driver/spi_master.h" -#include "driver/gpio.h" -#include "esp_log.h" -#include "esp_rom_sys.h" -#include "nvs_flash.h" -#include "nvs.h" +// #include "freertos/FreeRTOS.h" +// #include "freertos/task.h" +// #include "freertos/semphr.h" +// #include "driver/spi_master.h" +// #include "driver/gpio.h" +// #include "esp_log.h" +// #include "esp_rom_sys.h" +// #include "nvs_flash.h" +// #include "nvs.h" -ESP_EVENT_DEFINE_BASE(ZH_NRF_GATEWAY_EVENTS); +ESP_EVENT_DEFINE_BASE(ZH_NRF24_GATEWAY_EVENTS); static const char *TAG = "NRF_GW"; +#define ZH_NRF_GATEWAY_MAX_BINDINGS 254 /* ================== nRF24 КОМАНДЫ / РЕГИСТРЫ ================== */ #define NRF_CMD_R_REGISTER 0x00 @@ -49,12 +50,8 @@ static const char *TAG = "NRF_GW"; #define NRF_CONFIG_PWR_UP 0x02 #define NRF_CONFIG_PRIM_RX 0x01 -#define NRF_CONFIG_ALL_MASKED \ - (NRF_CONFIG_MASK_RX_DR | NRF_CONFIG_MASK_TX_DS | \ - NRF_CONFIG_MASK_MAX_RT | NRF_CONFIG_EN_CRC) - -#define NRF_CONFIG_RX_UNMASKED \ - (NRF_CONFIG_EN_CRC | NRF_CONFIG_PWR_UP | NRF_CONFIG_PRIM_RX) +#define NRF_CONFIG_ALL_MASKED (NRF_CONFIG_MASK_RX_DR | NRF_CONFIG_MASK_TX_DS | NRF_CONFIG_MASK_MAX_RT | NRF_CONFIG_EN_CRC) +#define NRF_CONFIG_RX_UNMASKED (NRF_CONFIG_EN_CRC | NRF_CONFIG_PWR_UP | NRF_CONFIG_PRIM_RX) #define NRF_STATUS_RX_DR 0x40 #define NRF_STATUS_TX_DS 0x20 @@ -80,7 +77,7 @@ typedef struct __attribute__((packed)) static struct { - zh_nrf_gateway_config_t cfg; + zh_nrf24_gateway_init_config_t cfg; spi_device_handle_t spi; SemaphoreHandle_t irq_sem; SemaphoreHandle_t bindings_mutex; @@ -177,26 +174,30 @@ static void IRAM_ATTR nrf_irq_isr(void *arg) { BaseType_t woken = pdFALSE; xSemaphoreGiveFromISR(s_ctx.irq_sem, &woken); - if (woken) portYIELD_FROM_ISR(); + if (woken) + portYIELD_FROM_ISR(); } static esp_err_t nrf_irq_init(void) { s_ctx.irq_sem = xSemaphoreCreateBinary(); - if (!s_ctx.irq_sem) return ESP_ERR_NO_MEM; + if (!s_ctx.irq_sem) + return ESP_ERR_NO_MEM; gpio_config_t io_conf = { .pin_bit_mask = (1ULL << s_ctx.cfg.pin_irq), - .mode = GPIO_MODE_INPUT, - .pull_up_en = GPIO_PULLUP_ENABLE, + .mode = GPIO_MODE_INPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, - .intr_type = GPIO_INTR_NEGEDGE, + .intr_type = GPIO_INTR_NEGEDGE, }; esp_err_t err = gpio_config(&io_conf); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; err = gpio_install_isr_service(0); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) return err; + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) + return err; return gpio_isr_handler_add(s_ctx.cfg.pin_irq, nrf_irq_isr, NULL); } @@ -208,7 +209,8 @@ static esp_err_t bindings_load(void) { nvs_handle_t h; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h); - if (err != ESP_OK) { + if (err != ESP_OK) + { memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings)); return ESP_OK; } @@ -217,17 +219,20 @@ static esp_err_t bindings_load(void) err = nvs_get_blob(h, NVS_KEY_BINDINGS, &s_ctx.bindings, &size); nvs_close(h); - if (err == ESP_ERR_NVS_NOT_FOUND) { + if (err == ESP_ERR_NVS_NOT_FOUND) + { memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings)); ESP_LOGI(TAG, "Bindings: empty (first run)"); return ESP_OK; } - if (err != ESP_OK) { + if (err != ESP_OK) + { memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings)); return err; } - if (s_ctx.bindings.count > ZH_NRF_GATEWAY_MAX_BINDINGS) { + if (s_ctx.bindings.count > ZH_NRF_GATEWAY_MAX_BINDINGS) + { ESP_LOGW(TAG, "Bindings: corrupt count %u, resetting", s_ctx.bindings.count); memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings)); return ESP_OK; @@ -241,12 +246,14 @@ static esp_err_t bindings_save(void) { nvs_handle_t h; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; size_t size = sizeof(s_ctx.bindings.count) + s_ctx.bindings.count * sizeof(zh_nrf_gateway_binding_t); err = nvs_set_blob(h, NVS_KEY_BINDINGS, &s_ctx.bindings, size); - if (err == ESP_OK) err = nvs_commit(h); + if (err == ESP_OK) + err = nvs_commit(h); nvs_close(h); return err; } @@ -254,9 +261,11 @@ static esp_err_t bindings_save(void) /* Caller must hold bindings_mutex. */ static bool bindings_exists_locked(uint8_t id, uint8_t type) { - for (uint16_t i = 0; i < s_ctx.bindings.count; i++) { + for (uint16_t i = 0; i < s_ctx.bindings.count; i++) + { if (s_ctx.bindings.items[i].id == id && - s_ctx.bindings.items[i].type == type) { + s_ctx.bindings.items[i].type == type) + { return true; } } @@ -266,8 +275,10 @@ static bool bindings_exists_locked(uint8_t id, uint8_t type) /* Caller must hold bindings_mutex. */ static uint8_t bindings_alloc_id(uint8_t type) { - for (uint16_t id = BINDING_ID_MIN; id <= BINDING_ID_MAX; id++) { - if (!bindings_exists_locked((uint8_t)id, type)) { + for (uint16_t id = BINDING_ID_MIN; id <= BINDING_ID_MAX; id++) + { + if (!bindings_exists_locked((uint8_t)id, type)) + { return (uint8_t)id; } } @@ -277,10 +288,11 @@ static uint8_t bindings_alloc_id(uint8_t type) /* Caller must hold bindings_mutex. */ static esp_err_t bindings_add(uint8_t id, uint8_t type) { - if (s_ctx.bindings.count >= ZH_NRF_GATEWAY_MAX_BINDINGS) { + if (s_ctx.bindings.count >= ZH_NRF_GATEWAY_MAX_BINDINGS) + { return ESP_ERR_NO_MEM; } - s_ctx.bindings.items[s_ctx.bindings.count].id = id; + s_ctx.bindings.items[s_ctx.bindings.count].id = id; s_ctx.bindings.items[s_ctx.bindings.count].type = type; s_ctx.bindings.count++; return bindings_save(); @@ -289,9 +301,11 @@ static esp_err_t bindings_add(uint8_t id, uint8_t type) /* Caller must hold bindings_mutex. */ static esp_err_t bindings_delete(uint8_t id, uint8_t type) { - for (uint16_t i = 0; i < s_ctx.bindings.count; i++) { + for (uint16_t i = 0; i < s_ctx.bindings.count; i++) + { if (s_ctx.bindings.items[i].id == id && - s_ctx.bindings.items[i].type == type) { + s_ctx.bindings.items[i].type == type) + { memmove(&s_ctx.bindings.items[i], &s_ctx.bindings.items[i + 1], (s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t)); @@ -307,7 +321,8 @@ static esp_err_t bindings_delete(uint8_t id, uint8_t type) * ============================================================ */ size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count) { - if (!buf || max_count == 0 || !s_ctx.bindings_mutex) return 0; + if (!buf || max_count == 0 || !s_ctx.bindings_mutex) + return 0; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); size_t n = s_ctx.bindings.count < max_count ? s_ctx.bindings.count : max_count; memcpy(buf, s_ctx.bindings.items, n * sizeof(zh_nrf_gateway_binding_t)); @@ -317,7 +332,8 @@ size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_cou size_t zh_nrf_gateway_bindings_count(void) { - if (!s_ctx.bindings_mutex) return 0; + if (!s_ctx.bindings_mutex) + return 0; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); size_t n = s_ctx.bindings.count; xSemaphoreGive(s_ctx.bindings_mutex); @@ -326,7 +342,8 @@ size_t zh_nrf_gateway_bindings_count(void) bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type) { - if (!s_ctx.initialized || !s_ctx.bindings_mutex) return false; + if (!s_ctx.initialized || !s_ctx.bindings_mutex) + return false; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); bool found = bindings_exists_locked(id, type); xSemaphoreGive(s_ctx.bindings_mutex); @@ -335,21 +352,29 @@ bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type) int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type) { - if (!s_ctx.initialized || !s_ctx.bindings_mutex) return -ESP_ERR_INVALID_STATE; - if (id < BINDING_ID_MIN || id > BINDING_ID_MAX) return -ESP_ERR_INVALID_ARG; - if (zh_get_nrf24_sensor_payload_size(type) == 0) return -ESP_ERR_INVALID_ARG; + if (!s_ctx.initialized || !s_ctx.bindings_mutex) + return -ESP_ERR_INVALID_STATE; + if (id < BINDING_ID_MIN || id > BINDING_ID_MAX) + return -ESP_ERR_INVALID_ARG; + if (zh_get_nrf24_sensor_payload_size(type) == 0) + return -ESP_ERR_INVALID_ARG; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); int result = 0; - if (!bindings_exists_locked(id, type)) { + if (!bindings_exists_locked(id, type)) + { esp_err_t err = bindings_add(id, type); - if (err == ESP_OK) { + if (err == ESP_OK) + { result = 1; - } else { + } + else + { if (s_ctx.bindings.count > 0 && - s_ctx.bindings.items[s_ctx.bindings.count - 1].id == id && - s_ctx.bindings.items[s_ctx.bindings.count - 1].type == type) { + s_ctx.bindings.items[s_ctx.bindings.count - 1].id == id && + s_ctx.bindings.items[s_ctx.bindings.count - 1].type == type) + { s_ctx.bindings.count--; } result = -(int)err; @@ -362,21 +387,29 @@ int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type) esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type) { - if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE; - if (id == 0 || id == 0xFF) return ESP_ERR_INVALID_ARG; - if (zh_get_nrf24_sensor_payload_size(type) == 0) return ESP_ERR_INVALID_ARG; + if (!s_ctx.initialized) + return ESP_ERR_INVALID_STATE; + if (id == 0 || id == 0xFF) + return ESP_ERR_INVALID_ARG; + if (zh_get_nrf24_sensor_payload_size(type) == 0) + return ESP_ERR_INVALID_ARG; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); esp_err_t err = bindings_delete(id, type); xSemaphoreGive(s_ctx.bindings_mutex); - if (err == ESP_OK) { + if (err == ESP_OK) + { ESP_LOGI(TAG, "Binding deleted: id=%u type=%u (%s)", id, type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type)); - } else if (err == ESP_ERR_NOT_FOUND) { + } + else if (err == ESP_ERR_NOT_FOUND) + { ESP_LOGW(TAG, "Binding not found: id=%u type=%u (%s)", id, type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type)); - } else { + } + else + { ESP_LOGE(TAG, "Binding delete failed (id=%u type=%u): %s", id, type, esp_err_to_name(err)); } @@ -385,57 +418,76 @@ esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type) int zh_nrf_gateway_bindings_delete_by_id(uint8_t id) { - if (!s_ctx.initialized) return -ESP_ERR_INVALID_STATE; - if (id == 0 || id == 0xFF) return -ESP_ERR_INVALID_ARG; + if (!s_ctx.initialized) + return -ESP_ERR_INVALID_STATE; + if (id == 0 || id == 0xFF) + return -ESP_ERR_INVALID_ARG; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); int deleted = 0; - for (uint16_t i = 0; i < s_ctx.bindings.count; ) { - if (s_ctx.bindings.items[i].id == id) { + for (uint16_t i = 0; i < s_ctx.bindings.count;) + { + if (s_ctx.bindings.items[i].id == id) + { memmove(&s_ctx.bindings.items[i], &s_ctx.bindings.items[i + 1], (s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t)); s_ctx.bindings.count--; deleted++; - } else { + } + else + { i++; } } esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK; xSemaphoreGive(s_ctx.bindings_mutex); - if (err != ESP_OK) return -(int)err; - if (deleted > 0) ESP_LOGI(TAG, "Deleted %d binding(s) with id=%u", deleted, id); - else ESP_LOGW(TAG, "No bindings with id=%u", id); + if (err != ESP_OK) + return -(int)err; + if (deleted > 0) + ESP_LOGI(TAG, "Deleted %d binding(s) with id=%u", deleted, id); + else + ESP_LOGW(TAG, "No bindings with id=%u", id); return deleted; } int zh_nrf_gateway_bindings_delete_by_type(uint8_t type) { - if (!s_ctx.initialized) return -ESP_ERR_INVALID_STATE; - if (zh_get_nrf24_sensor_payload_size(type) == 0) return -ESP_ERR_INVALID_ARG; + if (!s_ctx.initialized) + return -ESP_ERR_INVALID_STATE; + if (zh_get_nrf24_sensor_payload_size(type) == 0) + return -ESP_ERR_INVALID_ARG; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); int deleted = 0; - for (uint16_t i = 0; i < s_ctx.bindings.count; ) { - if (s_ctx.bindings.items[i].type == type) { + for (uint16_t i = 0; i < s_ctx.bindings.count;) + { + if (s_ctx.bindings.items[i].type == type) + { memmove(&s_ctx.bindings.items[i], &s_ctx.bindings.items[i + 1], (s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t)); s_ctx.bindings.count--; deleted++; - } else { + } + else + { i++; } } esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK; xSemaphoreGive(s_ctx.bindings_mutex); - if (err != ESP_OK) return -(int)err; - if (deleted > 0) { + if (err != ESP_OK) + return -(int)err; + if (deleted > 0) + { ESP_LOGI(TAG, "Deleted %d binding(s) of type=%u (%s)", deleted, type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type)); - } else { + } + else + { ESP_LOGW(TAG, "No bindings of type=%u (%s)", type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type)); } @@ -444,12 +496,14 @@ int zh_nrf_gateway_bindings_delete_by_type(uint8_t type) esp_err_t zh_nrf_gateway_binding_clear_all(void) { - if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE; + if (!s_ctx.initialized) + return ESP_ERR_INVALID_STATE; xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); s_ctx.bindings.count = 0; esp_err_t err = bindings_save(); xSemaphoreGive(s_ctx.bindings_mutex); - if (err == ESP_OK) ESP_LOGI(TAG, "All bindings cleared"); + if (err == ESP_OK) + ESP_LOGI(TAG, "All bindings cleared"); return err; } @@ -463,8 +517,7 @@ static bool send_pairing_ack(uint8_t req_type, uint16_t token, uint8_t new_id) ZH_NRF24_PAIRING_ACK_MAGIC, (uint8_t)(token >> 8), (uint8_t)(token & 0xFF), - new_id - }; + new_id}; nrf_ce_low(); nrf_write_register(NRF_REG_CONFIG, NRF_CONFIG_ALL_MASKED | NRF_CONFIG_PWR_UP); @@ -489,9 +542,11 @@ static bool send_pairing_ack(uint8_t req_type, uint16_t token, uint8_t new_id) nrf_ce_low(); uint8_t status = 0; - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 100; i++) + { status = nrf_send_command(NRF_CMD_NOP); - if (status & (NRF_STATUS_TX_DS | NRF_STATUS_MAX_RT)) break; + if (status & (NRF_STATUS_TX_DS | NRF_STATUS_MAX_RT)) + break; vTaskDelay(pdMS_TO_TICKS(1)); } @@ -513,8 +568,8 @@ static bool send_pairing_ack(uint8_t req_type, uint16_t token, uint8_t new_id) * ============================================================ */ static void handle_pairing_request(const uint8_t *data) { - uint8_t req_type = data[0]; - uint16_t token = ((uint16_t)data[2] << 8) | data[3]; + uint8_t req_type = data[0]; + uint16_t token = ((uint16_t)data[2] << 8) | data[3]; ESP_LOGI(TAG, "Pairing request: type=%u (%s), token=0x%04X", req_type, @@ -524,7 +579,8 @@ static void handle_pairing_request(const uint8_t *data) xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); uint8_t new_id = bindings_alloc_id(req_type); - if (new_id == 0) { + if (new_id == 0) + { xSemaphoreGive(s_ctx.bindings_mutex); ESP_LOGW(TAG, "Pairing: no free id for type %u (all %d used)", req_type, BINDING_ID_MAX); @@ -532,10 +588,12 @@ static void handle_pairing_request(const uint8_t *data) } esp_err_t err = bindings_add(new_id, req_type); - if (err != ESP_OK) { + if (err != ESP_OK) + { if (s_ctx.bindings.count > 0 && - s_ctx.bindings.items[s_ctx.bindings.count - 1].id == new_id && - s_ctx.bindings.items[s_ctx.bindings.count - 1].type == req_type) { + s_ctx.bindings.items[s_ctx.bindings.count - 1].id == new_id && + s_ctx.bindings.items[s_ctx.bindings.count - 1].type == req_type) + { s_ctx.bindings.count--; } xSemaphoreGive(s_ctx.bindings_mutex); @@ -546,7 +604,8 @@ static void handle_pairing_request(const uint8_t *data) xSemaphoreGive(s_ctx.bindings_mutex); ESP_LOGI(TAG, "Pairing: allocated id=%u for type=%u", new_id, req_type); - if (!send_pairing_ack(req_type, token, new_id)) { + if (!send_pairing_ack(req_type, token, new_id)) + { ESP_LOGW(TAG, "Pairing: ACK not delivered, removing binding id=%u type=%u", new_id, req_type); xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY); @@ -558,72 +617,84 @@ static void handle_pairing_request(const uint8_t *data) ESP_LOGI(TAG, "Pairing complete: id=%u type=%u", new_id, req_type); zh_nrf_gateway_binding_t paired = { - .id = new_id, + .id = new_id, .type = req_type, }; - esp_err_t post_err = esp_event_post(ZH_NRF_GATEWAY_EVENTS, + esp_err_t post_err = esp_event_post(ZH_NRF24_GATEWAY_EVENTS, ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED, &paired, sizeof(paired), pdMS_TO_TICKS(100)); - if (post_err != ESP_OK) { + if (post_err != ESP_OK) + { ESP_LOGW(TAG, "esp_event_post(paired) failed: %s", esp_err_to_name(post_err)); } } static void handle_sensor_data(const uint8_t *buf, uint8_t len) { - if (len < ZH_NRF24_DATA_HEADER_SIZE) { + if (len < ZH_NRF24_DATA_HEADER_SIZE) + { ESP_LOGW(TAG, "Too short data packet (%u)", len); return; } zh_nrf24_sensor_transmitted_data_t d = {0}; - d.id = zh_nrf24_sensor_read_i16_le_at(buf, 0); - d.type = zh_nrf24_sensor_read_i16_le_at(buf, 2); + d.id = zh_nrf24_sensor_read_i16_le_at(buf, 0); + d.type = zh_nrf24_sensor_read_i16_le_at(buf, 2); d.battery = zh_nrf24_sensor_read_i16_le_at(buf, 4); uint8_t expected = zh_get_nrf24_sensor_payload_size(d.type); - if (expected == 0) { + if (expected == 0) + { ESP_LOGW(TAG, "Unknown sensor type %d, dropping", d.type); return; } - if (len != expected) { + if (len != expected) + { ESP_LOGW(TAG, "Length %u != expected %u for type %d", len, expected, d.type); } /* ----- Auto-register unknown {id, type} ----- */ - if (d.id >= BINDING_ID_MIN && d.id <= BINDING_ID_MAX) { + if (d.id >= BINDING_ID_MIN && d.id <= BINDING_ID_MAX) + { int r = zh_nrf_gateway_binding_auto_register((uint8_t)d.id, (uint8_t)d.type); - if (r == 1) { + if (r == 1) + { ESP_LOGI(TAG, "Auto-registered sensor: id=%d type=%d (%s)", d.id, d.type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d.type)); zh_nrf_gateway_binding_t b = { - .id = (uint8_t)d.id, + .id = (uint8_t)d.id, .type = (uint8_t)d.type, }; - esp_err_t perr = esp_event_post(ZH_NRF_GATEWAY_EVENTS, + esp_err_t perr = esp_event_post(ZH_NRF24_GATEWAY_EVENTS, ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED, &b, sizeof(b), pdMS_TO_TICKS(100)); - if (perr != ESP_OK) { + if (perr != ESP_OK) + { ESP_LOGW(TAG, "esp_event_post(registered) failed: %s", esp_err_to_name(perr)); } - } else if (r < 0) { + } + else if (r < 0) + { ESP_LOGW(TAG, "Auto-register failed for id=%d type=%d: %s", d.id, d.type, esp_err_to_name((esp_err_t)(-r))); } - } else { + } + else + { ESP_LOGW(TAG, "Sensor id %d out of range [%d..%d], skipping auto-register", d.id, BINDING_ID_MIN, BINDING_ID_MAX); } /* ----- Parse type-specific fields ----- */ - switch (d.type) { + switch (d.type) + { case ZH_NRF24_SENSOR_TOUCH_SWITCH: break; case ZH_NRF24_SENSOR_WATER_LEAKAGE: @@ -633,20 +704,23 @@ static void handle_sensor_data(const uint8_t *buf, uint8_t len) d.value_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6); break; case ZH_NRF24_SENSOR_BMP280: - if (len >= ZH_NRF24_DATA_HEADER_SIZE + 2 * ZH_NRF24_DATA_FIELD_SIZE) { + if (len >= ZH_NRF24_DATA_HEADER_SIZE + 2 * ZH_NRF24_DATA_FIELD_SIZE) + { d.value_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6); d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8); } break; case ZH_NRF24_SENSOR_BME280: - if (len >= ZH_NRF24_DATA_HEADER_SIZE + 3 * ZH_NRF24_DATA_FIELD_SIZE) { + if (len >= ZH_NRF24_DATA_HEADER_SIZE + 3 * ZH_NRF24_DATA_FIELD_SIZE) + { d.value_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6); d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8); d.value_3 = zh_nrf24_sensor_read_i16_le_at(buf, 10); } break; case ZH_NRF24_SENSOR_BME680: - if (len >= ZH_NRF24_DATA_HEADER_SIZE + 4 * ZH_NRF24_DATA_FIELD_SIZE) { + if (len >= ZH_NRF24_DATA_HEADER_SIZE + 4 * ZH_NRF24_DATA_FIELD_SIZE) + { d.value_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6); d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8); d.value_3 = zh_nrf24_sensor_read_i16_le_at(buf, 10); @@ -658,10 +732,11 @@ static void handle_sensor_data(const uint8_t *buf, uint8_t len) } /* ----- Post SENSOR_DATA ----- */ - esp_err_t err = esp_event_post(ZH_NRF_GATEWAY_EVENTS, + esp_err_t err = esp_event_post(ZH_NRF24_GATEWAY_EVENTS, ZH_NRF_GATEWAY_EVENT_SENSOR_DATA, &d, sizeof(d), pdMS_TO_TICKS(100)); - if (err != ESP_OK) { + if (err != ESP_OK) + { ESP_LOGW(TAG, "esp_event_post(data) failed: %s", esp_err_to_name(err)); } } @@ -669,10 +744,12 @@ static void handle_sensor_data(const uint8_t *buf, uint8_t len) static bool process_one_packet(void) { uint8_t fifo = nrf_read_register(NRF_REG_FIFO_STATUS); - if (fifo & NRF_FIFO_RX_EMPTY) return false; + if (fifo & NRF_FIFO_RX_EMPTY) + return false; uint8_t width = nrf_read_payload_width(); - if (width > ZH_NRF24_MAX_PAYLOAD_SIZE) { + if (width > ZH_NRF24_MAX_PAYLOAD_SIZE) + { ESP_LOGW(TAG, "Corrupt payload width %u, FLUSH_RX", width); nrf_send_command(NRF_CMD_FLUSH_RX); nrf_write_register(NRF_REG_STATUS, NRF_STATUS_RX_DR); @@ -683,9 +760,12 @@ static bool process_one_packet(void) nrf_read_payload(buf, width); nrf_write_register(NRF_REG_STATUS, NRF_STATUS_RX_DR); - if (width == ZH_NRF24_PAIRING_PACKET_SIZE && buf[1] == ZH_NRF24_PAIRING_REQ_MAGIC) { + if (width == ZH_NRF24_PAIRING_PACKET_SIZE && buf[1] == ZH_NRF24_PAIRING_REQ_MAGIC) + { handle_pairing_request(buf); - } else { + } + else + { handle_sensor_data(buf, width); } return true; @@ -693,15 +773,21 @@ static bool process_one_packet(void) static void process_all_pending(void) { - while (process_one_packet()) { } + while (process_one_packet()) + { + } } static void gateway_task(void *arg) { - while (1) { - if (xSemaphoreTake(s_ctx.irq_sem, pdMS_TO_TICKS(1000)) == pdTRUE) { + while (1) + { + if (xSemaphoreTake(s_ctx.irq_sem, pdMS_TO_TICKS(1000)) == pdTRUE) + { process_all_pending(); - } else { + } + else + { process_all_pending(); } } @@ -710,34 +796,43 @@ static void gateway_task(void *arg) /* ============================================================ * PUBLIC API * ============================================================ */ -esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) +esp_err_t zh_nrf_gateway_init(const zh_nrf24_gateway_init_config_t *config) { - if (!config) return ESP_ERR_INVALID_ARG; - if (s_ctx.initialized) return ESP_ERR_INVALID_STATE; + if (!config) + return ESP_ERR_INVALID_ARG; + if (s_ctx.initialized) + return ESP_ERR_INVALID_STATE; s_ctx.cfg = *config; - if (s_ctx.cfg.spi_clock_hz == 0) s_ctx.cfg.spi_clock_hz = 4 * 1000 * 1000; - if (s_ctx.cfg.channel > 125) s_ctx.cfg.channel = 120; + if (s_ctx.cfg.spi_clock_hz == 0) + s_ctx.cfg.spi_clock_hz = 4 * 1000 * 1000; + if (s_ctx.cfg.channel > 125) + s_ctx.cfg.channel = 120; esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) + { ESP_LOGW(TAG, "NVS flash needs erase, erasing"); ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; s_ctx.bindings_mutex = xSemaphoreCreateMutex(); - if (!s_ctx.bindings_mutex) return ESP_ERR_NO_MEM; + if (!s_ctx.bindings_mutex) + return ESP_ERR_NO_MEM; err = bindings_load(); - if (err != ESP_OK) { + if (err != ESP_OK) + { ESP_LOGW(TAG, "Bindings load failed (%s), starting empty", esp_err_to_name(err)); memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings)); } err = esp_event_loop_create_default(); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) return err; + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) + return err; spi_bus_config_t buscfg = { .miso_io_num = s_ctx.cfg.pin_miso, @@ -748,7 +843,8 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) .max_transfer_sz = ZH_NRF24_MAX_PAYLOAD_SIZE, }; err = spi_bus_initialize(s_ctx.cfg.spi_host, &buscfg, SPI_DMA_CH_AUTO); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; spi_device_interface_config_t devcfg = { .clock_speed_hz = (int)s_ctx.cfg.spi_clock_hz, @@ -757,14 +853,16 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) .queue_size = 1, }; err = spi_bus_add_device(s_ctx.cfg.spi_host, &devcfg, &s_ctx.spi); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; gpio_config_t ce_conf = { .pin_bit_mask = (1ULL << s_ctx.cfg.pin_ce), .mode = GPIO_MODE_OUTPUT, }; err = gpio_config(&ce_conf); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; nrf_ce_low(); vTaskDelay(pdMS_TO_TICKS(100)); @@ -772,10 +870,10 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) nrf_write_register(NRF_REG_CONFIG, 0x00); nrf_write_register(NRF_REG_EN_AA, 0x01); nrf_write_register(NRF_REG_EN_RXADDR, 0x01); - nrf_write_register(NRF_REG_SETUP_AW, 0x01); /* 3-byte address */ + nrf_write_register(NRF_REG_SETUP_AW, 0x01); /* 3-byte address */ nrf_write_register(NRF_REG_SETUP_RETR, 0xFF); nrf_write_register(NRF_REG_RF_CH, s_ctx.cfg.channel); - nrf_write_register(NRF_REG_RF_SETUP, 0x26); /* 250 kbps, 0 dBm */ + nrf_write_register(NRF_REG_RF_SETUP, 0x26); /* 250 kbps, 0 dBm */ uint8_t addr_bytes[3] = { (uint8_t)(s_ctx.cfg.address >> 0), @@ -786,12 +884,12 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) nrf_write_buffer(NRF_REG_RX_ADDR_P0, addr_bytes, 3); nrf_write_register(NRF_REG_STATUS, - NRF_STATUS_RX_DR | NRF_STATUS_TX_DS | NRF_STATUS_MAX_RT); + NRF_STATUS_RX_DR | NRF_STATUS_TX_DS | NRF_STATUS_MAX_RT); /* Enable Dynamic Payload Length */ nrf_activate(); nrf_write_register(NRF_REG_FEATURE, NRF_FEATURE_EN_DPL); - nrf_write_register(NRF_REG_DYNPD, NRF_DYNPD_DPL_P0); + nrf_write_register(NRF_REG_DYNPD, NRF_DYNPD_DPL_P0); /* Enter RX */ nrf_write_register(NRF_REG_CONFIG, NRF_CONFIG_RX_UNMASKED); @@ -800,7 +898,8 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) vTaskDelay(pdMS_TO_TICKS(1)); err = nrf_irq_init(); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; xSemaphoreTake(s_ctx.irq_sem, 0); @@ -813,13 +912,16 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config) esp_err_t zh_nrf_gateway_start(void) { - if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE; - if (s_ctx.task) return ESP_OK; + if (!s_ctx.initialized) + return ESP_ERR_INVALID_STATE; + if (s_ctx.task) + return ESP_OK; BaseType_t r = xTaskCreatePinnedToCore(gateway_task, "nrf_gateway", 4096, NULL, 5, &s_ctx.task, tskNO_AFFINITY); - if (r != pdPASS) { + if (r != pdPASS) + { s_ctx.task = NULL; return ESP_ERR_NO_MEM; }