From 9a668b759ef693e3bf262065dfa24c1bb5f85558 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov <git@zh.com.ru> Date: Thu, 16 May 2024 16:02:27 +0300 Subject: [PATCH] 5 --- CMakeLists.txt | 2 +- include/zh_rf24.h | 69 +++------- main.c | 72 ++++++++++ zh_rf24.c | 336 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 401 insertions(+), 78 deletions(-) create mode 100644 main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e01365a..71e28a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1 +1 @@ -idf_component_register(SRCS "zh_rf24.c" INCLUDE_DIRS "include" REQUIRES driver esp_event) \ No newline at end of file +idf_component_register(SRCS "main.c" "zh_rf24.c" INCLUDE_DIRS "include" REQUIRES driver esp_event) \ No newline at end of file diff --git a/include/zh_rf24.h b/include/zh_rf24.h index 247bff5..8befd55 100644 --- a/include/zh_rf24.h +++ b/include/zh_rf24.h @@ -26,28 +26,24 @@ * @brief Default values for zh_rf24_init_config_t structure for initial initialization of RF24 interface. * */ -#define ZH_RF24_INIT_CONFIG_DEFAULT() \ - { \ - .ce_pin = 1, \ - .csn_pin = 2, \ - .sck_pin = 3, \ - .mosi_pin = 4, \ - .miso_pin = 5, \ - .irq_pin = 6, \ - .work_mode = ZH_RF24_RECEIVER, \ - .channel = 100, \ - .pa_level = ZH_RF24_PA_MAX, \ - .data_rate = ZH_RF24_250KBPS, \ - .tx_address = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}, \ - .rx_address_preamble = {0xC2, 0xC2, 0xC2, 0xC2}, \ - .rx_pipe_1_address = 0xC2, \ - .rx_pipe_2_address = 0xC3, \ - .rx_pipe_3_address = 0xC4, \ - .rx_pipe_4_address = 0xC5, \ - .rx_pipe_5_address = 0xC6, \ - .task_priority = 3, \ - .stack_size = 2048, \ - .queue_size = 16 \ +#define ZH_RF24_INIT_CONFIG_DEFAULT() \ + { \ + .ce_pin = 1, \ + .csn_pin = 2, \ + .sck_pin = 3, \ + .mosi_pin = 4, \ + .miso_pin = 5, \ + .irq_pin = 6, \ + .channel = 100, \ + .tx_address = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}, \ + .rx_pipe_1_address = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2}, \ + .rx_pipe_2_address = 0xC3, \ + .rx_pipe_3_address = 0xC4, \ + .rx_pipe_4_address = 0xC5, \ + .rx_pipe_5_address = 0xC6, \ + .task_priority = 3, \ + .stack_size = 2048, \ + .queue_size = 16 \ } #ifdef __cplusplus @@ -55,27 +51,6 @@ extern "C" { #endif - typedef enum - { - ZH_RF24_PA_MIN, - ZH_RF24_PA_LOW, - ZH_RF24_PA_HIGH, - ZH_RF24_PA_MAX, - } __attribute__((packed)) zh_rf24_pa_level_t; - - typedef enum - { - ZH_RF24_1MBPS, - ZH_RF24_2MBPS, - ZH_RF24_250KBPS - } __attribute__((packed)) zh_rf24_data_rate_t; - - typedef enum - { - ZH_RF24_TRANSMITTER, - ZH_RF24_RECEIVER - } __attribute__((packed)) zh_rf24_work_mode_t; - /** * @brief Structure for initial initialization of RF24 interface. * @@ -93,13 +68,9 @@ extern "C" uint8_t mosi_pin; uint8_t miso_pin; uint8_t irq_pin; - zh_rf24_work_mode_t work_mode; uint8_t channel; - zh_rf24_pa_level_t pa_level; - zh_rf24_data_rate_t data_rate; uint8_t tx_address[5]; - uint8_t rx_address_preamble[4]; - uint8_t rx_pipe_1_address; + uint8_t rx_pipe_1_address[5]; uint8_t rx_pipe_2_address; uint8_t rx_pipe_3_address; uint8_t rx_pipe_4_address; @@ -198,7 +169,7 @@ extern "C" * - ESP_ERR_INVALID_STATE if queue for outgoing data is almost full * - ESP_FAIL if ESP-NOW is not initialized */ - esp_err_t zh_rf24_send(const uint8_t *data, const uint8_t data_len, const bool confirm); + esp_err_t zh_rf24_send(const uint8_t *data, const uint8_t data_len); #ifdef __cplusplus } diff --git a/main.c b/main.c new file mode 100644 index 0000000..56258de --- /dev/null +++ b/main.c @@ -0,0 +1,72 @@ +#include "nvs_flash.h" +#include "esp_netif.h" +#include "zh_rf24.h" +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include "esp_system.h" +#else +#include "esp_random.h" +#endif + +void zh_rf24_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); + +typedef struct +{ + char char_value[10]; + int int_value; + float float_value; + bool bool_value; +} example_message_t; + +void app_main(void) +{ + // esp_log_level_set("zh_rf24", ESP_LOG_NONE); + nvs_flash_init(); + esp_netif_init(); + esp_event_loop_create_default(); + zh_rf24_init_config_t zh_rf24_init_config = ZH_RF24_INIT_CONFIG_DEFAULT(); + zh_rf24_init(&zh_rf24_init_config); +#ifdef CONFIG_IDF_TARGET_ESP8266 + esp_event_handler_register(ZH_RF24, ESP_EVENT_ANY_ID, &zh_rf24_event_handler, NULL); +#else + esp_event_handler_instance_register(ZH_RF24, ESP_EVENT_ANY_ID, &zh_rf24_event_handler, NULL, NULL); +#endif + example_message_t send_message = {0}; + strcpy(send_message.char_value, "CHAR"); + send_message.float_value = 1.234; + send_message.bool_value = false; + for (;;) + { + send_message.int_value = esp_random(); + // zh_rf24_send((uint8_t *)&send_message, sizeof(send_message), true); + vTaskDelay(5000 / portTICK_PERIOD_MS); + } +} + +void zh_rf24_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + switch (event_id) + { + case ZH_RF24_ON_RECV_EVENT:; + zh_rf24_event_on_recv_t *recv_data = event_data; + printf("Message via pipe %d is received. Data lenght %d bytes.\n", recv_data->pipe, recv_data->data_len); + example_message_t *recv_message = (example_message_t *)recv_data->data; + printf("Char %s\n", recv_message->char_value); + printf("Int %d\n", recv_message->int_value); + printf("Float %f\n", recv_message->float_value); + printf("Bool %d\n", recv_message->bool_value); + free(recv_data->data); // Do not delete to avoid memory leaks! + break; + case ZH_RF24_ON_SEND_EVENT:; + zh_rf24_event_on_send_t *send_data = event_data; + if (send_data->status == ZH_RF24_SEND_SUCCESS) + { + printf("Message sent success.\n"); + } + else + { + printf("Message sent fail.\n"); + } + default: + break; + } +} \ No newline at end of file diff --git a/zh_rf24.c b/zh_rf24.c index 933ce27..2637ea7 100644 --- a/zh_rf24.c +++ b/zh_rf24.c @@ -12,10 +12,178 @@ #define ZH_SPI_HOST SPI2_HOST /// \endcond +/* Команды */ + +#define R_REGISTER 0x00 // + n Прочитать регистр n +#define W_REGISTER 0x20 // + n Записать регистр n +#define R_RX_PAYLOAD 0x61 // Принять данные данные из верхнего слота очереди приёмника. +#define W_TX_PAYLOAD 0xA0 // Записать в очередь передатчика данные для отправки +#define FLUSH_TX 0xE1 // Сбросить очередь передатчика +#define FLUSH_RX 0xE2 // Сбросить очередь приёмника +#define REUSE_TX_PL 0xE3 // Использовать повторно последний переданный пакет +#define R_RX_PL_WID 0x60 // Прочитать размер данных принятого пакета в начале очереди приёмника. +#define W_ACK_PAYLOAD 0xA8 // + p Записать данные для отправки с пакетом подтверждения по каналу p. +#define W_TX_PAYLOAD_NOACK 0xB0 // Записать в очередь передатчика данные, для отправки без подтверждения +#define NOP 0xFF // Нет операции. Может быть использовано для чтения регистра статуса + +/* Регистры */ + +#define CONFIG 0x00 // Регистр настроек +#define EN_AA 0x01 // Выбор автоподтверждения +#define EN_RXADDR 0x02 // Выбор каналов приёмника +#define SETUP_AW 0x03 // Настройка размера адреса +#define SETUP_RETR 0x04 // Настройка повторной отправки +#define RF_CH 0x05 // Номер радиоканала, на котором осуществляется работа. От 0 до 125. +#define RF_SETUP 0x06 // Настройка радиоканала +#define STATUS 0x07 // Регистр статуса. +#define OBSERVE_TX 0x08 // Количество повторов передачи и потерянных пакетов +#define RPD 0x09 // Мощность принимаемого сигнала. Если младший бит = 1, то уровень более -64dBm +#define RX_ADDR_P0 0x0A // 3-5 байт (начиная с младшего байта). Адрес канала 0 приёмника. +#define RX_ADDR_P1 0x0B // 3-5 байт (начиная с младшего байта). Адрес канала 1 приёмника. +#define RX_ADDR_P2 0x0C // Младший байт адреса канала 2 приёмника. Старшие байты из RX_ADDR_P1 +#define RX_ADDR_P3 0x0D // Младший байт адреса канала 3 приёмника. Старшие байты из RX_ADDR_P1 +#define RX_ADDR_P4 0x0E // Младший байт адреса канала 4 приёмника. Старшие байты из RX_ADDR_P1 +#define RX_ADDR_P5 0x0F // Младший байт адреса канала 5 приёмника. Старшие байты из RX_ADDR_P1 +#define TX_ADDR 0x10 // 3-5 байт (начиная с младшего байта). Адрес удалённого устройства для передачи +#define RX_PW_P0 0x11 // Размер данных при приёме по каналу 0: от 1 до 32. 0 - канал не используется. +#define RX_PW_P1 0x12 // Размер данных при приёме по каналу 1: от 1 до 32. 0 - канал не используется. +#define RX_PW_P2 0x13 // Размер данных при приёме по каналу 2: от 1 до 32. 0 - канал не используется. +#define RX_PW_P3 0x14 // Размер данных при приёме по каналу 3: от 1 до 32. 0 - канал не используется. +#define RX_PW_P4 0x15 // Размер данных при приёме по каналу 4: от 1 до 32. 0 - канал не используется. +#define RX_PW_P5 0x16 // Размер данных при приёме по каналу 5: от 1 до 32. 0 - канал не используется. +#define FIFO_STATUS 0x17 // Состояние очередей FIFO приёмника и передатчика +#define DYNPD 0x1C // Выбор каналов приёмника для которых используется произвольная длина пакетов. +#define FEATURE 0x1D // Регистр опций + +/* Биты регистров */ + +// CONFIG +#define MASK_RX_DR 6 // Запрещает прерывание по RX_DR (получение пакета) +#define MASK_TX_DS 5 // Запрещает прерывание по TX_DS (завершение отправки пакета) +#define MASK_MAX_RT 4 // Запрещает прерывание по MAX_RT (превышение числа повторных попыток отправки) +#define EN_CRC 3 // Включает CRC +#define CRCO 2 // Размер поля CRC: 0 - 1 байт; 1 - 2 байта +#define PWR_UP 1 // Включение питания +#define PRIM_RX 0 // Выбор режима: 0 - PTX (передатчик) 1 - PRX (приёмник) + +// EN_AA +#define ENAA_P5 5 // Включает автоподтверждение данных, полученных по каналу 5 +#define ENAA_P4 4 // Включает автоподтверждение данных, полученных по каналу 4 +#define ENAA_P3 3 // Включает автоподтверждение данных, полученных по каналу 3 +#define ENAA_P2 2 // Включает автоподтверждение данных, полученных по каналу 2 +#define ENAA_P1 1 // Включает автоподтверждение данных, полученных по каналу 1 +#define ENAA_P0 0 // Включает автоподтверждение данных, полученных по каналу 0 + +// EN_RXADDR +#define ERX_P5 5 // Включает канал 5 приёмника +#define ERX_P4 4 // Включает канал 4 приёмника +#define ERX_P3 3 // Включает канал 3 приёмника +#define ERX_P2 2 // Включает канал 2 приёмника +#define ERX_P1 1 // Включает канал 1 приёмника +#define ERX_P0 0 // Включает канал 0 приёмника + +// SETUP_AW +#define AW 0 // Два бита, Выбирает ширину поля адреса: 1 - 3 байта; 2 - 4 байта; 3 - 5 байт. + +#define SETUP_AW_3BYTES_ADDRESS (1 << AW) +#define SETUP_AW_4BYTES_ADDRESS (2 << AW) +#define SETUP_AW_5BYTES_ADDRESS (3 << AW) + +// SETUP_RETR +#define ARD 4 // 4 бита. Задаёт значение задержки перед повторной отправкой пакета: 250 x (n + 1) мкс +#define ARC 0 // 4 битай. Количество повторных попыток отправки, 0 - повторная отправка отключена. + +#define SETUP_RETR_DELAY_250MKS (0 << ARD) +#define SETUP_RETR_DELAY_500MKS (1 << ARD) +#define SETUP_RETR_DELAY_750MKS (2 << ARD) +#define SETUP_RETR_DELAY_1000MKS (3 << ARD) +#define SETUP_RETR_DELAY_1250MKS (4 << ARD) +#define SETUP_RETR_DELAY_1500MKS (5 << ARD) +#define SETUP_RETR_DELAY_1750MKS (6 << ARD) +#define SETUP_RETR_DELAY_2000MKS (7 << ARD) +#define SETUP_RETR_DELAY_2250MKS (8 << ARD) +#define SETUP_RETR_DELAY_2500MKS (9 << ARD) +#define SETUP_RETR_DELAY_2750MKS (10 << ARD) +#define SETUP_RETR_DELAY_3000MKS (11 << ARD) +#define SETUP_RETR_DELAY_3250MKS (12 << ARD) +#define SETUP_RETR_DELAY_3500MKS (13 << ARD) +#define SETUP_RETR_DELAY_3750MKS (14 << ARD) +#define SETUP_RETR_DELAY_4000MKS (15 << ARD) + +#define SETUP_RETR_NO_RETRANSMIT (0 << ARC) +#define SETUP_RETR_UP_TO_1_RETRANSMIT (1 << ARC) +#define SETUP_RETR_UP_TO_2_RETRANSMIT (2 << ARC) +#define SETUP_RETR_UP_TO_3_RETRANSMIT (3 << ARC) +#define SETUP_RETR_UP_TO_4_RETRANSMIT (4 << ARC) +#define SETUP_RETR_UP_TO_5_RETRANSMIT (5 << ARC) +#define SETUP_RETR_UP_TO_6_RETRANSMIT (6 << ARC) +#define SETUP_RETR_UP_TO_7_RETRANSMIT (7 << ARC) +#define SETUP_RETR_UP_TO_8_RETRANSMIT (8 << ARC) +#define SETUP_RETR_UP_TO_9_RETRANSMIT (9 << ARC) +#define SETUP_RETR_UP_TO_10_RETRANSMIT (10 << ARC) +#define SETUP_RETR_UP_TO_11_RETRANSMIT (11 << ARC) +#define SETUP_RETR_UP_TO_12_RETRANSMIT (12 << ARC) +#define SETUP_RETR_UP_TO_13_RETRANSMIT (13 << ARC) +#define SETUP_RETR_UP_TO_14_RETRANSMIT (14 << ARC) +#define SETUP_RETR_UP_TO_15_RETRANSMIT (15 << ARC) + +// RF_SETUP +#define CONT_WAVE 7 // (Только для nRF24L01+) Непрерывная передача несущей (для тестов) +#define RF_DR_LOW 5 // (Только для nRF24L01+) Включает скорость 250кбит/с. RF_DR_HIGH должен быть 0 +#define PLL_LOCK 4 // Для тестов +#define RF_DR_HIGH 3 // Выбор скорости обмена (при значении бита RF_DR_LOW = 0): 0 - 1Мбит/с; 1 - 2Мбит/с +#define RF_PWR 1 // 2бита. Выбирает мощность передатчика: 0 - -18dBm; 1 - -16dBm; 2 - -6dBm; 3 - 0dBm + +#define RF_SETUP_MINUS18DBM (0 << RF_PWR) +#define RF_SETUP_MINUS12DBM (1 << RF_PWR) +#define RF_SETUP_MINUS6DBM (2 << RF_PWR) +#define RF_SETUP_0DBM (3 << RF_PWR) + +#define RF_SETUP_1MBPS (0 << RF_DR_HIGH) +#define RF_SETUP_2MBPS (1 << RF_DR_HIGH) +#define RF_SETUP_250KBPS (1 << RF_DR_LOW) // этот режим не должен использоваться с контролем доставки + +// STATUS +#define RX_DR 6 // Флаг получения новых данных в FIFO приёмника. Для сброса флага нужно записать 1 +#define TX_DS 5 // Флаг завершения передачи. Для сброса флага нужно записать 1 +#define MAX_RT 4 // Флаг превышения установленного числа повторов. Без сброса (записать 1) обмен невозможен +#define RX_P_NO 1 // 3 бита. Номер канала, данные для которого доступны в FIFO приёмника. 7 - FIFO пусто. +#define TX_FULL_STATUS 0 // Признак заполнения FIFO передатчика: 1 - заполнено; 0 - есть доступные слоты + // (переименовано из TX_FULL во избежание путаницы с одноимённым битом из регистра FIFO_STATUS) + +// OBSERVE_TX +#define PLOS_CNT 4 // 4 бита. Общее количество пакетов без подтверждения. Сбрасывается записью RF_CH +#define ARC_CNT 0 // 4 бита. Количество предпринятых повторов при последней отправке. + +// FIFO_STATUS +#define TX_REUSE 6 // Признак готовности последнего пакета для повторной отправки. +#define TX_FULL_FIFO 5 // Флаг переполнения FIFO очереди передатчика. + // (переименовано из TX_FULL во избежание путаницы с одноимённым битом из регистра STATUS) +#define TX_EMPTY 4 // Флаг освобождения FIFO очереди передатчика. +#define RX_FULL 1 // Флаг переполнения FIFO очереди приёмника. +#define RX_EMPTY 0 // Флаг освобождения FIFO очереди приёмника. + +// DYNDP +#define DPL_P5 5 // Включает приём пакетов произвольной длины по каналу 5 +#define DPL_P4 4 // Включает приём пакетов произвольной длины по каналу 4 +#define DPL_P3 3 // Включает приём пакетов произвольной длины по каналу 3 +#define DPL_P2 2 // Включает приём пакетов произвольной длины по каналу 2 +#define DPL_P1 1 // Включает приём пакетов произвольной длины по каналу 1 +#define DPL_P0 0 // Включает приём пакетов произвольной длины по каналу 0 + +// FEATURE +#define EN_DPL 2 // Включает поддержку приёма и передачи пакетов произвольной длины +#define EN_ACK_PAY 1 // Разрешает передачу данных с пакетами подтверждения приёма +#define EN_DYN_ACK 0 // Разрешает использование W_TX_PAYLOAD_NOACK + static void s_zh_rf24_processing(void *pvParameter); static void s_zh_rf24_irq_isr_handler(void *arg); static void s_zh_rf24_irq_processing(void *pvParameter); -static void s_zh_rf24_read_register(const uint8_t *address, uint8_t *value, const uint8_t length); +static void s_zh_rf24_read_register(const uint8_t *reg, uint8_t *value, const uint8_t length); +static void s_zh_rf24_write_register(const uint8_t *reg, uint8_t *value, const uint8_t length); +static void s_zh_rf24_read_data(uint8_t *data, const uint8_t length); +static void s_zh_rf24_write_data(uint8_t *data, const uint8_t length); +static uint8_t s_zh_rf24_send_command(uint8_t *command); static const char *TAG = "zh_rf24"; @@ -37,7 +205,6 @@ typedef enum typedef struct { uint8_t pipe; - bool confirm; uint8_t *data; uint8_t data_len; } __attribute__((packed)) zh_rf24_queue_data_t; @@ -99,8 +266,8 @@ esp_err_t zh_rf24_init(zh_rf24_init_config_t *config) .sclk_io_num = s_zh_rf24_init_config.sck_pin, .mosi_io_num = s_zh_rf24_init_config.mosi_pin, .miso_io_num = s_zh_rf24_init_config.miso_pin, - .quadwp_io_num = -1, - .quadhd_io_num = -1}; + .quadwp_io_num = -1, // ?? + .quadhd_io_num = -1}; // ?? if (spi_bus_initialize(ZH_SPI_HOST, &spi_bus_config, SPI_DMA_CH_AUTO) != ESP_OK) { ESP_LOGE(TAG, "RF24 initialization fail. SPI initialization error."); @@ -109,28 +276,63 @@ esp_err_t zh_rf24_init(zh_rf24_init_config_t *config) spi_device_interface_config_t spi_device_interface_config = { .clock_speed_hz = 4000000, .spics_io_num = -1, - .queue_size = 7, - .mode = 0, + .queue_size = 7, // ?? + .mode = 0, // ?? .flags = SPI_DEVICE_NO_DUMMY}; if (spi_bus_add_device(ZH_SPI_HOST, &spi_device_interface_config, &s_zh_rf24_spi_handle) != ESP_OK) { ESP_LOGE(TAG, "RF24 initialization fail. SPI initialization error."); return ESP_FAIL; } - s_zh_rf24_irq_semaphore = xSemaphoreCreateBinary(); - if (gpio_install_isr_service(0) != ESP_OK || gpio_isr_handler_add(s_zh_rf24_init_config.irq_pin, s_zh_rf24_irq_isr_handler, NULL) != ESP_OK) + for (uint8_t i = 0; i < 100; ++i) { - ESP_LOGE(TAG, "RF24 initialization fail. Internal error."); - return ESP_FAIL; + s_zh_rf24_write_register(CONFIG, (1 << EN_CRC) | (1 << CRCO) | (1 << PRIM_RX), 1); + uint8_t value = 0; + s_zh_rf24_read_register(CONFIG, &value, 1); + if (value == ((1 << EN_CRC) | (1 << CRCO) | (1 << PRIM_RX))) + { + s_zh_rf24_write_register(EN_AA, 0x3F, 1); // Enable auto acknowledgment for all pipes. + s_zh_rf24_write_register(EN_RXADDR, 0x3F, 1); // Enable all pipes. + s_zh_rf24_write_register(SETUP_AW, 0x03, 1); // Setup address widths for 5 bytes. // выбор длины адреса 5 байт + s_zh_rf24_write_register(SETUP_RETR, 0x1F, 1); // Setup automatic retransmission a maximum of 15 times with delay of 500 µs between attempts. + s_zh_rf24_write_register(RF_CH, &s_zh_rf24_init_config.channel, 1); // Setup RF channel. + s_zh_rf24_write_register(RF_SETUP, 0x06, 1); // Setup data rate 1 Mbps and 0 dBm RF output power in TX mode. + s_zh_rf24_write_register(RX_ADDR_P0, &s_zh_rf24_init_config.tx_address, 5); // Setup receive address for pipe 0. + s_zh_rf24_write_register(RX_ADDR_P1, &s_zh_rf24_init_config.rx_pipe_1_address, 5); // Setup receive address for pipe 1. + s_zh_rf24_write_register(RX_ADDR_P2, &s_zh_rf24_init_config.rx_pipe_2_address, 1); // Setup receive address for pipe 2. + s_zh_rf24_write_register(RX_ADDR_P3, &s_zh_rf24_init_config.rx_pipe_3_address, 1); // Setup receive address for pipe 3. + s_zh_rf24_write_register(RX_ADDR_P4, &s_zh_rf24_init_config.rx_pipe_4_address, 1); // Setup receive address for pipe 4. + s_zh_rf24_write_register(RX_ADDR_P5, &s_zh_rf24_init_config.rx_pipe_5_address, 1); // Setup receive address for pipe 5. + s_zh_rf24_write_register(TX_ADDR, &s_zh_rf24_init_config.tx_address, 5); // Setup transmitter address. + s_zh_rf24_write_register(RX_PW_P0, 32, 1); // Setup the maximum data length for pipe 0. + s_zh_rf24_write_register(RX_PW_P1, 32, 1); // Setup the maximum data length for pipe 1. + s_zh_rf24_write_register(RX_PW_P2, 32, 1); // Setup the maximum data length for pipe 2. + s_zh_rf24_write_register(RX_PW_P3, 32, 1); // Setup the maximum data length for pipe 3. + s_zh_rf24_write_register(RX_PW_P4, 32, 1); // Setup the maximum data length for pipe 4. + s_zh_rf24_write_register(RX_PW_P5, 32, 1); // Setup the maximum data length for pipe 5. + s_zh_rf24_write_register(FEATURE, 0x04, 1); // Enable dynamic payload length. + s_zh_rf24_write_register(DYNPD, 0x3F, 1); // Setup dynamic payload length for all pipes. + s_zh_rf24_write_register(CONFIG, (1 << EN_CRC) | (1 << CRCO) | (1 << PWR_UP) | (1 << PRIM_RX), 1); + s_zh_rf24_irq_semaphore = xSemaphoreCreateBinary(); + if (gpio_install_isr_service(0) != ESP_OK || gpio_isr_handler_add(s_zh_rf24_init_config.irq_pin, s_zh_rf24_irq_isr_handler, NULL) != ESP_OK) + { + ESP_LOGE(TAG, "RF24 initialization fail. Internal error."); + return ESP_FAIL; + } + if (xTaskCreatePinnedToCore(&s_zh_rf24_irq_processing, "NULL", s_zh_rf24_init_config.stack_size, NULL, s_zh_rf24_init_config.task_priority, NULL, tskNO_AFFINITY) != pdPASS) + { + ESP_LOGE(TAG, "RF24 initialization fail. Internal error."); + return ESP_FAIL; + } + s_zh_rf24_is_initialized = true; + gpio_set_level(s_zh_rf24_init_config.ce_pin, 1); + ESP_LOGI(TAG, "RF24 initialization success."); + return ESP_OK; + } + esp_rom_delay_us(1); } - if (xTaskCreatePinnedToCore(&s_zh_rf24_irq_processing, "NULL", s_zh_rf24_init_config.stack_size, NULL, s_zh_rf24_init_config.task_priority, NULL, tskNO_AFFINITY) != pdPASS) - { - ESP_LOGE(TAG, "RF24 initialization fail. Internal error."); - return ESP_FAIL; - } - s_zh_rf24_is_initialized = true; - ESP_LOGI(TAG, "RF24 initialization success."); - return ESP_OK; + ESP_LOGE(TAG, "RF24 initialization fail. Module not connected or not responding."); + return ESP_FAIL; } esp_err_t zh_rf24_deinit(void) @@ -138,9 +340,49 @@ esp_err_t zh_rf24_deinit(void) return 0; } -esp_err_t zh_rf24_send(const uint8_t *data, const uint8_t data_len, const bool confirm) +esp_err_t zh_rf24_send(const uint8_t *data, const uint8_t data_len) { - return 0; + ESP_LOGI(TAG, "Adding outgoing RF24 data to queue begin."); + if (s_zh_rf24_is_initialized == false) + { + ESP_LOGE(TAG, "Adding outgoing RF24 data to queue fail. RF24 not initialized."); + return ESP_FAIL; + } + if (data == NULL || data_len == 0 || data_len > ZH_RF24_MAX_MESSAGE_SIZE) + { + ESP_LOGE(TAG, "Adding outgoing RF24 data to queue fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (uxQueueSpacesAvailable(s_zh_rf24_queue_handle) < s_zh_rf24_init_config.queue_size / 10) + { + ESP_LOGW(TAG, "Adding outgoing RF24 data to queue fail. Queue is almost full."); + return ESP_ERR_INVALID_STATE; + } + zh_rf24_queue_t rf24_queue = {0}; + rf24_queue.id = ZH_RF24_SEND; + zh_rf24_queue_data_t *send_data = &rf24_queue.data; + if (data_len / sizeof(void *) == 0) + { + send_data->data = heap_caps_malloc(data_len, MALLOC_CAP_32BIT); + } + else + { + send_data->data = heap_caps_malloc(data_len, MALLOC_CAP_8BIT); + } + if (send_data->data == NULL) + { + ESP_LOGE(TAG, "Adding outgoing ESP-NOW data to queue fail. Memory allocation fail or no free memory in the heap."); + return ESP_ERR_NO_MEM; + } + memset(send_data->data, 0, data_len); + memcpy(send_data->data, data, data_len); + send_data->data_len = data_len; + ESP_LOGI(TAG, "Adding outgoing RF24 data to queue success."); + if (xQueueSend(s_zh_rf24_queue_handle, &rf24_queue, portTICK_PERIOD_MS) != pdTRUE) + { + ESP_LOGE(TAG, "RF24 message processing task internal error."); + } + return ESP_OK; } static void s_zh_rf24_processing(void *pvParameter) @@ -171,17 +413,55 @@ static void s_zh_rf24_irq_processing(void *pvParameter) vTaskDelete(NULL); } -static void s_zh_rf24_read_register(const uint8_t *address, uint8_t *value, const uint8_t length) +static void s_zh_rf24_read_register(const uint8_t *reg, uint8_t *value, const uint8_t length) { + // uint8_t status = 0; gpio_set_level(s_zh_rf24_init_config.csn_pin, 0); spi_transaction_t spi_transaction = {0}; - // spi_transaction.length = DataLength * 8; - // spi_transaction.tx_buffer = Dataout; - // spi_transaction.rx_buffer = Datain; + spi_transaction.length = 8; + spi_transaction.tx_buffer = ((*reg & 0x1F) | R_REGISTER); + spi_transaction.rx_buffer = NULL; + spi_device_transmit(s_zh_rf24_spi_handle, &spi_transaction); + spi_transaction.length = length * 8; + spi_transaction.tx_buffer = NULL; + spi_transaction.rx_buffer = value; spi_device_transmit(s_zh_rf24_spi_handle, &spi_transaction); - - // spi_transfer(dev, R_REGISTER | (REGISTER_MASK & reg)); - // spi_read_byte(dev, value, value, len); - gpio_set_level(s_zh_rf24_init_config.csn_pin, 1); +} + +static void s_zh_rf24_write_register(const uint8_t *reg, uint8_t *value, const uint8_t length) +{ + // uint8_t status = 0; + gpio_set_level(s_zh_rf24_init_config.csn_pin, 0); + spi_transaction_t spi_transaction = {0}; + spi_transaction.length = 8; + spi_transaction.tx_buffer = ((*reg & 0x1F) | W_REGISTER); + spi_transaction.rx_buffer = NULL; + spi_device_transmit(s_zh_rf24_spi_handle, &spi_transaction); + spi_transaction.length = length * 8; + spi_transaction.tx_buffer = value; + spi_transaction.rx_buffer = NULL; + spi_device_transmit(s_zh_rf24_spi_handle, &spi_transaction); + gpio_set_level(s_zh_rf24_init_config.csn_pin, 1); +} + +static void s_zh_rf24_read_data(uint8_t *data, const uint8_t length) +{ +} + +static void s_zh_rf24_write_data(uint8_t *data, const uint8_t length) +{ +} + +static uint8_t s_zh_rf24_send_command(uint8_t *command) +{ + uint8_t status = 0; + gpio_set_level(s_zh_rf24_init_config.csn_pin, 0); + spi_transaction_t spi_transaction = {0}; + spi_transaction.length = 8; + spi_transaction.tx_buffer = command; + spi_transaction.rx_buffer = status; + spi_device_transmit(s_zh_rf24_spi_handle, &spi_transaction); + gpio_set_level(s_zh_rf24_init_config.csn_pin, 1); + return status; } \ No newline at end of file