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

No files matched your search

+238 -136
View File
@@ -1,21 +1,22 @@
#include "zh_nrf24_gateway.h"
#include <stdio.h>
#include <string.h>
// #include <stdio.h>
// #include <string.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"
// #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;
}