diff options
Diffstat (limited to 'lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c')
-rw-r--r-- | lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c | 1114 |
1 files changed, 1114 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c b/lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c new file mode 100644 index 000000000..9829935e7 --- /dev/null +++ b/lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c | |||
@@ -0,0 +1,1114 @@ | |||
1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. | ||
2 | * | ||
3 | * The information contained herein is property of Nordic Semiconductor ASA. | ||
4 | * Terms and conditions of usage are described in detail in NORDIC | ||
5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. | ||
6 | * | ||
7 | * Licensees are granted free, non-transferable use of the information. NO | ||
8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from | ||
9 | * the file. | ||
10 | * | ||
11 | * Enhanced ShockBurst proprietary protocol to ChibiOS port | ||
12 | * | ||
13 | * ported on: 25/10/2018, by andru | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <stdint.h> | ||
18 | #include <string.h> | ||
19 | |||
20 | #include "ch.h" | ||
21 | #include "hal.h" | ||
22 | |||
23 | #include "nrf52_radio.h" | ||
24 | |||
25 | |||
26 | #define BIT_MASK_UINT_8(x) (0xFF >> (8 - (x))) | ||
27 | #define NRF52_PIPE_COUNT 9 | ||
28 | |||
29 | #define RADIO_SHORTS_COMMON ( RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \ | ||
30 | RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk ) | ||
31 | |||
32 | // Constant parameters | ||
33 | #define RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS (48) /**< 2MBit RX wait for ack timeout value. Smallest reliable value - 43 */ | ||
34 | #define RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS (64) /**< 1MBit RX wait for ack timeout value. Smallest reliable value - 59 */ | ||
35 | |||
36 | #define NRF52_ADDR_UPDATE_MASK_BASE0 (1 << 0) /*< Mask value to signal updating BASE0 radio address. */ | ||
37 | #define NRF52_ADDR_UPDATE_MASK_BASE1 (1 << 1) /*< Mask value to signal updating BASE1 radio address. */ | ||
38 | #define NRF52_ADDR_UPDATE_MASK_PREFIX (1 << 2) /*< Mask value to signal updating radio prefixes */ | ||
39 | |||
40 | #define NRF52_PID_RESET_VALUE 0xFF /**< Invalid PID value which is guaranteed to not collide with any valid PID value. */ | ||
41 | #define NRF52_PID_MAX 3 /**< Maximum value for PID. */ | ||
42 | #define NRF52_CRC_RESET_VALUE 0xFFFF /**< CRC reset value*/ | ||
43 | |||
44 | #ifndef NRF52_RADIO_USE_TIMER0 | ||
45 | #define NRF52_RADIO_USE_TIMER0 FALSE | ||
46 | #endif | ||
47 | |||
48 | #ifndef NRF52_RADIO_USE_TIMER1 | ||
49 | #define NRF52_RADIO_USE_TIMER1 FALSE | ||
50 | #endif | ||
51 | |||
52 | #ifndef NRF52_RADIO_USE_TIMER2 | ||
53 | #define NRF52_RADIO_USE_TIMER2 FALSE | ||
54 | #endif | ||
55 | |||
56 | #ifndef NRF52_RADIO_USE_TIMER3 | ||
57 | #define NRF52_RADIO_USE_TIMER3 FALSE | ||
58 | #endif | ||
59 | |||
60 | #ifndef NRF52_RADIO_USE_TIMER4 | ||
61 | #define NRF52_RADIO_USE_TIMER4 FALSE | ||
62 | #endif | ||
63 | |||
64 | #ifndef NRF52_RADIO_IRQ_PRIORITY | ||
65 | #define NRF52_RADIO_IRQ_PRIORITY 3 /**< RADIO interrupt priority. */ | ||
66 | #endif | ||
67 | |||
68 | #ifndef NRF52_RADIO_PPI_TIMER_START | ||
69 | #error "PPI channel NRF52_RADIO_PPI_TIMER_START need to be defined" | ||
70 | #endif | ||
71 | |||
72 | #ifndef NRF52_RADIO_PPI_TIMER_STOP | ||
73 | #error "PPI channel NRF52_RADIO_PPI_TIMER_STOP need to be defined" | ||
74 | #endif | ||
75 | |||
76 | #ifndef NRF52_RADIO_PPI_RX_TIMEOUT | ||
77 | #error "PPI channel NRF52_RADIO_PPI_RX_TIMEOUT need to be defined" | ||
78 | #endif | ||
79 | |||
80 | #ifndef NRF52_RADIO_PPI_TX_START | ||
81 | #error "PPI channel NRF52_RADIO_PPI_TX_START need to be defined" | ||
82 | #endif | ||
83 | |||
84 | #if (NRF52_RADIO_USE_TIMER0 == FALSE) && (NRF52_RADIO_USE_TIMER1 == FALSE) && \ | ||
85 | (NRF52_RADIO_USE_TIMER2 == FALSE) && (NRF52_RADIO_USE_TIMER3 == FALSE) && \ | ||
86 | (NRF52_RADIO_USE_TIMER4 == FALSE) | ||
87 | #error "At least one hardware TIMER must be defined" | ||
88 | #endif | ||
89 | |||
90 | #ifndef NRF52_RADIO_INTTHD_PRIORITY | ||
91 | #error "Interrupt handle thread priority need to be defined" | ||
92 | #endif | ||
93 | |||
94 | #ifndef NRF52_RADIO_EVTTHD_PRIORITY | ||
95 | #error "Event thread priority need to be defined" | ||
96 | #endif | ||
97 | |||
98 | #define VERIFY_PAYLOAD_LENGTH(p) \ | ||
99 | do \ | ||
100 | { \ | ||
101 | if(p->length == 0 || \ | ||
102 | p->length > NRF52_MAX_PAYLOAD_LENGTH || \ | ||
103 | (RFD1.config.protocol == NRF52_PROTOCOL_ESB && \ | ||
104 | p->length > RFD1.config.payload_length)) \ | ||
105 | { \ | ||
106 | return NRF52_ERROR_INVALID_LENGTH; \ | ||
107 | } \ | ||
108 | }while(0) | ||
109 | |||
110 | //Structure holding pipe info PID and CRC and ack payload. | ||
111 | typedef struct | ||
112 | { | ||
113 | uint16_t m_crc; | ||
114 | uint8_t m_pid; | ||
115 | uint8_t m_ack_payload; | ||
116 | } pipe_info_t; | ||
117 | |||
118 | // First in first out queue of payloads to be transmitted. | ||
119 | typedef struct | ||
120 | { | ||
121 | nrf52_payload_t * p_payload[NRF52_TX_FIFO_SIZE]; /**< Pointer to the actual queue. */ | ||
122 | uint32_t entry_point; /**< Current start of queue. */ | ||
123 | uint32_t exit_point; /**< Current end of queue. */ | ||
124 | uint32_t count; /**< Current number of elements in the queue. */ | ||
125 | } nrf52_payload_tx_fifo_t; | ||
126 | |||
127 | // First in first out queue of received payloads. | ||
128 | typedef struct | ||
129 | { | ||
130 | nrf52_payload_t * p_payload[NRF52_RX_FIFO_SIZE]; /**< Pointer to the actual queue. */ | ||
131 | uint32_t entry_point; /**< Current start of queue. */ | ||
132 | uint32_t exit_point; /**< Current end of queue. */ | ||
133 | uint32_t count; /**< Current number of elements in the queue. */ | ||
134 | } nrf52_payload_rx_fifo_t; | ||
135 | |||
136 | // These function pointers are changed dynamically, depending on protocol configuration and state. | ||
137 | //static void (*on_radio_end)(RFDriver *rfp) = NULL; | ||
138 | static void (*set_rf_payload_format)(RFDriver *rfp, uint32_t payload_length) = NULL; | ||
139 | |||
140 | // The following functions are assigned to the function pointers above. | ||
141 | static void on_radio_disabled_tx_noack(RFDriver *rfp); | ||
142 | static void on_radio_disabled_tx(RFDriver *rfp); | ||
143 | static void on_radio_disabled_tx_wait_for_ack(RFDriver *rfp); | ||
144 | static void on_radio_disabled_rx(RFDriver *rfp); | ||
145 | static void on_radio_disabled_rx_ack(RFDriver *rfp); | ||
146 | |||
147 | static volatile uint16_t wait_for_ack_timeout_us; | ||
148 | static nrf52_payload_t * p_current_payload; | ||
149 | |||
150 | // TX FIFO | ||
151 | static nrf52_payload_t tx_fifo_payload[NRF52_TX_FIFO_SIZE]; | ||
152 | static nrf52_payload_tx_fifo_t tx_fifo; | ||
153 | |||
154 | // RX FIFO | ||
155 | static nrf52_payload_t rx_fifo_payload[NRF52_RX_FIFO_SIZE]; | ||
156 | static nrf52_payload_rx_fifo_t rx_fifo; | ||
157 | |||
158 | // Payload buffers | ||
159 | static uint8_t tx_payload_buffer[NRF52_MAX_PAYLOAD_LENGTH + 2]; | ||
160 | static uint8_t rx_payload_buffer[NRF52_MAX_PAYLOAD_LENGTH + 2]; | ||
161 | |||
162 | static uint8_t pids[NRF52_PIPE_COUNT]; | ||
163 | static pipe_info_t rx_pipe_info[NRF52_PIPE_COUNT]; | ||
164 | |||
165 | // disable and events semaphores. | ||
166 | static binary_semaphore_t disable_sem; | ||
167 | static binary_semaphore_t events_sem; | ||
168 | |||
169 | RFDriver RFD1; | ||
170 | |||
171 | // Function to do bytewise bit-swap on a unsigned 32 bit value | ||
172 | static uint32_t bytewise_bit_swap(uint8_t const * p_inp) { | ||
173 | uint32_t inp = (*(uint32_t*)p_inp); | ||
174 | |||
175 | return __REV((uint32_t)__RBIT(inp)); //lint -esym(628, __rev) -esym(526, __rev) -esym(628, __rbit) -esym(526, __rbit) */ | ||
176 | } | ||
177 | |||
178 | // Internal function to convert base addresses from nRF24L type addressing to nRF52 type addressing | ||
179 | static uint32_t addr_conv(uint8_t const* p_addr) { | ||
180 | return __REV(bytewise_bit_swap(p_addr)); //lint -esym(628, __rev) -esym(526, __rev) */ | ||
181 | } | ||
182 | |||
183 | static thread_t *rfEvtThread_p; | ||
184 | static THD_WORKING_AREA(waRFEvtThread, 128); | ||
185 | static THD_FUNCTION(rfEvtThread, arg) { | ||
186 | (void)arg; | ||
187 | |||
188 | chRegSetThreadName("rfevent"); | ||
189 | |||
190 | while (!chThdShouldTerminateX()) { | ||
191 | chBSemWait(&events_sem); | ||
192 | |||
193 | nrf52_int_flags_t interrupts = RFD1.flags; | ||
194 | RFD1.flags = 0; | ||
195 | |||
196 | if (interrupts & NRF52_INT_TX_SUCCESS_MSK) { | ||
197 | chEvtBroadcastFlags(&RFD1.eventsrc, (eventflags_t) NRF52_EVENT_TX_SUCCESS); | ||
198 | } | ||
199 | if (interrupts & NRF52_INT_TX_FAILED_MSK) { | ||
200 | chEvtBroadcastFlags(&RFD1.eventsrc, (eventflags_t) NRF52_EVENT_TX_FAILED); | ||
201 | } | ||
202 | if (interrupts & NRF52_INT_RX_DR_MSK) { | ||
203 | chEvtBroadcastFlags(&RFD1.eventsrc, (eventflags_t) NRF52_EVENT_RX_RECEIVED); | ||
204 | } | ||
205 | } | ||
206 | chThdExit((msg_t) 0); | ||
207 | } | ||
208 | |||
209 | static thread_t *rfIntThread_p; | ||
210 | static THD_WORKING_AREA(waRFIntThread, 128); | ||
211 | static THD_FUNCTION(rfIntThread, arg) { | ||
212 | (void)arg; | ||
213 | |||
214 | chRegSetThreadName("rfint"); | ||
215 | |||
216 | while (!chThdShouldTerminateX()) { | ||
217 | chBSemWait(&disable_sem); | ||
218 | switch (RFD1.state) { | ||
219 | case NRF52_STATE_PTX_TX: | ||
220 | on_radio_disabled_tx_noack(&RFD1); | ||
221 | break; | ||
222 | case NRF52_STATE_PTX_TX_ACK: | ||
223 | on_radio_disabled_tx(&RFD1); | ||
224 | break; | ||
225 | case NRF52_STATE_PTX_RX_ACK: | ||
226 | on_radio_disabled_tx_wait_for_ack(&RFD1); | ||
227 | break; | ||
228 | case NRF52_STATE_PRX: | ||
229 | on_radio_disabled_rx(&RFD1); | ||
230 | break; | ||
231 | case NRF52_STATE_PRX_SEND_ACK: | ||
232 | on_radio_disabled_rx_ack(&RFD1); | ||
233 | break; | ||
234 | default: | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | chThdExit((msg_t) 0); | ||
239 | } | ||
240 | |||
241 | static void serve_radio_interrupt(RFDriver *rfp) { | ||
242 | if ((NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk) && NRF_RADIO->EVENTS_READY) { | ||
243 | NRF_RADIO->EVENTS_READY = 0; | ||
244 | (void) NRF_RADIO->EVENTS_READY; | ||
245 | } | ||
246 | if ((NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { | ||
247 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
248 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
249 | chSysLockFromISR(); | ||
250 | chBSemSignalI(&disable_sem); | ||
251 | chSysUnlockFromISR(); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * @brief RADIO events interrupt handler. | ||
257 | * | ||
258 | * @isr | ||
259 | */ | ||
260 | OSAL_IRQ_HANDLER(Vector44) { | ||
261 | |||
262 | OSAL_IRQ_PROLOGUE(); | ||
263 | |||
264 | serve_radio_interrupt(&RFD1); | ||
265 | |||
266 | OSAL_IRQ_EPILOGUE(); | ||
267 | } | ||
268 | |||
269 | static void set_rf_payload_format_esb_dpl(RFDriver *rfp, uint32_t payload_length) { | ||
270 | #if (NRF52_MAX_PAYLOAD_LENGTH <= 32) | ||
271 | // Using 6 bits for length | ||
272 | NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | | ||
273 | (6 << RADIO_PCNF0_LFLEN_Pos) | | ||
274 | (3 << RADIO_PCNF0_S1LEN_Pos) ; | ||
275 | #else | ||
276 | // Using 8 bits for length | ||
277 | NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) | | ||
278 | (8 << RADIO_PCNF0_LFLEN_Pos) | | ||
279 | (3 << RADIO_PCNF0_S1LEN_Pos) ; | ||
280 | #endif | ||
281 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | | ||
282 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | | ||
283 | ((rfp->config.address.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | | ||
284 | (0 << RADIO_PCNF1_STATLEN_Pos) | | ||
285 | (NRF52_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_MAXLEN_Pos); | ||
286 | } | ||
287 | |||
288 | static void set_rf_payload_format_esb(RFDriver *rfp, uint32_t payload_length) { | ||
289 | NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) | | ||
290 | (0 << RADIO_PCNF0_LFLEN_Pos) | | ||
291 | (1 << RADIO_PCNF0_S1LEN_Pos); | ||
292 | |||
293 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | | ||
294 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | | ||
295 | ((rfp->config.address.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) | | ||
296 | (payload_length << RADIO_PCNF1_STATLEN_Pos) | | ||
297 | (payload_length << RADIO_PCNF1_MAXLEN_Pos); | ||
298 | } | ||
299 | |||
300 | /* Set BASE0 and BASE1 addresses & prefixes registers | ||
301 | * NRF52 { prefixes[0], base0_addr[0], base0_addr[1], base0_addr[2], base0_addr[3] } == | ||
302 | * NRF24 { addr[0], addr[1], addr[2], addr[3], addr[4] } | ||
303 | */ | ||
304 | static void set_addresses(RFDriver *rfp, uint8_t update_mask) { | ||
305 | if (update_mask & NRF52_ADDR_UPDATE_MASK_BASE0) { | ||
306 | NRF_RADIO->BASE0 = addr_conv(rfp->config.address.base_addr_p0); | ||
307 | NRF_RADIO->DAB[0] = addr_conv(rfp->config.address.base_addr_p0); | ||
308 | } | ||
309 | |||
310 | if (update_mask & NRF52_ADDR_UPDATE_MASK_BASE1) { | ||
311 | NRF_RADIO->BASE1 = addr_conv(rfp->config.address.base_addr_p1); | ||
312 | NRF_RADIO->DAB[1] = addr_conv(rfp->config.address.base_addr_p1); | ||
313 | } | ||
314 | |||
315 | if (update_mask & NRF52_ADDR_UPDATE_MASK_PREFIX) { | ||
316 | NRF_RADIO->PREFIX0 = bytewise_bit_swap(&rfp->config.address.pipe_prefixes[0]); | ||
317 | NRF_RADIO->DAP[0] = bytewise_bit_swap(&rfp->config.address.pipe_prefixes[0]); | ||
318 | NRF_RADIO->PREFIX1 = bytewise_bit_swap(&rfp->config.address.pipe_prefixes[4]); | ||
319 | NRF_RADIO->DAP[1] = bytewise_bit_swap(&rfp->config.address.pipe_prefixes[4]); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | static void set_tx_power(RFDriver *rfp) { | ||
324 | NRF_RADIO->TXPOWER = rfp->config.tx_power << RADIO_TXPOWER_TXPOWER_Pos; | ||
325 | } | ||
326 | |||
327 | static void set_bitrate(RFDriver *rfp) { | ||
328 | NRF_RADIO->MODE = rfp->config.bitrate << RADIO_MODE_MODE_Pos; | ||
329 | |||
330 | switch (rfp->config.bitrate) { | ||
331 | case NRF52_BITRATE_2MBPS: | ||
332 | wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_2MBPS; | ||
333 | break; | ||
334 | case NRF52_BITRATE_1MBPS: | ||
335 | wait_for_ack_timeout_us = RX_WAIT_FOR_ACK_TIMEOUT_US_1MBPS; | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | static void set_protocol(RFDriver *rfp) { | ||
341 | switch (rfp->config.protocol) { | ||
342 | case NRF52_PROTOCOL_ESB_DPL: | ||
343 | set_rf_payload_format = set_rf_payload_format_esb_dpl; | ||
344 | break; | ||
345 | case NRF52_PROTOCOL_ESB: | ||
346 | set_rf_payload_format = set_rf_payload_format_esb; | ||
347 | break; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static void set_crc(RFDriver *rfp) { | ||
352 | NRF_RADIO->CRCCNF = rfp->config.crc << RADIO_CRCCNF_LEN_Pos; | ||
353 | |||
354 | if (rfp->config.crc == RADIO_CRCCNF_LEN_Two) | ||
355 | { | ||
356 | NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value | ||
357 | NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 | ||
358 | } | ||
359 | else if (rfp->config.crc == RADIO_CRCCNF_LEN_One) | ||
360 | { | ||
361 | NRF_RADIO->CRCINIT = 0xFFUL; // Initial value | ||
362 | NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8+x^2^x^1+1 | ||
363 | } | ||
364 | } | ||
365 | |||
366 | static void ppi_init(RFDriver *rfp) { | ||
367 | NRF_PPI->CH[NRF52_RADIO_PPI_TIMER_START].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY; | ||
368 | NRF_PPI->CH[NRF52_RADIO_PPI_TIMER_START].TEP = (uint32_t)&rfp->timer->TASKS_START; | ||
369 | |||
370 | NRF_PPI->CH[NRF52_RADIO_PPI_TIMER_STOP].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS; | ||
371 | NRF_PPI->CH[NRF52_RADIO_PPI_TIMER_STOP].TEP = (uint32_t)&rfp->timer->TASKS_STOP; | ||
372 | |||
373 | NRF_PPI->CH[NRF52_RADIO_PPI_RX_TIMEOUT].EEP = (uint32_t)&rfp->timer->EVENTS_COMPARE[0]; | ||
374 | NRF_PPI->CH[NRF52_RADIO_PPI_RX_TIMEOUT].TEP = (uint32_t)&NRF_RADIO->TASKS_DISABLE; | ||
375 | |||
376 | NRF_PPI->CH[NRF52_RADIO_PPI_TX_START].EEP = (uint32_t)&rfp->timer->EVENTS_COMPARE[1]; | ||
377 | NRF_PPI->CH[NRF52_RADIO_PPI_TX_START].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN; | ||
378 | } | ||
379 | |||
380 | static void set_parameters(RFDriver *rfp) { | ||
381 | set_tx_power(rfp); | ||
382 | set_bitrate(rfp); | ||
383 | set_protocol(rfp); | ||
384 | set_crc(rfp); | ||
385 | set_rf_payload_format(rfp, rfp->config.payload_length); | ||
386 | } | ||
387 | |||
388 | static void reset_fifo(void) { | ||
389 | tx_fifo.entry_point = 0; | ||
390 | tx_fifo.exit_point = 0; | ||
391 | tx_fifo.count = 0; | ||
392 | |||
393 | rx_fifo.entry_point = 0; | ||
394 | rx_fifo.exit_point = 0; | ||
395 | rx_fifo.count = 0; | ||
396 | } | ||
397 | |||
398 | static void init_fifo(void) { | ||
399 | reset_fifo(); | ||
400 | |||
401 | for (int i = 0; i < NRF52_TX_FIFO_SIZE; i++) { | ||
402 | tx_fifo.p_payload[i] = &tx_fifo_payload[i]; | ||
403 | } | ||
404 | |||
405 | for (int i = 0; i < NRF52_RX_FIFO_SIZE; i++) { | ||
406 | rx_fifo.p_payload[i] = &rx_fifo_payload[i]; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | static void tx_fifo_remove_last(void) { | ||
411 | if (tx_fifo.count > 0) { | ||
412 | nvicDisableVector(RADIO_IRQn); | ||
413 | |||
414 | tx_fifo.count--; | ||
415 | if (++tx_fifo.exit_point >= NRF52_TX_FIFO_SIZE) { | ||
416 | tx_fifo.exit_point = 0; | ||
417 | } | ||
418 | |||
419 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /** @brief Function to push the content of the rx_buffer to the RX FIFO. | ||
424 | * | ||
425 | * The module will point the register NRF_RADIO->PACKETPTR to a buffer for receiving packets. | ||
426 | * After receiving a packet the module will call this function to copy the received data to | ||
427 | * the RX FIFO. | ||
428 | * | ||
429 | * @param pipe Pipe number to set for the packet. | ||
430 | * @param pid Packet ID. | ||
431 | * | ||
432 | * @retval true Operation successful. | ||
433 | * @retval false Operation failed. | ||
434 | */ | ||
435 | static bool rx_fifo_push_rfbuf(RFDriver *rfp, uint8_t pipe, uint8_t pid) { | ||
436 | if (rx_fifo.count < NRF52_RX_FIFO_SIZE) { | ||
437 | if (rfp->config.protocol == NRF52_PROTOCOL_ESB_DPL) { | ||
438 | if (rx_payload_buffer[0] > NRF52_MAX_PAYLOAD_LENGTH) { | ||
439 | return false; | ||
440 | } | ||
441 | |||
442 | rx_fifo.p_payload[rx_fifo.entry_point]->length = rx_payload_buffer[0]; | ||
443 | } | ||
444 | else if (rfp->state == NRF52_STATE_PTX_RX_ACK) { | ||
445 | // Received packet is an acknowledgment | ||
446 | rx_fifo.p_payload[rx_fifo.entry_point]->length = 0; | ||
447 | } | ||
448 | else { | ||
449 | rx_fifo.p_payload[rx_fifo.entry_point]->length = rfp->config.payload_length; | ||
450 | } | ||
451 | |||
452 | memcpy(rx_fifo.p_payload[rx_fifo.entry_point]->data, &rx_payload_buffer[2], | ||
453 | rx_fifo.p_payload[rx_fifo.entry_point]->length); | ||
454 | |||
455 | rx_fifo.p_payload[rx_fifo.entry_point]->pipe = pipe; | ||
456 | rx_fifo.p_payload[rx_fifo.entry_point]->rssi = NRF_RADIO->RSSISAMPLE; | ||
457 | rx_fifo.p_payload[rx_fifo.entry_point]->pid = pid; | ||
458 | if (++rx_fifo.entry_point >= NRF52_RX_FIFO_SIZE) { | ||
459 | rx_fifo.entry_point = 0; | ||
460 | } | ||
461 | rx_fifo.count++; | ||
462 | |||
463 | return true; | ||
464 | } | ||
465 | |||
466 | return false; | ||
467 | } | ||
468 | |||
469 | static void timer_init(RFDriver *rfp) { | ||
470 | // Configure the system timer with a 1 MHz base frequency | ||
471 | rfp->timer->PRESCALER = 4; | ||
472 | rfp->timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit; | ||
473 | rfp->timer->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk; | ||
474 | } | ||
475 | |||
476 | static void start_tx_transaction(RFDriver *rfp) { | ||
477 | bool ack; | ||
478 | |||
479 | rfp->tx_attempt = 1; | ||
480 | rfp->tx_remaining = rfp->config.retransmit.count; | ||
481 | |||
482 | // Prepare the payload | ||
483 | p_current_payload = tx_fifo.p_payload[tx_fifo.exit_point]; | ||
484 | |||
485 | // Handling ack if noack is set to false or if selctive auto ack is turned turned off | ||
486 | ack = !p_current_payload->noack || !rfp->config.selective_auto_ack; | ||
487 | |||
488 | switch (rfp->config.protocol) { | ||
489 | case NRF52_PROTOCOL_ESB: | ||
490 | set_rf_payload_format(rfp, p_current_payload->length); | ||
491 | tx_payload_buffer[0] = p_current_payload->pid; | ||
492 | tx_payload_buffer[1] = 0; | ||
493 | memcpy(&tx_payload_buffer[2], p_current_payload->data, p_current_payload->length); | ||
494 | |||
495 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; | ||
496 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; | ||
497 | |||
498 | // Configure the retransmit counter | ||
499 | rfp->tx_remaining = rfp->config.retransmit.count; | ||
500 | rfp->state = NRF52_STATE_PTX_TX_ACK; | ||
501 | break; | ||
502 | |||
503 | case NRF52_PROTOCOL_ESB_DPL: | ||
504 | tx_payload_buffer[0] = p_current_payload->length; | ||
505 | tx_payload_buffer[1] = p_current_payload->pid << 1; | ||
506 | tx_payload_buffer[1] |= ack ? 0x00 : 0x01; | ||
507 | memcpy(&tx_payload_buffer[2], p_current_payload->data, p_current_payload->length); | ||
508 | |||
509 | if (ack) { | ||
510 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; | ||
511 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk; | ||
512 | |||
513 | // Configure the retransmit counter | ||
514 | rfp->tx_remaining = rfp->config.retransmit.count; | ||
515 | rfp->state = NRF52_STATE_PTX_TX_ACK; | ||
516 | } | ||
517 | else { | ||
518 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; | ||
519 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; | ||
520 | rfp->state = NRF52_STATE_PTX_TX; | ||
521 | } | ||
522 | break; | ||
523 | } | ||
524 | |||
525 | NRF_RADIO->TXADDRESS = p_current_payload->pipe; | ||
526 | NRF_RADIO->RXADDRESSES = 1 << p_current_payload->pipe; | ||
527 | |||
528 | NRF_RADIO->FREQUENCY = rfp->config.address.rf_channel; | ||
529 | NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer; | ||
530 | |||
531 | NRF_RADIO->EVENTS_READY = 0; | ||
532 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
533 | (void)NRF_RADIO->EVENTS_READY; | ||
534 | (void)NRF_RADIO->EVENTS_DISABLED; | ||
535 | |||
536 | nvicClearPending(RADIO_IRQn); | ||
537 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
538 | |||
539 | NRF_RADIO->TASKS_TXEN = 1; | ||
540 | } | ||
541 | |||
542 | static void on_radio_disabled_tx_noack(RFDriver *rfp) { | ||
543 | rfp->flags |= NRF52_INT_TX_SUCCESS_MSK; | ||
544 | tx_fifo_remove_last(); | ||
545 | |||
546 | chBSemSignal(&events_sem); | ||
547 | |||
548 | if (tx_fifo.count == 0) { | ||
549 | rfp->state = NRF52_STATE_IDLE; | ||
550 | } | ||
551 | else { | ||
552 | start_tx_transaction(rfp); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | static void on_radio_disabled_tx(RFDriver *rfp) { | ||
557 | // Remove the DISABLED -> RXEN shortcut, to make sure the radio stays | ||
558 | // disabled after the RX window | ||
559 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; | ||
560 | |||
561 | // Make sure the timer is started the next time the radio is ready, | ||
562 | // and that it will disable the radio automatically if no packet is | ||
563 | // received by the time defined in m_wait_for_ack_timeout_us | ||
564 | rfp->timer->CC[0] = wait_for_ack_timeout_us + 130; | ||
565 | rfp->timer->CC[1] = rfp->config.retransmit.delay - 130; | ||
566 | rfp->timer->TASKS_CLEAR = 1; | ||
567 | rfp->timer->EVENTS_COMPARE[0] = 0; | ||
568 | rfp->timer->EVENTS_COMPARE[1] = 0; | ||
569 | (void)rfp->timer->EVENTS_COMPARE[0]; | ||
570 | (void)rfp->timer->EVENTS_COMPARE[1]; | ||
571 | |||
572 | NRF_PPI->CHENSET = (1 << NRF52_RADIO_PPI_TIMER_START) | | ||
573 | (1 << NRF52_RADIO_PPI_RX_TIMEOUT) | | ||
574 | (1 << NRF52_RADIO_PPI_TIMER_STOP); | ||
575 | NRF_PPI->CHENCLR = (1 << NRF52_RADIO_PPI_TX_START); | ||
576 | |||
577 | NRF_RADIO->EVENTS_END = 0; | ||
578 | (void)NRF_RADIO->EVENTS_END; | ||
579 | |||
580 | if (rfp->config.protocol == NRF52_PROTOCOL_ESB) { | ||
581 | set_rf_payload_format(rfp, 0); | ||
582 | } | ||
583 | |||
584 | NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer; | ||
585 | rfp->state = NRF52_STATE_PTX_RX_ACK; | ||
586 | } | ||
587 | |||
588 | static void on_radio_disabled_tx_wait_for_ack(RFDriver *rfp) { | ||
589 | // This marks the completion of a TX_RX sequence (TX with ACK) | ||
590 | |||
591 | // Make sure the timer will not deactivate the radio if a packet is received | ||
592 | NRF_PPI->CHENCLR = (1 << NRF52_RADIO_PPI_TIMER_START) | | ||
593 | (1 << NRF52_RADIO_PPI_RX_TIMEOUT) | | ||
594 | (1 << NRF52_RADIO_PPI_TIMER_STOP); | ||
595 | |||
596 | // If the radio has received a packet and the CRC status is OK | ||
597 | if (NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) { | ||
598 | rfp->timer->TASKS_STOP = 1; | ||
599 | NRF_PPI->CHENCLR = (1 << NRF52_RADIO_PPI_TX_START); | ||
600 | rfp->flags |= NRF52_INT_TX_SUCCESS_MSK; | ||
601 | rfp->tx_attempt++;// = rfp->config.retransmit.count - rfp->tx_remaining + 1; | ||
602 | |||
603 | tx_fifo_remove_last(); | ||
604 | |||
605 | if (rfp->config.protocol != NRF52_PROTOCOL_ESB && rx_payload_buffer[0] > 0) { | ||
606 | if (rx_fifo_push_rfbuf(rfp, (uint8_t)NRF_RADIO->TXADDRESS, 0)) { | ||
607 | rfp->flags |= NRF52_INT_RX_DR_MSK; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | chBSemSignal(&events_sem); | ||
612 | |||
613 | if ((tx_fifo.count == 0) || (rfp->config.tx_mode == NRF52_TXMODE_MANUAL)) { | ||
614 | rfp->state = NRF52_STATE_IDLE; | ||
615 | } | ||
616 | else { | ||
617 | start_tx_transaction(rfp); | ||
618 | } | ||
619 | } | ||
620 | else { | ||
621 | if (rfp->tx_remaining-- == 0) { | ||
622 | rfp->timer->TASKS_STOP = 1; | ||
623 | NRF_PPI->CHENCLR = (1 << NRF52_RADIO_PPI_TX_START); | ||
624 | // All retransmits are expended, and the TX operation is suspended | ||
625 | rfp->tx_attempt = rfp->config.retransmit.count + 1; | ||
626 | rfp->flags |= NRF52_INT_TX_FAILED_MSK; | ||
627 | |||
628 | chBSemSignal(&events_sem); | ||
629 | |||
630 | rfp->state = NRF52_STATE_IDLE; | ||
631 | } | ||
632 | else { | ||
633 | // There are still have more retransmits left, TX mode should be | ||
634 | // entered again as soon as the system timer reaches CC[1]. | ||
635 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; | ||
636 | set_rf_payload_format(rfp, p_current_payload->length); | ||
637 | NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer; | ||
638 | rfp->state = NRF52_STATE_PTX_TX_ACK; | ||
639 | rfp->timer->TASKS_START = 1; | ||
640 | NRF_PPI->CHENSET = (1 << NRF52_RADIO_PPI_TX_START); | ||
641 | if (rfp->timer->EVENTS_COMPARE[1]) | ||
642 | NRF_RADIO->TASKS_TXEN = 1; | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | |||
647 | static void clear_events_restart_rx(RFDriver *rfp) { | ||
648 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON; | ||
649 | set_rf_payload_format(rfp, rfp->config.payload_length); | ||
650 | NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer; | ||
651 | |||
652 | NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; | ||
653 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
654 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
655 | |||
656 | NRF_RADIO->TASKS_DISABLE = 1; | ||
657 | while (NRF_RADIO->EVENTS_DISABLED == 0); | ||
658 | |||
659 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
660 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
661 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; | ||
662 | |||
663 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; | ||
664 | NRF_RADIO->TASKS_RXEN = 1; | ||
665 | } | ||
666 | |||
667 | static void on_radio_disabled_rx(RFDriver *rfp) { | ||
668 | bool ack = false; | ||
669 | bool retransmit_payload = false; | ||
670 | bool send_rx_event = true; | ||
671 | pipe_info_t * p_pipe_info; | ||
672 | |||
673 | if (NRF_RADIO->CRCSTATUS == 0) { | ||
674 | clear_events_restart_rx(rfp); | ||
675 | return; | ||
676 | } | ||
677 | |||
678 | if(rx_fifo.count >= NRF52_RX_FIFO_SIZE) { | ||
679 | clear_events_restart_rx(rfp); | ||
680 | return; | ||
681 | } | ||
682 | |||
683 | p_pipe_info = &rx_pipe_info[NRF_RADIO->RXMATCH]; | ||
684 | if (NRF_RADIO->RXCRC == p_pipe_info->m_crc && | ||
685 | (rx_payload_buffer[1] >> 1) == p_pipe_info->m_pid ) { | ||
686 | retransmit_payload = true; | ||
687 | send_rx_event = false; | ||
688 | } | ||
689 | |||
690 | p_pipe_info->m_pid = rx_payload_buffer[1] >> 1; | ||
691 | p_pipe_info->m_crc = NRF_RADIO->RXCRC; | ||
692 | |||
693 | if(rfp->config.selective_auto_ack == false || ((rx_payload_buffer[1] & 0x01) == 0)) | ||
694 | ack = true; | ||
695 | |||
696 | if(ack) { | ||
697 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_RXEN_Msk; | ||
698 | |||
699 | switch(rfp->config.protocol) { | ||
700 | case NRF52_PROTOCOL_ESB_DPL: | ||
701 | { | ||
702 | if (tx_fifo.count > 0 && | ||
703 | (tx_fifo.p_payload[tx_fifo.exit_point]->pipe == NRF_RADIO->RXMATCH)) | ||
704 | { | ||
705 | // Pipe stays in ACK with payload until TX fifo is empty | ||
706 | // Do not report TX success on first ack payload or retransmit | ||
707 | if (p_pipe_info->m_ack_payload != 0 && !retransmit_payload) { | ||
708 | if(++tx_fifo.exit_point >= NRF52_TX_FIFO_SIZE) { | ||
709 | tx_fifo.exit_point = 0; | ||
710 | } | ||
711 | |||
712 | tx_fifo.count--; | ||
713 | |||
714 | // ACK payloads also require TX_DS | ||
715 | // (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf'). | ||
716 | rfp->flags |= NRF52_INT_TX_SUCCESS_MSK; | ||
717 | } | ||
718 | |||
719 | p_pipe_info->m_ack_payload = 1; | ||
720 | |||
721 | p_current_payload = tx_fifo.p_payload[tx_fifo.exit_point]; | ||
722 | |||
723 | set_rf_payload_format(rfp, p_current_payload->length); | ||
724 | tx_payload_buffer[0] = p_current_payload->length; | ||
725 | memcpy(&tx_payload_buffer[2], | ||
726 | p_current_payload->data, | ||
727 | p_current_payload->length); | ||
728 | } | ||
729 | else { | ||
730 | p_pipe_info->m_ack_payload = 0; | ||
731 | set_rf_payload_format(rfp, 0); | ||
732 | tx_payload_buffer[0] = 0; | ||
733 | } | ||
734 | |||
735 | tx_payload_buffer[1] = rx_payload_buffer[1]; | ||
736 | } | ||
737 | break; | ||
738 | |||
739 | case NRF52_PROTOCOL_ESB: | ||
740 | { | ||
741 | set_rf_payload_format(rfp, 0); | ||
742 | tx_payload_buffer[0] = rx_payload_buffer[0]; | ||
743 | tx_payload_buffer[1] = 0; | ||
744 | } | ||
745 | break; | ||
746 | } | ||
747 | |||
748 | rfp->state = NRF52_STATE_PRX_SEND_ACK; | ||
749 | NRF_RADIO->TXADDRESS = NRF_RADIO->RXMATCH; | ||
750 | NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer; | ||
751 | } | ||
752 | else { | ||
753 | clear_events_restart_rx(rfp); | ||
754 | } | ||
755 | |||
756 | if (send_rx_event) { | ||
757 | // Push the new packet to the RX buffer and trigger a received event if the operation was | ||
758 | // successful. | ||
759 | if (rx_fifo_push_rfbuf(rfp, NRF_RADIO->RXMATCH, p_pipe_info->m_pid)) { | ||
760 | rfp->flags |= NRF52_INT_RX_DR_MSK; | ||
761 | chBSemSignal(&events_sem); | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | |||
766 | static void on_radio_disabled_rx_ack(RFDriver *rfp) { | ||
767 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; | ||
768 | set_rf_payload_format(rfp, rfp->config.payload_length); | ||
769 | |||
770 | NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer; | ||
771 | |||
772 | rfp->state = NRF52_STATE_PRX; | ||
773 | } | ||
774 | |||
775 | nrf52_error_t radio_disable(void) { | ||
776 | NRF_RADIO->SHORTS = 0; | ||
777 | NRF_RADIO->INTENCLR = 0xFFFFFFFF; | ||
778 | |||
779 | nvicDisableVector(RADIO_IRQn); | ||
780 | |||
781 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
782 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
783 | |||
784 | NRF_RADIO->TASKS_STOP = 1; | ||
785 | NRF_RADIO->TASKS_DISABLE = 1; | ||
786 | |||
787 | RFD1.state = NRF52_STATE_IDLE; | ||
788 | |||
789 | // Clear PPI | ||
790 | NRF_PPI->CHENCLR = (1 << NRF52_RADIO_PPI_TIMER_START) | | ||
791 | (1 << NRF52_RADIO_PPI_TIMER_STOP) | | ||
792 | (1 << NRF52_RADIO_PPI_RX_TIMEOUT) | | ||
793 | (1 << NRF52_RADIO_PPI_TX_START); | ||
794 | |||
795 | reset_fifo(); | ||
796 | |||
797 | memset(rx_pipe_info, 0, sizeof(rx_pipe_info)); | ||
798 | memset(pids, 0, sizeof(pids)); | ||
799 | |||
800 | // Terminate interrupts handle thread | ||
801 | chThdTerminate(rfIntThread_p); | ||
802 | chBSemSignal(&disable_sem); | ||
803 | chThdWait(rfIntThread_p); | ||
804 | |||
805 | // Terminate events handle thread | ||
806 | chThdTerminate(rfEvtThread_p); | ||
807 | RFD1.flags = 0; | ||
808 | chBSemSignal(&events_sem); | ||
809 | chThdWait(rfEvtThread_p); | ||
810 | |||
811 | RFD1.state = NRF52_STATE_UNINIT; | ||
812 | |||
813 | return NRF52_SUCCESS; | ||
814 | } | ||
815 | |||
816 | // | ||
817 | nrf52_error_t radio_init(nrf52_config_t const *config) { | ||
818 | osalDbgAssert(config != NULL, | ||
819 | "config must be defined"); | ||
820 | osalDbgAssert(&config->address != NULL, | ||
821 | "address must be defined"); | ||
822 | osalDbgAssert(NRF52_RADIO_IRQ_PRIORITY <= 7, | ||
823 | "wrong radio irq priority"); | ||
824 | |||
825 | if (RFD1.state != NRF52_STATE_UNINIT) { | ||
826 | nrf52_error_t err = radio_disable(); | ||
827 | if (err != NRF52_SUCCESS) | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | RFD1.radio = NRF_RADIO; | ||
832 | RFD1.config = *config; | ||
833 | RFD1.flags = 0; | ||
834 | |||
835 | init_fifo(); | ||
836 | |||
837 | #if NRF52_RADIO_USE_TIMER0 | ||
838 | RFD1.timer = NRF_TIMER0; | ||
839 | #endif | ||
840 | #if NRF52_RADIO_USE_TIMER1 | ||
841 | RFD1.timer = NRF_TIMER1; | ||
842 | #endif | ||
843 | #if NRF52_RADIO_USE_TIMER2 | ||
844 | RFD1.timer = NRF_TIMER2; | ||
845 | #endif | ||
846 | #if NRF52_RADIO_USE_TIMER3 | ||
847 | RFD1.timer = NRF_TIMER3; | ||
848 | #endif | ||
849 | #if NRF52_RADIO_USE_TIMER4 | ||
850 | RFD1.timer = NRF_TIMER4; | ||
851 | #endif | ||
852 | |||
853 | set_parameters(&RFD1); | ||
854 | |||
855 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_BASE0); | ||
856 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_BASE1); | ||
857 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_PREFIX); | ||
858 | |||
859 | ppi_init(&RFD1); | ||
860 | timer_init(&RFD1); | ||
861 | |||
862 | chBSemObjectInit(&disable_sem, TRUE); | ||
863 | chBSemObjectInit(&events_sem, TRUE); | ||
864 | |||
865 | chEvtObjectInit(&RFD1.eventsrc); | ||
866 | |||
867 | // interrupt handle thread | ||
868 | rfIntThread_p = chThdCreateStatic(waRFIntThread, sizeof(waRFIntThread), | ||
869 | NRF52_RADIO_INTTHD_PRIORITY, rfIntThread, NULL); | ||
870 | |||
871 | // events handle thread | ||
872 | rfEvtThread_p = chThdCreateStatic(waRFEvtThread, sizeof(waRFEvtThread), | ||
873 | NRF52_RADIO_EVTTHD_PRIORITY, rfEvtThread, NULL); | ||
874 | |||
875 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
876 | |||
877 | RFD1.state = NRF52_STATE_IDLE; | ||
878 | |||
879 | return NRF52_SUCCESS; | ||
880 | } | ||
881 | |||
882 | nrf52_error_t radio_write_payload(nrf52_payload_t const * p_payload) { | ||
883 | if (RFD1.state == NRF52_STATE_UNINIT) | ||
884 | return NRF52_INVALID_STATE; | ||
885 | if(p_payload == NULL) | ||
886 | return NRF52_ERROR_NULL; | ||
887 | VERIFY_PAYLOAD_LENGTH(p_payload); | ||
888 | if (tx_fifo.count >= NRF52_TX_FIFO_SIZE) | ||
889 | return NRF52_ERROR_INVALID_LENGTH; | ||
890 | |||
891 | if (RFD1.config.mode == NRF52_MODE_PTX && | ||
892 | p_payload->noack && !RFD1.config.selective_auto_ack ) | ||
893 | { | ||
894 | return NRF52_ERROR_NOT_SUPPORTED; | ||
895 | } | ||
896 | |||
897 | nvicDisableVector(RADIO_IRQn); | ||
898 | |||
899 | memcpy(tx_fifo.p_payload[tx_fifo.entry_point], p_payload, sizeof(nrf52_payload_t)); | ||
900 | |||
901 | pids[p_payload->pipe] = (pids[p_payload->pipe] + 1) % (NRF52_PID_MAX + 1); | ||
902 | tx_fifo.p_payload[tx_fifo.entry_point]->pid = pids[p_payload->pipe]; | ||
903 | |||
904 | if (++tx_fifo.entry_point >= NRF52_TX_FIFO_SIZE) { | ||
905 | tx_fifo.entry_point = 0; | ||
906 | } | ||
907 | |||
908 | tx_fifo.count++; | ||
909 | |||
910 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
911 | |||
912 | if (RFD1.config.mode == NRF52_MODE_PTX && | ||
913 | RFD1.config.tx_mode == NRF52_TXMODE_AUTO && | ||
914 | RFD1.state == NRF52_STATE_IDLE) | ||
915 | { | ||
916 | start_tx_transaction(&RFD1); | ||
917 | } | ||
918 | |||
919 | return NRF52_SUCCESS; | ||
920 | } | ||
921 | |||
922 | nrf52_error_t radio_read_rx_payload(nrf52_payload_t * p_payload) { | ||
923 | if (RFD1.state == NRF52_STATE_UNINIT) | ||
924 | return NRF52_INVALID_STATE; | ||
925 | if (p_payload == NULL) | ||
926 | return NRF52_ERROR_NULL; | ||
927 | |||
928 | if (rx_fifo.count == 0) { | ||
929 | return NRF52_ERROR_INVALID_LENGTH; | ||
930 | } | ||
931 | |||
932 | nvicDisableVector(RADIO_IRQn); | ||
933 | |||
934 | p_payload->length = rx_fifo.p_payload[rx_fifo.exit_point]->length; | ||
935 | p_payload->pipe = rx_fifo.p_payload[rx_fifo.exit_point]->pipe; | ||
936 | p_payload->rssi = rx_fifo.p_payload[rx_fifo.exit_point]->rssi; | ||
937 | p_payload->pid = rx_fifo.p_payload[rx_fifo.exit_point]->pid; | ||
938 | memcpy(p_payload->data, rx_fifo.p_payload[rx_fifo.exit_point]->data, p_payload->length); | ||
939 | |||
940 | if (++rx_fifo.exit_point >= NRF52_RX_FIFO_SIZE) { | ||
941 | rx_fifo.exit_point = 0; | ||
942 | } | ||
943 | |||
944 | rx_fifo.count--; | ||
945 | |||
946 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
947 | |||
948 | return NRF52_SUCCESS; | ||
949 | } | ||
950 | |||
951 | nrf52_error_t radio_start_tx(void) { | ||
952 | if (RFD1.state != NRF52_STATE_IDLE) | ||
953 | return NRF52_ERROR_BUSY; | ||
954 | |||
955 | if (tx_fifo.count == 0) { | ||
956 | return NRF52_ERROR_INVALID_LENGTH; | ||
957 | } | ||
958 | |||
959 | start_tx_transaction(&RFD1); | ||
960 | |||
961 | return NRF52_SUCCESS; | ||
962 | } | ||
963 | |||
964 | nrf52_error_t radio_start_rx(void) { | ||
965 | if (RFD1.state != NRF52_STATE_IDLE) | ||
966 | return NRF52_ERROR_BUSY; | ||
967 | |||
968 | NRF_RADIO->INTENCLR = 0xFFFFFFFF; | ||
969 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
970 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
971 | |||
972 | NRF_RADIO->SHORTS = RADIO_SHORTS_COMMON | RADIO_SHORTS_DISABLED_TXEN_Msk; | ||
973 | NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; | ||
974 | RFD1.state = NRF52_STATE_PRX; | ||
975 | |||
976 | NRF_RADIO->RXADDRESSES = RFD1.config.address.rx_pipes; | ||
977 | NRF_RADIO->FREQUENCY = RFD1.config.address.rf_channel; | ||
978 | NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer; | ||
979 | |||
980 | nvicClearPending(RADIO_IRQn); | ||
981 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
982 | |||
983 | NRF_RADIO->EVENTS_ADDRESS = 0; | ||
984 | NRF_RADIO->EVENTS_PAYLOAD = 0; | ||
985 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
986 | (void) NRF_RADIO->EVENTS_ADDRESS; | ||
987 | (void) NRF_RADIO->EVENTS_PAYLOAD; | ||
988 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
989 | |||
990 | NRF_RADIO->TASKS_RXEN = 1; | ||
991 | |||
992 | return NRF52_SUCCESS; | ||
993 | } | ||
994 | |||
995 | nrf52_error_t radio_stop_rx(void) { | ||
996 | if (RFD1.state != NRF52_STATE_PRX) { | ||
997 | return NRF52_INVALID_STATE; | ||
998 | } | ||
999 | |||
1000 | NRF_RADIO->SHORTS = 0; | ||
1001 | NRF_RADIO->INTENCLR = 0xFFFFFFFF; | ||
1002 | NRF_RADIO->EVENTS_DISABLED = 0; | ||
1003 | (void) NRF_RADIO->EVENTS_DISABLED; | ||
1004 | NRF_RADIO->TASKS_DISABLE = 1; | ||
1005 | while (NRF_RADIO->EVENTS_DISABLED == 0); | ||
1006 | RFD1.state = NRF52_STATE_IDLE; | ||
1007 | |||
1008 | return NRF52_SUCCESS; | ||
1009 | } | ||
1010 | |||
1011 | nrf52_error_t radio_flush_tx(void) { | ||
1012 | if (RFD1.state == NRF52_STATE_UNINIT) | ||
1013 | return NRF52_INVALID_STATE; | ||
1014 | |||
1015 | nvicDisableVector(RADIO_IRQn); | ||
1016 | |||
1017 | tx_fifo.count = 0; | ||
1018 | tx_fifo.entry_point = 0; | ||
1019 | tx_fifo.exit_point = 0; | ||
1020 | |||
1021 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
1022 | |||
1023 | return NRF52_SUCCESS; | ||
1024 | } | ||
1025 | |||
1026 | nrf52_error_t radio_pop_tx(void) { | ||
1027 | if (RFD1.state == NRF52_STATE_UNINIT) | ||
1028 | return NRF52_INVALID_STATE; | ||
1029 | if (tx_fifo.count == 0) | ||
1030 | return NRF52_ERROR_INVALID_LENGTH; | ||
1031 | |||
1032 | nvicDisableVector(RADIO_IRQn); | ||
1033 | |||
1034 | if (++tx_fifo.entry_point >= NRF52_TX_FIFO_SIZE) { | ||
1035 | tx_fifo.entry_point = 0; | ||
1036 | } | ||
1037 | tx_fifo.count--; | ||
1038 | |||
1039 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
1040 | |||
1041 | return NRF52_SUCCESS; | ||
1042 | } | ||
1043 | |||
1044 | nrf52_error_t radio_flush_rx(void) { | ||
1045 | if (RFD1.state == NRF52_STATE_UNINIT) | ||
1046 | return NRF52_INVALID_STATE; | ||
1047 | |||
1048 | nvicDisableVector(RADIO_IRQn); | ||
1049 | |||
1050 | rx_fifo.count = 0; | ||
1051 | rx_fifo.entry_point = 0; | ||
1052 | rx_fifo.exit_point = 0; | ||
1053 | |||
1054 | memset(rx_pipe_info, 0, sizeof(rx_pipe_info)); | ||
1055 | |||
1056 | nvicEnableVector(RADIO_IRQn, NRF52_RADIO_IRQ_PRIORITY); | ||
1057 | |||
1058 | return NRF52_SUCCESS; | ||
1059 | } | ||
1060 | |||
1061 | nrf52_error_t radio_set_base_address_0(uint8_t const * p_addr) { | ||
1062 | if (RFD1.state != NRF52_STATE_IDLE) | ||
1063 | return NRF52_ERROR_BUSY; | ||
1064 | if (p_addr == NULL) | ||
1065 | return NRF52_ERROR_NULL; | ||
1066 | |||
1067 | memcpy(RFD1.config.address.base_addr_p0, p_addr, 4); | ||
1068 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_BASE0); | ||
1069 | |||
1070 | return NRF52_SUCCESS; | ||
1071 | } | ||
1072 | |||
1073 | nrf52_error_t radio_set_base_address_1(uint8_t const * p_addr) { | ||
1074 | if (RFD1.state != NRF52_STATE_IDLE) | ||
1075 | return NRF52_ERROR_BUSY; | ||
1076 | if (p_addr == NULL) | ||
1077 | return NRF52_ERROR_NULL; | ||
1078 | |||
1079 | memcpy(RFD1.config.address.base_addr_p1, p_addr, 4); | ||
1080 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_BASE1); | ||
1081 | |||
1082 | return NRF52_SUCCESS; | ||
1083 | } | ||
1084 | |||
1085 | nrf52_error_t radio_set_prefixes(uint8_t const * p_prefixes, uint8_t num_pipes) { | ||
1086 | if (RFD1.state != NRF52_STATE_IDLE) | ||
1087 | return NRF52_ERROR_BUSY; | ||
1088 | if (p_prefixes == NULL) | ||
1089 | return NRF52_ERROR_NULL; | ||
1090 | if (num_pipes > 8) | ||
1091 | return NRF52_ERROR_INVALID_PARAM; | ||
1092 | |||
1093 | memcpy(RFD1.config.address.pipe_prefixes, p_prefixes, num_pipes); | ||
1094 | RFD1.config.address.num_pipes = num_pipes; | ||
1095 | RFD1.config.address.rx_pipes = BIT_MASK_UINT_8(num_pipes); | ||
1096 | |||
1097 | set_addresses(&RFD1, NRF52_ADDR_UPDATE_MASK_PREFIX); | ||
1098 | |||
1099 | return NRF52_SUCCESS; | ||
1100 | } | ||
1101 | |||
1102 | nrf52_error_t radio_set_prefix(uint8_t pipe, uint8_t prefix) { | ||
1103 | if (RFD1.state != NRF52_STATE_IDLE) | ||
1104 | return NRF52_ERROR_BUSY; | ||
1105 | if (pipe > 8) | ||
1106 | return NRF52_ERROR_INVALID_PARAM; | ||
1107 | |||
1108 | RFD1.config.address.pipe_prefixes[pipe] = prefix; | ||
1109 | |||
1110 | NRF_RADIO->PREFIX0 = bytewise_bit_swap(&RFD1.config.address.pipe_prefixes[0]); | ||
1111 | NRF_RADIO->PREFIX1 = bytewise_bit_swap(&RFD1.config.address.pipe_prefixes[4]); | ||
1112 | |||
1113 | return NRF52_SUCCESS; | ||
1114 | } | ||