Contiki-NG
Loading...
Searching...
No Matches
prop-mode.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/**
31 * \addtogroup cc13xx-cc26xx-rf
32 * @{
33 *
34 * \defgroup cc13xx-cc26xx-rf-prop Prop-mode driver for CC13xx/CC26xx
35 *
36 * @{
37 *
38 * \file
39 * Implementation of the CC13xx/CC26xx prop-mode NETSTACK_RADIO driver.
40 * \author
41 * Edvard Pettersen <e.pettersen@ti.com>
42 */
43/*---------------------------------------------------------------------------*/
44#include "contiki.h"
45#include "net/packetbuf.h"
46#include "net/netstack.h"
47#include "sys/energest.h"
48#include "sys/clock.h"
49#include "sys/rtimer.h"
50#include "sys/cc.h"
51#include "dev/watchdog.h"
52/*---------------------------------------------------------------------------*/
53/* RF Core Mailbox API */
54#include <ti/devices/DeviceFamily.h>
55#include DeviceFamily_constructPath(driverlib/rf_mailbox.h)
56#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h)
57#include DeviceFamily_constructPath(driverlib/rf_data_entry.h)
58#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h)
59#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
60
61#include <ti/drivers/rf/RF.h>
62#include DeviceFamily_constructPath(inc/hw_rfc_dbell.h)
63#include DeviceFamily_constructPath(driverlib/rfc.h)
64/*---------------------------------------------------------------------------*/
65/* Platform RF dev */
66#include "rf/rf.h"
67#include "rf/dot-15-4g.h"
68#include "rf/sched.h"
69#include "rf/data-queue.h"
70#include "rf/tx-power.h"
71#include "rf/settings.h"
72#include "rf/rat.h"
73#include "rf/radio-mode.h"
74/*---------------------------------------------------------------------------*/
75#include <inttypes.h>
76#include <stdint.h>
77#include <string.h>
78#include <stdio.h>
79#include <stdbool.h>
80#include <assert.h>
81/*---------------------------------------------------------------------------*/
82#if RADIO_PAYLOAD_BIT_REVERSE
83#include "lib/bitrev.h"
84#endif
85/*---------------------------------------------------------------------------*/
86/* Log configuration */
87#include "sys/log.h"
88#define LOG_MODULE "Radio"
89#define LOG_LEVEL LOG_LEVEL_NONE
90/*---------------------------------------------------------------------------*/
91#undef CLAMP
92#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin))
93/*---------------------------------------------------------------------------*/
94/* Configuration parameters */
95#define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW
96#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16
97#define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ
98#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER
99#define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD
100/*---------------------------------------------------------------------------*/
101/* Used for checking result of CCA_REQ command */
102typedef enum {
103 CCA_STATE_IDLE = 0,
104 CCA_STATE_BUSY = 1,
105 CCA_STATE_INVALID = 2
106} cca_state_t;
107/*---------------------------------------------------------------------------*/
108#if MAC_CONF_WITH_TSCH
109static volatile uint8_t is_receiving_packet;
110#endif
111/*---------------------------------------------------------------------------*/
112/* Defines and variables related to the .15.4g PHY HDR */
113#define DOT_4G_PHR_NUM_BYTES 2
114#define DOT_4G_LEN_OFFSET 0xFC
115#define DOT_4G_SYNCWORD 0x0055904E
116
117/* PHY HDR bits */
118#define DOT_4G_PHR_CRC16 0x10
119#define DOT_4G_PHR_DW 0x08
120
121#if PROP_MODE_USE_CRC16
122/* CRC16 */
123#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16
124#define CRC_LEN 2
125#else
126/* CRC32 */
127#define DOT_4G_PHR_CRC_BIT 0
128#define CRC_LEN 4
129#endif /* PROP_MODE_USE_CRC16 */
130
131#if PROP_MODE_DYN_WHITENER
132#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW
133#else
134#define DOT_4G_PHR_DW_BIT 0
135#endif
136/*---------------------------------------------------------------------------*/
137/*
138 * The maximum number of bytes this driver can accept from the MAC layer for
139 * transmission or will deliver to the MAC layer after reception. Includes
140 * the MAC header and payload, but not the CRC.
141 *
142 * Unlike typical 2.4GHz radio drivers, this driver supports the .15.4g
143 * 32-bit CRC option.
144 *
145 * This radio hardware is perfectly happy to transmit frames longer than 127
146 * bytes, which is why it's OK to end up transmitting 125 payload bytes plus
147 * a 4-byte CRC.
148 *
149 * In the future we can change this to support transmission of long frames,
150 * for example as per .15.4g, which defines 2047 as the maximum frame size.
151 * The size of the TX and RX buffers would need to be adjusted accordingly.
152 */
153#define MAX_PAYLOAD_LEN 125
154/*---------------------------------------------------------------------------*/
155/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */
156#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10)
157
158/*---------------------------------------------------------------------------*/
159/*
160 * Offset of the end of SFD when compared to the radio HW-generated timestamp.
161 */
162#define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(RADIO_PHY_HEADER_LEN * RADIO_BYTE_AIR_TIME - 270)
163/*---------------------------------------------------------------------------*/
164/* TX buf configuration */
165#define TX_BUF_HDR_LEN 2
166#define TX_BUF_PAYLOAD_LEN 180
167
168#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN)
169/*---------------------------------------------------------------------------*/
170/* Size of the Length field in Data Entry, two bytes in this case */
171typedef uint16_t lensz_t;
172
173#define FRAME_OFFSET sizeof(lensz_t)
174#define FRAME_SHAVE 6 /**< RSSI (1) + Timestamp (4) + Status (1) */
175/*---------------------------------------------------------------------------*/
176/* Constants used when calculating the LQI from the RSSI */
177#define RX_SENSITIVITY_DBM -110
178#define RX_SATURATION_DBM 10
179#define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10
180#define ED_MAX 0xFF
181
182#define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY)
183#define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM
184/*---------------------------------------------------------------------------*/
185/* RF Core typedefs */
186typedef rfc_propRxOutput_t rx_output_t;
187
188typedef struct {
189 /* RF driver */
190 RF_Handle rf_handle;
191
192 /* Are we currently in poll mode? */
193 bool poll_mode;
194
195 /* RAT Overflow Upkeep */
196 struct {
197 struct ctimer overflow_timer;
198 rtimer_clock_t last_overflow;
199 volatile uint32_t overflow_count;
200 } rat;
201
202 bool (* rx_is_active)(void);
203
204 /* Outgoing frame buffer */
205 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
206
207 /* RX Statistics struct */
208 rx_output_t rx_stats;
209
210 /* RSSI Threshold */
211 int8_t rssi_threshold;
212 uint16_t channel;
213
214 /* Indicates RF is supposed to be on or off */
215 uint8_t rf_is_on;
216 /* Enable/disable CCA before sending */
217 bool send_on_cca;
218
219 /* Last RX operation stats */
220 struct {
221 int8_t rssi;
222 uint8_t corr_lqi;
223 uint32_t timestamp;
224 } last;
225} prop_radio_t;
226
227static prop_radio_t prop_radio;
228
229/*---------------------------------------------------------------------------*/
230/* Convenience macros for more succinct access of RF commands */
231#define cmd_radio_setup rf_cmd_prop_radio_div_setup
232#define cmd_fs rf_cmd_prop_fs
233#define cmd_tx rf_cmd_prop_tx_adv
234#define cmd_rx rf_cmd_prop_rx_adv
235
236/* Convenience macros for volatile access with the RF commands */
237#define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_PROP_RADIO_DIV_SETUP_t, rf_cmd_prop_radio_div_setup)
238#define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_prop_fs)
239#define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_PROP_TX_ADV_t, rf_cmd_prop_tx_adv)
240#define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_PROP_RX_ADV_t, rf_cmd_prop_rx_adv)
241/*---------------------------------------------------------------------------*/
242static inline bool
243tx_is_active(void)
244{
245 return v_cmd_tx.status == ACTIVE;
246}
247/*---------------------------------------------------------------------------*/
248static inline bool
249rx_is_active(void)
250{
251 return v_cmd_rx.status == ACTIVE;
252}
253/*---------------------------------------------------------------------------*/
254static int channel_clear(void);
255static int on(void);
256static int off(void);
257static rf_result_t set_channel_force(uint16_t channel);
258/*---------------------------------------------------------------------------*/
259static void
260init_rf_params(void)
261{
262 cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
263 cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
264 cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
265 cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
266
267 cmd_tx.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
268 cmd_tx.syncWord = DOT_4G_SYNCWORD;
269
270 cmd_rx.syncWord0 = DOT_4G_SYNCWORD;
271 cmd_rx.syncWord1 = 0x00000000;
272 cmd_rx.maxPktLen = RADIO_PHY_OVERHEAD + MAX_PAYLOAD_LEN;
273 cmd_rx.hdrConf.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
274 cmd_rx.lenOffset = DOT_4G_LEN_OFFSET;
275 cmd_rx.pQueue = data_queue_init(sizeof(lensz_t));
276 cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
277}
278/*---------------------------------------------------------------------------*/
279static int8_t
280get_rssi(void)
281{
282 rf_result_t res;
283 bool stop_rx = false;
284 int8_t rssi = RF_GET_RSSI_ERROR_VAL;
285
286 /* RX is required to be running in order to do a RSSI measurement */
287 if(!rx_is_active()) {
288 /* If RX is not pending, i.e. soon to be running, schedule the RX command */
289 if(v_cmd_rx.status != PENDING) {
290 res = netstack_sched_rx(false);
291 if(res != RF_RESULT_OK) {
292 LOG_ERR("RSSI measurement failed to schedule RX\n");
293 return res;
294 }
295
296 /* We only stop RX if we had to schedule it */
297 stop_rx = true;
298 }
299
300 /* Make sure RX is running before we continue, unless we timeout and fail */
301 RTIMER_BUSYWAIT_UNTIL(rx_is_active(), TIMEOUT_ENTER_RX_WAIT);
302
303 if(!rx_is_active()) {
304 LOG_ERR("RSSI measurement failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
305 return RF_RESULT_ERROR;
306 }
307 }
308
309 /* Perform the RSSI measurement */
310 rssi = RF_getRssi(prop_radio.rf_handle);
311
312 if(stop_rx) {
313 netstack_stop_rx();
314 }
315
316 return rssi;
317}
318/*---------------------------------------------------------------------------*/
319static uint8_t
320get_channel(void)
321{
322 uint32_t freq_khz = v_cmd_fs.frequency * 1000;
323
324 /*
325 * For some channels, fractFreq * 1000 / 65536 will return 324.99xx.
326 * Casting the result to uint32_t will truncate decimals resulting in the
327 * function returning channel - 1 instead of channel. Thus, we do a quick
328 * positive integer round up.
329 */
330 freq_khz += (((v_cmd_fs.fractFreq * 1000) + 65535) / 65536);
331
332 return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
333}
334/*---------------------------------------------------------------------------*/
335static rf_result_t
336set_channel(uint16_t channel)
337{
338 if(!dot_15_4g_chan_in_range(channel)) {
339 LOG_WARN("Supplied hannel %d is illegal, defaults to %d\n",
340 (int)channel, DOT_15_4G_DEFAULT_CHAN);
341 channel = DOT_15_4G_DEFAULT_CHAN;
342 }
343
344 if(channel == prop_radio.channel) {
345 /* We are already calibrated to this channel */
346 return RF_RESULT_OK;
347 }
348
349 return set_channel_force(channel);
350}
351/*---------------------------------------------------------------------------*/
352/* Sets the given channel without checking if it is a valid channel number. */
353static rf_result_t
354set_channel_force(uint16_t channel)
355{
356 rf_result_t res;
357
358 if(prop_radio.rf_is_on) {
359 /* Force RAT and RTC resync */
360 rf_restart_rat();
361 }
362
363 const uint32_t new_freq = dot_15_4g_freq(channel);
364 const uint16_t freq = (uint16_t)(new_freq / 1000);
365 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
366
367 LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%" PRIu32 ")\n",
368 (int)channel, freq, frac, new_freq);
369
370 v_cmd_fs.frequency = freq;
371 v_cmd_fs.fractFreq = frac;
372
373 res = netstack_sched_fs();
374
375 if(res != RF_RESULT_OK) {
376 return res;
377 }
378
379 prop_radio.channel = channel;
380 return RF_RESULT_OK;
381}
382/*---------------------------------------------------------------------------*/
383static uint8_t
384calculate_lqi(int8_t rssi)
385{
386 /*
387 * Note : Currently the LQI value is simply the energy detect measurement.
388 * A more accurate value could be derived by using the correlation
389 * value along with the RSSI value.
390 */
391 rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
392
393 /*
394 * Create energy detect measurement by normalizing and scaling RF power level.
395 * Note : The division operation below is designed for maximum accuracy and
396 * best granularity. This is done by grouping the math operations to
397 * compute the entire numerator before doing any division.
398 */
399 return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
400}
401/*---------------------------------------------------------------------------*/
402static void
403set_send_on_cca(bool enable)
404{
405 prop_radio.send_on_cca = enable;
406}
407/*---------------------------------------------------------------------------*/
408static int
409prepare(const void *payload, unsigned short payload_len)
410{
411 if(payload_len > TX_BUF_PAYLOAD_LEN || payload_len > MAX_PAYLOAD_LEN) {
412 return RADIO_TX_ERR;
413 }
414
415 memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, payload_len);
416
417 /* Bit reverse payload for 802.15.4g compliance */
418#if RADIO_PAYLOAD_BIT_REVERSE
419 bitrev_array(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload_len);
420#endif
421 return 0;
422}
423/*---------------------------------------------------------------------------*/
424static int
425transmit(unsigned short transmit_len)
426{
427 rf_result_t res;
428
429 if(transmit_len > MAX_PAYLOAD_LEN) {
430 LOG_ERR("Too long\n");
431 return RADIO_TX_ERR;
432 }
433
434 if(tx_is_active()) {
435 LOG_ERR("A transmission is already active\n");
436 return RADIO_TX_ERR;
437 }
438
439 if(prop_radio.send_on_cca && !channel_clear()) {
440 LOG_WARN("Channel is not clear for transmission\n");
441 return RADIO_TX_COLLISION;
442 }
443
444 /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */
445 const uint16_t total_length = transmit_len + CRC_LEN;
446 /*
447 * Prepare the .15.4g PHY header
448 * MS=0, Length MSBits=0, DW and CRC configurable
449 * Total length = transmit_len (payload) + CRC length
450 *
451 * The Radio will flip the bits around, so tx_buf[0] must have the length
452 * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0]
453 */
454 prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
455 prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
456
457 /* pktLen: Total number of bytes in the TX buffer, including the header if
458 * one exists, but not including the CRC (which is not present in the buffer) */
459 v_cmd_tx.pktLen = transmit_len + DOT_4G_PHR_NUM_BYTES;
460 v_cmd_tx.pPkt = prop_radio.tx_buf;
461
462 res = netstack_sched_prop_tx(transmit_len);
463
464 if(res != RF_RESULT_OK) {
465 LOG_WARN("Channel is not clear for transmission\n");
466 return RADIO_TX_ERR;
467 }
468
469 return (res == RF_RESULT_OK)
471 : RADIO_TX_ERR;
472}
473/*---------------------------------------------------------------------------*/
474static int
475send(const void *payload, unsigned short payload_len)
476{
477 prepare(payload, payload_len);
478 return transmit(payload_len);
479}
480/*---------------------------------------------------------------------------*/
481static int
482read(void *buf, unsigned short buf_len)
483{
484 volatile data_entry_t *data_entry = data_queue_current_entry();
485
486 /* Only wait if the Radio is accessing the entry */
487 const rtimer_clock_t t0 = RTIMER_NOW();
488 while((data_entry->status == DATA_ENTRY_BUSY) &&
489 RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + RADIO_FRAME_DURATION(MAX_PAYLOAD_LEN)));
490
491#if MAC_CONF_WITH_TSCH
492 /* Make sure the flag is reset */
493 is_receiving_packet = 0;
494#endif
495
496 if(data_entry->status != DATA_ENTRY_FINISHED) {
497 /* No available data */
498 return 0;
499 }
500
501 /*
502 * lensz bytes (2) in the data entry are the length of the received frame.
503 * Data frame is on the following format:
504 * Length (2) + Payload (N) + RSSI (1) + Timestamp (4) + Status (1)
505 * Data frame DOES NOT contain the following:
506 * no Header/PHY bytes
507 * no appended Received CRC bytes
508 * Visual representation of frame format:
509 *
510 * +---------+---------+--------+-----------+--------+
511 * | 2 bytes | N bytes | 1 byte | 4 bytes | 1 byte |
512 * +---------+---------+--------+-----------+--------+
513 * | Length | Payload | RSSI | Timestamp | Status |
514 * +---------+---------+--------+-----------+--------+
515 *
516 * Length bytes equal total length of entire frame excluding itself,
517 * Length = N + RSSI (1) + Timestamp (4) + Status (1)
518 * = N + 6
519 * N = Length - 6
520 */
521 uint8_t *const frame_ptr = (uint8_t *)&data_entry->data;
522 const lensz_t frame_len = *(lensz_t *)frame_ptr;
523
524 /* Sanity check that Frame is at least Frame Shave bytes long */
525 if(frame_len < FRAME_SHAVE) {
526 LOG_ERR("Received frame is too short, len=%d\n", frame_len);
527
528 data_queue_release_entry();
529 return 0;
530 }
531
532 const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t);
533 const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE);
534
535 /* Sanity check that Payload fits in Buffer */
536 if(payload_len > buf_len) {
537 LOG_ERR("Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
538 payload_len, buf_len);
539
540 data_queue_release_entry();
541 return 0;
542 }
543
544 memcpy(buf, payload_ptr, payload_len);
545
546 /* Bit reverse payload for 802.15.4g compliance */
547#if RADIO_PAYLOAD_BIT_REVERSE
548 bitrev_array(buf, payload_len);
549#endif
550
551 /* RSSI stored after payload */
552 prop_radio.last.rssi = (int8_t)payload_ptr[payload_len];
553 /* LQI calculated from RSSI */
554 prop_radio.last.corr_lqi = calculate_lqi(prop_radio.last.rssi);
555 /* Timestamp stored RSSI (1) bytes after payload. */
556 uint32_t rat_ticks;
557 memcpy(&rat_ticks, payload_ptr + payload_len + 1, 4);
558
559 /* Correct timestamp so that it refers to the end of the SFD */
560 prop_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
561
562 if(!prop_radio.poll_mode) {
563 /* Not in poll mode: packetbuf should not be accessed in interrupt context. */
564 /* In poll mode, the last packet RSSI and link quality can be obtained through */
565 /* RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */
566 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)prop_radio.last.rssi);
567 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)prop_radio.last.corr_lqi);
568 }
569
570 data_queue_release_entry();
571 return (int)payload_len;
572}
573/*---------------------------------------------------------------------------*/
574static uint8_t
575cca_request(void)
576{
577 const int8_t rssi = get_rssi();
578
579 if(rssi == RF_GET_RSSI_ERROR_VAL) {
580 return CCA_STATE_INVALID;
581 }
582
583 return (rssi < prop_radio.rssi_threshold)
584 ? CCA_STATE_IDLE
585 : CCA_STATE_BUSY;
586}
587/*---------------------------------------------------------------------------*/
588static int
589channel_clear(void)
590{
591 if(tx_is_active()) {
592 LOG_ERR("Channel clear called while in TX\n");
593 return 0;
594 }
595
596 const uint8_t cca_state = cca_request();
597
598 /* Channel is clear if CCA state is IDLE */
599 return cca_state == CCA_STATE_IDLE;
600}
601/*---------------------------------------------------------------------------*/
602static int
603receiving_packet(void)
604{
605 if(!prop_radio.rf_is_on) {
606 return 0;
607 }
608
609#if MAC_CONF_WITH_TSCH
610 /*
611 * Under TSCH operation, we rely on "hints" from the MDMSOFT interrupt
612 * flag. This flag is set by the radio upon sync word detection, but it is
613 * not cleared automatically by hardware. We store state in a variable after
614 * first call. The assumption is that the TSCH code will keep calling us
615 * until frame reception has completed, at which point we can clear MDMSOFT.
616 */
617 if(!is_receiving_packet) {
618 /* Look for the modem synchronization word detection interrupt flag.
619 * This flag is raised when the synchronization word is received.
620 */
621 if(HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIFG) & RFC_DBELL_RFHWIFG_MDMSOFT) {
622 is_receiving_packet = 1;
623 }
624 } else {
625 /* After the start of the packet: reset the Rx flag once the channel gets clear */
626 is_receiving_packet = (cca_request() == CCA_STATE_BUSY);
627 if(!is_receiving_packet) {
628 /* Clear the modem sync flag */
629 RFCHwIntClear(RFC_DBELL_RFHWIFG_MDMSOFT);
630 }
631 }
632
633 return is_receiving_packet;
634#else
635 /*
636 * Under CSMA operation, there is no immediately straightforward logic as to
637 * when it's OK to clear the MDMSOFT interrupt flag:
638 *
639 * - We cannot re-use the same logic as above, since CSMA may bail out of
640 * frame TX immediately after a single call this function here. In this
641 * scenario, is_receiving_packet would remain equal to one and we would
642 * therefore erroneously signal ongoing RX in subsequent calls to this
643 * function here, even _after_ reception has completed.
644 * - We can neither clear inside read_frame() nor inside the RX frame
645 * interrupt handler (remember, we are not in poll mode under CSMA),
646 * since we risk clearing MDMSOFT after we have seen a sync word for the
647 * _next_ frame. If this happens, this function here would incorrectly
648 * return 0 during RX of this next frame.
649 *
650 * So to avoid a very convoluted logic of how to handle MDMSOFT, we simply
651 * perform a clear channel assessment here: We interpret channel activity
652 * as frame reception.
653 */
654
655 if(cca_request() == CCA_STATE_BUSY) {
656 return 1;
657 }
658
659 return 0;
660
661#endif
662}
663/*---------------------------------------------------------------------------*/
664static int
665pending_packet(void)
666{
667 const data_entry_t *const read_entry = data_queue_current_entry();
668 volatile const data_entry_t *curr_entry = read_entry;
669
670 int num_pending = 0;
671
672 /* Go through RX Circular buffer and check their status */
673 do {
674 const uint8_t status = curr_entry->status;
675 if((status == DATA_ENTRY_FINISHED) ||
676 (status == DATA_ENTRY_BUSY)) {
677 num_pending += 1;
678 }
679
680 /* Stop when we have looped the circular buffer */
681 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
682 } while(curr_entry != read_entry);
683
684 if(num_pending > 0 && !prop_radio.poll_mode) {
685 process_poll(&rf_sched_process);
686 }
687
688 /* If we didn't find an entry at status finished, no frames are pending */
689 return num_pending;
690}
691/*---------------------------------------------------------------------------*/
692static int
693on(void)
694{
695 rf_result_t res;
696
697 if(prop_radio.rf_is_on) {
698 LOG_WARN("Radio is already on\n");
699 return RF_RESULT_OK;
700 }
701
702 data_queue_reset();
703
704 res = netstack_sched_rx(true);
705
706 if(res != RF_RESULT_OK) {
707 return RF_RESULT_ERROR;
708 }
709
710 prop_radio.rf_is_on = true;
711 return RF_RESULT_OK;
712}
713/*---------------------------------------------------------------------------*/
714static int
715off(void)
716{
717 if(!prop_radio.rf_is_on) {
718 LOG_WARN("Radio is already off\n");
719 return RF_RESULT_OK;
720 }
721
722 rf_yield();
723
724 prop_radio.rf_is_on = false;
725 return RF_RESULT_OK;
726}
727/*---------------------------------------------------------------------------*/
728static radio_result_t
729get_value(radio_param_t param, radio_value_t *value)
730{
731 rf_result_t res;
732
733 if(!value) {
735 }
736
737 switch(param) {
739 /* On / off */
740 *value = (prop_radio.rf_is_on)
743
744 return RADIO_RESULT_OK;
745
747 *value = (radio_value_t)get_channel();
748 return RADIO_RESULT_OK;
749
750 /* RX mode */
752 *value = 0;
753 if(prop_radio.poll_mode) {
755 }
756 return RADIO_RESULT_OK;
757
758 /* TX mode */
760 *value = 0;
761 return RADIO_RESULT_OK;
762
764 res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
765 return ((res == RF_RESULT_OK) &&
766 (*value != RF_TxPowerTable_INVALID_DBM))
769
771 *value = prop_radio.rssi_threshold;
772 return RADIO_RESULT_OK;
773
774 case RADIO_PARAM_RSSI:
775 *value = get_rssi();
776 return (*value == RF_GET_RSSI_ERROR_VAL)
779
781 *value = prop_radio.last.rssi;
782 return RADIO_RESULT_OK;
783
785 *value = prop_radio.last.corr_lqi;
786 return RADIO_RESULT_OK;
787
789 *value = DOT_15_4G_CHAN_MIN;
790 return RADIO_RESULT_OK;
791
793 *value = DOT_15_4G_CHAN_MAX;
794 return RADIO_RESULT_OK;
795
797 *value = (radio_value_t)tx_power_min(rf_tx_power_table);
798 return RADIO_RESULT_OK;
799
801 *value = (radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
802 return RADIO_RESULT_OK;
803
804 case RADIO_CONST_MAX_PAYLOAD_LEN:
805 *value = (radio_value_t)MAX_PAYLOAD_LEN;
806 return RADIO_RESULT_OK;
807
808 default:
810 }
811}
812/*---------------------------------------------------------------------------*/
813static radio_result_t
814set_value(radio_param_t param, radio_value_t value)
815{
816 rf_result_t res;
817
818 switch(param) {
820
821 if(value == RADIO_POWER_MODE_ON) {
822 return (on() == RF_RESULT_OK)
825 } else if(value == RADIO_POWER_MODE_OFF) {
826 off();
827 return RADIO_RESULT_OK;
828 }
829
831
833 res = set_channel((uint16_t)value);
834 return (res == RF_RESULT_OK)
837
839 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
841 }
842 res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
843 return (res == RF_RESULT_OK)
846
847 /* RX Mode */
849 if(value & ~(RADIO_RX_MODE_POLL_MODE)) {
851 }
852
853 const bool old_poll_mode = prop_radio.poll_mode;
854 prop_radio.poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0;
855 if(old_poll_mode == prop_radio.poll_mode) {
856 return RADIO_RESULT_OK;
857 }
858 if(!prop_radio.rf_is_on) {
859 return RADIO_RESULT_OK;
860 }
861
862 netstack_stop_rx();
863 res = netstack_sched_rx(false);
864 return (res == RF_RESULT_OK)
867
868 /* TX Mode */
870 if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
872 }
873 set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
874 return RADIO_RESULT_OK;
875
877 prop_radio.rssi_threshold = (int8_t)value;
878 return RADIO_RESULT_OK;
879
880 default:
882 }
883}
884/*---------------------------------------------------------------------------*/
885static radio_result_t
886get_object(radio_param_t param, void *dest, size_t size)
887{
888 if(!dest) {
890 }
891
892 switch(param) {
893 /* Last packet timestamp */
895 if(size != sizeof(rtimer_clock_t)) {
897 }
898
899 *(rtimer_clock_t *)dest = prop_radio.last.timestamp;
900
901 return RADIO_RESULT_OK;
902
903 default:
905 }
906}
907/*---------------------------------------------------------------------------*/
908static radio_result_t
909set_object(radio_param_t param, const void *src, size_t size)
910{
912}
913/*---------------------------------------------------------------------------*/
914static int
915init(void)
916{
917 RF_Params rf_params;
918 RF_TxPowerTable_Value tx_power_value;
919 RF_Stat rf_stat;
920
921 prop_radio.rx_is_active = rx_is_active;
922
923 radio_mode = (simplelink_radio_mode_t *)&prop_radio;
924
925 if(prop_radio.rf_handle) {
926 LOG_WARN("Radio is already initialized\n");
927 return RF_RESULT_OK;
928 }
929
930 /* RX is off */
931 prop_radio.rf_is_on = false;
932
933 /* Set configured RSSI threshold */
934 prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
935
936 init_rf_params();
937
938 /* Init RF params and specify non-default params */
939 RF_Params_init(&rf_params);
940 rf_params.nInactivityTimeout = RF_CONF_INACTIVITY_TIMEOUT;
941
942 /* Open RF Driver */
943 prop_radio.rf_handle = netstack_open(&rf_params);
944
945 if(prop_radio.rf_handle == NULL) {
946 LOG_ERR("Unable to open RF driver during initialization\n");
947 return RF_RESULT_ERROR;
948 }
949
950 set_channel_force(IEEE802154_DEFAULT_CHANNEL);
951
952 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
953 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
954 rf_stat = RF_setTxPower(prop_radio.rf_handle, tx_power_value);
955 if(rf_stat == RF_StatSuccess) {
956 LOG_INFO("TX power configured to %d dBm\n", RF_TXPOWER_DBM);
957 } else {
958 LOG_WARN("Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
959 }
960 } else {
961 LOG_WARN("Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
962 }
963
964 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
965
966 /* Start RAT overflow upkeep */
967 rat_init();
968
969 /* Start RF process */
970 process_start(&rf_sched_process, NULL);
971
972 return RF_RESULT_OK;
973}
974/*---------------------------------------------------------------------------*/
975const struct radio_driver prop_mode_driver = {
976 init,
977 prepare,
978 transmit,
979 send,
980 read,
984 on,
985 off,
986 get_value,
987 set_value,
990};
991/*---------------------------------------------------------------------------*/
992/**
993 * @}
994 * @}
995 */
Bit reversal library header.
Default definitions of C compiler quirk work-arounds.
Header file of the CC13xx/CC26xx RF data queue.
Header file for the energy estimation mechanism.
void bitrev_array(uint8_t *data, size_t len)
Reverse bits in all bytes of an array (in-place)
Definition bitrev.c:72
#define RF_CONF_INACTIVITY_TIMEOUT
2 ms
#define FRAME_SHAVE
RSSI (1) + Timestamp (4) + Status (1)
Definition prop-mode.c:174
static int read(void *buf, unsigned short buf_len)
Definition prop-mode.c:482
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:121
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:366
#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
@ RADIO_RESULT_ERROR
An error occurred when getting/setting the parameter, but the arguments were otherwise correct.
Definition radio.h:488
@ 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_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_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_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
Definition radio.h:244
@ RADIO_PARAM_TXPOWER
Transmission power in dBm.
Definition radio.h:192
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
Definition radio.h:316
@ 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_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_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
Definition rtimer.h:217
#define RTIMER_NOW()
Get the current clock time.
Definition rtimer.h:191
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 of the generic radio mode API.
Header file of the CC13xx/CC26xx RAT timer handler.
Header file of common CC13xx/CC26xx RF functionality.
Header file for the real-time timer module.
Header file of the CC13xx/CC26xx RF scheduler.
Header file of RF settings for CC13xx/CC26xx.
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
Header file of TX power functionality of CC13xx/CC26xx.