aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/os/various/devices_lib/rf/nrf52_radio.c
diff options
context:
space:
mode:
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.c1114
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) \
99do \
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.
111typedef 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.
119typedef 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.
128typedef 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;
138static void (*set_rf_payload_format)(RFDriver *rfp, uint32_t payload_length) = NULL;
139
140// The following functions are assigned to the function pointers above.
141static void on_radio_disabled_tx_noack(RFDriver *rfp);
142static void on_radio_disabled_tx(RFDriver *rfp);
143static void on_radio_disabled_tx_wait_for_ack(RFDriver *rfp);
144static void on_radio_disabled_rx(RFDriver *rfp);
145static void on_radio_disabled_rx_ack(RFDriver *rfp);
146
147static volatile uint16_t wait_for_ack_timeout_us;
148static nrf52_payload_t * p_current_payload;
149
150// TX FIFO
151static nrf52_payload_t tx_fifo_payload[NRF52_TX_FIFO_SIZE];
152static nrf52_payload_tx_fifo_t tx_fifo;
153
154// RX FIFO
155static nrf52_payload_t rx_fifo_payload[NRF52_RX_FIFO_SIZE];
156static nrf52_payload_rx_fifo_t rx_fifo;
157
158// Payload buffers
159static uint8_t tx_payload_buffer[NRF52_MAX_PAYLOAD_LENGTH + 2];
160static uint8_t rx_payload_buffer[NRF52_MAX_PAYLOAD_LENGTH + 2];
161
162static uint8_t pids[NRF52_PIPE_COUNT];
163static pipe_info_t rx_pipe_info[NRF52_PIPE_COUNT];
164
165 // disable and events semaphores.
166static binary_semaphore_t disable_sem;
167static binary_semaphore_t events_sem;
168
169RFDriver RFD1;
170
171// Function to do bytewise bit-swap on a unsigned 32 bit value
172static 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
179static 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
183static thread_t *rfEvtThread_p;
184static THD_WORKING_AREA(waRFEvtThread, 128);
185static 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
209static thread_t *rfIntThread_p;
210static THD_WORKING_AREA(waRFIntThread, 128);
211static 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
241static 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 */
260OSAL_IRQ_HANDLER(Vector44) {
261
262 OSAL_IRQ_PROLOGUE();
263
264 serve_radio_interrupt(&RFD1);
265
266 OSAL_IRQ_EPILOGUE();
267}
268
269static 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
288static 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 */
304static 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
323static void set_tx_power(RFDriver *rfp) {
324 NRF_RADIO->TXPOWER = rfp->config.tx_power << RADIO_TXPOWER_TXPOWER_Pos;
325}
326
327static 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
340static 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
351static 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
366static 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
380static 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
388static 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
398static 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
410static 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 */
435static 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
469static 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
476static 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
542static 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
556static 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
588static 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
647static 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
667static 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
766static 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
775nrf52_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//
817nrf52_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
882nrf52_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
922nrf52_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
951nrf52_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
964nrf52_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
995nrf52_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
1011nrf52_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
1026nrf52_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
1044nrf52_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
1061nrf52_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
1073nrf52_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
1085nrf52_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
1102nrf52_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}