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