Contiki-NG
nrf-ieee-driver-arch.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020, Toshiba BRIL
3 * Copyright (C) 2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31/*---------------------------------------------------------------------------*/
32/**
33 * \addtogroup nrf
34 * @{
35 *
36 * \addtogroup nrf-net Net drivers
37 * @{
38 *
39 * \addtogroup nrf-ieee-radio IEEE radio driver
40 * @{
41 *
42 * \file
43 * Implementation of the nRF IEEE NETSTACK_RADIO driver
44 *
45 * \author
46 * Toshiba BRIL
47 * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
48 */
49/*---------------------------------------------------------------------------*/
50#include "contiki.h"
51#include "dev/radio.h"
52#include "sys/energest.h"
53#include "sys/int-master.h"
54#include "sys/critical.h"
55#include "net/netstack.h"
56#include "net/packetbuf.h"
57#include "net/mac/tsch/tsch.h"
58#include "helpers/nrfx_gppi.h"
59#include <stdint.h>
60#include <stdbool.h>
61#include <string.h>
62#include <math.h>
63
64#include "nrf.h"
65
66/* Only compile the below if NRF_RADIO exists */
67#ifdef NRF_RADIO
68
69#include "hal/nrf_radio.h"
70#include "hal/nrf_timer.h"
71#include "hal/nrf_clock.h"
72#include "hal/nrf_temp.h"
73#include "nrf_erratas.h"
74
75/*---------------------------------------------------------------------------*/
76#include "sys/log.h"
77
78#define LOG_MODULE "nRF IEEE"
79#define LOG_LEVEL LOG_LEVEL_NONE
80/*---------------------------------------------------------------------------*/
81#define NRF_CCA_BUSY 0
82#define NRF_CCA_CLEAR 1
83/*---------------------------------------------------------------------------*/
84#define NRF_RECEIVING_NO 0
85#define NRF_RECEIVING_YES 1
86/*---------------------------------------------------------------------------*/
87#define NRF_PENDING_NO 0
88#define NRF_PENDING_YES 1
89/*---------------------------------------------------------------------------*/
90#define NRF_COMMAND_ERR 0
91#define NRF_COMMAND_OK 1
92/*---------------------------------------------------------------------------*/
93#define NRF_CHANNEL_MIN 11
94#define NRF_CHANNEL_MAX 26
95/*---------------------------------------------------------------------------*/
96#define ED_RSSISCALE 4
97/*---------------------------------------------------------------------------*/
98#define FCS_LEN 2
99#define MPDU_LEN 127
100/*
101 * The maximum number of bytes this driver can accept from the MAC layer for
102 * transmission or will deliver to the MAC layer after reception. Includes
103 * the MAC header and payload, but not the FCS.
104 */
105#define MAX_PAYLOAD_LEN (MPDU_LEN - FCS_LEN)
106
107#define ACK_MPDU_MIN_LEN 5
108#define ACK_PAYLOAD_MIN_LEN (ACK_MPDU_MIN_LEN - FCS_LEN)
109/*---------------------------------------------------------------------------*/
110/*
111 * The last frame's RSSI and LQI
112 *
113 * Unlike other radios that write RSSI and LQI in the FCS, the nrf
114 * only writes one value. This is a "hardware-reported" value, which needs
115 * converted to the .15.4 standard LQI scale using an 8-bit saturating
116 * multiplication by 4 (see the Product Spec). This value is based on the
117 * median of three RSSI samples taken during frame reception.
118 */
119static int8_t last_rssi;
120static uint8_t last_lqi;
121/*---------------------------------------------------------------------------*/
122PROCESS(nrf_ieee_rf_process, "nRF IEEE RF driver");
123/*---------------------------------------------------------------------------*/
124#ifndef NRF_CCA_MODE
125#define NRF_CCA_MODE RADIO_CCACTRL_CCAMODE_CarrierAndEdMode
126#endif
127
128#ifndef NRF_CCA_ED_THRESHOLD
129#define NRF_CCA_ED_THRESHOLD 0x14
130#endif
131
132#ifndef NRF_CCA_CORR_THRESHOLD
133#define NRF_CCA_CORR_THRESHOLD 0x14
134#endif
135
136#ifndef NRF_CCA_CORR_COUNT
137#define NRF_CCA_CORR_COUNT 0x02
138#endif
139/*---------------------------------------------------------------------------*/
140/*
141 * .15.4-compliant CRC:
142 *
143 * Lenght 2, Initial value 0.
144 *
145 * Polynomial x^16 + x^12 + x^5 + 1
146 * CRCPOLY: 1 00010000 00100001
147 */
148#define CRC_IEEE802154_LEN 2
149#define CRC_IEEE802154_POLY 0x11021
150#define CRC_IEEE802154_INIT 0
151/*---------------------------------------------------------------------------*/
152#define SYMBOL_DURATION_USEC 16
153#define SYMBOL_DURATION_RTIMER 1
154#define BYTE_DURATION_RTIMER (SYMBOL_DURATION_RTIMER * 2)
155#define TXRU_DURATION_TIMER 3
156/*---------------------------------------------------------------------------*/
157#define NRF_PPI_FRAMESTART_CHANNEL 1
158#define NRF_PPI_END_CHANNEL 2
159/*---------------------------------------------------------------------------*/
160typedef struct timestamps_s {
161 rtimer_clock_t sfd; /* Derived: 1 byte = 2 rtimer ticks before FRAMESTART */
162 rtimer_clock_t framestart; /* PPI Channel 1 */
163 rtimer_clock_t end; /* PPI Channel 2 */
164 rtimer_clock_t mpdu_duration; /* Calculated: PHR * 2 rtimer ticks */
165 uint8_t phr; /* PHR: The MPDU length in bytes */
166} timestamps_t;
167
168static timestamps_t timestamps;
169/*---------------------------------------------------------------------------*/
170typedef struct tx_buf_s {
171 uint8_t phr;
172 uint8_t mpdu[MAX_PAYLOAD_LEN];
173} tx_buf_t;
174
175static tx_buf_t tx_buf;
176/*---------------------------------------------------------------------------*/
177typedef struct rx_buf_s {
178 uint8_t phr;
179 uint8_t mpdu[MPDU_LEN];
180 bool full; /* Used in interrupt / non-poll mode for additional state */
181} rx_buf_t;
182
183static rx_buf_t rx_buf;
184/*---------------------------------------------------------------------------*/
185typedef struct rf_cfg_s {
186 bool poll_mode;
187 nrf_radio_txpower_t txpower;
188 uint8_t channel;
189 uint8_t send_on_cca; /* Perform CCA before TX */
190 uint8_t cca_mode;
191 uint8_t cca_corr_threshold;
192 uint8_t cca_corr_count;
193 uint8_t ed_threshold;
194} rf_cfg_t;
195
196static rf_cfg_t rf_config = {
197 .poll_mode = false,
198 .txpower = NRF_RADIO_TXPOWER_0DBM,
199 .send_on_cca = RADIO_TX_MODE_SEND_ON_CCA,
201 .cca_mode = NRF_CCA_MODE,
202 .cca_corr_threshold = NRF_CCA_CORR_THRESHOLD,
203 .cca_corr_count = NRF_CCA_CORR_COUNT,
204 .ed_threshold = NRF_CCA_ED_THRESHOLD,
205};
206
207static bool radio_power = false; /* Used as a POWER register when nrf53_errata_16 is present */
208
209/*---------------------------------------------------------------------------*/
210static bool
211phr_is_valid(uint8_t phr)
212{
213 if(phr < ACK_MPDU_MIN_LEN || phr > MPDU_LEN) {
214 return false;
215 }
216 return true;
217}
218/*---------------------------------------------------------------------------*/
219static bool
220radio_is_powered(void)
221{
222 if(nrf53_errata_16()) {
223 return radio_power;
224 } else {
225 return NRF_RADIO->POWER == 0 ? false : true;
226 }
227}
228/*---------------------------------------------------------------------------*/
229static void
230radio_set_power(bool power)
231{
232 if(nrf53_errata_16()) {
233 radio_power = power;
234 } else {
235 nrf_radio_power_set(NRF_RADIO, power);
236 }
237}
238/*---------------------------------------------------------------------------*/
239static uint8_t
240radio_rssi_sample_get(void)
241{
242 uint8_t rssi_sample;
243 uint8_t temp;
244
245 rssi_sample = nrf_radio_rssi_sample_get(NRF_RADIO);
246
247 if(nrf53_errata_87()) {
248 temp = nrf_temp_result_get(NRF_TEMP);
249 return (uint8_t)round(
250 (float)((float)(1.56f * rssi_sample) + (float)(4.9e-5 * pow(rssi_sample, 3)) -
251 (float)(9.9e-3 * pow(rssi_sample, 2)) - (0.05f * ((float)(temp) * 0.25f)) - 7.2f));
252 } else {
253 return rssi_sample;
254 }
255}
256/*---------------------------------------------------------------------------*/
257static uint8_t
258get_channel(void)
259{
260 return NRF_RADIO->FREQUENCY / 5 + 10;
261}
262/*---------------------------------------------------------------------------*/
263static void
264set_channel(uint8_t channel)
265{
266 NRF_RADIO->FREQUENCY = 5 * (channel - 10);
267}
268/*---------------------------------------------------------------------------*/
269static void
270cca_reconfigure(void)
271{
272 nrf_radio_cca_configure(NRF_RADIO, rf_config.cca_mode, rf_config.ed_threshold,
273 rf_config.cca_corr_threshold, rf_config.cca_corr_count);
274}
275/*---------------------------------------------------------------------------*/
276static void
277crc_init(void)
278{
279 /*
280 * Initialise the CRC engine in .15.4 mode:
281 * - Length: 2 bytes
282 * - Polynomial:
283 * - Initial value: 0
284 */
285 nrf_radio_crc_configure(NRF_RADIO, CRC_IEEE802154_LEN, NRF_RADIO_CRC_ADDR_IEEE802154,
286 CRC_IEEE802154_POLY);
287
288 nrf_radio_crcinit_set(NRF_RADIO, CRC_IEEE802154_INIT);
289}
290/*---------------------------------------------------------------------------*/
291static void
292packet_init(void)
293{
294 /* Configure packet format for .15.4 */
295 nrf_radio_packet_conf_t conf;
296
297 memset(&conf, 0, sizeof(conf));
298
299 conf.lflen = 8; /* Length field, in bits */
300 conf.s1incl = false;
301 conf.plen = NRF_RADIO_PREAMBLE_LENGTH_32BIT_ZERO;
302 conf.crcinc = true;
303 conf.big_endian = false;
304 conf.whiteen = false;
305 conf.maxlen = MPDU_LEN;
306
307 nrf_radio_packet_configure(NRF_RADIO, &conf);
308}
309/*---------------------------------------------------------------------------*/
310static void
311setup_interrupts(void)
312{
314 nrf_radio_int_mask_t interrupts = 0;
315
316 stat = critical_enter();
317
318 if(!rf_config.poll_mode) {
319 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
320 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
321 interrupts |= NRF_RADIO_INT_CRCOK_MASK | NRF_RADIO_INT_CRCERROR_MASK;
322 }
323
324 /* Make sure all interrupts are disabled before we enable selectively */
325 nrf_radio_int_disable(NRF_RADIO, 0xFFFFFFFF);
326 NVIC_ClearPendingIRQ(RADIO_IRQn);
327
328 if(interrupts) {
329 nrf_radio_int_enable(NRF_RADIO, interrupts);
330 NVIC_EnableIRQ(RADIO_IRQn);
331 } else {
332 /* No radio interrupts required. Make sure they are all off at the NVIC */
333 NVIC_DisableIRQ(RADIO_IRQn);
334 }
335
336 critical_exit(stat);
337}
338/*---------------------------------------------------------------------------*/
339/*
340 * Set up timestamping with PPI:
341 * - Programme Channel 1 for RADIO->FRAMESTART--->TIMER0->CAPTURE[3]
342 * - Programme Channel 2 for RADIO->END--->TIMER0->CAPTURE[2]
343 */
344static void
345setup_ppi_timestamping(void)
346{
347 nrfx_gppi_channel_endpoints_setup(
348 NRF_PPI_FRAMESTART_CHANNEL,
349 nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_FRAMESTART),
350 nrf_timer_task_address_get(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3));
351 nrfx_gppi_channel_endpoints_setup(
352 NRF_PPI_END_CHANNEL,
353 nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_END),
354 nrf_timer_task_address_get(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE2));
355 nrfx_gppi_channels_enable(1uL << NRF_PPI_FRAMESTART_CHANNEL
356 | 1uL << NRF_PPI_END_CHANNEL);
357}
358/*---------------------------------------------------------------------------*/
359static void
360set_poll_mode(bool enable)
361{
362 rf_config.poll_mode = enable;
363 setup_interrupts();
364}
365/*---------------------------------------------------------------------------*/
366static void
367rx_buf_clear(void)
368{
369 memset(&rx_buf, 0, sizeof(rx_buf));
370}
371/*---------------------------------------------------------------------------*/
372static void
373rx_events_clear()
374{
375 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_FRAMESTART);
376 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_END);
377 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
378 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
379 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
380}
381/*---------------------------------------------------------------------------*/
382/*
383 * Powering off the peripheral will reset all registers to default values
384 * This function here must be called at every power on to set the radio in a
385 * known state
386 */
387static void
388configure(void)
389{
390 nrf_radio_mode_set(NRF_RADIO, NRF_RADIO_MODE_IEEE802154_250KBIT);
391
392 if(nrf53_errata_117()) {
393 *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084);
394 }
395
396 set_channel(rf_config.channel);
397
398 cca_reconfigure();
399
400 /* Initialise the CRC engine in .15.4 mode */
401 crc_init();
402
403 /* Initialise the packet format */
404 packet_init();
405
406 /*
407 * MODECNF: Fast ramp up, DTX=center
408 * The Nordic driver is using DTX=0, but this is against the PS (v1.1 p351)
409 */
410 nrf_radio_modecnf0_set(NRF_RADIO, true, RADIO_MODECNF0_DTX_Center);
411}
412/*---------------------------------------------------------------------------*/
413static void
414power_on_and_configure(void)
415{
416 radio_set_power(true);
417 configure();
418}
419/*---------------------------------------------------------------------------*/
420/*
421 * The caller must first make sure the radio is powered and configured.
422 *
423 * When we enter this function we can be in one of the following states:
424 * - STATE_RX: We were already in RX. Do nothing
425 * - STATE_RXIDLE: A reception just finished and we reverted to RXIDLE.
426 * We just need to send the START task.
427 * - STATE_TXIDLE: A TX just finished and we reverted to TXIDLE.
428 * We just need to send the START task.
429 * - STATE_DISABLED: We just turned on. We need to request radio rampup
430 */
431static void
432enter_rx(void)
433{
434 nrf_radio_state_t curr_state = nrf_radio_state_get(NRF_RADIO);
435
436 LOG_DBG("Enter RX, state=%u", curr_state);
437
438 /* Do nothing if we are already in RX */
439 if(curr_state == NRF_RADIO_STATE_RX) {
440 LOG_DBG_(". Was in RX");
441 LOG_DBG_("\n");
442 return;
443 }
444
445 /* Prepare the RX buffer */
446 nrf_radio_packetptr_set(NRF_RADIO, &rx_buf);
447
448 /* Initiate PPI timestamping */
449 setup_ppi_timestamping();
450
451 /* Make sure the correct interrupts are enabled */
452 setup_interrupts();
453
454 nrf_radio_shorts_enable(NRF_RADIO, NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK);
455 nrf_radio_shorts_enable(NRF_RADIO, NRF_RADIO_SHORT_RXREADY_START_MASK);
456
457 if(curr_state != NRF_RADIO_STATE_RXIDLE) {
458 /* Clear EVENTS_RXREADY and trigger RXEN (which will trigger START) */
459 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_RXREADY);
460 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RXEN);
461 } else {
462 /* Trigger the Start task */
463 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_START);
464 }
465
466 LOG_DBG_("--->%u\n", nrf_radio_state_get(NRF_RADIO));
467
468 LOG_DBG("PACKETPTR=0x%08" PRIx32 " (rx_buf @ 0x%08" PRIx32 ")\n",
469 (uint32_t)nrf_radio_packetptr_get(NRF_RADIO), (uint32_t)&rx_buf);
470}
471/*---------------------------------------------------------------------------*/
472/* Retrieve an RSSI sample. The radio must be in RX mode */
473static int8_t
474rssi_read(void)
475{
476 uint8_t rssi_sample;
477
478 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RSSISTART);
479
480 while(nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND) == false);
481 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND);
482
483 rssi_sample = radio_rssi_sample_get();
484
485 return -((int8_t)rssi_sample);
486}
487/*---------------------------------------------------------------------------*/
488/*
489 * Convert the hardware-reported LQI to 802.15.4 range using an 8-bit
490 * saturating multiplication by 4, as per the Product Spec.
491 */
492static uint8_t
493lqi_convert_to_802154_scale(uint8_t lqi_hw)
494{
495 return (uint8_t)lqi_hw > 63 ? 255 : lqi_hw *ED_RSSISCALE;
496}
497/*---------------------------------------------------------------------------*/
498/* Netstack API functions */
499/*---------------------------------------------------------------------------*/
500static int
501on(void)
502{
503 LOG_DBG("On\n");
504
505 if(radio_is_powered() == false) {
506 LOG_DBG("Not powered\n");
507 power_on_and_configure();
508 }
509
510 enter_rx();
511
512 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
513 return NRF_COMMAND_OK;
514}
515/*---------------------------------------------------------------------------*/
516static int
517channel_clear(void)
518{
519 bool busy, idle;
520
521 LOG_DBG("channel_clear\n");
522
523 on();
524
525 /* Clear previous CCA-related events, if any */
526 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
527 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
528 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCASTOPPED);
529
530 LOG_DBG("channel_clear: CCACTRL=0x%08" PRIx32 "\n", NRF_RADIO->CCACTRL);
531
532 /* We are now in RX. Send CCASTART */
533 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_CCASTART);
534
535 while((nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY) == false) &&
536 (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE) == false));
537
538 busy = nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
539 idle = nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
540
541 LOG_DBG("channel_clear: I=%u, B=%u\n", idle, busy);
542
543 if(busy) {
544 return NRF_CCA_BUSY;
545 }
546
547 return NRF_CCA_CLEAR;
548}
549/*---------------------------------------------------------------------------*/
550static int
551init(void)
552{
553 LOG_DBG("Init\n");
554
555 last_rssi = 0;
556 last_lqi = 0;
557
558 timestamps.sfd = 0;
559 timestamps.framestart = 0;
560 timestamps.end = 0;
561 timestamps.mpdu_duration = 0;
562 timestamps.phr = 0;
563
564 /* Request the HF clock */
565 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
566 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
567 while(!nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED));
568 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
569
570 /* Start the RF driver process */
571 process_start(&nrf_ieee_rf_process, NULL);
572
573 /* Prepare the RX buffer */
574 rx_buf_clear();
575
576 /* Power on the radio */
577 power_on_and_configure();
578
579 /* Set up initial state of poll mode. This will configure interrupts. */
580 set_poll_mode(rf_config.poll_mode);
581
582 return RADIO_TX_OK;
583}
584/*---------------------------------------------------------------------------*/
585static int
586prepare(const void *payload, unsigned short payload_len)
587{
588 LOG_DBG("Prepare %u bytes\n", payload_len);
589
590 if(payload_len > MAX_PAYLOAD_LEN) {
591 LOG_ERR("Too long: %u bytes, max %u\n", payload_len, MAX_PAYLOAD_LEN);
592 return RADIO_TX_ERR;
593 }
594
595 /* Populate the PHR. Packet length, including the FCS */
596 tx_buf.phr = (uint8_t)payload_len + FCS_LEN;
597
598 /* Copy the payload over */
599 memcpy(tx_buf.mpdu, payload, payload_len);
600
601 return RADIO_TX_OK;
602}
603/*---------------------------------------------------------------------------*/
604static int
605transmit(unsigned short transmit_len)
606{
607 int i;
608
609 LOG_DBG("TX %u bytes + FCS, channel=%u\n", transmit_len, get_channel());
610
611 if(transmit_len > MAX_PAYLOAD_LEN) {
612 LOG_ERR("TX: too long (%u bytes)\n", transmit_len);
613 return RADIO_TX_ERR;
614 }
615
616 on();
617
618 if(rf_config.send_on_cca) {
619 if(channel_clear() == NRF_CCA_BUSY) {
620 LOG_DBG("TX: Busy\n");
621 return RADIO_TX_COLLISION;
622 }
623 }
624
625 nrf_radio_txpower_set(NRF_RADIO, rf_config.txpower);
626
627 /* When we reach here we are in state RX. Send a STOP to drop to RXIDLE */
628 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_STOP);
629 while(nrf_radio_state_get(NRF_RADIO) != NRF_RADIO_STATE_RXIDLE);
630
631 LOG_DBG("Transmit: %u bytes=000000", tx_buf.phr);
632 for(i = 0; i < tx_buf.phr - 2; i++) {
633 LOG_DBG_(" %02x", tx_buf.mpdu[i]);
634 }
635 LOG_DBG_("\n");
636
637 LOG_DBG("TX Start. State %u", nrf_radio_state_get(NRF_RADIO));
638
639 /* Pointer to the TX buffer in PACKETPTR before task START */
640 nrf_radio_packetptr_set(NRF_RADIO, &tx_buf);
641
642 /* Clear TX-related events */
643 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_END);
644 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
645 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_TXREADY);
646
647 /* Start the transmission */
648 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
649
650 /* Enable the SHORT between TXREADY and START before triggering TXRU */
651 nrf_radio_shorts_enable(NRF_RADIO, NRF_RADIO_SHORT_TXREADY_START_MASK);
652 nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_TXEN);
653
654 /*
655 * With fast rampup, the transition between TX and READY (TXRU duration)
656 * takes 40us. This means we will be in TX mode in less than 3 rtimer ticks
657 * (3x16=42 us). After this duration, we can busy wait for TX to finish.
658 */
659 RTIMER_BUSYWAIT(TXRU_DURATION_TIMER);
660
661 /*
662 * The workaround for errata 91 is to wait 10us more during ramp-up
663 * (1x16 = 16us)
664 */
665 if(nrf53_errata_91()) {
667 }
668
669 LOG_DBG_("--->%u\n", nrf_radio_state_get(NRF_RADIO));
670
671 /* Wait for TX to complete */
672 while(nrf_radio_state_get(NRF_RADIO) == NRF_RADIO_STATE_TX);
673
674 LOG_DBG("TX: Done\n");
675
676 /*
677 * Enter RX.
678 * TX has finished and we are in state TXIDLE. enter_rx will handle the
679 * transition from any state to RX, so we don't need to do anything further
680 * here.
681 */
682 enter_rx();
683
684 /* We are now in RX */
685 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
686
687 return RADIO_TX_OK;
688}
689/*---------------------------------------------------------------------------*/
690static int
691send(const void *payload, unsigned short payload_len)
692{
693 prepare(payload, payload_len);
694 return transmit(payload_len);
695}
696/*---------------------------------------------------------------------------*/
697static int
698read_frame(void *buf, unsigned short bufsize)
699{
700 int payload_len;
701
702 /* Clear all events */
703 rx_events_clear();
704
705 payload_len = rx_buf.phr - FCS_LEN;
706
707 if(phr_is_valid(rx_buf.phr) == false) {
708 LOG_DBG("Incorrect length: %d\n", payload_len);
709 rx_buf_clear();
710 enter_rx();
711 return 0;
712 }
713
714 memcpy(buf, rx_buf.mpdu, payload_len);
715 last_lqi = lqi_convert_to_802154_scale(rx_buf.mpdu[payload_len]);
716 last_rssi = -(radio_rssi_sample_get());
717
718 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi);
719 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, last_lqi);
720
721 /* Latch timestamp values for this most recently received frame */
722 timestamps.phr = rx_buf.phr;
723 timestamps.framestart = nrf_timer_cc_get(NRF_TIMER0, NRF_TIMER_CC_CHANNEL3);
724 timestamps.end = nrf_timer_cc_get(NRF_TIMER0, NRF_TIMER_CC_CHANNEL2);
725 timestamps.mpdu_duration = rx_buf.phr * BYTE_DURATION_RTIMER;
726
727 /*
728 * Timestamp in rtimer ticks of the reception of the SFD. The SFD was
729 * received 1 byte before the PHR, therefore all we need to do is subtract
730 * 2 symbols (2 rtimer ticks) from the PPI FRAMESTART timestamp.
731 */
732 timestamps.sfd = timestamps.framestart - BYTE_DURATION_RTIMER;
733
734 LOG_DBG("Read frame: len=%d, RSSI=%d, LQI=0x%02x\n", payload_len, last_rssi,
735 last_lqi);
736
737 rx_buf_clear();
738 enter_rx();
739
740 return payload_len;
741}
742/*---------------------------------------------------------------------------*/
743static int
744receiving_packet(void)
745{
746 /* If we are powered off, we are not receiving */
747 if(radio_is_powered() == false) {
748 return NRF_RECEIVING_NO;
749 }
750
751 /* If our state is not RX, we are not receiving */
752 if(nrf_radio_state_get(NRF_RADIO) != NRF_RADIO_STATE_RX) {
753 return NRF_RECEIVING_NO;
754 }
755
756 if(rf_config.poll_mode) {
757 /* In poll mode, if the PHR is invalid we can return early */
758 if(phr_is_valid(rx_buf.phr) == false) {
759 return NRF_RECEIVING_NO;
760 }
761
762 /*
763 * If the PHR is valid and we are actually on, inspect EVENTS_CRCOK and
764 * _CRCERROR. If both of them are clear then reception is ongoing
765 */
766 if((nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK) == false) &&
767 (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR) == false)) {
768 return NRF_RECEIVING_YES;
769 }
770
771 return NRF_RECEIVING_NO;
772 }
773
774 /*
775 * In non-poll mode, we are receiving if the PHR is valid but the buffer
776 * does not contain a full packet.
777 */
778 if(phr_is_valid(rx_buf.phr) == true && rx_buf.full == false) {
779 return NRF_RECEIVING_YES;
780 }
781 return NRF_RECEIVING_NO;
782}
783/*---------------------------------------------------------------------------*/
784static int
785pending_packet(void)
786{
787 /*
788 * First check if we have received a PHR. When we enter RX the value of the
789 * PHR in our RX buffer is zero so we can return early.
790 */
791 if(phr_is_valid(rx_buf.phr) == false) {
792 return NRF_PENDING_NO;
793 }
794
795 /*
796 * We have received a valid PHR. Either we are in the process of receiving
797 * a frame, or we have fully received one. If we have received a frame then
798 * EVENTS_CRCOK should be asserted. In poll mode that's enough. In non-poll
799 * mode the interrupt handler will clear the event (else the interrupt would
800 * fire again), but we save the state in rx_buf.full.
801 */
802 if((nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK) == true) ||
803 (rx_buf.full == true)) {
804 return NRF_PENDING_YES;
805 }
806
807 return NRF_PENDING_NO;
808}
809/*---------------------------------------------------------------------------*/
810static int
811off(void)
812{
813 radio_set_power(false);
814
815 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
816
817 return NRF_COMMAND_OK;
818}
819/*---------------------------------------------------------------------------*/
820static radio_result_t
821get_value(radio_param_t param, radio_value_t *value)
822{
823 if(!value) {
825 }
826
827 switch(param) {
829 return RADIO_RESULT_OK;
831 *value = (radio_value_t)get_channel();
832 return RADIO_RESULT_OK;
834 *value = 0;
835 if(rf_config.poll_mode) {
836 *value |= RADIO_RX_MODE_POLL_MODE;
837 }
838 return RADIO_RESULT_OK;
840 *value = 0;
841 if(rf_config.send_on_cca) {
843 }
844 return RADIO_RESULT_OK;
846 *value = (radio_value_t)rf_config.txpower;
847 return RADIO_RESULT_OK;
849 *value = (radio_value_t)rf_config.cca_corr_threshold;
850 return RADIO_RESULT_OK;
851 case RADIO_PARAM_RSSI:
852 *value = (radio_value_t)rssi_read();
853 return RADIO_RESULT_OK;
855 *value = (radio_value_t)last_rssi;
856 return RADIO_RESULT_OK;
858 *value = (radio_value_t)last_lqi;
859 return RADIO_RESULT_OK;
861 *value = 11;
862 return RADIO_RESULT_OK;
864 *value = 26;
865 return RADIO_RESULT_OK;
867 *value = (radio_value_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
868 return RADIO_RESULT_OK;
870#if defined(RADIO_TXPOWER_TXPOWER_Pos8dBm)
871 *value = (radio_value_t)RADIO_TXPOWER_TXPOWER_Pos8dBm;
872#else
873 *value = (radio_value_t)RADIO_TXPOWER_TXPOWER_0dBm;
874#endif
875 return RADIO_RESULT_OK;
877 *value = (radio_value_t)RADIO_PHY_OVERHEAD;
878 return RADIO_RESULT_OK;
880 *value = (radio_value_t)RADIO_BYTE_AIR_TIME;
881 return RADIO_RESULT_OK;
883 *value = (radio_value_t)RADIO_DELAY_BEFORE_TX;
884 return RADIO_RESULT_OK;
886 *value = (radio_value_t)RADIO_DELAY_BEFORE_RX;
887 return RADIO_RESULT_OK;
889 *value = (radio_value_t)RADIO_DELAY_BEFORE_DETECT;
890 return RADIO_RESULT_OK;
891 case RADIO_CONST_MAX_PAYLOAD_LEN:
892 *value = (radio_value_t)MAX_PAYLOAD_LEN;
893 return RADIO_RESULT_OK;
896 default:
898 }
899}
900/*---------------------------------------------------------------------------*/
901static radio_result_t
902set_value(radio_param_t param, radio_value_t value)
903{
904 switch(param) {
906 if(value == RADIO_POWER_MODE_ON) {
907 on();
908 return RADIO_RESULT_OK;
909 }
910 if(value == RADIO_POWER_MODE_OFF) {
911 off();
912 return RADIO_RESULT_OK;
913 }
916 if(value < NRF_CHANNEL_MIN ||
917 value > NRF_CHANNEL_MAX) {
919 }
920 rf_config.channel = value;
921
922 /* If we are powered on, apply immediately. */
923 if(radio_is_powered()) {
924 off();
925 set_channel(value);
926 on();
927 }
928 return RADIO_RESULT_OK;
930 if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
934 }
935
936 set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
937
938 return RADIO_RESULT_OK;
940 if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
942 }
943
944 rf_config.send_on_cca = (value & RADIO_TX_MODE_SEND_ON_CCA) != 0;
945 return RADIO_RESULT_OK;
947 rf_config.txpower = value;
948 /* If we are powered on, apply immediately. */
949 if(radio_is_powered()) {
950 nrf_radio_txpower_set(NRF_RADIO, value);
951 }
952 return RADIO_RESULT_OK;
954 rf_config.cca_corr_threshold = value;
955 /* If we are powered on, apply immediately. */
956 if(radio_is_powered()) {
957 cca_reconfigure();
958 }
959 return RADIO_RESULT_OK;
960
964 default:
966 }
967}
968/*---------------------------------------------------------------------------*/
969static radio_result_t
970get_object(radio_param_t param, void *dest, size_t size)
971{
973 if(size != sizeof(rtimer_clock_t) || !dest) {
975 }
976 *(rtimer_clock_t *)dest = timestamps.sfd;
977 return RADIO_RESULT_OK;
978 }
979
980#if MAC_CONF_WITH_TSCH
981 if(param == RADIO_CONST_TSCH_TIMING) {
982 if(size != sizeof(uint16_t *) || !dest) {
984 }
985 /* Assigned value: a pointer to the TSCH timing in usec */
986 *(const uint16_t **)dest = tsch_timeslot_timing_us_10000;
987 return RADIO_RESULT_OK;
988 }
989#endif /* MAC_CONF_WITH_TSCH */
990
991 /* The radio does not support h/w frame filtering based on addresses */
993}
994/*---------------------------------------------------------------------------*/
995static radio_result_t
996set_object(radio_param_t param, const void *src, size_t size)
997{
998 /* The radio does not support h/w frame filtering based on addresses */
1000}
1001/*---------------------------------------------------------------------------*/
1002const struct radio_driver nrf_ieee_driver = {
1003 init,
1004 prepare,
1005 transmit,
1006 send,
1007 read_frame,
1011 on,
1012 off,
1013 get_value,
1014 set_value,
1015 get_object,
1017};
1018/*---------------------------------------------------------------------------*/
1019PROCESS_THREAD(nrf_ieee_rf_process, ev, data)
1020{
1021 int len;
1022 PROCESS_BEGIN();
1023
1024 while(1) {
1025 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
1026
1027 LOG_DBG("Polled\n");
1028
1029 if(pending_packet()) {
1032 len = read_frame(packetbuf_dataptr(), PACKETBUF_SIZE);
1033 if(len > 0) {
1035 NETSTACK_MAC.input();
1036 LOG_DBG("last frame (%u bytes) timestamps:\n", timestamps.phr);
1037 LOG_DBG(" SFD=%" PRIu32 " (Derived)\n", timestamps.sfd);
1038 LOG_DBG(" PHY=%" PRIu32 " (PPI)\n", timestamps.framestart);
1039 LOG_DBG(" MPDU=%" PRIu32 " (Duration)\n", timestamps.mpdu_duration);
1040 LOG_DBG(" END=%" PRIu32 " (PPI)\n", timestamps.end);
1041 LOG_DBG(" Expected=%" PRIu32 " + %u + %" PRIu32 " = %" PRIu32 "\n",
1042 timestamps.sfd, BYTE_DURATION_RTIMER, timestamps.mpdu_duration,
1043 timestamps.sfd + BYTE_DURATION_RTIMER + timestamps.mpdu_duration);
1044 }
1045 }
1046 }
1047
1048 PROCESS_END();
1049}
1050/*---------------------------------------------------------------------------*/
1051void
1052RADIO_IRQHandler(void)
1053{
1054 if(!rf_config.poll_mode) {
1055 if(nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK)) {
1056 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
1057 rx_buf.full = true;
1058 process_poll(&nrf_ieee_rf_process);
1059 } else if(nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR)) {
1060 nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
1061 rx_buf_clear();
1062 enter_rx();
1063 }
1064 }
1065}
1066/*---------------------------------------------------------------------------*/
1067
1068#endif /* NRF_RADIO */
1069
1070/*---------------------------------------------------------------------------*/
1071/**
1072 * @}
1073 * @}
1074 * @}
1075 */
Header file for the energy estimation mechanism.
static uint8_t get_channel()
Get the current operating channel.
Definition: cc2538-rf.c:166
static void set_channel(uint8_t channel)
Set the current operating channel.
Definition: cc2538-rf.c:176
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
static void critical_exit(int_master_status_t status)
Exit a critical section and restore the master interrupt.
Definition: critical.h:81
static int_master_status_t critical_enter()
Enter a critical section.
Definition: critical.h:65
INT_MASTER_STATUS_DATATYPE int_master_status_t
Master interrupt state representation data type.
Definition: int-master.h:62
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
Definition: radio.h:451
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Definition: radio.h:461
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition: radio.h:474
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
Definition: radio.h:88
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
Definition: radio.h:456
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
Definition: radio.h:481
@ RADIO_RESULT_INVALID_VALUE
The value argument was incorrect.
Definition: radio.h:482
@ RADIO_RESULT_OK
The parameter was set/read successfully.
Definition: radio.h:480
@ RADIO_PARAM_POWER_MODE
When getting the value of this parameter, the radio driver should indicate whether the radio is on or...
Definition: radio.h:119
@ RADIO_CONST_PHY_OVERHEAD
The physical layer header (PHR) + MAC layer footer (MFR) overhead in bytes.
Definition: radio.h:338
@ RADIO_PARAM_RSSI
Received signal strength indicator in dBm.
Definition: radio.h:218
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
Definition: radio.h:286
@ RADIO_PARAM_LAST_RSSI
The RSSI value of the last received packet.
Definition: radio.h:226
@ RADIO_CONST_BYTE_AIR_TIME
The air time of one byte in usec, e.g.
Definition: radio.h:343
@ RADIO_PARAM_RX_MODE
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
Definition: radio.h:173
@ RADIO_PARAM_CHANNEL
Channel used for radio communication.
Definition: radio.h:134
@ RADIO_PARAM_SHR_SEARCH
For enabling and disabling the SHR search.
Definition: radio.h:304
@ RADIO_PARAM_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
Definition: radio.h:244
@ RADIO_CONST_DELAY_BEFORE_RX
The delay in usec between turning on the radio and it being actually listening (able to hear a preamb...
Definition: radio.h:355
@ RADIO_PARAM_TXPOWER
Transmission power in dBm.
Definition: radio.h:192
@ RADIO_CONST_DELAY_BEFORE_TX
The delay in usec between a call to the radio API's transmit function and the end of SFD transmission...
Definition: radio.h:349
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
Definition: radio.h:316
@ RADIO_PARAM_PAN_ID
The personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
Definition: radio.h:150
@ RADIO_PARAM_CCA_THRESHOLD
Clear channel assessment threshold in dBm.
Definition: radio.h:205
@ RADIO_CONST_TXPOWER_MIN
The minimum transmission power in dBm.
Definition: radio.h:321
@ RADIO_CONST_CHANNEL_MIN
The lowest radio channel number.
Definition: radio.h:311
@ RADIO_CONST_TXPOWER_MAX
The maximum transmission power in dBm.
Definition: radio.h:326
@ RADIO_CONST_DELAY_BEFORE_DETECT
The delay in usec between the end of SFD reception for an incoming frame and the radio API starting t...
Definition: radio.h:361
@ RADIO_PARAM_16BIT_ADDR
The short address (16 bits) for the radio, which is used by the h/w filter.
Definition: radio.h:166
@ RADIO_PARAM_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
Definition: radio.h:180
@ RADIO_POWER_MODE_OFF
Radio powered off and in the lowest possible power consumption state.
Definition: radio.h:395
@ RADIO_POWER_MODE_ON
Radio powered on and able to receive frames.
Definition: radio.h:400
@ RADIO_TX_COLLISION
TX failed due to a collision.
Definition: radio.h:511
@ RADIO_TX_ERR
An error occurred during transmission.
Definition: radio.h:506
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
Definition: radio.h:498
#define RTIMER_BUSYWAIT(duration)
Busy-wait for a fixed duration.
Definition: rtimer.h:218
const tsch_timeslot_timing_usec tsch_timeslot_timing_us_10000
TSCH timing attributes and description.
Header file for the logging system.
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
Definition: mac.h:52
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the radio API.
void(* input)(void)
Callback for getting notified of incoming packet.
Definition: mac.h:72
The structure of a Contiki-NG radio device driver.
Definition: radio.h:534
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:770
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
Definition: radio.h:580
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:756
int(* off)(void)
Turn the radio off.
Definition: radio.h:729
int(* init)(void)
Initialise the radio hardware.
Definition: radio.h:555
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
Definition: radio.h:631
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:684
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:787
int(* on)(void)
Turn the radio on.
Definition: radio.h:711
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Definition: radio.h:619
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
Definition: radio.h:697
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:741
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not.
Definition: radio.h:672
Main API declarations for TSCH.