Contiki-NG
cooja-radio.c
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
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 Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include "contiki.h"
35 
36 #include "sys/cooja_mt.h"
37 #include "lib/simEnvChange.h"
38 
39 #include "net/packetbuf.h"
40 #include "net/netstack.h"
41 #include "sys/energest.h"
42 
43 #include "dev/radio.h"
44 #include "dev/cooja-radio.h"
45 
46 /*
47  * The maximum number of bytes this driver can accept from the MAC layer for
48  * transmission or will deliver to the MAC layer after reception. Includes
49  * the MAC header and payload, but not the FCS.
50  */
51 #ifdef COOJA_RADIO_CONF_BUFSIZE
52 #define COOJA_RADIO_BUFSIZE COOJA_RADIO_CONF_BUFSIZE
53 #else
54 #define COOJA_RADIO_BUFSIZE 125
55 #endif
56 
57 #define CCA_SS_THRESHOLD -95
58 
59 const struct simInterface radio_interface;
60 
61 
62 
63 /* The radio driver can provide Cooja these values.
64  * But at present, Cooja ignores and overrides them.
65  * */
66 enum {
67  /*
68  * Tmote Sky (with CC2420 radio) gives value -100dB
69  * CC1310 gives about -110dB
70  */
71  RSSI_NO_SIGNAL = -110,
72 
73  /*
74  * Tmote Sky (with CC2420 radio) gives value 105
75  * CC1310 gives about 100
76  */
77  LQI_NO_SIGNAL = 100,
78 };
79 
80 /* COOJA */
81 char simReceiving = 0;
82 char simInDataBuffer[COOJA_RADIO_BUFSIZE];
83 int simInSize = 0;
84 rtimer_clock_t simLastPacketTimestamp = 0;
85 char simOutDataBuffer[COOJA_RADIO_BUFSIZE];
86 int simOutSize = 0;
87 char simRadioHWOn = 1;
88 int simSignalStrength = RSSI_NO_SIGNAL;
89 int simLastSignalStrength = RSSI_NO_SIGNAL;
90 char simPower = 100;
91 int simRadioChannel = 26;
92 int simLQI = LQI_NO_SIGNAL;
93 int simLastLQI = LQI_NO_SIGNAL;
94 
95 
96 
97 static const void *pending_data;
98 
99 /* If we are in the polling mode, poll_mode is 1; otherwise 0 */
100 static int poll_mode = 0; /* default 0, disabled */
101 static int auto_ack = 0; /* AUTO_ACK is not supported; always 0 */
102 static int addr_filter = 0; /* ADDRESS_FILTER is not supported; always 0 */
103 static int send_on_cca = (COOJA_TRANSMIT_ON_CCA != 0);
104 
105 PROCESS(cooja_radio_process, "cooja radio process");
106 /*---------------------------------------------------------------------------*/
107 static void
108 set_send_on_cca(uint8_t enable)
109 {
110  send_on_cca = enable;
111 }
112 /*---------------------------------------------------------------------------*/
113 static void
114 set_frame_filtering(int enable)
115 {
116  addr_filter = enable;
117 }
118 /*---------------------------------------------------------------------------*/
119 static void
120 set_auto_ack(int enable)
121 {
122  auto_ack = enable;
123 }
124 /*---------------------------------------------------------------------------*/
125 static void
126 set_poll_mode(int enable)
127 {
128  poll_mode = enable;
129 }
130 /*---------------------------------------------------------------------------*/
131 void
132 radio_set_channel(int channel)
133 {
134  simRadioChannel = channel;
135 }
136 /*---------------------------------------------------------------------------*/
137 void
138 radio_set_txpower(unsigned char power)
139 {
140  /* 1 - 100: Number indicating output power */
141  simPower = power;
142 }
143 /*---------------------------------------------------------------------------*/
144 int
145 radio_signal_strength_last(void)
146 {
147  return simLastSignalStrength;
148 }
149 /*---------------------------------------------------------------------------*/
150 int
151 radio_signal_strength_current(void)
152 {
153  return simSignalStrength;
154 }
155 /*---------------------------------------------------------------------------*/
156 int
157 radio_LQI(void)
158 {
159  return simLQI;
160 }
161 
162 static
163 int radio_lqi_last(void)
164 {
165  return simLastLQI;
166 }
167 
168 /*---------------------------------------------------------------------------*/
169 static int
170 radio_on(void)
171 {
172  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
173  simRadioHWOn = 1;
174  return 1;
175 }
176 /*---------------------------------------------------------------------------*/
177 static int
178 radio_off(void)
179 {
180  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
181  simRadioHWOn = 0;
182  return 1;
183 }
184 /*---------------------------------------------------------------------------*/
185 static void
186 doInterfaceActionsBeforeTick(void)
187 {
188  if(!simRadioHWOn) {
189  simInSize = 0;
190  return;
191  }
192  if(simReceiving) {
193  simLastSignalStrength = simSignalStrength;
194  simLastLQI = simLQI;
195  return;
196  }
197 
198  if(simInSize > 0) {
199  process_poll(&cooja_radio_process);
200  }
201 }
202 /*---------------------------------------------------------------------------*/
203 static void
204 doInterfaceActionsAfterTick(void)
205 {
206 }
207 /*---------------------------------------------------------------------------*/
208 static int
209 radio_read(void *buf, unsigned short bufsize)
210 {
211  int tmp = simInSize;
212 
213  if(simInSize == 0) {
214  return 0;
215  }
216  if(bufsize < simInSize) {
217  simInSize = 0; /* rx flush */
218  return 0;
219  }
220 
221  memcpy(buf, simInDataBuffer, simInSize);
222  simInSize = 0;
223  if(!poll_mode) {
224  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_signal_strength_last());
225  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_lqi_last() );
226  }
227 
228  return tmp;
229 }
230 /*---------------------------------------------------------------------------*/
231 static int
232 channel_clear(void)
233 {
234  if(simSignalStrength > CCA_SS_THRESHOLD) {
235  return 0;
236  }
237  return 1;
238 }
239 /*---------------------------------------------------------------------------*/
240 static int
241 radio_send(const void *payload, unsigned short payload_len)
242 {
243  int result;
244  int radio_was_on = simRadioHWOn;
245 
246  if(payload_len > COOJA_RADIO_BUFSIZE) {
247  return RADIO_TX_ERR;
248  }
249  if(payload_len == 0) {
250  return RADIO_TX_ERR;
251  }
252  if(simOutSize > 0) {
253  return RADIO_TX_ERR;
254  }
255 
256  if(radio_was_on) {
257  ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
258  } else {
259  /* Turn on radio temporarily */
260  simRadioHWOn = 1;
261  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
262  }
263 
264 #if COOJA_SIMULATE_TURNAROUND
265  simProcessRunValue = 1;
266  cooja_mt_yield();
267  if(payload_len > 3) {
268  simProcessRunValue = 1;
269  cooja_mt_yield();
270  }
271 #endif /* COOJA_SIMULATE_TURNAROUND */
272 
273  /* Transmit on CCA */
274  if(COOJA_TRANSMIT_ON_CCA && send_on_cca && !channel_clear()) {
275  result = RADIO_TX_COLLISION;
276  } else {
277  /* Copy packet data to temporary storage */
278  memcpy(simOutDataBuffer, payload, payload_len);
279  simOutSize = payload_len;
280 
281  /* Transmit */
282  while(simOutSize > 0) {
283  cooja_mt_yield();
284  }
285 
286  result = RADIO_TX_OK;
287  }
288 
289  if(radio_was_on) {
290  ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
291  } else {
292  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
293  }
294 
295  simRadioHWOn = radio_was_on;
296  return result;
297 }
298 /*---------------------------------------------------------------------------*/
299 static int
300 prepare_packet(const void *data, unsigned short len)
301 {
302  if(len > COOJA_RADIO_BUFSIZE) {
303  return RADIO_TX_ERR;
304  }
305  pending_data = data;
306  return 0;
307 }
308 /*---------------------------------------------------------------------------*/
309 static int
310 transmit_packet(unsigned short len)
311 {
312  int ret = RADIO_TX_ERR;
313  if(pending_data != NULL) {
314  ret = radio_send(pending_data, len);
315  }
316  return ret;
317 }
318 /*---------------------------------------------------------------------------*/
319 static int
320 receiving_packet(void)
321 {
322  return simReceiving;
323 }
324 /*---------------------------------------------------------------------------*/
325 static int
326 pending_packet(void)
327 {
328  return !simReceiving && simInSize > 0;
329 }
330 /*---------------------------------------------------------------------------*/
331 PROCESS_THREAD(cooja_radio_process, ev, data)
332 {
333  int len;
334 
335  PROCESS_BEGIN();
336 
337  while(1) {
338  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
339  if(poll_mode) {
340  continue;
341  }
342 
343  packetbuf_clear();
344  len = radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
345  if(len > 0) {
347  NETSTACK_MAC.input();
348  }
349  }
350 
351  PROCESS_END();
352 }
353 /*---------------------------------------------------------------------------*/
354 static int
355 init(void)
356 {
357  process_start(&cooja_radio_process, NULL);
358  return 1;
359 }
360 /*---------------------------------------------------------------------------*/
361 static radio_result_t
362 get_value(radio_param_t param, radio_value_t *value)
363 {
364  switch(param) {
365  case RADIO_PARAM_RX_MODE:
366  *value = 0;
367  if(addr_filter) {
369  }
370  if(auto_ack) {
371  *value |= RADIO_RX_MODE_AUTOACK;
372  }
373  if(poll_mode) {
374  *value |= RADIO_RX_MODE_POLL_MODE;
375  }
376  return RADIO_RESULT_OK;
377  case RADIO_PARAM_TX_MODE:
378  *value = 0;
379  if(send_on_cca) {
380  *value |= RADIO_TX_MODE_SEND_ON_CCA;
381  }
382  return RADIO_RESULT_OK;
384  *value = radio_signal_strength_last();
385  return RADIO_RESULT_OK;
386 
388  *value = radio_lqi_last();
389  return RADIO_RESULT_OK;
390 
391  case RADIO_PARAM_RSSI:
392  *value = radio_signal_strength_current();
393  return RADIO_RESULT_OK;
394 
395  case RADIO_CONST_MAX_PAYLOAD_LEN:
396  *value = (radio_value_t)COOJA_RADIO_BUFSIZE;
397  return RADIO_RESULT_OK;
398  default:
400  }
401 }
402 /*---------------------------------------------------------------------------*/
403 static radio_result_t
404 set_value(radio_param_t param, radio_value_t value)
405 {
406  switch(param) {
407  case RADIO_PARAM_RX_MODE:
408  if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
411  }
412 
413  /* Only disabling is acceptable for RADIO_RX_MODE_ADDRESS_FILTER */
414  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
416  }
417  set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
418 
419  /* Only disabling is acceptable for RADIO_RX_MODE_AUTOACK */
420  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
422  }
423  set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
424 
425  set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
426  return RADIO_RESULT_OK;
427  case RADIO_PARAM_TX_MODE:
428  if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
430  }
431  set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
432  return RADIO_RESULT_OK;
433  case RADIO_PARAM_CHANNEL:
434  /* With channel value < 0 Cooja matches any channels:
435  * - send packets on a negative channel -> to any receiver's channels.
436  * - receive on a negative channel <- get packets from any sender's channels.
437  * So, negative channel are useful for wide-band noise generation.
438  * Or for wide-band sniffing.
439  * */
440  radio_set_channel(value);
441  return RADIO_RESULT_OK;
442  default:
444  }
445 }
446 /*---------------------------------------------------------------------------*/
447 static radio_result_t
448 get_object(radio_param_t param, void *dest, size_t size)
449 {
450  if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
451  if(size != sizeof(rtimer_clock_t) || !dest) {
453  }
454  *(rtimer_clock_t *)dest = (rtimer_clock_t)simLastPacketTimestamp;
455  return RADIO_RESULT_OK;
456  }
458 }
459 /*---------------------------------------------------------------------------*/
460 static radio_result_t
461 set_object(radio_param_t param, const void *src, size_t size)
462 {
464 }
465 /*---------------------------------------------------------------------------*/
466 const struct radio_driver cooja_radio_driver =
467 {
468  init,
469  prepare_packet,
470  transmit_packet,
471  radio_send,
472  radio_read,
476  radio_on,
477  radio_off,
478  get_value,
479  set_value,
480  get_object,
481  set_object
482 };
483 /*---------------------------------------------------------------------------*/
484 SIM_INTERFACE(radio_interface,
485  doInterfaceActionsBeforeTick,
486  doInterfaceActionsAfterTick);
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:762
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
The parameter is not supported.
Definition: radio.h:473
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
Header file for the energy estimation mechanism
TX failed due to a collision.
Definition: radio.h:503
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
Header file for the radio API
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
Received signal strength indicator in dBm.
Definition: radio.h:218
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:676
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:748
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver&#39;s buffers.
Definition: radio.h:689
The structure of a Contiki-NG radio device driver.
Definition: radio.h:526
Channel used for radio communication.
Definition: radio.h:134
The value argument was incorrect.
Definition: radio.h:474
The parameter was set/read successfully.
Definition: radio.h:472
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:664
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 transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
Definition: radio.h:180
The RSSI value of the last received packet.
Definition: radio.h:226
void(* input)(void)
Callback for getting notified of incoming packet.
Definition: mac.h:72
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
Definition: radio.h:173
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
Definition: radio.h:443
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition: radio.h:466
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
Definition: radio.h:448
int(* init)(void)
Initialise the radio hardware.
Definition: radio.h:547
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Definition: radio.h:453
Link quality indicator of the last received packet.
Definition: radio.h:236
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:733
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
Last packet timestamp, of type rtimer_clock_t.
Definition: radio.h:278
An error occurred during transmission.
Definition: radio.h:498
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:779
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
TX was successful and where an ACK was requested one was received.
Definition: radio.h:490
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99