Wouter van Kleunen
/
nrf52_esb
NRF52_esb
Diff: micro_esb.c
- Revision:
- 1:66f95e364222
- Parent:
- 0:a01a54c0dc90
--- a/micro_esb.c Mon Mar 23 04:09:41 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,871 +0,0 @@ -/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. - * - * The information contained herein is property of Nordic Semiconductor ASA. - * Terms and conditions of usage are described in detail in NORDIC - * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. - * - * Licensees are granted free, non-transferable use of the information. NO - * WARRANTY of ANY KIND is provided. This heading must NOT be removed from - * the file. - * - */ - -#include "micro_esb.h" -#include "uesb_error_codes.h" -//#include "nrf_gpio.h" -#include <string.h> - - -static uesb_event_handler_t m_event_handler; - -// RF parameters -static uesb_config_t m_config_local; - -// TX FIFO -static uesb_payload_t m_tx_fifo_payload[UESB_CORE_TX_FIFO_SIZE]; -static uesb_payload_tx_fifo_t m_tx_fifo; - -// RX FIFO -static uesb_payload_t m_rx_fifo_payload[UESB_CORE_RX_FIFO_SIZE]; -static uesb_payload_rx_fifo_t m_rx_fifo; - -static uint8_t m_tx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; -static uint8_t m_rx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; - -// Run time variables -static volatile uint32_t m_interrupt_flags = 0; -static uint32_t m_pid = 0; -static volatile uint32_t m_retransmits_remaining; -static volatile uint32_t m_last_tx_attempts; -static volatile uint8_t m_last_rx_packet_pid = 0xFF; -static volatile uint32_t m_last_rx_packet_crc = 0xFFFFFFFF; -static volatile uint32_t m_wait_for_ack_timeout_us; - -static uesb_payload_t *current_payload; - -static uesb_mainstate_t m_uesb_mainstate = UESB_STATE_UNINITIALIZED; - -// Constant parameters -#define RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS 48 // Smallest reliable value - 43 -#define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS 64 // Smallest reliable value - 59 -#define RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS 250 - -// Macros -#define DISABLE_RF_IRQ NVIC_DisableIRQ(RADIO_IRQn) -#define ENABLE_RF_IRQ NVIC_EnableIRQ(RADIO_IRQn) - -#define RADIO_SHORTS_COMMON ( RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \ - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk ) - -// These function pointers are changed dynamically, depending on protocol configuration and state -static void (*on_radio_disabled)(void) = 0; -static void (*on_radio_end)(void) = 0; -static void (*update_rf_payload_format)(uint32_t payload_length) = 0; - -// The following functions are assigned to the function pointers above -static void on_radio_disabled_esb_dpl_tx_noack(void); -static void on_radio_disabled_esb_dpl_tx(void); -static void on_radio_disabled_esb_dpl_tx_wait_for_ack(void); -static void on_radio_disabled_esb_dpl_rx(void); -static void on_radio_disabled_esb_dpl_rx_ack(void); - -static void on_radio_end_sb_tx(void); -static void on_radio_end_sb_rx(void); - -static void update_rf_payload_format_esb_dpl(uint32_t payload_length) -{ -#if(UESB_CORE_MAX_PAYLOAD_LENGTH <= 32) - NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (6 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); -#else - NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (8 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); -#endif - NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | - (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | - ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | - (0 << RADIO_PCNF1_STATLEN_Pos) | - (UESB_CORE_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_MAXLEN_Pos); -} - -static void update_rf_payload_format_esb(uint32_t payload_length) -{ - NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (1 << RADIO_PCNF0_S1LEN_Pos); - NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | - (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | - ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | - (payload_length << RADIO_PCNF1_STATLEN_Pos) | - (payload_length << RADIO_PCNF1_MAXLEN_Pos); -} - -static void update_rf_payload_format_sb(uint32_t payload_length) -{ - NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (0 << RADIO_PCNF0_S1LEN_Pos); - NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | - (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | - ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | - (payload_length << RADIO_PCNF1_STATLEN_Pos) | - (payload_length << RADIO_PCNF1_MAXLEN_Pos); -} - -// Function that swaps the bits within each byte in a uint32. Used to convert from nRF24L type addressing to nRF51 type addressing -static uint32_t bytewise_bit_swap(uint32_t inp) -{ - inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; - inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; - return (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; -} - -static void update_radio_parameters() -{ - // Protocol - switch(m_config_local.protocol) - { - case UESB_PROTOCOL_ESB_DPL: - update_rf_payload_format = update_rf_payload_format_esb_dpl; - break; - case UESB_PROTOCOL_ESB: - update_rf_payload_format = update_rf_payload_format_esb; - break; - case UESB_PROTOCOL_SB: - update_rf_payload_format = update_rf_payload_format_sb; - on_radio_end = (m_config_local.mode == UESB_MODE_PTX ? on_radio_end_sb_tx : on_radio_end_sb_rx); - break; - } - // TX power - NRF_RADIO->TXPOWER = m_config_local.tx_output_power << RADIO_TXPOWER_TXPOWER_Pos; - - // RF bitrate - NRF_RADIO->MODE = m_config_local.bitrate << RADIO_MODE_MODE_Pos; - switch(m_config_local.bitrate) - { - case UESB_BITRATE_2MBPS: - m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS; - break; - case UESB_BITRATE_1MBPS: - m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS; - break; - case UESB_BITRATE_250KBPS: - m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS; - break; - } - - // CRC configuration - NRF_RADIO->CRCCNF = m_config_local.crc << RADIO_CRCCNF_LEN_Pos; - if(m_config_local.crc == RADIO_CRCCNF_LEN_Two) - { - NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value - NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 - } - else if(m_config_local.crc == RADIO_CRCCNF_LEN_One) - { - NRF_RADIO->CRCINIT = 0xFFUL; // Initial value - NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8+x^2^x^1+1 - } - - // Packet format - update_rf_payload_format(m_config_local.payload_length); - - // Radio address config - NRF_RADIO->PREFIX0 = bytewise_bit_swap(m_config_local.rx_address_p3 << 24 | m_config_local.rx_address_p2 << 16 | m_config_local.rx_address_p1[0] << 8 | m_config_local.rx_address_p0[0]); - NRF_RADIO->PREFIX1 = bytewise_bit_swap(m_config_local.rx_address_p7 << 24 | m_config_local.rx_address_p6 << 16 | m_config_local.rx_address_p5 << 8 | m_config_local.rx_address_p4); - NRF_RADIO->BASE0 = bytewise_bit_swap(m_config_local.rx_address_p0[1] << 24 | m_config_local.rx_address_p0[2] << 16 | m_config_local.rx_address_p0[3] << 8 | m_config_local.rx_address_p0[4]); - NRF_RADIO->BASE1 = bytewise_bit_swap(m_config_local.rx_address_p1[1] << 24 | m_config_local.rx_address_p1[2] << 16 | m_config_local.rx_address_p1[3] << 8 | m_config_local.rx_address_p1[4]); -} - -static void initialize_fifos() -{ - m_tx_fifo.entry_point = 0; - m_tx_fifo.exit_point = 0; - m_tx_fifo.count = 0; - for(int i = 0; i < UESB_CORE_TX_FIFO_SIZE; i++) - { - m_tx_fifo.payload_ptr[i] = &m_tx_fifo_payload[i]; - } - - m_rx_fifo.entry_point = 0; - m_rx_fifo.exit_point = 0; - m_rx_fifo.count = 0; - for(int i = 0; i < UESB_CORE_RX_FIFO_SIZE; i++) - { - m_rx_fifo.payload_ptr[i] = &m_rx_fifo_payload[i]; - } -} - -static void tx_fifo_remove_last() -{ - if(m_tx_fifo.count > 0) - { - DISABLE_RF_IRQ; - m_tx_fifo.count--; - m_tx_fifo.exit_point++; - if(m_tx_fifo.exit_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.exit_point = 0; - ENABLE_RF_IRQ; - } -} - -static bool rx_fifo_push_rfbuf(uint8_t pipe) -{ - if(m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) - { - if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) - { - if(m_rx_payload_buffer[0] > UESB_CORE_MAX_PAYLOAD_LENGTH) return false; - m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_rx_payload_buffer[0]; - } - else - { - m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_config_local.payload_length; - } - if(m_config_local.protocol == UESB_PROTOCOL_SB) - { - memcpy(m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->data, &m_rx_payload_buffer[0], m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length); - } - else - { - memcpy(m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->data, &m_rx_payload_buffer[2], m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length); - } - m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->pipe = pipe; - m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->rssi = NRF_RADIO->RSSISAMPLE; - if(++m_rx_fifo.entry_point >= UESB_CORE_RX_FIFO_SIZE) m_rx_fifo.entry_point = 0; - m_rx_fifo.count++; - return true; - } - return false; -} - -static void sys_timer_init() -{ - // Configure the system timer with a 1 MHz base frequency - UESB_SYS_TIMER->PRESCALER = 4; - UESB_SYS_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; - UESB_SYS_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk; -} - -static void ppi_init() -{ - NRF_PPI->CH[UESB_PPI_TIMER_START].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY; - NRF_PPI->CH[UESB_PPI_TIMER_START].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_START; - NRF_PPI->CH[UESB_PPI_TIMER_STOP].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; - NRF_PPI->CH[UESB_PPI_TIMER_STOP].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_STOP; - NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[0]; - NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].TEP = (uint32_t)&NRF_RADIO->TASKS_DISABLE; - NRF_PPI->CH[UESB_PPI_TX_START].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[1]; - NRF_PPI->CH[UESB_PPI_TX_START].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN; -} - -uint32_t uesb_init(uesb_config_t *parameters) -{ - if(m_uesb_mainstate != UESB_STATE_UNINITIALIZED) return UESB_ERROR_ALREADY_INITIALIZED; - m_event_handler = parameters->event_handler; - memcpy(&m_config_local, parameters, sizeof(uesb_config_t)); - - m_interrupt_flags = 0; - m_pid = 0; - m_last_rx_packet_pid = 0xFF; - m_last_rx_packet_crc = 0xFFFFFFFF; - - update_radio_parameters(); - - initialize_fifos(); - - sys_timer_init(); - - ppi_init(); - - NVIC_SetPriority(RADIO_IRQn, m_config_local.radio_irq_priority & 0x03); - - //m_uesb_initialized = true; - m_uesb_mainstate = UESB_STATE_IDLE; - - return UESB_SUCCESS; -} - -uint32_t uesb_disable(void) -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - NRF_PPI->CHENCLR = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_TIMER_STOP) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TX_START); - m_uesb_mainstate = UESB_STATE_UNINITIALIZED; - return UESB_SUCCESS; -} - -static void start_tx_transaction() -{ - bool ack; - m_last_tx_attempts = 1; - // Prepare the payload - current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; - m_pid = (m_pid + 1) % 4; - switch(m_config_local.protocol) - { - case UESB_PROTOCOL_SB: - update_rf_payload_format(current_payload->length); - memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); - NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; - on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; - m_uesb_mainstate = UESB_STATE_PTX_TX; - break; - - case UESB_PROTOCOL_ESB: - update_rf_payload_format(current_payload->length); - m_tx_payload_buffer[0] = 0xCC | m_pid; - m_tx_payload_buffer[1] = 0; - memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); - - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; - - // Configure the retransmit counter - m_retransmits_remaining = m_config_local.retransmit_count; - on_radio_disabled = on_radio_disabled_esb_dpl_tx; - m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; - break; - - case UESB_PROTOCOL_ESB_DPL: - ack = current_payload->noack == 0 || m_config_local.dynamic_ack_enabled == 0; - m_tx_payload_buffer[0] = current_payload->length; - m_tx_payload_buffer[1] = m_pid << 1 | ((current_payload->noack == 0 && m_config_local.dynamic_ack_enabled) ? 0x01 : 0x00); - memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); - if(ack) - { - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; - - // Configure the retransmit counter - m_retransmits_remaining = m_config_local.retransmit_count; - on_radio_disabled = on_radio_disabled_esb_dpl_tx; - m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; - } - else - { - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; - m_uesb_mainstate = UESB_STATE_PTX_TX; - } - break; - } - - NRF_RADIO->TXADDRESS = current_payload->pipe; - NRF_RADIO->RXADDRESSES = 1 << current_payload->pipe; - - NRF_RADIO->FREQUENCY = m_config_local.rf_channel; - - NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; - - NVIC_ClearPendingIRQ(RADIO_IRQn); - NVIC_EnableIRQ(RADIO_IRQn); - - NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; - DEBUG_PIN_SET(DEBUGPIN4); - NRF_RADIO->TASKS_TXEN = 1; -} - -static uint32_t write_tx_payload(uesb_payload_t *payload, bool noack) // ~50us @ 61 bytes SB -{ - if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; - if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; - - DISABLE_RF_IRQ; - if(noack && m_config_local.dynamic_ack_enabled) payload->noack = 1; - else payload->noack = 0; - memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); - m_tx_fifo.entry_point++; - if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; - m_tx_fifo.count++; - ENABLE_RF_IRQ; - - if(m_config_local.tx_mode == UESB_TXMODE_AUTO && m_uesb_mainstate == UESB_STATE_IDLE) - { - start_tx_transaction(); - } - - return UESB_SUCCESS; -} - -uint32_t uesb_write_tx_payload(uesb_payload_t *payload) -{ - return write_tx_payload(payload, false); -} - -uint32_t uesb_write_tx_payload_noack(uesb_payload_t *payload) -{ - if(m_config_local.dynamic_ack_enabled == 0) return UESB_ERROR_DYN_ACK_NOT_ENABLED; - return write_tx_payload(payload, true); -} - -uint32_t uesb_write_ack_payload(uesb_payload_t *payload) -{ - if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; - if((m_uesb_mainstate != UESB_STATE_PRX) && - (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK) && - (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK_PAYLOAD)) - { - return UESB_ERROR_NOT_IN_RX_MODE; - } - if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; - - DISABLE_RF_IRQ; - memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); - m_tx_fifo.entry_point++; - if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; - m_tx_fifo.count++; - ENABLE_RF_IRQ; - - return UESB_SUCCESS; -} - -uint32_t uesb_read_rx_payload(uesb_payload_t *payload) -{ - if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; - if(m_rx_fifo.count == 0) return UESB_ERROR_RX_FIFO_EMPTY; - - DISABLE_RF_IRQ; - payload->length = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->length; - payload->pipe = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->pipe; - payload->rssi = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->rssi; - memcpy(payload->data, m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->data, payload->length); - if(++m_rx_fifo.exit_point >= UESB_CORE_RX_FIFO_SIZE) m_rx_fifo.exit_point = 0; - m_rx_fifo.count--; - ENABLE_RF_IRQ; - - return UESB_SUCCESS; -} - -uint32_t uesb_start_tx() -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - if(m_tx_fifo.count == 0) return UESB_ERROR_TX_FIFO_EMPTY; - start_tx_transaction(); - return UESB_SUCCESS; -} - -uint32_t uesb_start_rx(void) -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - - NRF_RADIO->INTENCLR = 0xFFFFFFFF; - NRF_RADIO->EVENTS_DISABLED = 0; - on_radio_disabled = on_radio_disabled_esb_dpl_rx; - switch(m_config_local.protocol) - { - case UESB_PROTOCOL_SB: - NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_START_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; - m_uesb_mainstate = UESB_STATE_PRX; - break; - case UESB_PROTOCOL_ESB: - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - m_uesb_mainstate = UESB_STATE_PRX; - break; - case UESB_PROTOCOL_ESB_DPL: - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - m_uesb_mainstate = UESB_STATE_PRX; - break; - } - - NRF_RADIO->RXADDRESSES = m_config_local.rx_pipes_enabled; - - NRF_RADIO->FREQUENCY = m_config_local.rf_channel; - - NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; - - NVIC_ClearPendingIRQ(RADIO_IRQn); - NVIC_EnableIRQ(RADIO_IRQn); - - NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->TASKS_RXEN = 1; - return UESB_SUCCESS; -} - -uint32_t uesb_stop_rx(void) -{ - if((m_uesb_mainstate == UESB_STATE_PRX) || (m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD)) - { - NRF_RADIO->SHORTS = 0; - NRF_RADIO->INTENCLR = 0xFFFFFFFF; - on_radio_disabled = NULL; - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->TASKS_DISABLE = 1; - while(NRF_RADIO->EVENTS_DISABLED == 0); - m_uesb_mainstate = UESB_STATE_IDLE; - return UESB_SUCCESS; - } - return UESB_ERROR_NOT_IN_RX_MODE; -} - -uint32_t uesb_get_tx_attempts(uint32_t *attempts) -{ - if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; - *attempts = m_last_tx_attempts; - return UESB_SUCCESS; -} - -uint32_t uesb_flush_tx(void) -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - DISABLE_RF_IRQ; - m_tx_fifo.count = 0; - m_tx_fifo.entry_point = m_tx_fifo.exit_point = 0; - ENABLE_RF_IRQ; - return UESB_SUCCESS; -} - -uint32_t uesb_flush_rx(void) -{ - DISABLE_RF_IRQ; - m_rx_fifo.count = 0; - m_rx_fifo.entry_point = 0; - ENABLE_RF_IRQ; - return UESB_SUCCESS; -} - -uint32_t uesb_get_clear_interrupts(uint32_t *interrupts) -{ - DISABLE_RF_IRQ; - *interrupts = m_interrupt_flags; - m_interrupt_flags = 0; - ENABLE_RF_IRQ; - return UESB_SUCCESS; -} - -uint32_t uesb_set_address(uesb_address_type_t address, const uint8_t *data_ptr) -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - switch(address) - { - case UESB_ADDRESS_PIPE0: - memcpy(m_config_local.rx_address_p0, data_ptr, m_config_local.rf_addr_length); - break; - case UESB_ADDRESS_PIPE1: - memcpy(m_config_local.rx_address_p1, data_ptr, m_config_local.rf_addr_length); - break; - case UESB_ADDRESS_PIPE2: - m_config_local.rx_address_p2 = *data_ptr; - break; - case UESB_ADDRESS_PIPE3: - m_config_local.rx_address_p3 = *data_ptr; - break; - case UESB_ADDRESS_PIPE4: - m_config_local.rx_address_p4 = *data_ptr; - break; - case UESB_ADDRESS_PIPE5: - m_config_local.rx_address_p5 = *data_ptr; - break; - case UESB_ADDRESS_PIPE6: - m_config_local.rx_address_p6 = *data_ptr; - break; - case UESB_ADDRESS_PIPE7: - m_config_local.rx_address_p7 = *data_ptr; - break; - default: - return UESB_ERROR_INVALID_PARAMETERS; - } - update_radio_parameters(); - return UESB_SUCCESS; -} - -uint32_t uesb_set_rf_channel(uint32_t channel) -{ - if(channel > 125) return UESB_ERROR_INVALID_PARAMETERS; - m_config_local.rf_channel = channel; - return UESB_SUCCESS; -} - -uint32_t uesb_set_tx_power(uesb_tx_power_t tx_output_power) -{ - if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; - if ( m_config_local.tx_output_power == tx_output_power ) return UESB_SUCCESS; - m_config_local.tx_output_power = tx_output_power; - update_radio_parameters(); - return UESB_SUCCESS; -} - -void RADIO_IRQHandler() -{ - if(NRF_RADIO->EVENTS_READY && (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) - { - NRF_RADIO->EVENTS_READY = 0; - - DEBUG_PIN_SET(DEBUGPIN1); - } - - if(NRF_RADIO->EVENTS_END && (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) - { - NRF_RADIO->EVENTS_END = 0; - - DEBUG_PIN_SET(DEBUGPIN2); - - // Call the correct on_radio_end function, depending on the current protocol state - if(on_radio_end) - { - on_radio_end(); - } - } - - if(NRF_RADIO->EVENTS_DISABLED && (NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk)) - { - NRF_RADIO->EVENTS_DISABLED = 0; - - DEBUG_PIN_SET(DEBUGPIN3); - - // Call the correct on_radio_disable function, depending on the current protocol state - if(on_radio_disabled) - { - on_radio_disabled(); - } - } - - DEBUG_PIN_CLR(DEBUGPIN1); - DEBUG_PIN_CLR(DEBUGPIN2); - DEBUG_PIN_CLR(DEBUGPIN3); - DEBUG_PIN_CLR(DEBUGPIN4); -} - -static void on_radio_disabled_esb_dpl_tx_noack() -{ - m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; - tx_fifo_remove_last(); - - if(m_tx_fifo.count == 0) - { - m_uesb_mainstate = UESB_STATE_IDLE; - if(m_event_handler != 0) m_event_handler(); - } - else - { - if(m_event_handler != 0) m_event_handler(); - start_tx_transaction(); - } -} - -static void on_radio_disabled_esb_dpl_tx() -{ - // Remove the DISABLED -> RXEN shortcut, to make sure the radio stays disabled after the RX window - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; - - // Make sure the timer is started the next time the radio is ready, - // and that it will disable the radio automatically if no packet is received by the time defined in m_wait_for_ack_timeout_us - UESB_SYS_TIMER->CC[0] = m_wait_for_ack_timeout_us; - UESB_SYS_TIMER->CC[1] = m_config_local.retransmit_delay - 130; - UESB_SYS_TIMER->TASKS_CLEAR = 1; - UESB_SYS_TIMER->EVENTS_COMPARE[0] = 0; - UESB_SYS_TIMER->EVENTS_COMPARE[1] = 0; - NRF_PPI->CHENSET = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TIMER_STOP); - NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); - NRF_RADIO->EVENTS_END = 0; - if(m_config_local.protocol == UESB_PROTOCOL_ESB) - { - update_rf_payload_format(0); - } - NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; - on_radio_disabled = on_radio_disabled_esb_dpl_tx_wait_for_ack; - m_uesb_mainstate = UESB_STATE_PTX_RX_ACK; -} - -static void on_radio_disabled_esb_dpl_tx_wait_for_ack() -{ - // This marks the completion of a TX_RX sequence (TX with ACK) - - // Make sure the timer will not deactivate the radio if a packet is received - NRF_PPI->CHENCLR = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TIMER_STOP); - - // If the radio has received a packet and the CRC status is OK - if(NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) - { - UESB_SYS_TIMER->TASKS_STOP = 1; - NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); - m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; - m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1; - tx_fifo_remove_last(); - if(m_rx_payload_buffer[0] > 0) - { - if(rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS)) - { - m_interrupt_flags |= UESB_INT_RX_DR_MSK; - } - } - - if((m_tx_fifo.count == 0) || (m_config_local.tx_mode == UESB_TXMODE_MANUAL)) - { - m_uesb_mainstate = UESB_STATE_IDLE; - if(m_event_handler != 0) m_event_handler(); - } - else - { - if(m_event_handler != 0) m_event_handler(); - start_tx_transaction(); - } - } - else - { - if(m_retransmits_remaining-- == 0) - { - UESB_SYS_TIMER->TASKS_STOP = 1; - NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); - // All retransmits are expended, and the TX operation is suspended - m_last_tx_attempts = m_config_local.retransmit_count + 1; - m_interrupt_flags |= UESB_INT_TX_FAILED_MSK; - - m_uesb_mainstate = UESB_STATE_IDLE; - if(m_event_handler != 0) m_event_handler(); - } - else - { - // We still have more retransmits left, and we should enter TX mode again as soon as the system timer reaches CC[1] - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; - update_rf_payload_format(current_payload->length); - NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; - on_radio_disabled = on_radio_disabled_esb_dpl_tx; - m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; - UESB_SYS_TIMER->TASKS_START = 1; - NRF_PPI->CHENSET = (1 << UESB_PPI_TX_START); - if(UESB_SYS_TIMER->EVENTS_COMPARE[1]) - { - NRF_RADIO->TASKS_TXEN = 1; - } - } - } -} - -static void on_radio_disabled_esb_dpl_rx(void) -{ - bool send_ack = false; - bool set_rx_interrupt = false; - if(NRF_RADIO->CRCSTATUS != 0 && m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) - { - send_ack = true; - } - if(send_ack) - { - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; - - // For a packet to be considered new (and not a retransmit) the PID or the CRC has to be different - if(NRF_RADIO->RXCRC != m_last_rx_packet_crc || (m_rx_payload_buffer[1] >> 1) != m_last_rx_packet_pid) - { - if((m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD) && (m_tx_fifo.count > 0)) - { - // It is assumed that the last ACK payload was recieved. - if(++m_tx_fifo.exit_point >= UESB_CORE_RX_FIFO_SIZE) m_tx_fifo.exit_point = 0; - m_tx_fifo.count--; - - // ACK payloads also require TX_DS (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf'). - m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; - } - - set_rx_interrupt = true; - m_last_rx_packet_pid = m_rx_payload_buffer[1] >> 1; - m_last_rx_packet_crc = NRF_RADIO->RXCRC; - } - - if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) - { - if(m_tx_fifo.count > 0) - { - current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; - - update_rf_payload_format(current_payload->length); - m_tx_payload_buffer[0] = current_payload->length; - memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); - - m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK_PAYLOAD; - } - else - { - update_rf_payload_format(0); - m_tx_payload_buffer[0] = 0; - - m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK; - } - - m_tx_payload_buffer[1] = m_rx_payload_buffer[1]; - } - else if(m_config_local.protocol == UESB_PROTOCOL_ESB) - { - m_tx_payload_buffer[0] = m_rx_payload_buffer[0]; - m_tx_payload_buffer[1] = 0; - - m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK; - } - - NRF_RADIO->TXADDRESS = NRF_RADIO->RXMATCH; - NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; - - on_radio_disabled = on_radio_disabled_esb_dpl_rx_ack; - } - else - { - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; - update_rf_payload_format(m_config_local.payload_length); - NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->TASKS_DISABLE = 1; - while(NRF_RADIO->EVENTS_DISABLED == 0); - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; - NRF_RADIO->TASKS_RXEN = 1; - } - if(set_rx_interrupt) - { - rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH); - m_interrupt_flags |= UESB_INT_RX_DR_MSK; - if(m_event_handler != 0) m_event_handler(); - } -} - -static void on_radio_disabled_esb_dpl_rx_ack(void) -{ - NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; - update_rf_payload_format(m_config_local.payload_length); - NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; - on_radio_disabled = on_radio_disabled_esb_dpl_rx; - - if(m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK) - { - // In the case of UESB_STATE_PRX_SEND_ACK_PAYLOAD the state will be updated when the next packet is received. - m_uesb_mainstate = UESB_STATE_PRX; - } -} - -static void on_radio_end_sb_tx(void) -{ - m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; - tx_fifo_remove_last(); - if(m_config_local.tx_mode == UESB_TXMODE_MANUAL || m_tx_fifo.count == 0) - { - // No more packets to send. Disable the radio and set the state to idle. - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->TASKS_DISABLE = 1; - while(!NRF_RADIO->EVENTS_DISABLED); - NRF_RADIO->EVENTS_DISABLED = 0; - m_uesb_mainstate = UESB_STATE_IDLE; - if(m_event_handler != 0) m_event_handler(); - } - else - { - // Send another packet automatically without disabling the radio first. - current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; - - update_rf_payload_format(current_payload->length); - memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); - - NRF_RADIO->TXADDRESS = current_payload->pipe; - - NVIC_ClearPendingIRQ(RADIO_IRQn); - NVIC_EnableIRQ(RADIO_IRQn); - - NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = 0; - NRF_RADIO->TASKS_START = 1; - - } -} - -static void on_radio_end_sb_rx(void) -{ - if(NRF_RADIO->CRCSTATUS != 0 && rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH)) - { - m_interrupt_flags |= UESB_INT_RX_DR_MSK; - if(m_event_handler != 0) m_event_handler(); - } -}