diff --git a/Makefile b/Makefile index ac37f7f..22ff961 100755 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ GEN_IMAGES= $(TARGET).elf GEN_BINS = $(TARGET).bin SUBDIRS = \ $(TOP_DIR)/app \ + $(TOP_DIR)/app/app_lib \ $(TOP_DIR)/app/third_party/nano-shell-master \ $(TOP_DIR)/app/third_party/driver/NRF24L01P endif # } PDIR @@ -32,8 +33,9 @@ endif COMPONENTS_$(TARGET) = \ $(TOP_DIR)/app/libuser$(LIB_EXT) \ + $(TOP_DIR)/app/app_lib/libapplib$(LIB_EXT) \ $(TOP_DIR)/app/third_party/nano-shell-master/libnanoshell$(LIB_EXT) \ - $(TOP_DIR)/app/third_party/driver/libnrf24l01p$(LIB_EXT) + $(TOP_DIR)/app/third_party/driver/NRF24L01P/libnrf24l01p$(LIB_EXT) ifeq ($(USE_LIB), 0) COMPONENTS_$(TARGET) += \ diff --git a/app/app_lib/Makefile b/app/app_lib/Makefile new file mode 100644 index 0000000..429641a --- /dev/null +++ b/app/app_lib/Makefile @@ -0,0 +1,15 @@ +TOP_DIR = ../.. +sinclude $(TOP_DIR)/tools/w800/conf.mk + +ifndef PDIR +GEN_LIBS = libapplib$(LIB_EXT) +endif + +#DEFINES += + +sinclude $(TOP_DIR)/tools/w800/rules.mk + +INCLUDES := $(INCLUDES) -I $(PDIR)include + +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile \ No newline at end of file diff --git a/app/app_lib/app_utils.c b/app/app_lib/app_utils.c new file mode 100644 index 0000000..ddfecaa --- /dev/null +++ b/app/app_lib/app_utils.c @@ -0,0 +1,13 @@ +#include "app_utils.h" + +static uint32_t millis_cnt = 0; + +uint32_t millis(void) +{ + return millis_cnt; +} + +void millis_run_cb(void *arg) +{ + millis_cnt++; +} \ No newline at end of file diff --git a/app/app_lib/app_utils.h b/app/app_lib/app_utils.h new file mode 100644 index 0000000..620d864 --- /dev/null +++ b/app/app_lib/app_utils.h @@ -0,0 +1,10 @@ +#ifndef APP_UTILS_H +#define APP_UTILS_H + +#include "wm_include.h" + +uint32_t millis(void); + +void millis_run_cb(void *arg); + +#endif //APP_UTILS_H \ No newline at end of file diff --git a/app/main.c b/app/main.c index 591e91f..8a75ae6 100644 --- a/app/main.c +++ b/app/main.c @@ -21,6 +21,8 @@ #include "FreeRTOS.h" #include "FreeRTOSConfig.h" #include "app_common.h" +#include "NRF24L01P.h" +#include "app_utils.h" tls_os_task_t nano_shell_task_handle = NULL; tls_os_task_t nano_shell_server_task_handle = NULL; @@ -29,7 +31,6 @@ extern s16 uart1_rx_callback(u16 len, void *user_data); #define NANO_SHELL_TASK_STK_SIZE 640 #define NANO_SHELL_SERVER_TASK_STK_SIZE 640 -#define STATUS_LED WM_IO_PB_18 #define PWM_STATUS_LED WM_IO_PB_25 #define FADE_DOWN 1 #define FADE_UP -1 @@ -40,6 +41,7 @@ extern s16 uart1_rx_callback(u16 len, void *user_data); u8 pulse_rate = PULSE_SLOW; +bool nrf_irq = false; void tls_netif_status_event_cb(u8 status) { @@ -97,6 +99,32 @@ void tls_gpio_irq_cb(void *arg) tls_clr_gpio_irq_status(WM_IO_PB_07); } +void tls_gpio_pb11_irq_cb(void *arg) +{ + tls_clr_gpio_irq_status(WM_IO_PB_11); + nrf_irq = true; +} + +void delay_ms(uint32_t ms) +{ + tls_os_time_delay(pdMS_TO_TICKS(ms)); +} + +uint32_t elapsed_ms(void) +{ + return millis(); +} + +void CE_HIGH(void) +{ + tls_gpio_write(WM_IO_PB_10, 1); +} + +void CE_LOW(void) +{ + tls_gpio_write(WM_IO_PB_10, 0); +} + void user_main(void *param) { u8 pwm_led_duty_cycle = 255; @@ -109,6 +137,7 @@ void user_main(void *param) wm_uart1_rx_config(WM_IO_PB_07); tls_gpio_irq_enable(WM_IO_PB_07, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); tls_gpio_isr_register(WM_IO_PB_07, &(tls_gpio_irq_cb), NULL); + //We set a a pin as touch sensor : wm_touch_sensor_config(WM_IO_PA_07); tls_touchsensor_threshold_config(1, 120); @@ -116,9 +145,25 @@ void user_main(void *param) tls_touchsensor_irq_enable(1); tls_touchsensor_irq_register(&(touchsensor_cb)); + //We set the CE and IRQ pin for the NRF module + tls_gpio_cfg(WM_IO_PB_10, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING); //CE pin + tls_gpio_cfg(WM_IO_PB_11, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); //IRQ pins + tls_gpio_irq_enable(WM_IO_PB_11, WM_GPIO_IRQ_TRIG_FALLING_EDGE); + tls_gpio_isr_register(WM_IO_PB_11, &(tls_gpio_pb11_irq_cb), NULL); + + //We init the uart 1 tls_uart_port_init(TLS_UART_1, NULL, 0); + //We create and start a timer to run the millis counter + struct tls_timer_cfg tmr_millis = {0}; + tmr_millis.arg = NULL; + tmr_millis.is_repeat = true; + tmr_millis.timeout = 1; + tmr_millis.unit = TLS_TIMER_UNIT_MS; + tmr_millis.callback = &(millis_run_cb); + u8 tmr_millis_id = tls_timer_create(&tmr_millis); + tls_timer_start(tmr_millis_id); //We create a task for the nano_shell process u8 *nano_shell_task_stack = NULL, *nano_shell_server_task_stack = NULL; @@ -126,6 +171,32 @@ void user_main(void *param) tls_uart_rx_callback_register(TLS_UART_0, &(uart0_rx_callback), NULL); tls_uart_rx_callback_register(TLS_UART_1, &(uart1_rx_callback), NULL); + //we test the NRF lib here + NRF24L01P_t NRF; + shell_printf("Checking NRF setup."NEW_LINE); + shell_printf("Setting SPI to 1 Mhz : %d."NEW_LINE, tls_spi_setup(SPI_DEFAULT_MODE, SPI_CS_ACTIVE_MODE, 8000000)); + shell_printf("NRF begin : %d."NEW_LINE, NRF24L01P_begin(&NRF)); + shell_printf("Is NRF connected : %d."NEW_LINE, NRF24L01P_isChipConnected(&NRF)); + //NRF24L01P_setChannel(&NRF, 2); + NRF24L01P_setPALevel(&NRF, RF24_PA_LOW, false); + //NRF24L01P_setDataRate(&NRF, RF24_250KBPS); + //NRF24L01P_setRetries(&NRF, 8, 15); + NRF24L01P_enableDynamicPayloads(&NRF); + NRF24L01P_enableAckPayload(&NRF); + NRF24L01P_maskIRQ(&NRF, true, true, false); + + const uint8_t ADDR[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; + const uint8_t ack_pl[] = "1234567"; + NRF24L01P_openWritingPipe(&NRF, "1Node"); + NRF24L01P_openReadingPipe(&NRF, 1, "2Node"); + NRF24L01P_writeAckPayload(&NRF, 1, ack_pl, sizeof ack_pl); + NRF24L01P_startListening(&NRF); + shell_printf("NRF PA level : %d"NEW_LINE, NRF24L01P_getPALevel(&NRF)); + NRF24L01P_printDetails(&NRF); + /*uint8_t payload[32] = "Hello W801"; + shell_printf("Sending payload : %d"NEW_LINE, NRF24L01P_write(&NRF, payload, sizeof payload)); + NRF24L01P_printDetails(&NRF);*/ + nano_shell_server_task_stack = tls_mem_alloc(sizeof(u32) * NANO_SHELL_SERVER_TASK_STK_SIZE); if(nano_shell_server_task_stack != NULL) { @@ -178,6 +249,23 @@ void user_main(void *param) pwm_led_duty_cycle+=fading_direction; tls_os_time_delay(pdMS_TO_TICKS(pulse_rate)); + + if(nrf_irq) + { + bool tx_ok, tx_fail, rx_ready; + NRF24L01P_whatHappened(&NRF, &tx_ok, &tx_fail, &rx_ready); + shell_printf("NRF event : tx_ok %d, tx_fail %d and rx_ready : %d, rx fifo full ? %u, tx fifo full ? %u"NEW_LINE, tx_ok, tx_fail, rx_ready, NRF24L01P_rxFifoFull(&NRF), NRF24L01P_txFifoFull(&NRF)); + + if(NRF24L01P_available(&NRF)) + { + char payload[32] = ""; + NRF24L01P_read(&NRF, payload, 8); + shell_printf("Received : #%s#\r\n", payload); + NRF24L01P_writeAckPayload(&NRF, 1, ack_pl, sizeof ack_pl); + } + + nrf_irq = false; + } } } diff --git a/app/nano_shell_command.c b/app/nano_shell_command.c index cf31467..a68e6cf 100644 --- a/app/nano_shell_command.c +++ b/app/nano_shell_command.c @@ -133,11 +133,17 @@ int _reset(const shell_cmd_t *pcmd, int argc, char *const argv[]) int _bus(const shell_cmd_t *pcmd, int argc, char *const argv[]) { char spi_recv_buff[32] = ""; + u32 fclk = SPI_DEFAULT_SPEED; if(argc > 1) { if(strcmp(argv[1], "spi_init") == 0) { - shell_printf("SPI init : %d"NEW_LINE, tls_spi_setup(SPI_DEFAULT_MODE, SPI_CS_ACTIVE_MODE, SPI_DEFAULT_SPEED)); + if(argc == 3) + { + fclk = strtoul(argv[2], NULL, 10); + if(!fclk) fclk = SPI_DEFAULT_SPEED; + } + shell_printf("SPI init : %d, clk -> %u Hz"NEW_LINE, tls_spi_setup(SPI_DEFAULT_MODE, SPI_CS_ACTIVE_MODE, fclk), fclk); } else if(strcmp(argv[1], "spi_w") == 0) { diff --git a/app/third_party/driver/NRF24L01P/NRF24L01P.c b/app/third_party/driver/NRF24L01P/NRF24L01P.c index c095433..460f3a9 100644 --- a/app/third_party/driver/NRF24L01P/NRF24L01P.c +++ b/app/third_party/driver/NRF24L01P/NRF24L01P.c @@ -1,6 +1,1153 @@ #include "NRF24L01P.h" +#include -bool NRF24L01_init(void) +/*PRIVATE API*/ + +/*MACROS*/ +#define _BV(X) (1 << (X)) +#define assert_not_bool(what, assert_not_val, ret_val) do \ +{ \ + if((what) == (assert_not_val)) \ + { \ + debug_printf("Failure : ["#what"] is ["#assert_not_val"] in file ["__FILE__"] in function [%s] at line [%d]", __FUNCTION__, __LINE__); \ + return (bool)(ret_val); \ + } \ +} while(0) + +#define assert_not_uint8_t(what, assert_not_val, ret_val) do \ +{ \ + if((what) == (assert_not_val)) \ + { \ + debug_printf("Failure : ["#what"] is ["#assert_not_val"] in file ["__FILE__"] in function [%s] at line [%d]", __FUNCTION__, __LINE__); \ + return (uint8_t)(ret_val); \ + } \ +} while(0) + +#define assert_not_void(what, assert_not_val) do \ +{ \ + if((what) == (assert_not_val)) \ + { \ + debug_printf("Failure : ["#what"] is ["#assert_not_val"] in file ["__FILE__"] in function [%s] at line [%d]", __FUNCTION__, __LINE__); \ + return; \ + } \ +} while(0) + +/*REGISTER LIST*/ +typedef enum NRF_REGISTER { + CONFIG = 0x00, + EN_AA, + EN_RXADDR, + SETUP_AW, + SETUP_RETR, + RF_CH, + RF_SETUP, + STATUS, + OBSERVE_TX, + RPD, + RX_ADDR_P0, + RX_ADDR_P1, + RX_ADDR_P2, + RX_ADDR_P3, + RX_ADDR_P4, + RX_ADDR_P5, + TX_ADDR, + RX_PW_P0, + RX_PW_P1, + RX_PW_P2, + RX_PW_P3, + RX_PW_P4, + RX_PW_P5, + FIFO_STATUS, + DYNPD = 0x1C, + FEATURE +} NRF_REGISTER_e; + +/*REGISTER BITS*/ +typedef enum NRF_CONFIG_REGISTER_BIT +{ + CONFIG_PRIM_RX_BIT = 0, + CONFIG_PWR_UP_BIT, + CONFIG_CRCO_BIT, + CONFIG_EN_CRC_BIT, + CONFIG_MASK_MAX_RT_BIT, + CONFIG_MASK_TX_DS_BIT, + CONFIG_MASK_RX_DR_BIT +} NRF_CONFIG_REGISTER_BIT_e; + +typedef enum NRF_RF_SETUP_REGISTER_BIT +{ + RF_SETUP_LNA_HCURR_BIT = 0, + RF_SETUP_RF_PWR_LOW_BIT, + RF_SETUP_RF_PWR_HIGH_BIT, + RF_SETUP_RF_DR_HIGH_BIT, + RF_SETUP_PLL_LOCK_BIT, + RF_SETUP_RF_DR_LOW_BIT, + RF_SETUP_CONT_WAVE_BIT = 7, +} NRF_RF_SETUP_REGISTER_BIT_e; + +typedef enum NRF_STATUS_REGISTER_BIT +{ + STATUS_TX_FULL_BIT = 0, + STATUS_RX_P_NO_BIT, + STATUS_MAX_RT_BIT = 4, + STATUS_TX_DS_BIT, + STATUS_RX_DR_BIT +} NRF_STATUS_REGISTER_BIT_e; + +typedef enum NRF_FEATURE_REGISTER_BIT +{ + FEATURE_EN_DYN_ACK_BIT = 0, + FEATURE_EN_ACK_PAY_BIT, + FEATURE_EN_DPL_BIT +} NRF_FEATURE_REGISTER_BIT_e; + +typedef enum NRF_FIFO_STATUS_REGISTER_BIT +{ + FIFO_STATUS_RX_EMPTY_BIT = 0, + FIFO_STATUS_RX_FULL_BIT, + FIFO_STATUS_TX_EMPTY_BIT = 4, + FIFO_STATUS_TX_FULL_BIT, + FIFO_STATUS_TX_REUSE_BIT +} NRF_FIFO_STATUS_REGISTER_BIT_e; + +typedef enum NRF_DYNPD_REGISTER_BIT +{ + DYNPD_DPL_P0_BIT = 0, + DYNPD_DPL_P1_BIT, + DYNPD_DPL_P2_BIT, + DYNPD_DPL_P3_BIT, + DYNPD_DPL_P4_BIT, + DYNPD_DPL_P5_BIT, +} NRF_DYNPD_REGISTER_BIT_e; + +/*COMMAND LIST*/ +typedef enum NRF_COMMAND +{ + R_REGISTER = 0x00, + W_REGISTER = 0x20, + R_RX_PAYLOAD = 0x61, + W_TX_PAYLOAD = 0xA0, + FLUSH_TX = 0xE1, + FLUSH_RX = 0xE2, + REUSE_TX_PL = 0xE3, + ACTIVATE = 0x50, + R_RX_PL_WID = 0x60, + W_ACK_PAYLOAD = 0xA8, + W_TX_PAYLOAD_NOACK = 0xB0, + NRF_NOP = 0xFF +} NRF_COMMAND_e; + +static void read_registers(NRF24L01P_t *NRF, NRF_REGISTER_e reg, uint8_t *buffer, uint8_t length) +{ + assert_not_void(NRF, NULL); + assert_not_void(buffer, NULL); + assert_not_void(length, 0); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = R_REGISTER | reg; + tls_spi_read_with_cmd(&command, sizeof command, buffer, length); +} + +static uint8_t read_register(NRF24L01P_t *NRF, NRF_REGISTER_e reg) +{ + assert_not_uint8_t(NRF, NULL, 0); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS, reg_value = 0; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = R_REGISTER | reg; + tls_spi_read_with_cmd(&command, sizeof command, ®_value, sizeof reg_value); + + return reg_value; +} + +static void write_registers(NRF24L01P_t *NRF, NRF_REGISTER_e reg, const uint8_t *buffer, uint8_t length) +{ + assert_not_void(NRF, NULL); + assert_not_void(buffer, NULL); + assert_not_void(length, 0); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = W_REGISTER | reg; + tls_spi_write_with_cmd(&command, sizeof command, buffer, length); +} + +static void write_register(NRF24L01P_t *NRF, NRF_REGISTER_e reg, uint8_t value) +{ + assert_not_void(NRF, NULL); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = W_REGISTER | reg; + tls_spi_write_with_cmd(&command, sizeof command, &value, sizeof value); +} + +static void write_payload(NRF24L01P_t *NRF, const void *payload, uint8_t length, NRF_COMMAND_e type) +{ + assert_not_void(NRF, NULL); + assert_not_void(payload, NULL); + assert_not_void(length, 0); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + if(!NRF->dynamic_payloads_enabled) + { + length = length < NRF->payload_size ? length : NRF->payload_size; + } + else + { + length = length < 32 ? length : 32; + } + + command = type; + tls_spi_write_with_cmd(&command, sizeof command, payload, length); +} + +static void read_payload(NRF24L01P_t *NRF, void *payload, uint8_t length) +{ + assert_not_void(NRF, NULL); + assert_not_void(payload, NULL); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS, full_payload[32] = {0}; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + if(!NRF->dynamic_payloads_enabled) + { + length = length < NRF->payload_size ? length : NRF->payload_size; + } + else + { + length = length < 32 ? length : 32; + } + + command = R_RX_PAYLOAD; + + tls_spi_read_with_cmd(&command, sizeof command, full_payload, sizeof full_payload); + memcpy(payload, full_payload, length); +} + +static void reuse_tx_payload(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = REUSE_TX_PL; + tls_spi_write(&command, sizeof command); +} + +static uint8_t r_rx_pl_wid(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, 0); + + //We first read the STATUS reg because there is no combo write/read SPI function. + uint8_t command = R_REGISTER | STATUS, pl_wid = 0; + tls_spi_read_with_cmd(&command, sizeof command, &NRF->status, sizeof NRF->status); + + command = R_RX_PL_WID; + tls_spi_read_with_cmd(&command, sizeof command, &pl_wid, sizeof pl_wid); + + return pl_wid; +} + +static void toggle_features(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + uint8_t command = ACTIVATE, activate_magic_value = 0x73; + tls_spi_write_with_cmd(&command, sizeof command, &activate_magic_value, sizeof activate_magic_value); +} + +static uint8_t get_status(NRF24L01P_t *NRF) +{ + return read_register(NRF, STATUS); +} + +static void err_notify(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + debug_printf("RF24 HARDWARE FAIL: Radio not responding, verify pin connections, wiring, etc."); + + NRF->failure_detected = true; +} +/*PUBLIC API*/ +bool NRF24L01P_begin(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + memset(NRF, 0, sizeof *NRF); + + CE_LOW(); + delay_ms(5); + NRF24L01P_setRetries(NRF, 5, 15); + NRF24L01P_setDataRate(NRF, RF24_1MBPS); + + //Detect if the chip is a plus variant & use old toggle features command accordingly + uint8_t before_toggle = read_register(NRF, FEATURE); + toggle_features(NRF); + uint8_t after_toggle = read_register(NRF, FEATURE); + NRF->is_p_variant = before_toggle == after_toggle; + if(after_toggle) + { + if(NRF->is_p_variant) + { + toggle_features(NRF); + } + + write_register(NRF, FEATURE, 0); + } + + NRF->ack_payloads_enabled = false; + write_register(NRF, DYNPD, 0); + NRF->dynamic_payloads_enabled = false; + write_register(NRF, EN_AA, 0x3F); + write_register(NRF, EN_RXADDR, 0); + NRF24L01P_setPayloadSize(NRF, 32); + NRF24L01P_setAddressWidth(NRF, 5); + + NRF24L01P_setChannel(NRF, 76); + + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT) | _BV(STATUS_TX_DS_BIT) | _BV(STATUS_RX_DR_BIT)); + + NRF24L01P_flush_rx(NRF); + NRF24L01P_flush_tx(NRF); + + write_register(NRF, CONFIG, _BV(CONFIG_EN_CRC_BIT) | _BV(CONFIG_CRCO_BIT)); + NRF->config_reg = read_register(NRF, CONFIG); + + NRF24L01P_powerUp(NRF); + + return NRF->config_reg == (_BV(CONFIG_EN_CRC_BIT) | _BV(CONFIG_CRCO_BIT) | _BV(CONFIG_PWR_UP_BIT)); +} + +bool NRF24L01P_isChipConnected(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + uint8_t value = read_register(NRF, SETUP_AW); + + return value >= 1 && value <= 3; +} + +void NRF24L01P_startListening(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + NRF24L01P_powerUp(NRF); + NRF->config_reg |= _BV(CONFIG_PRIM_RX_BIT); + write_register(NRF, CONFIG, NRF->config_reg); + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT) | _BV(STATUS_TX_DS_BIT) | _BV(STATUS_RX_DR_BIT)); + + CE_HIGH(); + + if(NRF->pipe0_reading_address[0] > 0) + { + write_registers(NRF, RX_ADDR_P0, NRF->pipe0_reading_address, NRF->addr_width); + } + else + { + NRF24L01P_closeReadingPipe(NRF, 0); + } +} + +void NRF24L01P_stopListening(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + CE_LOW(); + + delay_ms(1); + if(NRF->ack_payloads_enabled) + { + NRF24L01P_flush_tx(NRF); + } + + NRF->config_reg &= ~_BV(CONFIG_PRIM_RX_BIT); + write_register(NRF, CONFIG, NRF->config_reg); + + uint8_t en_rxaddr = read_register(NRF, EN_RXADDR); + en_rxaddr |= _BV(0); + write_register(NRF, EN_RXADDR, en_rxaddr); +} + +bool NRF24L01P_available(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return NRF24L01P_availablePipe(NRF, NULL); +} + +void NRF24L01P_powerDown(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + uint8_t reg = read_register(NRF, CONFIG); + reg &= ~_BV(CONFIG_PWR_UP_BIT); + write_register(NRF, CONFIG, reg); +} + +void NRF24L01P_powerUp(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + if(!(NRF->config_reg & _BV(CONFIG_PWR_UP_BIT))) + { + NRF->config_reg = read_register(NRF, CONFIG); + NRF->config_reg |= _BV(CONFIG_PWR_UP_BIT); + write_register(NRF, CONFIG, NRF->config_reg); + + delay_ms(5); + } +} + +bool NRF24L01P_writeMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + NRF24L01P_startFastWrite(NRF, payload, length, multicast, true); + + uint32_t timer = elapsed_ms(); + + while( !(get_status(NRF) & (_BV(STATUS_TX_DS_BIT) | _BV(STATUS_MAX_RT_BIT))) ) + { + if(elapsed_ms() - timer > 95) + { + err_notify(NRF); + return false; + } + } + + CE_LOW(); + + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT) | _BV(STATUS_TX_DS_BIT) | _BV(STATUS_RX_DR_BIT)); + + if(NRF->status & _BV(STATUS_MAX_RT_BIT)) + { + NRF24L01P_flush_tx(NRF); + return false; + } + return true; +} + +bool NRF24L01P_write(NRF24L01P_t *NRF, const void *payload, uint8_t length) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + return NRF24L01P_writeMulticast(NRF, payload, length, false); +} + +bool NRF24L01P_writeBlocking(NRF24L01P_t *NRF, const void *payload, uint8_t length, uint32_t timeout) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + uint32_t timer = elapsed_ms(); + + while(get_status(NRF) & _BV(STATUS_TX_FULL_BIT)) + { + if(NRF->status & _BV(STATUS_MAX_RT_BIT)) + { + NRF24L01P_reUseTX(NRF); + if(elapsed_ms() - timer > timeout) + { + return false; + } + } + + if(elapsed_ms() - timer > timeout + 95) + { + err_notify(NRF); + } + } + + NRF24L01P_startFastWrite(NRF, payload, length, false, true); + + return true; +} + +void NRF24L01P_reUseTX(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT)); + reuse_tx_payload(NRF); + + CE_LOW(); + delay_ms(1); + CE_HIGH(); +} + +bool NRF24L01P_writeFastMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + uint32_t timer = elapsed_ms(); + + while(get_status(NRF) & _BV(STATUS_TX_FULL_BIT)) + { + if(NRF->status & _BV(STATUS_MAX_RT_BIT)) + { + return false; + } + + if(elapsed_ms() - timer > 95) + { + err_notify(NRF); + return false; + } + } + + NRF24L01P_startFastWrite(NRF, payload, length, multicast, true); + + return true; +} + +bool NRF24L01P_writeFast(NRF24L01P_t *NRF, const void *payload, uint8_t length) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + return NRF24L01P_writeFastMulticast(NRF, payload, length, false); +} + +void NRF24L01P_startFastWrite(NRF24L01P_t *NRF, const void* payload, uint8_t length, const bool multicast, bool start_tx) +{ + assert_not_void(NRF, NULL); + assert_not_void(payload, NULL); + assert_not_void(length, 0); + + write_payload(NRF, payload, length, multicast ? W_TX_PAYLOAD_NOACK : W_TX_PAYLOAD); + + if(start_tx) + { + CE_HIGH(); + } +} + +bool NRF24L01P_startWrite(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + assert_not_bool(length, 0, false); + + write_payload(NRF, payload, length, multicast ? W_TX_PAYLOAD_NOACK : W_TX_PAYLOAD); + CE_HIGH(); + delay_ms(1); + CE_LOW(); + + return !(get_status(NRF) & _BV(STATUS_TX_FULL_BIT)); +} + +bool NRF24L01P_rxFifoFull(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return read_register(NRF, FIFO_STATUS) & _BV(FIFO_STATUS_RX_FULL_BIT) ? true : false; +} + +bool NRF24L01P_txFifoFull(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return read_register(NRF, FIFO_STATUS) & _BV(FIFO_STATUS_TX_FULL_BIT) ? true : false; +} + +bool NRF24L01P_txStandBy(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + uint32_t timeout = elapsed_ms(); + + while(!(read_register(NRF, FIFO_STATUS) & _BV(FIFO_STATUS_TX_EMPTY_BIT))) + { + if(NRF->status & _BV(STATUS_MAX_RT_BIT)) + { + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT)); + CE_LOW(); + NRF24L01P_flush_tx(NRF); + + return false; + } + + if(elapsed_ms() - timeout > 95) + { + err_notify(NRF); + return false; + } + } + + CE_LOW(); + return true; +} + +bool NRF24L01P_txStandByTimeout(NRF24L01P_t *NRF, uint32_t timeout, bool start_tx) +{ + assert_not_bool(NRF, NULL, false); + + if(start_tx) + { + NRF24L01P_stopListening(NRF); + CE_HIGH(); + } + + uint32_t start = elapsed_ms(); + + while(!(read_register(NRF, FIFO_STATUS) & _BV(FIFO_STATUS_TX_EMPTY_BIT))) + { + if(NRF->status & _BV(STATUS_MAX_RT_BIT)) + { + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT)); + CE_LOW(); + delay_ms(1); + CE_HIGH(); + if(elapsed_ms() - start >= timeout) + { + CE_LOW(); + NRF24L01P_flush_tx(NRF); + return false; + } + } + + if(elapsed_ms() - start > timeout + 95) + { + err_notify(NRF); + return false; + } + } + + CE_LOW(); + + return true; +} + +void NRF24L01P_maskIRQ(NRF24L01P_t *NRF, bool tx, bool fail, bool rx) +{ + assert_not_void(NRF, NULL); + + NRF->config_reg &= ~(1 << CONFIG_MASK_MAX_RT_BIT | 1 << CONFIG_MASK_TX_DS_BIT | 1 << CONFIG_MASK_RX_DR_BIT); + NRF->config_reg |= fail << CONFIG_MASK_MAX_RT_BIT | tx << CONFIG_MASK_TX_DS_BIT | rx << CONFIG_MASK_RX_DR_BIT; + write_register(NRF, CONFIG, NRF->config_reg); +} + +uint8_t NRF24L01P_getDynamicPayloadSize(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, 0); + + uint8_t pl_wid = r_rx_pl_wid(NRF); + + if(pl_wid > 32) + { + NRF24L01P_flush_rx(NRF); + delay_ms(2); + return 0; + } + + return pl_wid; +} + +bool NRF24L01P_availablePipe(NRF24L01P_t *NRF, uint8_t *pipe) +{ + assert_not_bool(NRF, NULL, false); + + uint8_t get_pipe = (get_status(NRF) >> STATUS_RX_P_NO_BIT) & 0x07; + + if(get_pipe > 5) return false; + + if(pipe) *pipe = get_pipe; + + return true; +} + +void NRF24L01P_read(NRF24L01P_t *NRF, void *payload, uint8_t length) +{ + assert_not_void(NRF, NULL); + + read_payload(NRF, payload, length); + + write_register(NRF, STATUS, _BV(STATUS_RX_DR_BIT)); +} + +void NRF24L01P_whatHappened(NRF24L01P_t *NRF, bool *tx_ok, bool *tx_fail, bool *rx_ready) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, STATUS, _BV(STATUS_MAX_RT_BIT) | _BV(STATUS_TX_DS_BIT) | _BV(STATUS_RX_DR_BIT)); + + if(tx_ok) *tx_ok = NRF->status & _BV(STATUS_TX_DS_BIT) ? true : false; + if(tx_fail) *tx_fail = NRF->status & _BV(STATUS_MAX_RT_BIT) ? true : false; + if(rx_ready) *rx_ready = NRF->status & _BV(STATUS_RX_DR_BIT) ? true : false; +} + +void NRF24L01P_openWritingPipe(NRF24L01P_t *NRF, const uint8_t* address) +{ + assert_not_void(NRF, NULL); + + write_registers(NRF, RX_ADDR_P0, address, NRF->addr_width); + write_registers(NRF, TX_ADDR, address, NRF->addr_width); +} + +void NRF24L01P_setAddressWidth(NRF24L01P_t *NRF, uint8_t a_width) +{ + assert_not_void(NRF, NULL); + if(a_width < 3 || a_width > 5) return; + + NRF->addr_width = a_width; + write_register(NRF, SETUP_AW, NRF->addr_width - 2); +} + +void NRF24L01P_openReadingPipe(NRF24L01P_t *NRF, uint8_t pipe, const uint8_t *address) +{ + assert_not_void(NRF, NULL); + assert_not_void(address, NULL); + + if(pipe == 0) + { + memcpy(NRF->pipe0_reading_address, address, NRF->addr_width); + } + + if(pipe <= 5) + { + if(pipe < 2) + { + write_registers(NRF, RX_ADDR_P0 + pipe, address, NRF->addr_width); + } + else + { + write_register(NRF, RX_ADDR_P0 + pipe, address[0]); + } + + uint8_t en_rxaddr = read_register(NRF, EN_RXADDR); + en_rxaddr |= _BV(pipe); + write_register(NRF, EN_RXADDR, en_rxaddr); + } +} + +void NRF24L01P_closeReadingPipe(NRF24L01P_t *NRF, uint8_t pipe) +{ + assert_not_void(NRF, NULL); + + if(pipe > 5) return; + + uint8_t en_rxaddr = read_register(NRF, EN_RXADDR); + en_rxaddr &= ~_BV(pipe); + write_register(NRF, EN_RXADDR, en_rxaddr); +} + +void NRF24L01P_enableDynamicPayloads(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, FEATURE, read_register(NRF, FEATURE) | _BV(FEATURE_EN_DPL_BIT)); + write_register(NRF, DYNPD, read_register(NRF, DYNPD) | _BV(DYNPD_DPL_P0_BIT) | _BV(DYNPD_DPL_P1_BIT) | _BV(DYNPD_DPL_P2_BIT) | _BV(DYNPD_DPL_P3_BIT) | _BV(DYNPD_DPL_P4_BIT) | _BV(DYNPD_DPL_P5_BIT)); + + NRF->dynamic_payloads_enabled = true; +} + +void NRF24L01P_disableDynamicPayloads(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, FEATURE, 0); + write_register(NRF, DYNPD, 0); + + NRF->dynamic_payloads_enabled = false; + NRF->ack_payloads_enabled = false; +} + +void NRF24L01P_enableAckPayload(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + if(!NRF->ack_payloads_enabled) + { + write_register(NRF, FEATURE, read_register(NRF, FEATURE) | _BV(FEATURE_EN_ACK_PAY_BIT) | _BV(FEATURE_EN_DPL_BIT)); + write_register(NRF, DYNPD, read_register(NRF, DYNPD) | _BV(DYNPD_DPL_P0_BIT)); + + NRF->dynamic_payloads_enabled = true; + NRF->ack_payloads_enabled = true; + } +} + +void NRF24L01P_disableAckPayload(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + if(NRF->ack_payloads_enabled) + { + write_register(NRF, FEATURE, read_register(NRF, FEATURE) | ~_BV(FEATURE_EN_ACK_PAY_BIT)); + + NRF->ack_payloads_enabled = true; + } +} + +void NRF24L01P_enableDynamicAck(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, FEATURE, read_register(NRF, FEATURE) | _BV(FEATURE_EN_DYN_ACK_BIT)); +} + +bool NRF24L01P_writeAckPayload(NRF24L01P_t *NRF, uint8_t pipe, const void *payload, uint8_t length) +{ + assert_not_bool(NRF, NULL, false); + assert_not_bool(payload, NULL, false); + + if(pipe > 5) return false; + + if(NRF->ack_payloads_enabled) + { + write_payload(NRF, payload, length, W_ACK_PAYLOAD | pipe); + return !(NRF->status & _BV(STATUS_TX_FULL_BIT)); + } + return false; +} + +bool NRF24L01P_isAckPayloadAvailable(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return NRF24L01P_available(NRF); +} + +bool NRF24L01P_isPVariant(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return NRF->is_p_variant; +} + +void NRF24L01P_setAutoAck(NRF24L01P_t *NRF, bool enable) +{ + assert_not_void(NRF, NULL); + + if(enable) + { + write_register(NRF, EN_AA, 0x3F); + } + else + { + write_register(NRF, EN_AA, 0); + // accomodate ACK payloads feature + if(NRF->ack_payloads_enabled) + { + NRF24L01P_disableAckPayload(NRF); + } + } +} + +void NRF24L01P_setAutoAckPipe(NRF24L01P_t *NRF, uint8_t pipe, bool enable) +{ + assert_not_void(NRF, NULL); + + if(pipe < 6) + { + uint8_t en_aa = read_register(NRF, EN_AA); + if(enable) + { + en_aa |= _BV(pipe); + } + else + { + en_aa &= ~_BV(pipe); + if(NRF->ack_payloads_enabled && !pipe) + { + NRF24L01P_disableAckPayload(NRF); + } + } + write_register(NRF, EN_AA, en_aa); + } +} + +bool NRF24L01P_testCarrier(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return read_register(NRF, RPD) & 1; +} + +bool NRF24L01P_testRPD(NRF24L01P_t *NRF) +{ + assert_not_bool(NRF, NULL, false); + + return NRF24L01P_testCarrier(NRF); +} + +void NRF24L01P_setPALevel(NRF24L01P_t *NRF, rf24_pa_dbm_e level, bool lna_enable) +{ + assert_not_void(NRF, NULL); + + uint8_t setup = read_register(NRF, RF_SETUP) & 0xF8; + + if (level > 3) { // If invalid level, go to max PA + level = (RF24_PA_MAX << 1) + lna_enable; // +1 to support the SI24R1 chip extra bit + } else { + level = (level << 1) + lna_enable; // Else set level as requested + } + + write_register(NRF, RF_SETUP, setup |= level); // Write it to the chip +} + +rf24_pa_dbm_e NRF24L01P_getPALevel(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, RF24_PA_MIN); + + return (read_register(NRF, RF_SETUP) & (_BV(RF_SETUP_RF_PWR_LOW_BIT) | _BV(RF_SETUP_RF_PWR_HIGH_BIT))) >> 1; +} + +uint8_t NRF24L01P_getARC(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, 0); + + return read_register(NRF, OBSERVE_TX) & 0x0F; +} + +void NRF24L01P_printDetails(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + shell_printf("\ ++-------------------------+"NEW_LINE"\ +| NRF REGISTERS |"NEW_LINE"\ ++-------------------------+"NEW_LINE); + shell_printf("CONFIG(%u) : 0x%02X"NEW_LINE, CONFIG, read_register(NRF, CONFIG)); + shell_printf("EN_RXADDR(%u) : 0x%02X"NEW_LINE, EN_RXADDR, read_register(NRF, EN_RXADDR)); + shell_printf("SETUP_AW(%u) : 0x%02X"NEW_LINE, SETUP_AW, read_register(NRF, SETUP_AW)); + shell_printf("SETUP_RETR(%u) : 0x%02X"NEW_LINE, SETUP_RETR, read_register(NRF, SETUP_RETR)); + shell_printf("RF_CH(%u) : 0x%02X"NEW_LINE, RF_CH, read_register(NRF, RF_CH)); + shell_printf("RF_SETUP(%u) : 0x%02X"NEW_LINE, RF_SETUP, read_register(NRF, RF_SETUP)); + shell_printf("STATUS(%u) : 0x%02X"NEW_LINE, STATUS, read_register(NRF, STATUS)); + uint8_t addr[5] = {0}; + read_registers(NRF, RX_ADDR_P0, addr, sizeof addr); + shell_printf("RX_ADDR_P0(%u) : 0x%02X%02X%02X%02X%02X"NEW_LINE, RX_ADDR_P0, addr[0], addr[1], addr[2], addr[3], addr[4]); + read_registers(NRF, RX_ADDR_P1, addr, sizeof addr); + shell_printf("RX_ADDR_P1(%u) : 0x%02X%02X%02X%02X%02X"NEW_LINE, RX_ADDR_P1, addr[0], addr[1], addr[2], addr[3], addr[4]); + read_registers(NRF, TX_ADDR, addr, sizeof addr); + shell_printf("TX_ADDR(%u) : 0x%02X%02X%02X%02X%02X"NEW_LINE, TX_ADDR, addr[0], addr[1], addr[2], addr[3], addr[4]); + shell_printf("RX_PW_P0(%u) : %u"NEW_LINE, RX_PW_P0, read_register(NRF, RX_PW_P0)); + shell_printf("RX_PW_P1(%u) : %u"NEW_LINE, RX_PW_P1, read_register(NRF, RX_PW_P1)); + shell_printf("RX_PW_P2(%u) : %u"NEW_LINE, RX_PW_P2, read_register(NRF, RX_PW_P2)); + shell_printf("RX_PW_P3(%u) : %u"NEW_LINE, RX_PW_P3, read_register(NRF, RX_PW_P3)); + shell_printf("RX_PW_P4(%u) : %u"NEW_LINE, RX_PW_P4, read_register(NRF, RX_PW_P4)); + shell_printf("RX_PW_P5(%u) : %u"NEW_LINE, RX_PW_P5, read_register(NRF, RX_PW_P5)); +} + +void NRF24L01P_setRetries(NRF24L01P_t *NRF, uint8_t delay, uint8_t count) +{ + assert_not_void(NRF, NULL); + + write_register(NRF, SETUP_RETR, (delay << 4) | (count & 0xF)); +} + +uint8_t NRF24L01P_flush_tx(NRF24L01P_t *NRF) +{ + write_register(NRF, FLUSH_TX, NRF_NOP); + + return read_register(NRF, STATUS); +} + +uint8_t NRF24L01P_flush_rx(NRF24L01P_t *NRF) +{ + write_register(NRF, FLUSH_RX, NRF_NOP); + + return read_register(NRF, STATUS); +} + +bool NRF24L01P_setDataRate(NRF24L01P_t *NRF, rf24_datarate_e data_rate) +{ + assert_not_bool(NRF, NULL, false); + + uint8_t rf_setup = read_register(NRF, RF_SETUP); + + rf_setup &= ~(_BV(RF_SETUP_RF_DR_LOW_BIT) | _BV(RF_SETUP_RF_DR_HIGH_BIT)); + + if(data_rate == RF24_250KBPS) + { + rf_setup |= _BV(RF_SETUP_RF_DR_LOW_BIT); + } + else if(data_rate == RF24_2MBPS) + { + rf_setup |= _BV(RF_SETUP_RF_DR_HIGH_BIT); + } + write_register(NRF, RF_SETUP, rf_setup); + + if(read_register(NRF, RF_SETUP) == rf_setup) + { + return true; + } + return false; +} + +rf24_datarate_e NRF24L01P_getDataRate(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, RF24_1MBPS); + + uint8_t dr = read_register(NRF, RF_SETUP); + + if(dr == _BV(RF_SETUP_RF_DR_LOW_BIT)) + { + // '10' = 250KBPS + return RF24_250KBPS; + } + else if(dr == _BV(RF_SETUP_RF_DR_HIGH_BIT)) + { + // '01' = 2MBPS + return RF24_2MBPS; + } + else + { + // '00' = 1MBPS + return RF24_1MBPS; + } +} + +void NRF24L01P_setCRCLength(NRF24L01P_t *NRF, rf24_crclength_e length) +{ + assert_not_void(NRF, NULL); + + NRF->config_reg &= ~(_BV(CONFIG_CRCO_BIT) | _BV(CONFIG_EN_CRC_BIT)); + + if(length == RF24_CRC_8) + { + NRF->config_reg |= _BV(CONFIG_EN_CRC_BIT); + } + else if(length == RF24_CRC_16) + { + NRF->config_reg |= _BV(CONFIG_EN_CRC_BIT) | _BV(CONFIG_CRCO_BIT); + } + + write_register(NRF, CONFIG, NRF->config_reg); +} + +rf24_crclength_e NRF24L01P_getCRCLength(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, RF24_CRC_DISABLED); + + rf24_crclength_e result = RF24_CRC_DISABLED; + uint8_t AA = read_register(NRF, EN_AA); + NRF->config_reg = read_register(NRF, CONFIG); + + if(NRF->config_reg & _BV(CONFIG_EN_CRC_BIT) || AA) + { + if(NRF->config_reg & _BV(CONFIG_CRCO_BIT)) + { + result = RF24_CRC_16; + } + else + { + result = RF24_CRC_8; + } + } + + return result; +} + +void NRF24L01P_disableCRC(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + NRF->config_reg &= ~_BV(CONFIG_EN_CRC_BIT); + write_register(NRF, CONFIG, NRF->config_reg); +} + +void NRF24L01P_setPayloadSize(NRF24L01P_t *NRF, uint8_t size) +{ + assert_not_void(NRF, NULL); + if(size < 1 || size > 32) return; + + NRF->payload_size = size; + + for(uint8_t i = 0; i < 6; i++) + { + write_register(NRF, RX_PW_P0 + i, NRF->payload_size); + } +} + +uint8_t NRF24L01P_getPayloadSize(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, 0); + + return NRF->payload_size; +} + +void NRF24L01P_setChannel(NRF24L01P_t *NRF, uint8_t channel) +{ + assert_not_void(NRF, NULL); + if(channel > 125) return; + + write_register(NRF, RF_CH, channel); +} + +uint8_t NRF24L01P_getChannel(NRF24L01P_t *NRF) +{ + assert_not_uint8_t(NRF, NULL, 0); + + return read_register(NRF, RF_CH); +} + +void NRF24L01P_startConstCarrier(NRF24L01P_t *NRF, rf24_pa_dbm_e level, uint8_t channel) +{ + assert_not_void(NRF, NULL); + + NRF24L01P_stopListening(NRF); + write_register(NRF, RF_SETUP, read_register(NRF, RF_SETUP) | _BV(RF_SETUP_CONT_WAVE_BIT) | _BV(RF_SETUP_PLL_LOCK_BIT)); + if(NRF24L01P_isPVariant(NRF)) + { + NRF24L01P_setAutoAck(NRF, false); + NRF24L01P_setRetries(NRF, 0, 0); + uint8_t dummy_buf[32]; + memset(dummy_buf, 0xFF, sizeof dummy_buf); + + write_registers(NRF, TX_ADDR, dummy_buf, 5); + NRF24L01P_flush_tx(NRF); + + write_payload(NRF, dummy_buf, sizeof dummy_buf, W_TX_PAYLOAD); + + NRF24L01P_disableCRC(NRF); + } + + NRF24L01P_setPALevel(NRF, level, false); + NRF24L01P_setChannel(NRF, channel); + + CE_HIGH(); + + if(NRF24L01P_isPVariant(NRF)) + { + delay_ms(1); + CE_LOW(); + NRF24L01P_reUseTX(NRF); + } +} + +void NRF24L01P_stopConstCarrier(NRF24L01P_t *NRF) +{ + assert_not_void(NRF, NULL); + + NRF24L01P_powerDown(NRF); + write_register(NRF, RF_SETUP, read_register(NRF, RF_SETUP) & ~_BV(RF_SETUP_CONT_WAVE_BIT) & ~_BV(RF_SETUP_PLL_LOCK_BIT)); + CE_LOW(); } \ No newline at end of file diff --git a/app/third_party/driver/NRF24L01P/NRF24L01P.h b/app/third_party/driver/NRF24L01P/NRF24L01P.h index e28dedb..f87e36e 100644 --- a/app/third_party/driver/NRF24L01P/NRF24L01P.h +++ b/app/third_party/driver/NRF24L01P/NRF24L01P.h @@ -1,4 +1,192 @@ -#include "wm_include.h" -#include "app_common.h" +#ifndef NRF24L01P_H +#define NRF24L01P_H -bool NRF24L01_init(void); \ No newline at end of file +#include "NRF24L01P_hw_interface.h" + +/*PUBLIC API*/ +typedef enum rf24_datarate +{ + /** (0) represents 1 Mbps */ + RF24_1MBPS = 0, + /** (1) represents 2 Mbps */ + RF24_2MBPS, + /** (2) represents 250 kbps */ + RF24_250KBPS +} rf24_datarate_e; + +typedef enum rf24_pa_dbm +{ + /** + * (0) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -18 dBm | -6 dBm | -12 dBm + */ + RF24_PA_MIN = 0, + /** + * (1) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -12 dBm | 0 dBm | -4 dBm + */ + RF24_PA_LOW, + /** + * (2) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -6 dBm | 3 dBm | 1 dBm + */ + RF24_PA_HIGH, + /** + * (3) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * 0 dBm | 7 dBm | 4 dBm + */ + RF24_PA_MAX, + /** + * (4) This should not be used and remains for backward compatibility. + */ + RF24_PA_ERROR +} rf24_pa_dbm_e; + +typedef enum rf24_crclength +{ + /** (0) represents no CRC checksum is used */ + RF24_CRC_DISABLED = 0, + /** (1) represents CRC 8 bit checksum is used */ + RF24_CRC_8, + /** (2) represents CRC 16 bit checksum is used */ + RF24_CRC_16 +} rf24_crclength_e; + +typedef struct NRF24L01P +{ + uint8_t status; + uint8_t payload_size; + bool dynamic_payloads_enabled; + bool ack_payloads_enabled; + uint8_t pipe0_reading_address[5]; + uint8_t addr_width; + uint8_t config_reg; + bool is_p_variant; + bool failure_detected; +} NRF24L01P_t; + +bool NRF24L01P_begin(NRF24L01P_t *NRF); + +bool NRF24L01P_isChipConnected(NRF24L01P_t *NRF); + +void NRF24L01P_startListening(NRF24L01P_t *NRF); + +void NRF24L01P_stopListening(NRF24L01P_t *NRF); + +bool NRF24L01P_available(NRF24L01P_t *NRF); + +void NRF24L01P_read(NRF24L01P_t *NRF, void *payload, uint8_t length); + +bool NRF24L01P_write(NRF24L01P_t *NRF, const void *payload, uint8_t length); + +void NRF24L01P_openWritingPipe(NRF24L01P_t *NRF, const uint8_t* address); + +void NRF24L01P_openReadingPipe(NRF24L01P_t *NRF, uint8_t pipe, const uint8_t *address); + +void NRF24L01P_printDetails(NRF24L01P_t *NRF); + +bool NRF24L01P_availablePipe(NRF24L01P_t *NRF, uint8_t *pipe); + +bool NRF24L01P_rxFifoFull(NRF24L01P_t *NRF); + +bool NRF24L01P_txFifoFull(NRF24L01P_t *NRF); + +void NRF24L01P_powerDown(NRF24L01P_t *NRF); + +void NRF24L01P_powerUp(NRF24L01P_t *NRF); + +bool NRF24L01P_writeMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast); + +bool NRF24L01P_writeFast(NRF24L01P_t *NRF, const void *payload, uint8_t length); + +bool NRF24L01P_writeFastMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast); + +bool NRF24L01P_writeBlocking(NRF24L01P_t *NRF, const void *payload, uint8_t length, uint32_t timeout); + +bool NRF24L01P_txStandBy(NRF24L01P_t *NRF); + +bool NRF24L01P_txStandByTimeout(NRF24L01P_t *NRF, uint32_t timeout, bool start_tx); + +bool NRF24L01P_writeAckPayload(NRF24L01P_t *NRF, uint8_t pipe, const void *payload, uint8_t length); + +void NRF24L01P_whatHappened(NRF24L01P_t *NRF, bool *tx_ok, bool *tx_fail, bool *rx_ready); + +void NRF24L01P_startFastWrite(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast, bool start_tx); + +bool NRF24L01P_startWrite(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast); + +void NRF24L01P_reUseTX(NRF24L01P_t *NRF); + +uint8_t NRF24L01P_flush_tx(NRF24L01P_t *NRF); + +uint8_t NRF24L01P_flush_rx(NRF24L01P_t *NRF); + +bool NRF24L01P_testCarrier(NRF24L01P_t *NRF); + +bool NRF24L01P_testRPD(NRF24L01P_t *NRF); + +void NRF24L01P_closeReadingPipe(NRF24L01P_t *NRF, uint8_t pipe); + +void NRF24L01P_setAddressWidth(NRF24L01P_t *NRF, uint8_t a_width); + +void NRF24L01P_setRetries(NRF24L01P_t *NRF, uint8_t delay, uint8_t count); + +void NRF24L01P_setChannel(NRF24L01P_t *NRF, uint8_t channel); + +uint8_t NRF24L01P_getChannel(NRF24L01P_t *NRF); + +void NRF24L01P_setPayloadSize(NRF24L01P_t *NRF, uint8_t size); + +uint8_t NRF24L01P_getPayloadSize(NRF24L01P_t *NRF); + +uint8_t NRF24L01P_getDynamicPayloadSize(NRF24L01P_t *NRF); + +void NRF24L01P_enableAckPayload(NRF24L01P_t *NRF); + +void NRF24L01P_disableAckPayload(NRF24L01P_t *NRF); + +void NRF24L01P_enableDynamicPayloads(NRF24L01P_t *NRF); + +void NRF24L01P_disableDynamicPayloads(NRF24L01P_t *NRF); + +void NRF24L01P_enableDynamicAck(NRF24L01P_t *NRF); + +bool NRF24L01P_isPVariant(NRF24L01P_t *NRF); + +void NRF24L01P_setAutoAck(NRF24L01P_t *NRF, bool enable); + +void NRF24L01P_setAutoAckPipe(NRF24L01P_t *NRF, uint8_t pipe, bool enable); + +void NRF24L01P_setPALevel(NRF24L01P_t *NRF, rf24_pa_dbm_e level, bool lna_enable); + +rf24_pa_dbm_e NRF24L01P_getPALevel(NRF24L01P_t *NRF); + +uint8_t NRF24L01P_getARC(NRF24L01P_t *NRF); + +bool NRF24L01P_setDataRate(NRF24L01P_t *NRF, rf24_datarate_e data_rate); + +rf24_datarate_e NRF24L01P_getDataRate(NRF24L01P_t *NRF); + +void NRF24L01P_setCRCLength(NRF24L01P_t *NRF, rf24_crclength_e length); + +rf24_crclength_e NRF24L01P_getCRCLength(NRF24L01P_t *NRF); + +void NRF24L01P_disableCRC(NRF24L01P_t *NRF); + +void NRF24L01P_maskIRQ(NRF24L01P_t *NRF, bool tx, bool fail, bool rx); + +void NRF24L01P_startConstCarrier(NRF24L01P_t *NRF, rf24_pa_dbm_e level, uint8_t channel); + +void NRF24L01P_stopConstCarrier(NRF24L01P_t *NRF); + +bool NRF24L01P_isAckPayloadAvailable(NRF24L01P_t *NRF); + +#endif //NRF24L01P_H \ No newline at end of file diff --git a/app/third_party/driver/NRF24L01P/NRF24L01P_hw_interface.h b/app/third_party/driver/NRF24L01P/NRF24L01P_hw_interface.h new file mode 100644 index 0000000..db3bd4a --- /dev/null +++ b/app/third_party/driver/NRF24L01P/NRF24L01P_hw_interface.h @@ -0,0 +1,20 @@ +#ifndef NRF24L01P_HW_INTERFACE_H +#define NRF24L01P_HW_INTERFACE_H + +#include "wm_include.h" +#include "FreeRTOS.h" +#include "app_common.h" +#include "nano_shell_interface.h" +#include "app_utils.h" + +#define debug_printf(...) shell_printf(__VA_ARGS__); shell_printf(NEW_LINE) + +void delay_ms(uint32_t ms); + +uint32_t elapsed_ms(void); + +void CE_HIGH(void); + +void CE_LOW(void); + +#endif //NRF24L01P_HW_INTERFACE_H \ No newline at end of file diff --git a/include/wm_include.h b/include/wm_include.h index 9e60364..2bea2fa 100644 --- a/include/wm_include.h +++ b/include/wm_include.h @@ -87,6 +87,7 @@ #include "wm_touchsensor.h" #include "wm_irq.h" #include "wm_rtc.h" +#include "wm_timer.h" #include "wm_ble.h" diff --git a/tools/w800/inc.mk b/tools/w800/inc.mk index 5edc40e..7426027 100644 --- a/tools/w800/inc.mk +++ b/tools/w800/inc.mk @@ -43,6 +43,7 @@ INCLUDES += -I $(TOP_DIR)/src/os/rtos/include INCLUDES += -I $(TOP_DIR)/src/app/factorycmd INCLUDES += -I $(TOP_DIR)/app_include +INCLUDES += -I $(TOP_DIR)/app/app_lib INCLUDES += -I $(TOP_DIR)/app/third_party/nano-shell-master INCLUDES += -I $(TOP_DIR)/app/third_party/driver/NRF24L01P #nimble host