Wouter van Kleunen
/
nrf52_esb
NRF52_esb
micro_esb.cpp@1:66f95e364222, 2021-02-04 (annotated)
- Committer:
- wkleunen
- Date:
- Thu Feb 04 10:36:44 2021 +0000
- Revision:
- 1:66f95e364222
Initial compile;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
wkleunen | 1:66f95e364222 | 1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. |
wkleunen | 1:66f95e364222 | 2 | * |
wkleunen | 1:66f95e364222 | 3 | * The information contained herein is property of Nordic Semiconductor ASA. |
wkleunen | 1:66f95e364222 | 4 | * Terms and conditions of usage are described in detail in NORDIC |
wkleunen | 1:66f95e364222 | 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. |
wkleunen | 1:66f95e364222 | 6 | * |
wkleunen | 1:66f95e364222 | 7 | * Licensees are granted free, non-transferable use of the information. NO |
wkleunen | 1:66f95e364222 | 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from |
wkleunen | 1:66f95e364222 | 9 | * the file. |
wkleunen | 1:66f95e364222 | 10 | * |
wkleunen | 1:66f95e364222 | 11 | */ |
wkleunen | 1:66f95e364222 | 12 | |
wkleunen | 1:66f95e364222 | 13 | #include "micro_esb.h" |
wkleunen | 1:66f95e364222 | 14 | #include "uesb_error_codes.h" |
wkleunen | 1:66f95e364222 | 15 | //#include "nrf_gpio.h" |
wkleunen | 1:66f95e364222 | 16 | #include <string.h> |
wkleunen | 1:66f95e364222 | 17 | |
wkleunen | 1:66f95e364222 | 18 | |
wkleunen | 1:66f95e364222 | 19 | static uesb_event_handler_t m_event_handler; |
wkleunen | 1:66f95e364222 | 20 | |
wkleunen | 1:66f95e364222 | 21 | // RF parameters |
wkleunen | 1:66f95e364222 | 22 | static uesb_config_t m_config_local; |
wkleunen | 1:66f95e364222 | 23 | |
wkleunen | 1:66f95e364222 | 24 | // TX FIFO |
wkleunen | 1:66f95e364222 | 25 | static uesb_payload_t m_tx_fifo_payload[UESB_CORE_TX_FIFO_SIZE]; |
wkleunen | 1:66f95e364222 | 26 | static uesb_payload_tx_fifo_t m_tx_fifo; |
wkleunen | 1:66f95e364222 | 27 | |
wkleunen | 1:66f95e364222 | 28 | // RX FIFO |
wkleunen | 1:66f95e364222 | 29 | static uesb_payload_t m_rx_fifo_payload[UESB_CORE_RX_FIFO_SIZE]; |
wkleunen | 1:66f95e364222 | 30 | static uesb_payload_rx_fifo_t m_rx_fifo; |
wkleunen | 1:66f95e364222 | 31 | |
wkleunen | 1:66f95e364222 | 32 | static uint8_t m_tx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; |
wkleunen | 1:66f95e364222 | 33 | static uint8_t m_rx_payload_buffer[UESB_CORE_MAX_PAYLOAD_LENGTH + 2]; |
wkleunen | 1:66f95e364222 | 34 | |
wkleunen | 1:66f95e364222 | 35 | // Run time variables |
wkleunen | 1:66f95e364222 | 36 | static volatile uint32_t m_interrupt_flags = 0; |
wkleunen | 1:66f95e364222 | 37 | static uint32_t m_pid = 0; |
wkleunen | 1:66f95e364222 | 38 | static volatile uint32_t m_retransmits_remaining; |
wkleunen | 1:66f95e364222 | 39 | static volatile uint32_t m_last_tx_attempts; |
wkleunen | 1:66f95e364222 | 40 | static volatile uint8_t m_last_rx_packet_pid = 0xFF; |
wkleunen | 1:66f95e364222 | 41 | static volatile uint32_t m_last_rx_packet_crc = 0xFFFFFFFF; |
wkleunen | 1:66f95e364222 | 42 | static volatile uint32_t m_wait_for_ack_timeout_us; |
wkleunen | 1:66f95e364222 | 43 | |
wkleunen | 1:66f95e364222 | 44 | static uesb_payload_t *current_payload; |
wkleunen | 1:66f95e364222 | 45 | |
wkleunen | 1:66f95e364222 | 46 | static uesb_mainstate_t m_uesb_mainstate = UESB_STATE_UNINITIALIZED; |
wkleunen | 1:66f95e364222 | 47 | |
wkleunen | 1:66f95e364222 | 48 | // Constant parameters |
wkleunen | 1:66f95e364222 | 49 | #define RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS 48 // Smallest reliable value - 43 |
wkleunen | 1:66f95e364222 | 50 | #define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS 64 // Smallest reliable value - 59 |
wkleunen | 1:66f95e364222 | 51 | #define RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS 250 |
wkleunen | 1:66f95e364222 | 52 | |
wkleunen | 1:66f95e364222 | 53 | // Macros |
wkleunen | 1:66f95e364222 | 54 | #define DISABLE_RF_IRQ NVIC_DisableIRQ(RADIO_IRQn) |
wkleunen | 1:66f95e364222 | 55 | #define ENABLE_RF_IRQ NVIC_EnableIRQ(RADIO_IRQn) |
wkleunen | 1:66f95e364222 | 56 | |
wkleunen | 1:66f95e364222 | 57 | #define RADIO_SHORTS_COMMON ( RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \ |
wkleunen | 1:66f95e364222 | 58 | RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk ) |
wkleunen | 1:66f95e364222 | 59 | |
wkleunen | 1:66f95e364222 | 60 | // These function pointers are changed dynamically, depending on protocol configuration and state |
wkleunen | 1:66f95e364222 | 61 | static void (*on_radio_disabled)(void) = 0; |
wkleunen | 1:66f95e364222 | 62 | static void (*on_radio_end)(void) = 0; |
wkleunen | 1:66f95e364222 | 63 | static void (*update_rf_payload_format)(uint32_t payload_length) = 0; |
wkleunen | 1:66f95e364222 | 64 | |
wkleunen | 1:66f95e364222 | 65 | // The following functions are assigned to the function pointers above |
wkleunen | 1:66f95e364222 | 66 | static void on_radio_disabled_esb_dpl_tx_noack(void); |
wkleunen | 1:66f95e364222 | 67 | static void on_radio_disabled_esb_dpl_tx(void); |
wkleunen | 1:66f95e364222 | 68 | static void on_radio_disabled_esb_dpl_tx_wait_for_ack(void); |
wkleunen | 1:66f95e364222 | 69 | static void on_radio_disabled_esb_dpl_rx(void); |
wkleunen | 1:66f95e364222 | 70 | static void on_radio_disabled_esb_dpl_rx_ack(void); |
wkleunen | 1:66f95e364222 | 71 | |
wkleunen | 1:66f95e364222 | 72 | static void on_radio_end_sb_tx(void); |
wkleunen | 1:66f95e364222 | 73 | static void on_radio_end_sb_rx(void); |
wkleunen | 1:66f95e364222 | 74 | |
wkleunen | 1:66f95e364222 | 75 | static void update_rf_payload_format_esb_dpl(uint32_t payload_length) |
wkleunen | 1:66f95e364222 | 76 | { |
wkleunen | 1:66f95e364222 | 77 | #if(UESB_CORE_MAX_PAYLOAD_LENGTH <= 32) |
wkleunen | 1:66f95e364222 | 78 | NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (6 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); |
wkleunen | 1:66f95e364222 | 79 | #else |
wkleunen | 1:66f95e364222 | 80 | NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (8 << RADIO_PCNF0_LFLEN_Pos) | (3 << RADIO_PCNF0_S1LEN_Pos); |
wkleunen | 1:66f95e364222 | 81 | #endif |
wkleunen | 1:66f95e364222 | 82 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | |
wkleunen | 1:66f95e364222 | 83 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | |
wkleunen | 1:66f95e364222 | 84 | ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | |
wkleunen | 1:66f95e364222 | 85 | (0 << RADIO_PCNF1_STATLEN_Pos) | |
wkleunen | 1:66f95e364222 | 86 | (UESB_CORE_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_MAXLEN_Pos); |
wkleunen | 1:66f95e364222 | 87 | } |
wkleunen | 1:66f95e364222 | 88 | |
wkleunen | 1:66f95e364222 | 89 | static void update_rf_payload_format_esb(uint32_t payload_length) |
wkleunen | 1:66f95e364222 | 90 | { |
wkleunen | 1:66f95e364222 | 91 | NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (1 << RADIO_PCNF0_S1LEN_Pos); |
wkleunen | 1:66f95e364222 | 92 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | |
wkleunen | 1:66f95e364222 | 93 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | |
wkleunen | 1:66f95e364222 | 94 | ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | |
wkleunen | 1:66f95e364222 | 95 | (payload_length << RADIO_PCNF1_STATLEN_Pos) | |
wkleunen | 1:66f95e364222 | 96 | (payload_length << RADIO_PCNF1_MAXLEN_Pos); |
wkleunen | 1:66f95e364222 | 97 | } |
wkleunen | 1:66f95e364222 | 98 | |
wkleunen | 1:66f95e364222 | 99 | static void update_rf_payload_format_sb(uint32_t payload_length) |
wkleunen | 1:66f95e364222 | 100 | { |
wkleunen | 1:66f95e364222 | 101 | NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | (0 << RADIO_PCNF0_LFLEN_Pos) | (0 << RADIO_PCNF0_S1LEN_Pos); |
wkleunen | 1:66f95e364222 | 102 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | |
wkleunen | 1:66f95e364222 | 103 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | |
wkleunen | 1:66f95e364222 | 104 | ((m_config_local.rf_addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | |
wkleunen | 1:66f95e364222 | 105 | (payload_length << RADIO_PCNF1_STATLEN_Pos) | |
wkleunen | 1:66f95e364222 | 106 | (payload_length << RADIO_PCNF1_MAXLEN_Pos); |
wkleunen | 1:66f95e364222 | 107 | } |
wkleunen | 1:66f95e364222 | 108 | |
wkleunen | 1:66f95e364222 | 109 | // Function that swaps the bits within each byte in a uint32. Used to convert from nRF24L type addressing to nRF51 type addressing |
wkleunen | 1:66f95e364222 | 110 | static uint32_t bytewise_bit_swap(uint32_t inp) |
wkleunen | 1:66f95e364222 | 111 | { |
wkleunen | 1:66f95e364222 | 112 | inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; |
wkleunen | 1:66f95e364222 | 113 | inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; |
wkleunen | 1:66f95e364222 | 114 | return (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; |
wkleunen | 1:66f95e364222 | 115 | } |
wkleunen | 1:66f95e364222 | 116 | |
wkleunen | 1:66f95e364222 | 117 | static void update_radio_parameters() |
wkleunen | 1:66f95e364222 | 118 | { |
wkleunen | 1:66f95e364222 | 119 | // Protocol |
wkleunen | 1:66f95e364222 | 120 | switch(m_config_local.protocol) |
wkleunen | 1:66f95e364222 | 121 | { |
wkleunen | 1:66f95e364222 | 122 | case UESB_PROTOCOL_ESB_DPL: |
wkleunen | 1:66f95e364222 | 123 | update_rf_payload_format = update_rf_payload_format_esb_dpl; |
wkleunen | 1:66f95e364222 | 124 | break; |
wkleunen | 1:66f95e364222 | 125 | case UESB_PROTOCOL_ESB: |
wkleunen | 1:66f95e364222 | 126 | update_rf_payload_format = update_rf_payload_format_esb; |
wkleunen | 1:66f95e364222 | 127 | break; |
wkleunen | 1:66f95e364222 | 128 | case UESB_PROTOCOL_SB: |
wkleunen | 1:66f95e364222 | 129 | update_rf_payload_format = update_rf_payload_format_sb; |
wkleunen | 1:66f95e364222 | 130 | on_radio_end = (m_config_local.mode == UESB_MODE_PTX ? on_radio_end_sb_tx : on_radio_end_sb_rx); |
wkleunen | 1:66f95e364222 | 131 | break; |
wkleunen | 1:66f95e364222 | 132 | } |
wkleunen | 1:66f95e364222 | 133 | // TX power |
wkleunen | 1:66f95e364222 | 134 | NRF_RADIO->TXPOWER = m_config_local.tx_output_power << RADIO_TXPOWER_TXPOWER_Pos; |
wkleunen | 1:66f95e364222 | 135 | |
wkleunen | 1:66f95e364222 | 136 | // RF bitrate |
wkleunen | 1:66f95e364222 | 137 | NRF_RADIO->MODE = m_config_local.bitrate << RADIO_MODE_MODE_Pos; |
wkleunen | 1:66f95e364222 | 138 | switch(m_config_local.bitrate) |
wkleunen | 1:66f95e364222 | 139 | { |
wkleunen | 1:66f95e364222 | 140 | case UESB_BITRATE_2MBPS: |
wkleunen | 1:66f95e364222 | 141 | m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS; |
wkleunen | 1:66f95e364222 | 142 | break; |
wkleunen | 1:66f95e364222 | 143 | case UESB_BITRATE_1MBPS: |
wkleunen | 1:66f95e364222 | 144 | m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS; |
wkleunen | 1:66f95e364222 | 145 | break; |
wkleunen | 1:66f95e364222 | 146 | case UESB_BITRATE_250KBPS: |
wkleunen | 1:66f95e364222 | 147 | m_wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_250KBPS; |
wkleunen | 1:66f95e364222 | 148 | break; |
wkleunen | 1:66f95e364222 | 149 | } |
wkleunen | 1:66f95e364222 | 150 | |
wkleunen | 1:66f95e364222 | 151 | // CRC configuration |
wkleunen | 1:66f95e364222 | 152 | NRF_RADIO->CRCCNF = m_config_local.crc << RADIO_CRCCNF_LEN_Pos; |
wkleunen | 1:66f95e364222 | 153 | if(m_config_local.crc == RADIO_CRCCNF_LEN_Two) |
wkleunen | 1:66f95e364222 | 154 | { |
wkleunen | 1:66f95e364222 | 155 | NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value |
wkleunen | 1:66f95e364222 | 156 | NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 |
wkleunen | 1:66f95e364222 | 157 | } |
wkleunen | 1:66f95e364222 | 158 | else if(m_config_local.crc == RADIO_CRCCNF_LEN_One) |
wkleunen | 1:66f95e364222 | 159 | { |
wkleunen | 1:66f95e364222 | 160 | NRF_RADIO->CRCINIT = 0xFFUL; // Initial value |
wkleunen | 1:66f95e364222 | 161 | NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8+x^2^x^1+1 |
wkleunen | 1:66f95e364222 | 162 | } |
wkleunen | 1:66f95e364222 | 163 | |
wkleunen | 1:66f95e364222 | 164 | // Packet format |
wkleunen | 1:66f95e364222 | 165 | update_rf_payload_format(m_config_local.payload_length); |
wkleunen | 1:66f95e364222 | 166 | |
wkleunen | 1:66f95e364222 | 167 | // Radio address config |
wkleunen | 1:66f95e364222 | 168 | 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]); |
wkleunen | 1:66f95e364222 | 169 | 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); |
wkleunen | 1:66f95e364222 | 170 | 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]); |
wkleunen | 1:66f95e364222 | 171 | 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]); |
wkleunen | 1:66f95e364222 | 172 | } |
wkleunen | 1:66f95e364222 | 173 | |
wkleunen | 1:66f95e364222 | 174 | static void initialize_fifos() |
wkleunen | 1:66f95e364222 | 175 | { |
wkleunen | 1:66f95e364222 | 176 | m_tx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 177 | m_tx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 178 | m_tx_fifo.count = 0; |
wkleunen | 1:66f95e364222 | 179 | for(int i = 0; i < UESB_CORE_TX_FIFO_SIZE; i++) |
wkleunen | 1:66f95e364222 | 180 | { |
wkleunen | 1:66f95e364222 | 181 | m_tx_fifo.payload_ptr[i] = &m_tx_fifo_payload[i]; |
wkleunen | 1:66f95e364222 | 182 | } |
wkleunen | 1:66f95e364222 | 183 | |
wkleunen | 1:66f95e364222 | 184 | m_rx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 185 | m_rx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 186 | m_rx_fifo.count = 0; |
wkleunen | 1:66f95e364222 | 187 | for(int i = 0; i < UESB_CORE_RX_FIFO_SIZE; i++) |
wkleunen | 1:66f95e364222 | 188 | { |
wkleunen | 1:66f95e364222 | 189 | m_rx_fifo.payload_ptr[i] = &m_rx_fifo_payload[i]; |
wkleunen | 1:66f95e364222 | 190 | } |
wkleunen | 1:66f95e364222 | 191 | } |
wkleunen | 1:66f95e364222 | 192 | |
wkleunen | 1:66f95e364222 | 193 | static void tx_fifo_remove_last() |
wkleunen | 1:66f95e364222 | 194 | { |
wkleunen | 1:66f95e364222 | 195 | if(m_tx_fifo.count > 0) |
wkleunen | 1:66f95e364222 | 196 | { |
wkleunen | 1:66f95e364222 | 197 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 198 | m_tx_fifo.count--; |
wkleunen | 1:66f95e364222 | 199 | m_tx_fifo.exit_point++; |
wkleunen | 1:66f95e364222 | 200 | if(m_tx_fifo.exit_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 201 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 202 | } |
wkleunen | 1:66f95e364222 | 203 | } |
wkleunen | 1:66f95e364222 | 204 | |
wkleunen | 1:66f95e364222 | 205 | static bool rx_fifo_push_rfbuf(uint8_t pipe) |
wkleunen | 1:66f95e364222 | 206 | { |
wkleunen | 1:66f95e364222 | 207 | if(m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) |
wkleunen | 1:66f95e364222 | 208 | { |
wkleunen | 1:66f95e364222 | 209 | if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) |
wkleunen | 1:66f95e364222 | 210 | { |
wkleunen | 1:66f95e364222 | 211 | if(m_rx_payload_buffer[0] > UESB_CORE_MAX_PAYLOAD_LENGTH) return false; |
wkleunen | 1:66f95e364222 | 212 | m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_rx_payload_buffer[0]; |
wkleunen | 1:66f95e364222 | 213 | } |
wkleunen | 1:66f95e364222 | 214 | else |
wkleunen | 1:66f95e364222 | 215 | { |
wkleunen | 1:66f95e364222 | 216 | m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->length = m_config_local.payload_length; |
wkleunen | 1:66f95e364222 | 217 | } |
wkleunen | 1:66f95e364222 | 218 | if(m_config_local.protocol == UESB_PROTOCOL_SB) |
wkleunen | 1:66f95e364222 | 219 | { |
wkleunen | 1:66f95e364222 | 220 | 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); |
wkleunen | 1:66f95e364222 | 221 | } |
wkleunen | 1:66f95e364222 | 222 | else |
wkleunen | 1:66f95e364222 | 223 | { |
wkleunen | 1:66f95e364222 | 224 | 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); |
wkleunen | 1:66f95e364222 | 225 | } |
wkleunen | 1:66f95e364222 | 226 | m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->pipe = pipe; |
wkleunen | 1:66f95e364222 | 227 | m_rx_fifo.payload_ptr[m_rx_fifo.entry_point]->rssi = NRF_RADIO->RSSISAMPLE; |
wkleunen | 1:66f95e364222 | 228 | if(++m_rx_fifo.entry_point >= UESB_CORE_RX_FIFO_SIZE) m_rx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 229 | m_rx_fifo.count++; |
wkleunen | 1:66f95e364222 | 230 | return true; |
wkleunen | 1:66f95e364222 | 231 | } |
wkleunen | 1:66f95e364222 | 232 | return false; |
wkleunen | 1:66f95e364222 | 233 | } |
wkleunen | 1:66f95e364222 | 234 | |
wkleunen | 1:66f95e364222 | 235 | static void sys_timer_init() |
wkleunen | 1:66f95e364222 | 236 | { |
wkleunen | 1:66f95e364222 | 237 | // Configure the system timer with a 1 MHz base frequency |
wkleunen | 1:66f95e364222 | 238 | UESB_SYS_TIMER->PRESCALER = 4; |
wkleunen | 1:66f95e364222 | 239 | UESB_SYS_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; |
wkleunen | 1:66f95e364222 | 240 | UESB_SYS_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk; |
wkleunen | 1:66f95e364222 | 241 | } |
wkleunen | 1:66f95e364222 | 242 | |
wkleunen | 1:66f95e364222 | 243 | static void ppi_init() |
wkleunen | 1:66f95e364222 | 244 | { |
wkleunen | 1:66f95e364222 | 245 | NRF_PPI->CH[UESB_PPI_TIMER_START].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY; |
wkleunen | 1:66f95e364222 | 246 | NRF_PPI->CH[UESB_PPI_TIMER_START].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_START; |
wkleunen | 1:66f95e364222 | 247 | NRF_PPI->CH[UESB_PPI_TIMER_STOP].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; |
wkleunen | 1:66f95e364222 | 248 | NRF_PPI->CH[UESB_PPI_TIMER_STOP].TEP = (uint32_t)&UESB_SYS_TIMER->TASKS_STOP; |
wkleunen | 1:66f95e364222 | 249 | NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[0]; |
wkleunen | 1:66f95e364222 | 250 | NRF_PPI->CH[UESB_PPI_RX_TIMEOUT].TEP = (uint32_t)&NRF_RADIO->TASKS_DISABLE; |
wkleunen | 1:66f95e364222 | 251 | NRF_PPI->CH[UESB_PPI_TX_START].EEP = (uint32_t)&UESB_SYS_TIMER->EVENTS_COMPARE[1]; |
wkleunen | 1:66f95e364222 | 252 | NRF_PPI->CH[UESB_PPI_TX_START].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN; |
wkleunen | 1:66f95e364222 | 253 | } |
wkleunen | 1:66f95e364222 | 254 | |
wkleunen | 1:66f95e364222 | 255 | uint32_t uesb_read_rx_payload(uesb_payload_t *payload) |
wkleunen | 1:66f95e364222 | 256 | { |
wkleunen | 1:66f95e364222 | 257 | if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; |
wkleunen | 1:66f95e364222 | 258 | if(m_rx_fifo.count == 0) return UESB_ERROR_RX_FIFO_EMPTY; |
wkleunen | 1:66f95e364222 | 259 | |
wkleunen | 1:66f95e364222 | 260 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 261 | payload->length = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->length; |
wkleunen | 1:66f95e364222 | 262 | payload->pipe = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->pipe; |
wkleunen | 1:66f95e364222 | 263 | payload->rssi = m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->rssi; |
wkleunen | 1:66f95e364222 | 264 | memcpy(payload->data, m_rx_fifo.payload_ptr[m_rx_fifo.exit_point]->data, payload->length); |
wkleunen | 1:66f95e364222 | 265 | if(++m_rx_fifo.exit_point >= UESB_CORE_RX_FIFO_SIZE) m_rx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 266 | m_rx_fifo.count--; |
wkleunen | 1:66f95e364222 | 267 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 268 | |
wkleunen | 1:66f95e364222 | 269 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 270 | } |
wkleunen | 1:66f95e364222 | 271 | |
wkleunen | 1:66f95e364222 | 272 | |
wkleunen | 1:66f95e364222 | 273 | uint32_t uesb_init(uesb_config_t *parameters) |
wkleunen | 1:66f95e364222 | 274 | { |
wkleunen | 1:66f95e364222 | 275 | if(m_uesb_mainstate != UESB_STATE_UNINITIALIZED) return UESB_ERROR_ALREADY_INITIALIZED; |
wkleunen | 1:66f95e364222 | 276 | m_event_handler = parameters->event_handler; |
wkleunen | 1:66f95e364222 | 277 | memcpy(&m_config_local, parameters, sizeof(uesb_config_t)); |
wkleunen | 1:66f95e364222 | 278 | |
wkleunen | 1:66f95e364222 | 279 | m_interrupt_flags = 0; |
wkleunen | 1:66f95e364222 | 280 | m_pid = 0; |
wkleunen | 1:66f95e364222 | 281 | m_last_rx_packet_pid = 0xFF; |
wkleunen | 1:66f95e364222 | 282 | m_last_rx_packet_crc = 0xFFFFFFFF; |
wkleunen | 1:66f95e364222 | 283 | |
wkleunen | 1:66f95e364222 | 284 | update_radio_parameters(); |
wkleunen | 1:66f95e364222 | 285 | |
wkleunen | 1:66f95e364222 | 286 | initialize_fifos(); |
wkleunen | 1:66f95e364222 | 287 | |
wkleunen | 1:66f95e364222 | 288 | sys_timer_init(); |
wkleunen | 1:66f95e364222 | 289 | |
wkleunen | 1:66f95e364222 | 290 | ppi_init(); |
wkleunen | 1:66f95e364222 | 291 | |
wkleunen | 1:66f95e364222 | 292 | NVIC_SetPriority(RADIO_IRQn, m_config_local.radio_irq_priority & 0x03); |
wkleunen | 1:66f95e364222 | 293 | |
wkleunen | 1:66f95e364222 | 294 | //m_uesb_initialized = true; |
wkleunen | 1:66f95e364222 | 295 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 296 | |
wkleunen | 1:66f95e364222 | 297 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 298 | } |
wkleunen | 1:66f95e364222 | 299 | |
wkleunen | 1:66f95e364222 | 300 | uint32_t uesb_disable(void) |
wkleunen | 1:66f95e364222 | 301 | { |
wkleunen | 1:66f95e364222 | 302 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 303 | NRF_PPI->CHENCLR = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_TIMER_STOP) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TX_START); |
wkleunen | 1:66f95e364222 | 304 | m_uesb_mainstate = UESB_STATE_UNINITIALIZED; |
wkleunen | 1:66f95e364222 | 305 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 306 | } |
wkleunen | 1:66f95e364222 | 307 | |
wkleunen | 1:66f95e364222 | 308 | static void start_tx_transaction() |
wkleunen | 1:66f95e364222 | 309 | { |
wkleunen | 1:66f95e364222 | 310 | bool ack; |
wkleunen | 1:66f95e364222 | 311 | m_last_tx_attempts = 1; |
wkleunen | 1:66f95e364222 | 312 | // Prepare the payload |
wkleunen | 1:66f95e364222 | 313 | current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; |
wkleunen | 1:66f95e364222 | 314 | m_pid = (m_pid + 1) % 4; |
wkleunen | 1:66f95e364222 | 315 | switch(m_config_local.protocol) |
wkleunen | 1:66f95e364222 | 316 | { |
wkleunen | 1:66f95e364222 | 317 | case UESB_PROTOCOL_SB: |
wkleunen | 1:66f95e364222 | 318 | update_rf_payload_format(current_payload->length); |
wkleunen | 1:66f95e364222 | 319 | memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); |
wkleunen | 1:66f95e364222 | 320 | NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; |
wkleunen | 1:66f95e364222 | 321 | NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; |
wkleunen | 1:66f95e364222 | 322 | on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; |
wkleunen | 1:66f95e364222 | 323 | m_uesb_mainstate = UESB_STATE_PTX_TX; |
wkleunen | 1:66f95e364222 | 324 | break; |
wkleunen | 1:66f95e364222 | 325 | |
wkleunen | 1:66f95e364222 | 326 | case UESB_PROTOCOL_ESB: |
wkleunen | 1:66f95e364222 | 327 | update_rf_payload_format(current_payload->length); |
wkleunen | 1:66f95e364222 | 328 | m_tx_payload_buffer[0] = 0xCC | m_pid; |
wkleunen | 1:66f95e364222 | 329 | m_tx_payload_buffer[1] = 0; |
wkleunen | 1:66f95e364222 | 330 | memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); |
wkleunen | 1:66f95e364222 | 331 | |
wkleunen | 1:66f95e364222 | 332 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; |
wkleunen | 1:66f95e364222 | 333 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; |
wkleunen | 1:66f95e364222 | 334 | |
wkleunen | 1:66f95e364222 | 335 | // Configure the retransmit counter |
wkleunen | 1:66f95e364222 | 336 | m_retransmits_remaining = m_config_local.retransmit_count; |
wkleunen | 1:66f95e364222 | 337 | on_radio_disabled = on_radio_disabled_esb_dpl_tx; |
wkleunen | 1:66f95e364222 | 338 | m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; |
wkleunen | 1:66f95e364222 | 339 | break; |
wkleunen | 1:66f95e364222 | 340 | |
wkleunen | 1:66f95e364222 | 341 | case UESB_PROTOCOL_ESB_DPL: |
wkleunen | 1:66f95e364222 | 342 | ack = current_payload->noack == 0 || m_config_local.dynamic_ack_enabled == 0; |
wkleunen | 1:66f95e364222 | 343 | m_tx_payload_buffer[0] = current_payload->length; |
wkleunen | 1:66f95e364222 | 344 | m_tx_payload_buffer[1] = m_pid << 1 | ((current_payload->noack == 0 && m_config_local.dynamic_ack_enabled) ? 0x01 : 0x00); |
wkleunen | 1:66f95e364222 | 345 | memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); |
wkleunen | 1:66f95e364222 | 346 | if(ack) |
wkleunen | 1:66f95e364222 | 347 | { |
wkleunen | 1:66f95e364222 | 348 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; |
wkleunen | 1:66f95e364222 | 349 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; |
wkleunen | 1:66f95e364222 | 350 | |
wkleunen | 1:66f95e364222 | 351 | // Configure the retransmit counter |
wkleunen | 1:66f95e364222 | 352 | m_retransmits_remaining = m_config_local.retransmit_count; |
wkleunen | 1:66f95e364222 | 353 | on_radio_disabled = on_radio_disabled_esb_dpl_tx; |
wkleunen | 1:66f95e364222 | 354 | m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; |
wkleunen | 1:66f95e364222 | 355 | } |
wkleunen | 1:66f95e364222 | 356 | else |
wkleunen | 1:66f95e364222 | 357 | { |
wkleunen | 1:66f95e364222 | 358 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; |
wkleunen | 1:66f95e364222 | 359 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; |
wkleunen | 1:66f95e364222 | 360 | on_radio_disabled = on_radio_disabled_esb_dpl_tx_noack; |
wkleunen | 1:66f95e364222 | 361 | m_uesb_mainstate = UESB_STATE_PTX_TX; |
wkleunen | 1:66f95e364222 | 362 | } |
wkleunen | 1:66f95e364222 | 363 | break; |
wkleunen | 1:66f95e364222 | 364 | } |
wkleunen | 1:66f95e364222 | 365 | |
wkleunen | 1:66f95e364222 | 366 | NRF_RADIO->TXADDRESS = current_payload->pipe; |
wkleunen | 1:66f95e364222 | 367 | NRF_RADIO->RXADDRESSES = 1 << current_payload->pipe; |
wkleunen | 1:66f95e364222 | 368 | |
wkleunen | 1:66f95e364222 | 369 | NRF_RADIO->FREQUENCY = m_config_local.rf_channel; |
wkleunen | 1:66f95e364222 | 370 | |
wkleunen | 1:66f95e364222 | 371 | NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; |
wkleunen | 1:66f95e364222 | 372 | |
wkleunen | 1:66f95e364222 | 373 | NVIC_ClearPendingIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 374 | NVIC_EnableIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 375 | |
wkleunen | 1:66f95e364222 | 376 | NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 377 | DEBUG_PIN_SET(DEBUGPIN4); |
wkleunen | 1:66f95e364222 | 378 | NRF_RADIO->TASKS_TXEN = 1; |
wkleunen | 1:66f95e364222 | 379 | } |
wkleunen | 1:66f95e364222 | 380 | |
wkleunen | 1:66f95e364222 | 381 | static uint32_t write_tx_payload(uesb_payload_t *payload, bool noack) // ~50us @ 61 bytes SB |
wkleunen | 1:66f95e364222 | 382 | { |
wkleunen | 1:66f95e364222 | 383 | if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; |
wkleunen | 1:66f95e364222 | 384 | if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; |
wkleunen | 1:66f95e364222 | 385 | |
wkleunen | 1:66f95e364222 | 386 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 387 | if(noack && m_config_local.dynamic_ack_enabled) payload->noack = 1; |
wkleunen | 1:66f95e364222 | 388 | else payload->noack = 0; |
wkleunen | 1:66f95e364222 | 389 | memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); |
wkleunen | 1:66f95e364222 | 390 | m_tx_fifo.entry_point++; |
wkleunen | 1:66f95e364222 | 391 | if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 392 | m_tx_fifo.count++; |
wkleunen | 1:66f95e364222 | 393 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 394 | |
wkleunen | 1:66f95e364222 | 395 | if(m_config_local.tx_mode == UESB_TXMODE_AUTO && m_uesb_mainstate == UESB_STATE_IDLE) |
wkleunen | 1:66f95e364222 | 396 | { |
wkleunen | 1:66f95e364222 | 397 | start_tx_transaction(); |
wkleunen | 1:66f95e364222 | 398 | } |
wkleunen | 1:66f95e364222 | 399 | |
wkleunen | 1:66f95e364222 | 400 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 401 | } |
wkleunen | 1:66f95e364222 | 402 | |
wkleunen | 1:66f95e364222 | 403 | uint32_t uesb_write_tx_payload(uesb_payload_t *payload) |
wkleunen | 1:66f95e364222 | 404 | { |
wkleunen | 1:66f95e364222 | 405 | return write_tx_payload(payload, false); |
wkleunen | 1:66f95e364222 | 406 | } |
wkleunen | 1:66f95e364222 | 407 | |
wkleunen | 1:66f95e364222 | 408 | uint32_t uesb_write_tx_payload_noack(uesb_payload_t *payload) |
wkleunen | 1:66f95e364222 | 409 | { |
wkleunen | 1:66f95e364222 | 410 | if(m_config_local.dynamic_ack_enabled == 0) return UESB_ERROR_DYN_ACK_NOT_ENABLED; |
wkleunen | 1:66f95e364222 | 411 | return write_tx_payload(payload, true); |
wkleunen | 1:66f95e364222 | 412 | } |
wkleunen | 1:66f95e364222 | 413 | |
wkleunen | 1:66f95e364222 | 414 | uint32_t uesb_write_ack_payload(uesb_payload_t *payload) |
wkleunen | 1:66f95e364222 | 415 | { |
wkleunen | 1:66f95e364222 | 416 | if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; |
wkleunen | 1:66f95e364222 | 417 | if((m_uesb_mainstate != UESB_STATE_PRX) && |
wkleunen | 1:66f95e364222 | 418 | (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK) && |
wkleunen | 1:66f95e364222 | 419 | (m_uesb_mainstate != UESB_STATE_PRX_SEND_ACK_PAYLOAD)) |
wkleunen | 1:66f95e364222 | 420 | { |
wkleunen | 1:66f95e364222 | 421 | return UESB_ERROR_NOT_IN_RX_MODE; |
wkleunen | 1:66f95e364222 | 422 | } |
wkleunen | 1:66f95e364222 | 423 | if(m_tx_fifo.count >= UESB_CORE_TX_FIFO_SIZE) return UESB_ERROR_TX_FIFO_FULL; |
wkleunen | 1:66f95e364222 | 424 | |
wkleunen | 1:66f95e364222 | 425 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 426 | memcpy(m_tx_fifo.payload_ptr[m_tx_fifo.entry_point], payload, sizeof(uesb_payload_t)); |
wkleunen | 1:66f95e364222 | 427 | m_tx_fifo.entry_point++; |
wkleunen | 1:66f95e364222 | 428 | if(m_tx_fifo.entry_point >= UESB_CORE_TX_FIFO_SIZE) m_tx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 429 | m_tx_fifo.count++; |
wkleunen | 1:66f95e364222 | 430 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 431 | |
wkleunen | 1:66f95e364222 | 432 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 433 | } |
wkleunen | 1:66f95e364222 | 434 | |
wkleunen | 1:66f95e364222 | 435 | |
wkleunen | 1:66f95e364222 | 436 | uint32_t uesb_start_tx() |
wkleunen | 1:66f95e364222 | 437 | { |
wkleunen | 1:66f95e364222 | 438 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 439 | if(m_tx_fifo.count == 0) return UESB_ERROR_TX_FIFO_EMPTY; |
wkleunen | 1:66f95e364222 | 440 | start_tx_transaction(); |
wkleunen | 1:66f95e364222 | 441 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 442 | } |
wkleunen | 1:66f95e364222 | 443 | |
wkleunen | 1:66f95e364222 | 444 | uint32_t uesb_start_rx(void) |
wkleunen | 1:66f95e364222 | 445 | { |
wkleunen | 1:66f95e364222 | 446 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 447 | |
wkleunen | 1:66f95e364222 | 448 | NRF_RADIO->INTENCLR = 0xFFFFFFFF; |
wkleunen | 1:66f95e364222 | 449 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 450 | on_radio_disabled = on_radio_disabled_esb_dpl_rx; |
wkleunen | 1:66f95e364222 | 451 | switch(m_config_local.protocol) |
wkleunen | 1:66f95e364222 | 452 | { |
wkleunen | 1:66f95e364222 | 453 | case UESB_PROTOCOL_SB: |
wkleunen | 1:66f95e364222 | 454 | NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_START_Msk; |
wkleunen | 1:66f95e364222 | 455 | NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; |
wkleunen | 1:66f95e364222 | 456 | m_uesb_mainstate = UESB_STATE_PRX; |
wkleunen | 1:66f95e364222 | 457 | break; |
wkleunen | 1:66f95e364222 | 458 | case UESB_PROTOCOL_ESB: |
wkleunen | 1:66f95e364222 | 459 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; |
wkleunen | 1:66f95e364222 | 460 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; |
wkleunen | 1:66f95e364222 | 461 | m_uesb_mainstate = UESB_STATE_PRX; |
wkleunen | 1:66f95e364222 | 462 | break; |
wkleunen | 1:66f95e364222 | 463 | case UESB_PROTOCOL_ESB_DPL: |
wkleunen | 1:66f95e364222 | 464 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; |
wkleunen | 1:66f95e364222 | 465 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; |
wkleunen | 1:66f95e364222 | 466 | m_uesb_mainstate = UESB_STATE_PRX; |
wkleunen | 1:66f95e364222 | 467 | break; |
wkleunen | 1:66f95e364222 | 468 | } |
wkleunen | 1:66f95e364222 | 469 | |
wkleunen | 1:66f95e364222 | 470 | NRF_RADIO->RXADDRESSES = m_config_local.rx_pipes_enabled; |
wkleunen | 1:66f95e364222 | 471 | |
wkleunen | 1:66f95e364222 | 472 | NRF_RADIO->FREQUENCY = m_config_local.rf_channel; |
wkleunen | 1:66f95e364222 | 473 | |
wkleunen | 1:66f95e364222 | 474 | NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; |
wkleunen | 1:66f95e364222 | 475 | |
wkleunen | 1:66f95e364222 | 476 | NVIC_ClearPendingIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 477 | NVIC_EnableIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 478 | |
wkleunen | 1:66f95e364222 | 479 | NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 480 | NRF_RADIO->TASKS_RXEN = 1; |
wkleunen | 1:66f95e364222 | 481 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 482 | } |
wkleunen | 1:66f95e364222 | 483 | |
wkleunen | 1:66f95e364222 | 484 | uint32_t uesb_stop_rx(void) |
wkleunen | 1:66f95e364222 | 485 | { |
wkleunen | 1:66f95e364222 | 486 | if((m_uesb_mainstate == UESB_STATE_PRX) || (m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD)) |
wkleunen | 1:66f95e364222 | 487 | { |
wkleunen | 1:66f95e364222 | 488 | NRF_RADIO->SHORTS = 0; |
wkleunen | 1:66f95e364222 | 489 | NRF_RADIO->INTENCLR = 0xFFFFFFFF; |
wkleunen | 1:66f95e364222 | 490 | on_radio_disabled = NULL; |
wkleunen | 1:66f95e364222 | 491 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 492 | NRF_RADIO->TASKS_DISABLE = 1; |
wkleunen | 1:66f95e364222 | 493 | while(NRF_RADIO->EVENTS_DISABLED == 0); |
wkleunen | 1:66f95e364222 | 494 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 495 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 496 | } |
wkleunen | 1:66f95e364222 | 497 | return UESB_ERROR_NOT_IN_RX_MODE; |
wkleunen | 1:66f95e364222 | 498 | } |
wkleunen | 1:66f95e364222 | 499 | |
wkleunen | 1:66f95e364222 | 500 | uint32_t uesb_get_tx_attempts(uint32_t *attempts) |
wkleunen | 1:66f95e364222 | 501 | { |
wkleunen | 1:66f95e364222 | 502 | if(m_uesb_mainstate == UESB_STATE_UNINITIALIZED) return UESB_ERROR_NOT_INITIALIZED; |
wkleunen | 1:66f95e364222 | 503 | *attempts = m_last_tx_attempts; |
wkleunen | 1:66f95e364222 | 504 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 505 | } |
wkleunen | 1:66f95e364222 | 506 | |
wkleunen | 1:66f95e364222 | 507 | uint32_t uesb_flush_tx(void) |
wkleunen | 1:66f95e364222 | 508 | { |
wkleunen | 1:66f95e364222 | 509 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 510 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 511 | m_tx_fifo.count = 0; |
wkleunen | 1:66f95e364222 | 512 | m_tx_fifo.entry_point = m_tx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 513 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 514 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 515 | } |
wkleunen | 1:66f95e364222 | 516 | |
wkleunen | 1:66f95e364222 | 517 | uint32_t uesb_flush_rx(void) |
wkleunen | 1:66f95e364222 | 518 | { |
wkleunen | 1:66f95e364222 | 519 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 520 | m_rx_fifo.count = 0; |
wkleunen | 1:66f95e364222 | 521 | m_rx_fifo.entry_point = 0; |
wkleunen | 1:66f95e364222 | 522 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 523 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 524 | } |
wkleunen | 1:66f95e364222 | 525 | |
wkleunen | 1:66f95e364222 | 526 | uint32_t uesb_get_clear_interrupts(uint32_t *interrupts) |
wkleunen | 1:66f95e364222 | 527 | { |
wkleunen | 1:66f95e364222 | 528 | DISABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 529 | *interrupts = m_interrupt_flags; |
wkleunen | 1:66f95e364222 | 530 | m_interrupt_flags = 0; |
wkleunen | 1:66f95e364222 | 531 | ENABLE_RF_IRQ; |
wkleunen | 1:66f95e364222 | 532 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 533 | } |
wkleunen | 1:66f95e364222 | 534 | |
wkleunen | 1:66f95e364222 | 535 | uint32_t uesb_set_address(uesb_address_type_t address, const uint8_t *data_ptr) |
wkleunen | 1:66f95e364222 | 536 | { |
wkleunen | 1:66f95e364222 | 537 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 538 | switch(address) |
wkleunen | 1:66f95e364222 | 539 | { |
wkleunen | 1:66f95e364222 | 540 | case UESB_ADDRESS_PIPE0: |
wkleunen | 1:66f95e364222 | 541 | memcpy(m_config_local.rx_address_p0, data_ptr, m_config_local.rf_addr_length); |
wkleunen | 1:66f95e364222 | 542 | break; |
wkleunen | 1:66f95e364222 | 543 | case UESB_ADDRESS_PIPE1: |
wkleunen | 1:66f95e364222 | 544 | memcpy(m_config_local.rx_address_p1, data_ptr, m_config_local.rf_addr_length); |
wkleunen | 1:66f95e364222 | 545 | break; |
wkleunen | 1:66f95e364222 | 546 | case UESB_ADDRESS_PIPE2: |
wkleunen | 1:66f95e364222 | 547 | m_config_local.rx_address_p2 = *data_ptr; |
wkleunen | 1:66f95e364222 | 548 | break; |
wkleunen | 1:66f95e364222 | 549 | case UESB_ADDRESS_PIPE3: |
wkleunen | 1:66f95e364222 | 550 | m_config_local.rx_address_p3 = *data_ptr; |
wkleunen | 1:66f95e364222 | 551 | break; |
wkleunen | 1:66f95e364222 | 552 | case UESB_ADDRESS_PIPE4: |
wkleunen | 1:66f95e364222 | 553 | m_config_local.rx_address_p4 = *data_ptr; |
wkleunen | 1:66f95e364222 | 554 | break; |
wkleunen | 1:66f95e364222 | 555 | case UESB_ADDRESS_PIPE5: |
wkleunen | 1:66f95e364222 | 556 | m_config_local.rx_address_p5 = *data_ptr; |
wkleunen | 1:66f95e364222 | 557 | break; |
wkleunen | 1:66f95e364222 | 558 | case UESB_ADDRESS_PIPE6: |
wkleunen | 1:66f95e364222 | 559 | m_config_local.rx_address_p6 = *data_ptr; |
wkleunen | 1:66f95e364222 | 560 | break; |
wkleunen | 1:66f95e364222 | 561 | case UESB_ADDRESS_PIPE7: |
wkleunen | 1:66f95e364222 | 562 | m_config_local.rx_address_p7 = *data_ptr; |
wkleunen | 1:66f95e364222 | 563 | break; |
wkleunen | 1:66f95e364222 | 564 | default: |
wkleunen | 1:66f95e364222 | 565 | return UESB_ERROR_INVALID_PARAMETERS; |
wkleunen | 1:66f95e364222 | 566 | } |
wkleunen | 1:66f95e364222 | 567 | update_radio_parameters(); |
wkleunen | 1:66f95e364222 | 568 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 569 | } |
wkleunen | 1:66f95e364222 | 570 | |
wkleunen | 1:66f95e364222 | 571 | uint32_t uesb_set_rf_channel(uint32_t channel) |
wkleunen | 1:66f95e364222 | 572 | { |
wkleunen | 1:66f95e364222 | 573 | if(channel > 125) return UESB_ERROR_INVALID_PARAMETERS; |
wkleunen | 1:66f95e364222 | 574 | m_config_local.rf_channel = channel; |
wkleunen | 1:66f95e364222 | 575 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 576 | } |
wkleunen | 1:66f95e364222 | 577 | |
wkleunen | 1:66f95e364222 | 578 | uint32_t uesb_set_tx_power(uesb_tx_power_t tx_output_power) |
wkleunen | 1:66f95e364222 | 579 | { |
wkleunen | 1:66f95e364222 | 580 | if(m_uesb_mainstate != UESB_STATE_IDLE) return UESB_ERROR_NOT_IDLE; |
wkleunen | 1:66f95e364222 | 581 | if ( m_config_local.tx_output_power == tx_output_power ) return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 582 | m_config_local.tx_output_power = tx_output_power; |
wkleunen | 1:66f95e364222 | 583 | update_radio_parameters(); |
wkleunen | 1:66f95e364222 | 584 | return UESB_SUCCESS; |
wkleunen | 1:66f95e364222 | 585 | } |
wkleunen | 1:66f95e364222 | 586 | |
wkleunen | 1:66f95e364222 | 587 | /* |
wkleunen | 1:66f95e364222 | 588 | |
wkleunen | 1:66f95e364222 | 589 | void RADIO_IRQHandler() |
wkleunen | 1:66f95e364222 | 590 | { |
wkleunen | 1:66f95e364222 | 591 | if(NRF_RADIO->EVENTS_READY && (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) |
wkleunen | 1:66f95e364222 | 592 | { |
wkleunen | 1:66f95e364222 | 593 | NRF_RADIO->EVENTS_READY = 0; |
wkleunen | 1:66f95e364222 | 594 | |
wkleunen | 1:66f95e364222 | 595 | DEBUG_PIN_SET(DEBUGPIN1); |
wkleunen | 1:66f95e364222 | 596 | } |
wkleunen | 1:66f95e364222 | 597 | |
wkleunen | 1:66f95e364222 | 598 | if(NRF_RADIO->EVENTS_END && (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) |
wkleunen | 1:66f95e364222 | 599 | { |
wkleunen | 1:66f95e364222 | 600 | NRF_RADIO->EVENTS_END = 0; |
wkleunen | 1:66f95e364222 | 601 | |
wkleunen | 1:66f95e364222 | 602 | DEBUG_PIN_SET(DEBUGPIN2); |
wkleunen | 1:66f95e364222 | 603 | |
wkleunen | 1:66f95e364222 | 604 | // Call the correct on_radio_end function, depending on the current protocol state |
wkleunen | 1:66f95e364222 | 605 | if(on_radio_end) |
wkleunen | 1:66f95e364222 | 606 | { |
wkleunen | 1:66f95e364222 | 607 | on_radio_end(); |
wkleunen | 1:66f95e364222 | 608 | } |
wkleunen | 1:66f95e364222 | 609 | } |
wkleunen | 1:66f95e364222 | 610 | |
wkleunen | 1:66f95e364222 | 611 | if(NRF_RADIO->EVENTS_DISABLED && (NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk)) |
wkleunen | 1:66f95e364222 | 612 | { |
wkleunen | 1:66f95e364222 | 613 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 614 | |
wkleunen | 1:66f95e364222 | 615 | DEBUG_PIN_SET(DEBUGPIN3); |
wkleunen | 1:66f95e364222 | 616 | |
wkleunen | 1:66f95e364222 | 617 | // Call the correct on_radio_disable function, depending on the current protocol state |
wkleunen | 1:66f95e364222 | 618 | if(on_radio_disabled) |
wkleunen | 1:66f95e364222 | 619 | { |
wkleunen | 1:66f95e364222 | 620 | on_radio_disabled(); |
wkleunen | 1:66f95e364222 | 621 | } |
wkleunen | 1:66f95e364222 | 622 | } |
wkleunen | 1:66f95e364222 | 623 | |
wkleunen | 1:66f95e364222 | 624 | DEBUG_PIN_CLR(DEBUGPIN1); |
wkleunen | 1:66f95e364222 | 625 | DEBUG_PIN_CLR(DEBUGPIN2); |
wkleunen | 1:66f95e364222 | 626 | DEBUG_PIN_CLR(DEBUGPIN3); |
wkleunen | 1:66f95e364222 | 627 | DEBUG_PIN_CLR(DEBUGPIN4); |
wkleunen | 1:66f95e364222 | 628 | } */ |
wkleunen | 1:66f95e364222 | 629 | |
wkleunen | 1:66f95e364222 | 630 | static void on_radio_disabled_esb_dpl_tx_noack() |
wkleunen | 1:66f95e364222 | 631 | { |
wkleunen | 1:66f95e364222 | 632 | m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; |
wkleunen | 1:66f95e364222 | 633 | tx_fifo_remove_last(); |
wkleunen | 1:66f95e364222 | 634 | |
wkleunen | 1:66f95e364222 | 635 | if(m_tx_fifo.count == 0) |
wkleunen | 1:66f95e364222 | 636 | { |
wkleunen | 1:66f95e364222 | 637 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 638 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 639 | } |
wkleunen | 1:66f95e364222 | 640 | else |
wkleunen | 1:66f95e364222 | 641 | { |
wkleunen | 1:66f95e364222 | 642 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 643 | start_tx_transaction(); |
wkleunen | 1:66f95e364222 | 644 | } |
wkleunen | 1:66f95e364222 | 645 | } |
wkleunen | 1:66f95e364222 | 646 | |
wkleunen | 1:66f95e364222 | 647 | static void on_radio_disabled_esb_dpl_tx() |
wkleunen | 1:66f95e364222 | 648 | { |
wkleunen | 1:66f95e364222 | 649 | // Remove the DISABLED -> RXEN shortcut, to make sure the radio stays disabled after the RX window |
wkleunen | 1:66f95e364222 | 650 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; |
wkleunen | 1:66f95e364222 | 651 | |
wkleunen | 1:66f95e364222 | 652 | // Make sure the timer is started the next time the radio is ready, |
wkleunen | 1:66f95e364222 | 653 | // and that it will disable the radio automatically if no packet is received by the time defined in m_wait_for_ack_timeout_us |
wkleunen | 1:66f95e364222 | 654 | UESB_SYS_TIMER->CC[0] = m_wait_for_ack_timeout_us; |
wkleunen | 1:66f95e364222 | 655 | UESB_SYS_TIMER->CC[1] = m_config_local.retransmit_delay - 130; |
wkleunen | 1:66f95e364222 | 656 | UESB_SYS_TIMER->TASKS_CLEAR = 1; |
wkleunen | 1:66f95e364222 | 657 | UESB_SYS_TIMER->EVENTS_COMPARE[0] = 0; |
wkleunen | 1:66f95e364222 | 658 | UESB_SYS_TIMER->EVENTS_COMPARE[1] = 0; |
wkleunen | 1:66f95e364222 | 659 | NRF_PPI->CHENSET = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TIMER_STOP); |
wkleunen | 1:66f95e364222 | 660 | NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); |
wkleunen | 1:66f95e364222 | 661 | NRF_RADIO->EVENTS_END = 0; |
wkleunen | 1:66f95e364222 | 662 | if(m_config_local.protocol == UESB_PROTOCOL_ESB) |
wkleunen | 1:66f95e364222 | 663 | { |
wkleunen | 1:66f95e364222 | 664 | update_rf_payload_format(0); |
wkleunen | 1:66f95e364222 | 665 | } |
wkleunen | 1:66f95e364222 | 666 | NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; |
wkleunen | 1:66f95e364222 | 667 | on_radio_disabled = on_radio_disabled_esb_dpl_tx_wait_for_ack; |
wkleunen | 1:66f95e364222 | 668 | m_uesb_mainstate = UESB_STATE_PTX_RX_ACK; |
wkleunen | 1:66f95e364222 | 669 | } |
wkleunen | 1:66f95e364222 | 670 | |
wkleunen | 1:66f95e364222 | 671 | static void on_radio_disabled_esb_dpl_tx_wait_for_ack() |
wkleunen | 1:66f95e364222 | 672 | { |
wkleunen | 1:66f95e364222 | 673 | // This marks the completion of a TX_RX sequence (TX with ACK) |
wkleunen | 1:66f95e364222 | 674 | |
wkleunen | 1:66f95e364222 | 675 | // Make sure the timer will not deactivate the radio if a packet is received |
wkleunen | 1:66f95e364222 | 676 | NRF_PPI->CHENCLR = (1 << UESB_PPI_TIMER_START) | (1 << UESB_PPI_RX_TIMEOUT) | (1 << UESB_PPI_TIMER_STOP); |
wkleunen | 1:66f95e364222 | 677 | |
wkleunen | 1:66f95e364222 | 678 | // If the radio has received a packet and the CRC status is OK |
wkleunen | 1:66f95e364222 | 679 | if(NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) |
wkleunen | 1:66f95e364222 | 680 | { |
wkleunen | 1:66f95e364222 | 681 | UESB_SYS_TIMER->TASKS_STOP = 1; |
wkleunen | 1:66f95e364222 | 682 | NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); |
wkleunen | 1:66f95e364222 | 683 | m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; |
wkleunen | 1:66f95e364222 | 684 | m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1; |
wkleunen | 1:66f95e364222 | 685 | tx_fifo_remove_last(); |
wkleunen | 1:66f95e364222 | 686 | if(m_rx_payload_buffer[0] > 0) |
wkleunen | 1:66f95e364222 | 687 | { |
wkleunen | 1:66f95e364222 | 688 | if(rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS)) |
wkleunen | 1:66f95e364222 | 689 | { |
wkleunen | 1:66f95e364222 | 690 | m_interrupt_flags |= UESB_INT_RX_DR_MSK; |
wkleunen | 1:66f95e364222 | 691 | } |
wkleunen | 1:66f95e364222 | 692 | } |
wkleunen | 1:66f95e364222 | 693 | |
wkleunen | 1:66f95e364222 | 694 | if((m_tx_fifo.count == 0) || (m_config_local.tx_mode == UESB_TXMODE_MANUAL)) |
wkleunen | 1:66f95e364222 | 695 | { |
wkleunen | 1:66f95e364222 | 696 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 697 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 698 | } |
wkleunen | 1:66f95e364222 | 699 | else |
wkleunen | 1:66f95e364222 | 700 | { |
wkleunen | 1:66f95e364222 | 701 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 702 | start_tx_transaction(); |
wkleunen | 1:66f95e364222 | 703 | } |
wkleunen | 1:66f95e364222 | 704 | } |
wkleunen | 1:66f95e364222 | 705 | else |
wkleunen | 1:66f95e364222 | 706 | { |
wkleunen | 1:66f95e364222 | 707 | if(m_retransmits_remaining-- == 0) |
wkleunen | 1:66f95e364222 | 708 | { |
wkleunen | 1:66f95e364222 | 709 | UESB_SYS_TIMER->TASKS_STOP = 1; |
wkleunen | 1:66f95e364222 | 710 | NRF_PPI->CHENCLR = (1 << UESB_PPI_TX_START); |
wkleunen | 1:66f95e364222 | 711 | // All retransmits are expended, and the TX operation is suspended |
wkleunen | 1:66f95e364222 | 712 | m_last_tx_attempts = m_config_local.retransmit_count + 1; |
wkleunen | 1:66f95e364222 | 713 | m_interrupt_flags |= UESB_INT_TX_FAILED_MSK; |
wkleunen | 1:66f95e364222 | 714 | |
wkleunen | 1:66f95e364222 | 715 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 716 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 717 | } |
wkleunen | 1:66f95e364222 | 718 | else |
wkleunen | 1:66f95e364222 | 719 | { |
wkleunen | 1:66f95e364222 | 720 | // We still have more retransmits left, and we should enter TX mode again as soon as the system timer reaches CC[1] |
wkleunen | 1:66f95e364222 | 721 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; |
wkleunen | 1:66f95e364222 | 722 | update_rf_payload_format(current_payload->length); |
wkleunen | 1:66f95e364222 | 723 | NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; |
wkleunen | 1:66f95e364222 | 724 | on_radio_disabled = on_radio_disabled_esb_dpl_tx; |
wkleunen | 1:66f95e364222 | 725 | m_uesb_mainstate = UESB_STATE_PTX_TX_ACK; |
wkleunen | 1:66f95e364222 | 726 | UESB_SYS_TIMER->TASKS_START = 1; |
wkleunen | 1:66f95e364222 | 727 | NRF_PPI->CHENSET = (1 << UESB_PPI_TX_START); |
wkleunen | 1:66f95e364222 | 728 | if(UESB_SYS_TIMER->EVENTS_COMPARE[1]) |
wkleunen | 1:66f95e364222 | 729 | { |
wkleunen | 1:66f95e364222 | 730 | NRF_RADIO->TASKS_TXEN = 1; |
wkleunen | 1:66f95e364222 | 731 | } |
wkleunen | 1:66f95e364222 | 732 | } |
wkleunen | 1:66f95e364222 | 733 | } |
wkleunen | 1:66f95e364222 | 734 | } |
wkleunen | 1:66f95e364222 | 735 | |
wkleunen | 1:66f95e364222 | 736 | static void on_radio_disabled_esb_dpl_rx(void) |
wkleunen | 1:66f95e364222 | 737 | { |
wkleunen | 1:66f95e364222 | 738 | bool send_ack = false; |
wkleunen | 1:66f95e364222 | 739 | bool set_rx_interrupt = false; |
wkleunen | 1:66f95e364222 | 740 | if(NRF_RADIO->CRCSTATUS != 0 && m_rx_fifo.count < UESB_CORE_RX_FIFO_SIZE) |
wkleunen | 1:66f95e364222 | 741 | { |
wkleunen | 1:66f95e364222 | 742 | send_ack = true; |
wkleunen | 1:66f95e364222 | 743 | } |
wkleunen | 1:66f95e364222 | 744 | if(send_ack) |
wkleunen | 1:66f95e364222 | 745 | { |
wkleunen | 1:66f95e364222 | 746 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; |
wkleunen | 1:66f95e364222 | 747 | |
wkleunen | 1:66f95e364222 | 748 | // For a packet to be considered new (and not a retransmit) the PID or the CRC has to be different |
wkleunen | 1:66f95e364222 | 749 | if(NRF_RADIO->RXCRC != m_last_rx_packet_crc || (m_rx_payload_buffer[1] >> 1) != m_last_rx_packet_pid) |
wkleunen | 1:66f95e364222 | 750 | { |
wkleunen | 1:66f95e364222 | 751 | if((m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK_PAYLOAD) && (m_tx_fifo.count > 0)) |
wkleunen | 1:66f95e364222 | 752 | { |
wkleunen | 1:66f95e364222 | 753 | // It is assumed that the last ACK payload was recieved. |
wkleunen | 1:66f95e364222 | 754 | if(++m_tx_fifo.exit_point >= UESB_CORE_RX_FIFO_SIZE) m_tx_fifo.exit_point = 0; |
wkleunen | 1:66f95e364222 | 755 | m_tx_fifo.count--; |
wkleunen | 1:66f95e364222 | 756 | |
wkleunen | 1:66f95e364222 | 757 | // ACK payloads also require TX_DS (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf'). |
wkleunen | 1:66f95e364222 | 758 | m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; |
wkleunen | 1:66f95e364222 | 759 | } |
wkleunen | 1:66f95e364222 | 760 | |
wkleunen | 1:66f95e364222 | 761 | set_rx_interrupt = true; |
wkleunen | 1:66f95e364222 | 762 | m_last_rx_packet_pid = m_rx_payload_buffer[1] >> 1; |
wkleunen | 1:66f95e364222 | 763 | m_last_rx_packet_crc = NRF_RADIO->RXCRC; |
wkleunen | 1:66f95e364222 | 764 | } |
wkleunen | 1:66f95e364222 | 765 | |
wkleunen | 1:66f95e364222 | 766 | if(m_config_local.protocol == UESB_PROTOCOL_ESB_DPL) |
wkleunen | 1:66f95e364222 | 767 | { |
wkleunen | 1:66f95e364222 | 768 | if(m_tx_fifo.count > 0) |
wkleunen | 1:66f95e364222 | 769 | { |
wkleunen | 1:66f95e364222 | 770 | current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; |
wkleunen | 1:66f95e364222 | 771 | |
wkleunen | 1:66f95e364222 | 772 | update_rf_payload_format(current_payload->length); |
wkleunen | 1:66f95e364222 | 773 | m_tx_payload_buffer[0] = current_payload->length; |
wkleunen | 1:66f95e364222 | 774 | memcpy(&m_tx_payload_buffer[2], current_payload->data, current_payload->length); |
wkleunen | 1:66f95e364222 | 775 | |
wkleunen | 1:66f95e364222 | 776 | m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK_PAYLOAD; |
wkleunen | 1:66f95e364222 | 777 | } |
wkleunen | 1:66f95e364222 | 778 | else |
wkleunen | 1:66f95e364222 | 779 | { |
wkleunen | 1:66f95e364222 | 780 | update_rf_payload_format(0); |
wkleunen | 1:66f95e364222 | 781 | m_tx_payload_buffer[0] = 0; |
wkleunen | 1:66f95e364222 | 782 | |
wkleunen | 1:66f95e364222 | 783 | m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK; |
wkleunen | 1:66f95e364222 | 784 | } |
wkleunen | 1:66f95e364222 | 785 | |
wkleunen | 1:66f95e364222 | 786 | m_tx_payload_buffer[1] = m_rx_payload_buffer[1]; |
wkleunen | 1:66f95e364222 | 787 | } |
wkleunen | 1:66f95e364222 | 788 | else if(m_config_local.protocol == UESB_PROTOCOL_ESB) |
wkleunen | 1:66f95e364222 | 789 | { |
wkleunen | 1:66f95e364222 | 790 | m_tx_payload_buffer[0] = m_rx_payload_buffer[0]; |
wkleunen | 1:66f95e364222 | 791 | m_tx_payload_buffer[1] = 0; |
wkleunen | 1:66f95e364222 | 792 | |
wkleunen | 1:66f95e364222 | 793 | m_uesb_mainstate = UESB_STATE_PRX_SEND_ACK; |
wkleunen | 1:66f95e364222 | 794 | } |
wkleunen | 1:66f95e364222 | 795 | |
wkleunen | 1:66f95e364222 | 796 | NRF_RADIO->TXADDRESS = NRF_RADIO->RXMATCH; |
wkleunen | 1:66f95e364222 | 797 | NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer; |
wkleunen | 1:66f95e364222 | 798 | |
wkleunen | 1:66f95e364222 | 799 | on_radio_disabled = on_radio_disabled_esb_dpl_rx_ack; |
wkleunen | 1:66f95e364222 | 800 | } |
wkleunen | 1:66f95e364222 | 801 | else |
wkleunen | 1:66f95e364222 | 802 | { |
wkleunen | 1:66f95e364222 | 803 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; |
wkleunen | 1:66f95e364222 | 804 | update_rf_payload_format(m_config_local.payload_length); |
wkleunen | 1:66f95e364222 | 805 | NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; |
wkleunen | 1:66f95e364222 | 806 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 807 | NRF_RADIO->TASKS_DISABLE = 1; |
wkleunen | 1:66f95e364222 | 808 | while(NRF_RADIO->EVENTS_DISABLED == 0); |
wkleunen | 1:66f95e364222 | 809 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 810 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; |
wkleunen | 1:66f95e364222 | 811 | NRF_RADIO->TASKS_RXEN = 1; |
wkleunen | 1:66f95e364222 | 812 | } |
wkleunen | 1:66f95e364222 | 813 | if(set_rx_interrupt) |
wkleunen | 1:66f95e364222 | 814 | { |
wkleunen | 1:66f95e364222 | 815 | rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH); |
wkleunen | 1:66f95e364222 | 816 | m_interrupt_flags |= UESB_INT_RX_DR_MSK; |
wkleunen | 1:66f95e364222 | 817 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 818 | } |
wkleunen | 1:66f95e364222 | 819 | } |
wkleunen | 1:66f95e364222 | 820 | |
wkleunen | 1:66f95e364222 | 821 | static void on_radio_disabled_esb_dpl_rx_ack(void) |
wkleunen | 1:66f95e364222 | 822 | { |
wkleunen | 1:66f95e364222 | 823 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; |
wkleunen | 1:66f95e364222 | 824 | update_rf_payload_format(m_config_local.payload_length); |
wkleunen | 1:66f95e364222 | 825 | NRF_RADIO->PACKETPTR = (uint32_t)m_rx_payload_buffer; |
wkleunen | 1:66f95e364222 | 826 | on_radio_disabled = on_radio_disabled_esb_dpl_rx; |
wkleunen | 1:66f95e364222 | 827 | |
wkleunen | 1:66f95e364222 | 828 | if(m_uesb_mainstate == UESB_STATE_PRX_SEND_ACK) |
wkleunen | 1:66f95e364222 | 829 | { |
wkleunen | 1:66f95e364222 | 830 | // In the case of UESB_STATE_PRX_SEND_ACK_PAYLOAD the state will be updated when the next packet is received. |
wkleunen | 1:66f95e364222 | 831 | m_uesb_mainstate = UESB_STATE_PRX; |
wkleunen | 1:66f95e364222 | 832 | } |
wkleunen | 1:66f95e364222 | 833 | } |
wkleunen | 1:66f95e364222 | 834 | |
wkleunen | 1:66f95e364222 | 835 | static void on_radio_end_sb_tx(void) |
wkleunen | 1:66f95e364222 | 836 | { |
wkleunen | 1:66f95e364222 | 837 | m_interrupt_flags |= UESB_INT_TX_SUCCESS_MSK; |
wkleunen | 1:66f95e364222 | 838 | tx_fifo_remove_last(); |
wkleunen | 1:66f95e364222 | 839 | if(m_config_local.tx_mode == UESB_TXMODE_MANUAL || m_tx_fifo.count == 0) |
wkleunen | 1:66f95e364222 | 840 | { |
wkleunen | 1:66f95e364222 | 841 | // No more packets to send. Disable the radio and set the state to idle. |
wkleunen | 1:66f95e364222 | 842 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 843 | NRF_RADIO->TASKS_DISABLE = 1; |
wkleunen | 1:66f95e364222 | 844 | while(!NRF_RADIO->EVENTS_DISABLED); |
wkleunen | 1:66f95e364222 | 845 | NRF_RADIO->EVENTS_DISABLED = 0; |
wkleunen | 1:66f95e364222 | 846 | m_uesb_mainstate = UESB_STATE_IDLE; |
wkleunen | 1:66f95e364222 | 847 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 848 | } |
wkleunen | 1:66f95e364222 | 849 | else |
wkleunen | 1:66f95e364222 | 850 | { |
wkleunen | 1:66f95e364222 | 851 | // Send another packet automatically without disabling the radio first. |
wkleunen | 1:66f95e364222 | 852 | current_payload = m_tx_fifo.payload_ptr[m_tx_fifo.exit_point]; |
wkleunen | 1:66f95e364222 | 853 | |
wkleunen | 1:66f95e364222 | 854 | update_rf_payload_format(current_payload->length); |
wkleunen | 1:66f95e364222 | 855 | memcpy(&m_tx_payload_buffer[0], current_payload->data, current_payload->length); |
wkleunen | 1:66f95e364222 | 856 | |
wkleunen | 1:66f95e364222 | 857 | NRF_RADIO->TXADDRESS = current_payload->pipe; |
wkleunen | 1:66f95e364222 | 858 | |
wkleunen | 1:66f95e364222 | 859 | NVIC_ClearPendingIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 860 | NVIC_EnableIRQ(RADIO_IRQn); |
wkleunen | 1:66f95e364222 | 861 | |
wkleunen | 1:66f95e364222 | 862 | NRF_RADIO->EVENTS_ADDRESS = NRF_RADIO->EVENTS_PAYLOAD = 0; |
wkleunen | 1:66f95e364222 | 863 | NRF_RADIO->TASKS_START = 1; |
wkleunen | 1:66f95e364222 | 864 | |
wkleunen | 1:66f95e364222 | 865 | } |
wkleunen | 1:66f95e364222 | 866 | } |
wkleunen | 1:66f95e364222 | 867 | |
wkleunen | 1:66f95e364222 | 868 | static void on_radio_end_sb_rx(void) |
wkleunen | 1:66f95e364222 | 869 | { |
wkleunen | 1:66f95e364222 | 870 | if(NRF_RADIO->CRCSTATUS != 0 && rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH)) |
wkleunen | 1:66f95e364222 | 871 | { |
wkleunen | 1:66f95e364222 | 872 | m_interrupt_flags |= UESB_INT_RX_DR_MSK; |
wkleunen | 1:66f95e364222 | 873 | if(m_event_handler != 0) m_event_handler(); |
wkleunen | 1:66f95e364222 | 874 | } |
wkleunen | 1:66f95e364222 | 875 | } |
wkleunen | 1:66f95e364222 | 876 |