wip:
This commit is contained in:
1 parent
036b856a93
commit
384360d2a4
3 files changed
+326
-264
No files matched your search
@@ -1,20 +1,21 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
|
|
||||||
#include "zh_nrf24_gateway.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
|
void zh_nrf24_gateway_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
#define GW_ADDRESS 0xDDEEFF
|
|
||||||
|
|
||||||
static const zh_nrf_gateway_config_t s_gw_config = {
|
void app_main(void)
|
||||||
|
{
|
||||||
|
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,
|
.spi_host = SPI2_HOST,
|
||||||
.pin_sck = 18,
|
.pin_sck = 18,
|
||||||
.pin_miso = 19,
|
.pin_miso = 19,
|
||||||
@@ -22,101 +23,54 @@ static const zh_nrf_gateway_config_t s_gw_config = {
|
|||||||
.pin_csn = 17,
|
.pin_csn = 17,
|
||||||
.pin_ce = 16,
|
.pin_ce = 16,
|
||||||
.pin_irq = 4,
|
.pin_irq = 4,
|
||||||
.channel = GW_CHANNEL,
|
.channel = GATEWAY_CHANNEL,
|
||||||
.address = GW_ADDRESS,
|
.address = GATEWAY_ADDRESS,
|
||||||
.spi_clock_hz = 0,
|
.spi_clock_hz = 0,
|
||||||
};
|
};
|
||||||
|
zh_nrf_gateway_init(&config);
|
||||||
static void handle_paired_event(const zh_nrf_gateway_binding_t *b)
|
zh_nrf_gateway_start();
|
||||||
{
|
|
||||||
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)
|
void zh_nrf24_gateway_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||||
{
|
{
|
||||||
const char *name = zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d->type);
|
switch (event_id)
|
||||||
|
|
||||||
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:
|
case ZH_NRF_GATEWAY_EVENT_SENSOR_DATA:
|
||||||
handle_sensor_data_event((const zh_nrf24_sensor_transmitted_data_t *)event_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;
|
break;
|
||||||
|
|
||||||
case ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED:
|
case ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED:
|
||||||
handle_paired_event((const zh_nrf_gateway_binding_t *)event_data);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "Starting nRF24L01+ gateway");
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
+52
-46
@@ -30,35 +30,32 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.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_err.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "driver/spi_master.h"
|
#include "driver/spi_master.h"
|
||||||
#include "zh_nrf24_config.h"
|
#include "zh_nrf24_config.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Max entries in the binding table (RAM and NVS). */
|
extern TaskHandle_t zh_nrf24_gateway;
|
||||||
#define ZH_NRF_GATEWAY_MAX_BINDINGS 254
|
|
||||||
|
|
||||||
ESP_EVENT_DECLARE_BASE(ZH_NRF_GATEWAY_EVENTS);
|
typedef struct
|
||||||
|
{
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
/** Sensor telemetry (data: zh_nrf24_sensor_transmitted_data_t) */
|
|
||||||
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
|
|
||||||
|
|
||||||
/** Pairing completed (data: zh_nrf_gateway_binding_t) */
|
|
||||||
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
|
|
||||||
|
|
||||||
/** 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;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
spi_host_device_t spi_host; /*!< SPI host (SPI2_HOST / SPI3_HOST) */
|
spi_host_device_t spi_host; /*!< SPI host (SPI2_HOST / SPI3_HOST) */
|
||||||
int pin_sck; /*!< SCK GPIO */
|
int pin_sck; /*!< SCK GPIO */
|
||||||
int pin_miso; /*!< MISO GPIO */
|
int pin_miso; /*!< MISO GPIO */
|
||||||
@@ -69,16 +66,25 @@ typedef struct
|
|||||||
uint8_t channel; /*!< RF channel (0..125) */
|
uint8_t channel; /*!< RF channel (0..125) */
|
||||||
uint32_t address; /*!< 24-bit pipe address, transmitted as LE bytes */
|
uint32_t address; /*!< 24-bit pipe address, transmitted as LE bytes */
|
||||||
uint32_t spi_clock_hz; /*!< SPI clock, 0 → default 4 MHz */
|
uint32_t spi_clock_hz; /*!< SPI clock, 0 → default 4 MHz */
|
||||||
} zh_nrf_gateway_config_t;
|
} zh_nrf24_gateway_init_config_t;
|
||||||
|
|
||||||
/** A single {id, type} binding. */
|
typedef enum
|
||||||
typedef struct
|
{
|
||||||
{
|
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
|
||||||
|
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
|
||||||
|
ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED,
|
||||||
|
} zh_nrf24_gateway_event_t;
|
||||||
|
|
||||||
|
ESP_EVENT_DECLARE_BASE(ZH_NRF24_GATEWAY_EVENTS);
|
||||||
|
|
||||||
|
/** A single {id, type} binding. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
uint8_t id; /**< 1..254, 0xFF = unassigned */
|
uint8_t id; /**< 1..254, 0xFF = unassigned */
|
||||||
uint8_t type; /**< zh_nrf24_sensor_type_t */
|
uint8_t type; /**< zh_nrf24_sensor_type_t */
|
||||||
} zh_nrf_gateway_binding_t;
|
} zh_nrf_gateway_binding_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the gateway.
|
* @brief Initialize the gateway.
|
||||||
*
|
*
|
||||||
* Configures SPI, the IRQ GPIO with falling-edge interrupt, the nRF24L01+
|
* Configures SPI, the IRQ GPIO with falling-edge interrupt, the nRF24L01+
|
||||||
@@ -89,9 +95,9 @@ typedef struct
|
|||||||
*
|
*
|
||||||
* @return ESP_OK on success, or an ESP-IDF error code
|
* @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);
|
esp_err_t zh_nrf_gateway_init(const zh_nrf24_gateway_init_config_t *config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the receiver task.
|
* @brief Start the receiver task.
|
||||||
*
|
*
|
||||||
* The task blocks on the IRQ semaphore (or polls the FIFO as a fallback
|
* The task blocks on the IRQ semaphore (or polls the FIFO as a fallback
|
||||||
@@ -99,29 +105,29 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config);
|
|||||||
*
|
*
|
||||||
* @return ESP_OK on success
|
* @return ESP_OK on success
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_nrf_gateway_start(void);
|
esp_err_t zh_nrf_gateway_start(void);
|
||||||
|
|
||||||
/* ===================== BINDING TABLE API ===================== */
|
/* ===================== BINDING TABLE API ===================== */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copy current bindings into @p buf.
|
* @brief Copy current bindings into @p buf.
|
||||||
*
|
*
|
||||||
* Thread-safe. Returns number of entries copied (≤ max_count and ≤
|
* Thread-safe. Returns number of entries copied (≤ max_count and ≤
|
||||||
* current table size).
|
* current table size).
|
||||||
*/
|
*/
|
||||||
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count);
|
size_t zh_nrf_gateway_bindings_get(zh_nrf_gateway_binding_t *buf, size_t max_count);
|
||||||
|
|
||||||
/** @brief Current number of bindings in the table. */
|
/** @brief Current number of bindings in the table. */
|
||||||
size_t zh_nrf_gateway_bindings_count(void);
|
size_t zh_nrf_gateway_bindings_count(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check whether a {id, type} binding exists.
|
* @brief Check whether a {id, type} binding exists.
|
||||||
*
|
*
|
||||||
* @return true if the binding is present in the table
|
* @return true if the binding is present in the table
|
||||||
*/
|
*/
|
||||||
bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
|
bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Auto-register {id, type} if not present.
|
* @brief Auto-register {id, type} if not present.
|
||||||
*
|
*
|
||||||
* Validates both fields, then adds the pair to the table and persists
|
* Validates both fields, then adds the pair to the table and persists
|
||||||
@@ -132,9 +138,9 @@ bool zh_nrf_gateway_binding_exists(uint8_t id, uint8_t type);
|
|||||||
* @return 0 binding already existed
|
* @return 0 binding already existed
|
||||||
* @return negative ESP error (invalid arg, NVS failure, etc.)
|
* @return negative ESP error (invalid arg, NVS failure, etc.)
|
||||||
*/
|
*/
|
||||||
int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type);
|
int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete a {id, type} binding.
|
* @brief Delete a {id, type} binding.
|
||||||
*
|
*
|
||||||
* Composite key: both @p id AND @p type must match. If only one matches,
|
* Composite key: both @p id AND @p type must match. If only one matches,
|
||||||
@@ -142,16 +148,16 @@ int zh_nrf_gateway_binding_auto_register(uint8_t id, uint8_t type);
|
|||||||
*
|
*
|
||||||
* @return ESP_OK / ESP_ERR_NOT_FOUND / ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE / NVS error
|
* @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);
|
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type);
|
||||||
|
|
||||||
/** Delete every binding whose id equals @p id (any type). Returns count, or -err. */
|
/** 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);
|
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. */
|
/** 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);
|
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type);
|
||||||
|
|
||||||
/** Remove all bindings (persisted). */
|
/** Remove all bindings (persisted). */
|
||||||
esp_err_t zh_nrf_gateway_binding_clear_all(void);
|
esp_err_t zh_nrf_gateway_binding_clear_all(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+222
-120
@@ -1,21 +1,22 @@
|
|||||||
#include "zh_nrf24_gateway.h"
|
#include "zh_nrf24_gateway.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
// #include <stdio.h>
|
||||||
#include <string.h>
|
// #include <string.h>
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
// #include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
// #include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
// #include "freertos/semphr.h"
|
||||||
#include "driver/spi_master.h"
|
// #include "driver/spi_master.h"
|
||||||
#include "driver/gpio.h"
|
// #include "driver/gpio.h"
|
||||||
#include "esp_log.h"
|
// #include "esp_log.h"
|
||||||
#include "esp_rom_sys.h"
|
// #include "esp_rom_sys.h"
|
||||||
#include "nvs_flash.h"
|
// #include "nvs_flash.h"
|
||||||
#include "nvs.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";
|
static const char *TAG = "NRF_GW";
|
||||||
|
#define ZH_NRF_GATEWAY_MAX_BINDINGS 254
|
||||||
|
|
||||||
/* ================== nRF24 КОМАНДЫ / РЕГИСТРЫ ================== */
|
/* ================== nRF24 КОМАНДЫ / РЕГИСТРЫ ================== */
|
||||||
#define NRF_CMD_R_REGISTER 0x00
|
#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_PWR_UP 0x02
|
||||||
#define NRF_CONFIG_PRIM_RX 0x01
|
#define NRF_CONFIG_PRIM_RX 0x01
|
||||||
|
|
||||||
#define NRF_CONFIG_ALL_MASKED \
|
#define NRF_CONFIG_ALL_MASKED (NRF_CONFIG_MASK_RX_DR | NRF_CONFIG_MASK_TX_DS | NRF_CONFIG_MASK_MAX_RT | NRF_CONFIG_EN_CRC)
|
||||||
(NRF_CONFIG_MASK_RX_DR | NRF_CONFIG_MASK_TX_DS | \
|
#define NRF_CONFIG_RX_UNMASKED (NRF_CONFIG_EN_CRC | NRF_CONFIG_PWR_UP | NRF_CONFIG_PRIM_RX)
|
||||||
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_RX_DR 0x40
|
||||||
#define NRF_STATUS_TX_DS 0x20
|
#define NRF_STATUS_TX_DS 0x20
|
||||||
@@ -80,7 +77,7 @@ typedef struct __attribute__((packed))
|
|||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
zh_nrf_gateway_config_t cfg;
|
zh_nrf24_gateway_init_config_t cfg;
|
||||||
spi_device_handle_t spi;
|
spi_device_handle_t spi;
|
||||||
SemaphoreHandle_t irq_sem;
|
SemaphoreHandle_t irq_sem;
|
||||||
SemaphoreHandle_t bindings_mutex;
|
SemaphoreHandle_t bindings_mutex;
|
||||||
@@ -177,13 +174,15 @@ static void IRAM_ATTR nrf_irq_isr(void *arg)
|
|||||||
{
|
{
|
||||||
BaseType_t woken = pdFALSE;
|
BaseType_t woken = pdFALSE;
|
||||||
xSemaphoreGiveFromISR(s_ctx.irq_sem, &woken);
|
xSemaphoreGiveFromISR(s_ctx.irq_sem, &woken);
|
||||||
if (woken) portYIELD_FROM_ISR();
|
if (woken)
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t nrf_irq_init(void)
|
static esp_err_t nrf_irq_init(void)
|
||||||
{
|
{
|
||||||
s_ctx.irq_sem = xSemaphoreCreateBinary();
|
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 = {
|
gpio_config_t io_conf = {
|
||||||
.pin_bit_mask = (1ULL << s_ctx.cfg.pin_irq),
|
.pin_bit_mask = (1ULL << s_ctx.cfg.pin_irq),
|
||||||
@@ -193,10 +192,12 @@ static esp_err_t nrf_irq_init(void)
|
|||||||
.intr_type = GPIO_INTR_NEGEDGE,
|
.intr_type = GPIO_INTR_NEGEDGE,
|
||||||
};
|
};
|
||||||
esp_err_t err = gpio_config(&io_conf);
|
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);
|
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);
|
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;
|
nvs_handle_t h;
|
||||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &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));
|
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
||||||
return ESP_OK;
|
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);
|
err = nvs_get_blob(h, NVS_KEY_BINDINGS, &s_ctx.bindings, &size);
|
||||||
nvs_close(h);
|
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));
|
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
||||||
ESP_LOGI(TAG, "Bindings: empty (first run)");
|
ESP_LOGI(TAG, "Bindings: empty (first run)");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
||||||
return err;
|
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);
|
ESP_LOGW(TAG, "Bindings: corrupt count %u, resetting", s_ctx.bindings.count);
|
||||||
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -241,12 +246,14 @@ static esp_err_t bindings_save(void)
|
|||||||
{
|
{
|
||||||
nvs_handle_t h;
|
nvs_handle_t h;
|
||||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &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) +
|
size_t size = sizeof(s_ctx.bindings.count) +
|
||||||
s_ctx.bindings.count * sizeof(zh_nrf_gateway_binding_t);
|
s_ctx.bindings.count * sizeof(zh_nrf_gateway_binding_t);
|
||||||
err = nvs_set_blob(h, NVS_KEY_BINDINGS, &s_ctx.bindings, size);
|
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);
|
nvs_close(h);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -254,9 +261,11 @@ static esp_err_t bindings_save(void)
|
|||||||
/* Caller must hold bindings_mutex. */
|
/* Caller must hold bindings_mutex. */
|
||||||
static bool bindings_exists_locked(uint8_t id, uint8_t type)
|
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 &&
|
if (s_ctx.bindings.items[i].id == id &&
|
||||||
s_ctx.bindings.items[i].type == type) {
|
s_ctx.bindings.items[i].type == type)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,8 +275,10 @@ static bool bindings_exists_locked(uint8_t id, uint8_t type)
|
|||||||
/* Caller must hold bindings_mutex. */
|
/* Caller must hold bindings_mutex. */
|
||||||
static uint8_t bindings_alloc_id(uint8_t type)
|
static uint8_t bindings_alloc_id(uint8_t type)
|
||||||
{
|
{
|
||||||
for (uint16_t id = BINDING_ID_MIN; id <= BINDING_ID_MAX; id++) {
|
for (uint16_t id = BINDING_ID_MIN; id <= BINDING_ID_MAX; id++)
|
||||||
if (!bindings_exists_locked((uint8_t)id, type)) {
|
{
|
||||||
|
if (!bindings_exists_locked((uint8_t)id, type))
|
||||||
|
{
|
||||||
return (uint8_t)id;
|
return (uint8_t)id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +288,8 @@ static uint8_t bindings_alloc_id(uint8_t type)
|
|||||||
/* Caller must hold bindings_mutex. */
|
/* Caller must hold bindings_mutex. */
|
||||||
static esp_err_t bindings_add(uint8_t id, uint8_t type)
|
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;
|
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;
|
||||||
@@ -289,9 +301,11 @@ static esp_err_t bindings_add(uint8_t id, uint8_t type)
|
|||||||
/* Caller must hold bindings_mutex. */
|
/* Caller must hold bindings_mutex. */
|
||||||
static esp_err_t bindings_delete(uint8_t id, uint8_t type)
|
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 &&
|
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],
|
memmove(&s_ctx.bindings.items[i],
|
||||||
&s_ctx.bindings.items[i + 1],
|
&s_ctx.bindings.items[i + 1],
|
||||||
(s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t));
|
(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)
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
size_t n = s_ctx.bindings.count < max_count ? s_ctx.bindings.count : max_count;
|
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));
|
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)
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
size_t n = s_ctx.bindings.count;
|
size_t n = s_ctx.bindings.count;
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
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)
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
bool found = bindings_exists_locked(id, type);
|
bool found = bindings_exists_locked(id, type);
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
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)
|
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 (!s_ctx.initialized || !s_ctx.bindings_mutex)
|
||||||
if (id < BINDING_ID_MIN || id > BINDING_ID_MAX) return -ESP_ERR_INVALID_ARG;
|
return -ESP_ERR_INVALID_STATE;
|
||||||
if (zh_get_nrf24_sensor_payload_size(type) == 0) return -ESP_ERR_INVALID_ARG;
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (!bindings_exists_locked(id, type)) {
|
if (!bindings_exists_locked(id, type))
|
||||||
|
{
|
||||||
esp_err_t err = bindings_add(id, type);
|
esp_err_t err = bindings_add(id, type);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK)
|
||||||
|
{
|
||||||
result = 1;
|
result = 1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (s_ctx.bindings.count > 0 &&
|
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].id == id &&
|
||||||
s_ctx.bindings.items[s_ctx.bindings.count - 1].type == type) {
|
s_ctx.bindings.items[s_ctx.bindings.count - 1].type == type)
|
||||||
|
{
|
||||||
s_ctx.bindings.count--;
|
s_ctx.bindings.count--;
|
||||||
}
|
}
|
||||||
result = -(int)err;
|
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)
|
esp_err_t zh_nrf_gateway_binding_delete(uint8_t id, uint8_t type)
|
||||||
{
|
{
|
||||||
if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE;
|
if (!s_ctx.initialized)
|
||||||
if (id == 0 || id == 0xFF) return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_STATE;
|
||||||
if (zh_get_nrf24_sensor_payload_size(type) == 0) return ESP_ERR_INVALID_ARG;
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
esp_err_t err = bindings_delete(id, type);
|
esp_err_t err = bindings_delete(id, type);
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
|
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Binding deleted: id=%u type=%u (%s)",
|
ESP_LOGI(TAG, "Binding deleted: id=%u type=%u (%s)",
|
||||||
id, type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type));
|
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)",
|
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));
|
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",
|
ESP_LOGE(TAG, "Binding delete failed (id=%u type=%u): %s",
|
||||||
id, type, esp_err_to_name(err));
|
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)
|
int zh_nrf_gateway_bindings_delete_by_id(uint8_t id)
|
||||||
{
|
{
|
||||||
if (!s_ctx.initialized) return -ESP_ERR_INVALID_STATE;
|
if (!s_ctx.initialized)
|
||||||
if (id == 0 || id == 0xFF) return -ESP_ERR_INVALID_ARG;
|
return -ESP_ERR_INVALID_STATE;
|
||||||
|
if (id == 0 || id == 0xFF)
|
||||||
|
return -ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
for (uint16_t i = 0; i < s_ctx.bindings.count; ) {
|
for (uint16_t i = 0; i < s_ctx.bindings.count;)
|
||||||
if (s_ctx.bindings.items[i].id == id) {
|
{
|
||||||
|
if (s_ctx.bindings.items[i].id == id)
|
||||||
|
{
|
||||||
memmove(&s_ctx.bindings.items[i],
|
memmove(&s_ctx.bindings.items[i],
|
||||||
&s_ctx.bindings.items[i + 1],
|
&s_ctx.bindings.items[i + 1],
|
||||||
(s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t));
|
(s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t));
|
||||||
s_ctx.bindings.count--;
|
s_ctx.bindings.count--;
|
||||||
deleted++;
|
deleted++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK;
|
esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK;
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
|
|
||||||
if (err != ESP_OK) return -(int)err;
|
if (err != ESP_OK)
|
||||||
if (deleted > 0) ESP_LOGI(TAG, "Deleted %d binding(s) with id=%u", deleted, id);
|
return -(int)err;
|
||||||
else ESP_LOGW(TAG, "No bindings with id=%u", id);
|
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;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type)
|
int zh_nrf_gateway_bindings_delete_by_type(uint8_t type)
|
||||||
{
|
{
|
||||||
if (!s_ctx.initialized) return -ESP_ERR_INVALID_STATE;
|
if (!s_ctx.initialized)
|
||||||
if (zh_get_nrf24_sensor_payload_size(type) == 0) return -ESP_ERR_INVALID_ARG;
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
for (uint16_t i = 0; i < s_ctx.bindings.count; ) {
|
for (uint16_t i = 0; i < s_ctx.bindings.count;)
|
||||||
if (s_ctx.bindings.items[i].type == type) {
|
{
|
||||||
|
if (s_ctx.bindings.items[i].type == type)
|
||||||
|
{
|
||||||
memmove(&s_ctx.bindings.items[i],
|
memmove(&s_ctx.bindings.items[i],
|
||||||
&s_ctx.bindings.items[i + 1],
|
&s_ctx.bindings.items[i + 1],
|
||||||
(s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t));
|
(s_ctx.bindings.count - i - 1) * sizeof(zh_nrf_gateway_binding_t));
|
||||||
s_ctx.bindings.count--;
|
s_ctx.bindings.count--;
|
||||||
deleted++;
|
deleted++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK;
|
esp_err_t err = (deleted > 0) ? bindings_save() : ESP_OK;
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
|
|
||||||
if (err != ESP_OK) return -(int)err;
|
if (err != ESP_OK)
|
||||||
if (deleted > 0) {
|
return -(int)err;
|
||||||
|
if (deleted > 0)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Deleted %d binding(s) of type=%u (%s)",
|
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));
|
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)",
|
ESP_LOGW(TAG, "No bindings of type=%u (%s)",
|
||||||
type, zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)type));
|
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)
|
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);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
s_ctx.bindings.count = 0;
|
s_ctx.bindings.count = 0;
|
||||||
esp_err_t err = bindings_save();
|
esp_err_t err = bindings_save();
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
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;
|
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,
|
ZH_NRF24_PAIRING_ACK_MAGIC,
|
||||||
(uint8_t)(token >> 8),
|
(uint8_t)(token >> 8),
|
||||||
(uint8_t)(token & 0xFF),
|
(uint8_t)(token & 0xFF),
|
||||||
new_id
|
new_id};
|
||||||
};
|
|
||||||
|
|
||||||
nrf_ce_low();
|
nrf_ce_low();
|
||||||
nrf_write_register(NRF_REG_CONFIG, NRF_CONFIG_ALL_MASKED | NRF_CONFIG_PWR_UP);
|
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();
|
nrf_ce_low();
|
||||||
|
|
||||||
uint8_t status = 0;
|
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);
|
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));
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +579,8 @@ static void handle_pairing_request(const uint8_t *data)
|
|||||||
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
uint8_t new_id = bindings_alloc_id(req_type);
|
uint8_t new_id = bindings_alloc_id(req_type);
|
||||||
if (new_id == 0) {
|
if (new_id == 0)
|
||||||
|
{
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
ESP_LOGW(TAG, "Pairing: no free id for type %u (all %d used)",
|
ESP_LOGW(TAG, "Pairing: no free id for type %u (all %d used)",
|
||||||
req_type, BINDING_ID_MAX);
|
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);
|
esp_err_t err = bindings_add(new_id, req_type);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
if (s_ctx.bindings.count > 0 &&
|
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].id == new_id &&
|
||||||
s_ctx.bindings.items[s_ctx.bindings.count - 1].type == req_type) {
|
s_ctx.bindings.items[s_ctx.bindings.count - 1].type == req_type)
|
||||||
|
{
|
||||||
s_ctx.bindings.count--;
|
s_ctx.bindings.count--;
|
||||||
}
|
}
|
||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
@@ -546,7 +604,8 @@ static void handle_pairing_request(const uint8_t *data)
|
|||||||
xSemaphoreGive(s_ctx.bindings_mutex);
|
xSemaphoreGive(s_ctx.bindings_mutex);
|
||||||
ESP_LOGI(TAG, "Pairing: allocated id=%u for type=%u", new_id, req_type);
|
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",
|
ESP_LOGW(TAG, "Pairing: ACK not delivered, removing binding id=%u type=%u",
|
||||||
new_id, req_type);
|
new_id, req_type);
|
||||||
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
xSemaphoreTake(s_ctx.bindings_mutex, portMAX_DELAY);
|
||||||
@@ -561,18 +620,20 @@ static void handle_pairing_request(const uint8_t *data)
|
|||||||
.id = new_id,
|
.id = new_id,
|
||||||
.type = req_type,
|
.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,
|
ZH_NRF_GATEWAY_EVENT_SENSOR_PAIRED,
|
||||||
&paired, sizeof(paired),
|
&paired, sizeof(paired),
|
||||||
pdMS_TO_TICKS(100));
|
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));
|
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)
|
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);
|
ESP_LOGW(TAG, "Too short data packet (%u)", len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -583,20 +644,24 @@ static void handle_sensor_data(const uint8_t *buf, uint8_t len)
|
|||||||
d.battery = zh_nrf24_sensor_read_i16_le_at(buf, 4);
|
d.battery = zh_nrf24_sensor_read_i16_le_at(buf, 4);
|
||||||
|
|
||||||
uint8_t expected = zh_get_nrf24_sensor_payload_size(d.type);
|
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);
|
ESP_LOGW(TAG, "Unknown sensor type %d, dropping", d.type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (len != expected) {
|
if (len != expected)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "Length %u != expected %u for type %d",
|
ESP_LOGW(TAG, "Length %u != expected %u for type %d",
|
||||||
len, expected, d.type);
|
len, expected, d.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- Auto-register unknown {id, 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,
|
int r = zh_nrf_gateway_binding_auto_register((uint8_t)d.id,
|
||||||
(uint8_t)d.type);
|
(uint8_t)d.type);
|
||||||
if (r == 1) {
|
if (r == 1)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Auto-registered sensor: id=%d type=%d (%s)",
|
ESP_LOGI(TAG, "Auto-registered sensor: id=%d type=%d (%s)",
|
||||||
d.id, d.type,
|
d.id, d.type,
|
||||||
zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d.type));
|
zh_get_nrf24_sensor_type_name((zh_nrf24_sensor_type_t)d.type));
|
||||||
@@ -605,25 +670,31 @@ static void handle_sensor_data(const uint8_t *buf, uint8_t len)
|
|||||||
.id = (uint8_t)d.id,
|
.id = (uint8_t)d.id,
|
||||||
.type = (uint8_t)d.type,
|
.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,
|
ZH_NRF_GATEWAY_EVENT_SENSOR_REGISTERED,
|
||||||
&b, sizeof(b),
|
&b, sizeof(b),
|
||||||
pdMS_TO_TICKS(100));
|
pdMS_TO_TICKS(100));
|
||||||
if (perr != ESP_OK) {
|
if (perr != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "esp_event_post(registered) failed: %s",
|
ESP_LOGW(TAG, "esp_event_post(registered) failed: %s",
|
||||||
esp_err_to_name(perr));
|
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",
|
ESP_LOGW(TAG, "Auto-register failed for id=%d type=%d: %s",
|
||||||
d.id, d.type, esp_err_to_name((esp_err_t)(-r)));
|
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",
|
ESP_LOGW(TAG, "Sensor id %d out of range [%d..%d], skipping auto-register",
|
||||||
d.id, BINDING_ID_MIN, BINDING_ID_MAX);
|
d.id, BINDING_ID_MIN, BINDING_ID_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- Parse type-specific fields ----- */
|
/* ----- Parse type-specific fields ----- */
|
||||||
switch (d.type) {
|
switch (d.type)
|
||||||
|
{
|
||||||
case ZH_NRF24_SENSOR_TOUCH_SWITCH:
|
case ZH_NRF24_SENSOR_TOUCH_SWITCH:
|
||||||
break;
|
break;
|
||||||
case ZH_NRF24_SENSOR_WATER_LEAKAGE:
|
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);
|
d.value_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6);
|
||||||
break;
|
break;
|
||||||
case ZH_NRF24_SENSOR_BMP280:
|
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_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6);
|
||||||
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ZH_NRF24_SENSOR_BME280:
|
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_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6);
|
||||||
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
||||||
d.value_3 = zh_nrf24_sensor_read_i16_le_at(buf, 10);
|
d.value_3 = zh_nrf24_sensor_read_i16_le_at(buf, 10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ZH_NRF24_SENSOR_BME680:
|
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_1 = zh_nrf24_sensor_read_i16_le_at(buf, 6);
|
||||||
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
d.value_2 = zh_nrf24_sensor_read_i16_le_at(buf, 8);
|
||||||
d.value_3 = zh_nrf24_sensor_read_i16_le_at(buf, 10);
|
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 ----- */
|
/* ----- 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,
|
ZH_NRF_GATEWAY_EVENT_SENSOR_DATA,
|
||||||
&d, sizeof(d), pdMS_TO_TICKS(100));
|
&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));
|
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)
|
static bool process_one_packet(void)
|
||||||
{
|
{
|
||||||
uint8_t fifo = nrf_read_register(NRF_REG_FIFO_STATUS);
|
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();
|
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);
|
ESP_LOGW(TAG, "Corrupt payload width %u, FLUSH_RX", width);
|
||||||
nrf_send_command(NRF_CMD_FLUSH_RX);
|
nrf_send_command(NRF_CMD_FLUSH_RX);
|
||||||
nrf_write_register(NRF_REG_STATUS, NRF_STATUS_RX_DR);
|
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_read_payload(buf, width);
|
||||||
nrf_write_register(NRF_REG_STATUS, NRF_STATUS_RX_DR);
|
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);
|
handle_pairing_request(buf);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
handle_sensor_data(buf, width);
|
handle_sensor_data(buf, width);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -693,15 +773,21 @@ static bool process_one_packet(void)
|
|||||||
|
|
||||||
static void process_all_pending(void)
|
static void process_all_pending(void)
|
||||||
{
|
{
|
||||||
while (process_one_packet()) { }
|
while (process_one_packet())
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gateway_task(void *arg)
|
static void gateway_task(void *arg)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1)
|
||||||
if (xSemaphoreTake(s_ctx.irq_sem, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
{
|
||||||
|
if (xSemaphoreTake(s_ctx.irq_sem, pdMS_TO_TICKS(1000)) == pdTRUE)
|
||||||
|
{
|
||||||
process_all_pending();
|
process_all_pending();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
process_all_pending();
|
process_all_pending();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -710,34 +796,43 @@ static void gateway_task(void *arg)
|
|||||||
/* ============================================================
|
/* ============================================================
|
||||||
* PUBLIC API
|
* 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 (!config)
|
||||||
if (s_ctx.initialized) return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
if (s_ctx.initialized)
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
|
||||||
s_ctx.cfg = *config;
|
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.spi_clock_hz == 0)
|
||||||
if (s_ctx.cfg.channel > 125) s_ctx.cfg.channel = 120;
|
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();
|
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_LOGW(TAG, "NVS flash needs erase, erasing");
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
err = nvs_flash_init();
|
err = nvs_flash_init();
|
||||||
}
|
}
|
||||||
if (err != ESP_OK) return err;
|
if (err != ESP_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
s_ctx.bindings_mutex = xSemaphoreCreateMutex();
|
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();
|
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));
|
ESP_LOGW(TAG, "Bindings load failed (%s), starting empty", esp_err_to_name(err));
|
||||||
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
memset(&s_ctx.bindings, 0, sizeof(s_ctx.bindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
err = esp_event_loop_create_default();
|
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 = {
|
spi_bus_config_t buscfg = {
|
||||||
.miso_io_num = s_ctx.cfg.pin_miso,
|
.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,
|
.max_transfer_sz = ZH_NRF24_MAX_PAYLOAD_SIZE,
|
||||||
};
|
};
|
||||||
err = spi_bus_initialize(s_ctx.cfg.spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
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 = {
|
spi_device_interface_config_t devcfg = {
|
||||||
.clock_speed_hz = (int)s_ctx.cfg.spi_clock_hz,
|
.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,
|
.queue_size = 1,
|
||||||
};
|
};
|
||||||
err = spi_bus_add_device(s_ctx.cfg.spi_host, &devcfg, &s_ctx.spi);
|
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 = {
|
gpio_config_t ce_conf = {
|
||||||
.pin_bit_mask = (1ULL << s_ctx.cfg.pin_ce),
|
.pin_bit_mask = (1ULL << s_ctx.cfg.pin_ce),
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
};
|
};
|
||||||
err = gpio_config(&ce_conf);
|
err = gpio_config(&ce_conf);
|
||||||
if (err != ESP_OK) return err;
|
if (err != ESP_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
nrf_ce_low();
|
nrf_ce_low();
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
@@ -800,7 +898,8 @@ esp_err_t zh_nrf_gateway_init(const zh_nrf_gateway_config_t *config)
|
|||||||
vTaskDelay(pdMS_TO_TICKS(1));
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
|
|
||||||
err = nrf_irq_init();
|
err = nrf_irq_init();
|
||||||
if (err != ESP_OK) return err;
|
if (err != ESP_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
xSemaphoreTake(s_ctx.irq_sem, 0);
|
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)
|
esp_err_t zh_nrf_gateway_start(void)
|
||||||
{
|
{
|
||||||
if (!s_ctx.initialized) return ESP_ERR_INVALID_STATE;
|
if (!s_ctx.initialized)
|
||||||
if (s_ctx.task) return ESP_OK;
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
if (s_ctx.task)
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
BaseType_t r = xTaskCreatePinnedToCore(gateway_task, "nrf_gateway",
|
BaseType_t r = xTaskCreatePinnedToCore(gateway_task, "nrf_gateway",
|
||||||
4096, NULL, 5,
|
4096, NULL, 5,
|
||||||
&s_ctx.task, tskNO_AFFINITY);
|
&s_ctx.task, tskNO_AFFINITY);
|
||||||
if (r != pdPASS) {
|
if (r != pdPASS)
|
||||||
|
{
|
||||||
s_ctx.task = NULL;
|
s_ctx.task = NULL;
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user