Contiki-NG
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 /*---------------------------------------------------------------------------*/
63 /* Platform RF dev */
64 #include "rf/rf.h"
65 #include "rf/dot-15-4g.h"
66 #include "rf/sched.h"
67 #include "rf/data-queue.h"
68 #include "rf/tx-power.h"
69 #include "rf/settings.h"
70 /*---------------------------------------------------------------------------*/
71 #include <stdint.h>
72 #include <string.h>
73 #include <stdio.h>
74 #include <stdbool.h>
75 #include <assert.h>
76 /*---------------------------------------------------------------------------*/
77 /* Log configuration */
78 #include "sys/log.h"
79 #define LOG_MODULE "Radio"
80 #define LOG_LEVEL LOG_LEVEL_NONE
81 /*---------------------------------------------------------------------------*/
82 #undef CLAMP
83 #define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin))
84 /*---------------------------------------------------------------------------*/
85 /* Configuration parameters */
86 #define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW
87 #define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16
88 #define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ
89 #define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER
90 #define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD
91 /*---------------------------------------------------------------------------*/
92 /* Used for checking result of CCA_REQ command */
93 typedef enum {
94  CCA_STATE_IDLE = 0,
95  CCA_STATE_BUSY = 1,
96  CCA_STATE_INVALID = 2
97 } cca_state_t;
98 /*---------------------------------------------------------------------------*/
99 /* Defines and variables related to the .15.4g PHY HDR */
100 #define DOT_4G_MAX_FRAME_LEN 2047
101 #define DOT_4G_PHR_LEN 2
102 
103 /* PHY HDR bits */
104 #define DOT_4G_PHR_CRC16 0x10
105 #define DOT_4G_PHR_DW 0x08
106 
107 #if PROP_MODE_USE_CRC16
108 /* CRC16 */
109 #define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16
110 #define CRC_LEN 2
111 #else
112 /* CRC32 */
113 #define DOT_4G_PHR_CRC_BIT 0
114 #define CRC_LEN 4
115 #endif /* PROP_MODE_USE_CRC16 */
116 
117 #if PROP_MODE_DYN_WHITENER
118 #define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW
119 #else
120 #define DOT_4G_PHR_DW_BIT 0
121 #endif
122 /*---------------------------------------------------------------------------*/
123 /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */
124 #define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10)
125 
126 /* How long to wait for the rx read entry to become ready */
127 #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250)
128 /*---------------------------------------------------------------------------*/
129 /* TX buf configuration */
130 #define TX_BUF_HDR_LEN 2
131 #define TX_BUF_PAYLOAD_LEN 180
132 
133 #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN)
134 /*---------------------------------------------------------------------------*/
135 /* Size of the Length field in Data Entry, two bytes in this case */
136 typedef uint16_t lensz_t;
137 
138 #define FRAME_OFFSET sizeof(lensz_t)
139 #define FRAME_SHAVE 2 /**< RSSI (1) + Status (1) */
140 /*---------------------------------------------------------------------------*/
141 /* Constants used when calculating the LQI from the RSSI */
142 #define RX_SENSITIVITY_DBM -110
143 #define RX_SATURATION_DBM 10
144 #define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10
145 #define ED_MAX 0xFF
146 
147 #define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY)
148 #define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM
149 /*---------------------------------------------------------------------------*/
150 /* RF Core typedefs */
151 typedef rfc_propRxOutput_t rx_output_t;
152 
153 typedef struct {
154  /* Outgoing frame buffer */
155  uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
156 
157  /* RX Statistics struct */
158  rx_output_t rx_stats;
159 
160  /* RSSI Threshold */
161  int8_t rssi_threshold;
162  uint16_t channel;
163 
164  /* Indicates RF is supposed to be on or off */
165  uint8_t rf_is_on;
166 
167  /* RF driver */
168  RF_Handle rf_handle;
169 } prop_radio_t;
170 
171 static prop_radio_t prop_radio;
172 /*---------------------------------------------------------------------------*/
173 /* Convenience macros for volatile access with the RF commands */
174 #define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup)
175 #define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs)
176 #define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv)
177 #define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv)
178 /*---------------------------------------------------------------------------*/
179 static inline bool
180 tx_is_active(void)
181 {
182  return cmd_tx.status == ACTIVE;
183 }
184 /*---------------------------------------------------------------------------*/
185 static inline bool
186 rx_is_active(void)
187 {
188  return cmd_rx.status == ACTIVE;
189 }
190 /*---------------------------------------------------------------------------*/
191 static int on(void);
192 static int off(void);
193 /*---------------------------------------------------------------------------*/
194 static void
195 init_rf_params(void)
196 {
197  cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
198  cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
199  cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
200  cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
201 
202  data_queue_t *data_queue = data_queue_init(sizeof(lensz_t));
203 
204  cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset;
205  cmd_rx.pQueue = data_queue;
206  cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
207 }
208 /*---------------------------------------------------------------------------*/
209 static int8_t
210 get_rssi(void)
211 {
212  rf_result_t res;
213  bool stop_rx = false;
214  int8_t rssi = RF_GET_RSSI_ERROR_VAL;
215 
216  /* RX is required to be running in order to do a RSSI measurement */
217  if(!rx_is_active()) {
218  /* If RX is not pending, i.e. soon to be running, schedule the RX command */
219  if(cmd_rx.status != PENDING) {
220  res = netstack_sched_rx(false);
221  if(res != RF_RESULT_OK) {
222  LOG_ERR("RSSI measurement failed to schedule RX\n");
223  return res;
224  }
225 
226  /* We only stop RX if we had to schedule it */
227  stop_rx = true;
228  }
229 
230  /* Make sure RX is running before we continue, unless we timeout and fail */
231  RTIMER_BUSYWAIT_UNTIL(!rx_is_active(), TIMEOUT_ENTER_RX_WAIT);
232 
233  if(!rx_is_active()) {
234  LOG_ERR("RSSI measurement failed to turn on RX, RX status=0x%04X\n", cmd_rx.status);
235  return RF_RESULT_ERROR;
236  }
237  }
238 
239  /* Perform the RSSI measurement */
240  rssi = RF_getRssi(prop_radio.rf_handle);
241 
242  if(stop_rx) {
243  netstack_stop_rx();
244  }
245 
246  return rssi;
247 }
248 /*---------------------------------------------------------------------------*/
249 static uint8_t
250 get_channel(void)
251 {
252  uint32_t freq_khz = cmd_fs.frequency * 1000;
253 
254  /*
255  * For some channels, fractFreq * 1000 / 65536 will return 324.99xx.
256  * Casting the result to uint32_t will truncate decimals resulting in the
257  * function returning channel - 1 instead of channel. Thus, we do a quick
258  * positive integer round up.
259  */
260  freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536);
261 
262  return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
263 }
264 /*---------------------------------------------------------------------------*/
265 static rf_result_t
266 set_channel(uint16_t channel)
267 {
268  rf_result_t res;
269 
270  if(!dot_15_4g_chan_in_range(channel)) {
271  LOG_WARN("Supplied hannel %d is illegal, defaults to %d\n",
272  (int)channel, DOT_15_4G_DEFAULT_CHAN);
273  channel = DOT_15_4G_DEFAULT_CHAN;
274  }
275 
276  if(channel == prop_radio.channel) {
277  /* We are already calibrated to this channel */
278  return RF_RESULT_OK;
279  }
280 
281  const uint32_t new_freq = dot_15_4g_freq(channel);
282  const uint16_t freq = (uint16_t)(new_freq / 1000);
283  const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
284 
285  LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
286  (int)channel, freq, frac, new_freq);
287 
288  cmd_fs.frequency = freq;
289  cmd_fs.fractFreq = frac;
290 
291  res = netstack_sched_fs();
292 
293  if(res != RF_RESULT_OK) {
294  return res;
295  }
296 
297  prop_radio.channel = channel;
298  return RF_RESULT_OK;
299 }
300 /*---------------------------------------------------------------------------*/
301 static uint8_t
302 calculate_lqi(int8_t rssi)
303 {
304  /*
305  * Note : Currently the LQI value is simply the energy detect measurement.
306  * A more accurate value could be derived by using the correlation
307  * value along with the RSSI value.
308  */
309  rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
310 
311  /*
312  * Create energy detect measurement by normalizing and scaling RF power level.
313  * Note : The division operation below is designed for maximum accuracy and
314  * best granularity. This is done by grouping the math operations to
315  * compute the entire numerator before doing any division.
316  */
317  return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
318 }
319 /*---------------------------------------------------------------------------*/
320 static int
321 prepare(const void *payload, unsigned short payload_len)
322 {
323  if(payload_len > TX_BUF_PAYLOAD_LEN || payload_len > NETSTACK_RADIO_MAX_PAYLOAD_LEN) {
324  return RADIO_TX_ERR;
325  }
326 
327  memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, payload_len);
328  return 0;
329 }
330 /*---------------------------------------------------------------------------*/
331 static int
332 transmit(unsigned short transmit_len)
333 {
334  rf_result_t res;
335 
336  if(transmit_len > NETSTACK_RADIO_MAX_PAYLOAD_LEN) {
337  LOG_ERR("Too long\n");
338  return RADIO_TX_ERR;
339  }
340 
341  if(tx_is_active()) {
342  LOG_ERR("A transmission is already active\n");
343  return RADIO_TX_ERR;
344  }
345 
346  /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */
347  const uint16_t total_length = transmit_len + CRC_LEN;
348  /*
349  * Prepare the .15.4g PHY header
350  * MS=0, Length MSBits=0, DW and CRC configurable
351  * Total length = transmit_len (payload) + CRC length
352  *
353  * The Radio will flip the bits around, so tx_buf[0] must have the length
354  * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0]
355  */
356  prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
357  prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
358 
359  /* pktLen: Total number of bytes in the TX buffer, including the header if
360  * one exists, but not including the CRC (which is not present in the buffer) */
361  cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN;
362  cmd_tx.pPkt = prop_radio.tx_buf;
363 
364  res = netstack_sched_prop_tx();
365 
366  return (res == RF_RESULT_OK)
367  ? RADIO_TX_OK
368  : RADIO_TX_ERR;
369 }
370 /*---------------------------------------------------------------------------*/
371 static int
372 send(const void *payload, unsigned short payload_len)
373 {
374  prepare(payload, payload_len);
375  return transmit(payload_len);
376 }
377 /*---------------------------------------------------------------------------*/
378 static int
379 read(void *buf, unsigned short buf_len)
380 {
381  volatile data_entry_t *data_entry = data_queue_current_entry();
382 
383  const rtimer_clock_t t0 = RTIMER_NOW();
384  /* Only wait if the Radio is accessing the entry */
385  while((data_entry->status == DATA_ENTRY_BUSY) &&
386  RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ;
387 
388  if(data_entry->status != DATA_ENTRY_FINISHED) {
389  /* No available data */
390  return -1;
391  }
392 
393  /*
394  * lensz bytes (2) in the data entry are the length of the received frame.
395  * Data frame is on the following format:
396  * Length (2) + Payload (N) + RSSI (1) + Status (1)
397  * Data frame DOES NOT contain the following:
398  * no Header/PHY bytes
399  * no appended Received CRC bytes
400  * no Timestamp bytes
401  * Visual representation of frame format:
402  *
403  * +---------+---------+--------+--------+
404  * | 2 bytes | N bytes | 1 byte | 1 byte |
405  * +---------+---------+--------+--------+
406  * | Length | Payload | RSSI | Status |
407  * +---------+---------+--------+--------+
408  *
409  * Length bytes equal total length of entire frame excluding itself,
410  * Length = N + RSSI (1) + Status (1)
411  * = N + 2
412  * N = Length - 2
413  */
414  uint8_t *const frame_ptr = (uint8_t *)&data_entry->data;
415  const lensz_t frame_len = *(lensz_t *)frame_ptr;
416 
417  /* Sanity check that Frame is at least Frame Shave bytes long */
418  if(frame_len < FRAME_SHAVE) {
419  LOG_ERR("Received rame is too short, len=%d\n", frame_len);
420 
421  data_queue_release_entry();
422  return 0;
423  }
424 
425  const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t);
426  const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE);
427 
428  /* Sanity check that Payload fits in Buffer */
429  if(payload_len > buf_len) {
430  LOG_ERR("Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
431  payload_len, buf_len);
432 
433  data_queue_release_entry();
434  return 0;
435  }
436 
437  memcpy(buf, payload_ptr, payload_len);
438 
439  /* RSSI stored after payload */
440  const int8_t rssi = (int8_t)payload_ptr[payload_len];
441  /* LQI calculated from RSSI */
442  const uint8_t lqi = calculate_lqi(rssi);
443 
444  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi);
445  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi);
446 
447  data_queue_release_entry();
448  return (int)payload_len;
449 }
450 /*---------------------------------------------------------------------------*/
451 static uint8_t
452 cca_request(void)
453 {
454  const int8_t rssi = get_rssi();
455 
456  if(rssi == RF_GET_RSSI_ERROR_VAL) {
457  return CCA_STATE_INVALID;
458  }
459 
460  return (rssi < prop_radio.rssi_threshold)
461  ? CCA_STATE_IDLE
462  : CCA_STATE_BUSY;
463 }
464 /*---------------------------------------------------------------------------*/
465 static int
466 channel_clear(void)
467 {
468  if(tx_is_active()) {
469  LOG_ERR("Channel clear called while in TX\n");
470  return 0;
471  }
472 
473  const uint8_t cca_state = cca_request();
474 
475  /* Channel is clear if CCA state is IDLE */
476  return cca_state == CCA_STATE_IDLE;
477 }
478 /*---------------------------------------------------------------------------*/
479 static int
480 receiving_packet(void)
481 {
482  if(!rx_is_active()) {
483  return 0;
484  }
485 
486  const uint8_t cca_state = cca_request();
487 
488  return cca_state == CCA_STATE_BUSY;
489 }
490 /*---------------------------------------------------------------------------*/
491 static int
492 pending_packet(void)
493 {
494  const data_entry_t *const read_entry = data_queue_current_entry();
495  volatile const data_entry_t *curr_entry = read_entry;
496 
497  int num_pending = 0;
498 
499  /* Go through RX Circular buffer and check their status */
500  do {
501  const uint8_t status = curr_entry->status;
502  if((status == DATA_ENTRY_FINISHED) ||
503  (status == DATA_ENTRY_BUSY)) {
504  num_pending += 1;
505  }
506 
507  /* Stop when we have looped the circular buffer */
508  curr_entry = (data_entry_t *)curr_entry->pNextEntry;
509  } while(curr_entry != read_entry);
510 
511  if(num_pending > 0) {
512  process_poll(&rf_sched_process);
513  }
514 
515  /* If we didn't find an entry at status finished, no frames are pending */
516  return num_pending;
517 }
518 /*---------------------------------------------------------------------------*/
519 static int
520 on(void)
521 {
522  rf_result_t res;
523 
524  if(prop_radio.rf_is_on) {
525  LOG_WARN("Radio is already on\n");
526  return RF_RESULT_OK;
527  }
528 
529  data_queue_reset();
530 
531  res = netstack_sched_rx(true);
532 
533  if(res != RF_RESULT_OK) {
534  return RF_RESULT_ERROR;
535  }
536 
537  prop_radio.rf_is_on = true;
538  return RF_RESULT_OK;
539 }
540 /*---------------------------------------------------------------------------*/
541 static int
542 off(void)
543 {
544  if(!prop_radio.rf_is_on) {
545  LOG_WARN("Radio is already off\n");
546  return RF_RESULT_OK;
547  }
548 
549  rf_yield();
550 
551  prop_radio.rf_is_on = false;
552  return RF_RESULT_OK;
553 }
554 /*---------------------------------------------------------------------------*/
555 static radio_result_t
556 get_value(radio_param_t param, radio_value_t *value)
557 {
558  rf_result_t res;
559 
560  if(!value) {
561  return RADIO_RESULT_INVALID_VALUE;
562  }
563 
564  switch(param) {
565  case RADIO_PARAM_POWER_MODE:
566  /* On / off */
567  *value = (prop_radio.rf_is_on)
568  ? RADIO_POWER_MODE_ON
569  : RADIO_POWER_MODE_OFF;
570 
571  return RADIO_RESULT_OK;
572 
573  case RADIO_PARAM_CHANNEL:
574  *value = (radio_value_t)get_channel();
575  return RADIO_RESULT_OK;
576 
577  case RADIO_PARAM_TXPOWER:
578  res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
579  return ((res == RF_RESULT_OK) &&
580  (*value != RF_TxPowerTable_INVALID_DBM))
581  ? RADIO_RESULT_OK
582  : RADIO_RESULT_ERROR;
583 
584  case RADIO_PARAM_CCA_THRESHOLD:
585  *value = prop_radio.rssi_threshold;
586  return RADIO_RESULT_OK;
587 
588  case RADIO_PARAM_RSSI:
589  *value = get_rssi();
590  return (*value == RF_GET_RSSI_ERROR_VAL)
591  ? RADIO_RESULT_ERROR
592  : RADIO_RESULT_OK;
593 
594  case RADIO_CONST_CHANNEL_MIN:
595  *value = DOT_15_4G_CHAN_MIN;
596  return RADIO_RESULT_OK;
597 
598  case RADIO_CONST_CHANNEL_MAX:
599  *value = DOT_15_4G_CHAN_MAX;
600  return RADIO_RESULT_OK;
601 
602  case RADIO_CONST_TXPOWER_MIN:
603  *value = (radio_value_t)tx_power_min(rf_tx_power_table);
604  return RADIO_RESULT_OK;
605 
606  case RADIO_CONST_TXPOWER_MAX:
607  *value = (radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
608  return RADIO_RESULT_OK;
609 
610  default:
611  return RADIO_RESULT_NOT_SUPPORTED;
612  }
613 }
614 /*---------------------------------------------------------------------------*/
615 static radio_result_t
616 set_value(radio_param_t param, radio_value_t value)
617 {
618  rf_result_t res;
619 
620  switch(param) {
621  case RADIO_PARAM_POWER_MODE:
622 
623  if(value == RADIO_POWER_MODE_ON) {
624  return (on() == RF_RESULT_OK)
625  ? RADIO_RESULT_OK
626  : RADIO_RESULT_ERROR;
627  } else if(value == RADIO_POWER_MODE_OFF) {
628  off();
629  return RADIO_RESULT_OK;
630  }
631 
632  return RADIO_RESULT_INVALID_VALUE;
633 
634  case RADIO_PARAM_CHANNEL:
635  res = set_channel((uint16_t)value);
636  return (res == RF_RESULT_OK)
637  ? RADIO_RESULT_OK
638  : RADIO_RESULT_ERROR;
639 
640  case RADIO_PARAM_TXPOWER:
641  if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
642  return RADIO_RESULT_INVALID_VALUE;
643  }
644  res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
645  return (res == RF_RESULT_OK)
646  ? RADIO_RESULT_OK
647  : RADIO_RESULT_ERROR;
648 
649  case RADIO_PARAM_RX_MODE:
650  return RADIO_RESULT_OK;
651 
652  case RADIO_PARAM_CCA_THRESHOLD:
653  prop_radio.rssi_threshold = (int8_t)value;
654  return RADIO_RESULT_OK;
655 
656  default:
657  return RADIO_RESULT_NOT_SUPPORTED;
658  }
659 }
660 /*---------------------------------------------------------------------------*/
661 static radio_result_t
662 get_object(radio_param_t param, void *dest, size_t size)
663 {
664  return RADIO_RESULT_NOT_SUPPORTED;
665 }
666 /*---------------------------------------------------------------------------*/
667 static radio_result_t
668 set_object(radio_param_t param, const void *src, size_t size)
669 {
670  return RADIO_RESULT_NOT_SUPPORTED;
671 }
672 /*---------------------------------------------------------------------------*/
673 static int
674 init(void)
675 {
676  if(prop_radio.rf_handle) {
677  LOG_WARN("Radio is already initialized\n");
678  return RF_RESULT_OK;
679  }
680 
681  /* RX is off */
682  prop_radio.rf_is_on = false;
683 
684  /* Set configured RSSI threshold */
685  prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
686 
687  init_rf_params();
688 
689  /* Init RF params and specify non-default params */
690  RF_Params rf_params;
691  RF_Params_init(&rf_params);
692  rf_params.nInactivityTimeout = RF_CONF_INACTIVITY_TIMEOUT;
693 
694  /* Open RF Driver */
695  prop_radio.rf_handle = netstack_open(&rf_params);
696 
697  if(prop_radio.rf_handle == NULL) {
698  LOG_ERR("Unable to open RF driver during initialization\n");
699  return RF_RESULT_ERROR;
700  }
701 
703 
704  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
705 
706  /* Start RF process */
707  process_start(&rf_sched_process, NULL);
708 
709  return RF_RESULT_OK;
710 }
711 /*---------------------------------------------------------------------------*/
712 const struct radio_driver prop_mode_driver = {
713  init,
714  prepare,
715  transmit,
716  send,
717  read,
721  on,
722  off,
723  get_value,
724  set_value,
725  get_object,
726  set_object,
727 };
728 /*---------------------------------------------------------------------------*/
729 /**
730  * @}
731  * @}
732  */
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:307
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
Definition: radio.h:269
Header file of TX power functionality of CC13xx/CC26xx.
static uint8_t rf_is_on(void)
Checks whether the RFC domain is accessible and the RFC is in IEEE RX.
Definition: ieee-mode.c:254
#define FRAME_SHAVE
RSSI (1) + Status (1)
Definition: prop-mode.c:139
Header file for the energy estimation mechanism
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:285
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:300
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
Definition: radio.h:288
The structure of a device driver for a radio in Contiki.
Definition: radio.h:264
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
Definition: rtimer.h:202
static void set_channel(uint8_t channel)
Set the current operating channel.
Definition: cc2538-rf.c:168
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:282
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 IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
Definition: mac.h:52
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:160
Header file of the CC13xx/CC26xx RF scheduler.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
Definition: radio.h:275
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Definition: radio.h:272
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
int(* off)(void)
Turn the radio off.
Definition: radio.h:294
#define RF_CONF_INACTIVITY_TIMEOUT
2 ms
Header file for the real-time timer module.
Header file of the CC13xx/CC26xx RF data queue.
Header file of RF settings for CC13xx/CC26xx.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Definition: radio.h:278
Header file of common CC13xx/CC26xx RF functionality.
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:297
Default definitions of C compiler quirk work-arounds.
Header file for the logging system
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:313
int(* on)(void)
Turn the radio on.
Definition: radio.h:291
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
static uint8_t get_channel()
Get the current operating channel.
Definition: cc2538-rf.c:158