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 
42 #include "dev/radio.h"
43 #include "dev/cooja-radio.h"
44 
45 /*
46  * The maximum number of bytes this driver can accept from the MAC layer for
47  * transmission or will deliver to the MAC layer after reception. Includes
48  * the MAC header and payload, but not the FCS.
49  */
50 #ifdef COOJA_RADIO_CONF_BUFSIZE
51 #define COOJA_RADIO_BUFSIZE COOJA_RADIO_CONF_BUFSIZE
52 #else
53 #define COOJA_RADIO_BUFSIZE 125
54 #endif
55 
56 #define CCA_SS_THRESHOLD -95
57 
58 const struct simInterface radio_interface;
59 
60 /* COOJA */
61 char simReceiving = 0;
62 char simInDataBuffer[COOJA_RADIO_BUFSIZE];
63 int simInSize = 0;
64 rtimer_clock_t simLastPacketTimestamp = 0;
65 char simOutDataBuffer[COOJA_RADIO_BUFSIZE];
66 int simOutSize = 0;
67 char simRadioHWOn = 1;
68 int simSignalStrength = -100;
69 int simLastSignalStrength = -100;
70 char simPower = 100;
71 int simRadioChannel = 26;
72 int simLQI = 105;
73 
74 static const void *pending_data;
75 
76 /* If we are in the polling mode, poll_mode is 1; otherwise 0 */
77 static int poll_mode = 0; /* default 0, disabled */
78 static int auto_ack = 0; /* AUTO_ACK is not supported; always 0 */
79 static int addr_filter = 0; /* ADDRESS_FILTER is not supported; always 0 */
80 static int send_on_cca = (COOJA_TRANSMIT_ON_CCA != 0);
81 
82 PROCESS(cooja_radio_process, "cooja radio process");
83 /*---------------------------------------------------------------------------*/
84 static void
85 set_send_on_cca(uint8_t enable)
86 {
87  send_on_cca = enable;
88 }
89 /*---------------------------------------------------------------------------*/
90 static void
91 set_frame_filtering(int enable)
92 {
93  addr_filter = enable;
94 }
95 /*---------------------------------------------------------------------------*/
96 static void
97 set_auto_ack(int enable)
98 {
99  auto_ack = enable;
100 }
101 /*---------------------------------------------------------------------------*/
102 static void
103 set_poll_mode(int enable)
104 {
105  poll_mode = enable;
106 }
107 /*---------------------------------------------------------------------------*/
108 void
109 radio_set_channel(int channel)
110 {
111  simRadioChannel = channel;
112 }
113 /*---------------------------------------------------------------------------*/
114 void
115 radio_set_txpower(unsigned char power)
116 {
117  /* 1 - 100: Number indicating output power */
118  simPower = power;
119 }
120 /*---------------------------------------------------------------------------*/
121 int
122 radio_signal_strength_last(void)
123 {
124  return simLastSignalStrength;
125 }
126 /*---------------------------------------------------------------------------*/
127 int
128 radio_signal_strength_current(void)
129 {
130  return simSignalStrength;
131 }
132 /*---------------------------------------------------------------------------*/
133 int
134 radio_LQI(void)
135 {
136  return simLQI;
137 }
138 /*---------------------------------------------------------------------------*/
139 static int
140 radio_on(void)
141 {
142  simRadioHWOn = 1;
143  return 1;
144 }
145 /*---------------------------------------------------------------------------*/
146 static int
147 radio_off(void)
148 {
149  simRadioHWOn = 0;
150  return 1;
151 }
152 /*---------------------------------------------------------------------------*/
153 static void
154 doInterfaceActionsBeforeTick(void)
155 {
156  if(!simRadioHWOn) {
157  simInSize = 0;
158  return;
159  }
160  if(simReceiving) {
161  simLastSignalStrength = simSignalStrength;
162  return;
163  }
164 
165  if(simInSize > 0) {
166  process_poll(&cooja_radio_process);
167  }
168 }
169 /*---------------------------------------------------------------------------*/
170 static void
171 doInterfaceActionsAfterTick(void)
172 {
173 }
174 /*---------------------------------------------------------------------------*/
175 static int
176 radio_read(void *buf, unsigned short bufsize)
177 {
178  int tmp = simInSize;
179 
180  if(simInSize == 0) {
181  return 0;
182  }
183  if(bufsize < simInSize) {
184  simInSize = 0; /* rx flush */
185  return 0;
186  }
187 
188  memcpy(buf, simInDataBuffer, simInSize);
189  simInSize = 0;
190  if(!poll_mode) {
191  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, simSignalStrength);
192  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, simLQI);
193  }
194 
195  return tmp;
196 }
197 /*---------------------------------------------------------------------------*/
198 static int
199 channel_clear(void)
200 {
201  if(simSignalStrength > CCA_SS_THRESHOLD) {
202  return 0;
203  }
204  return 1;
205 }
206 /*---------------------------------------------------------------------------*/
207 static int
208 radio_send(const void *payload, unsigned short payload_len)
209 {
210  int radiostate = simRadioHWOn;
211 
212  /* Simulate turnaround time of 2ms for packets, 1ms for acks*/
213 #if COOJA_SIMULATE_TURNAROUND
214  simProcessRunValue = 1;
215  cooja_mt_yield();
216  if(payload_len > 3) {
217  simProcessRunValue = 1;
218  cooja_mt_yield();
219  }
220 #endif /* COOJA_SIMULATE_TURNAROUND */
221 
222  if(!simRadioHWOn) {
223  /* Turn on radio temporarily */
224  simRadioHWOn = 1;
225  }
226  if(payload_len > COOJA_RADIO_BUFSIZE) {
227  return RADIO_TX_ERR;
228  }
229  if(payload_len == 0) {
230  return RADIO_TX_ERR;
231  }
232  if(simOutSize > 0) {
233  return RADIO_TX_ERR;
234  }
235 
236  /* Transmit on CCA */
237 #if COOJA_TRANSMIT_ON_CCA
238  if(send_on_cca && !channel_clear()) {
239  return RADIO_TX_COLLISION;
240  }
241 #endif /* COOJA_TRANSMIT_ON_CCA */
242 
243  /* Copy packet data to temporary storage */
244  memcpy(simOutDataBuffer, payload, payload_len);
245  simOutSize = payload_len;
246 
247  /* Transmit */
248  while(simOutSize > 0) {
249  cooja_mt_yield();
250  }
251 
252  simRadioHWOn = radiostate;
253  return RADIO_TX_OK;
254 }
255 /*---------------------------------------------------------------------------*/
256 static int
257 prepare_packet(const void *data, unsigned short len)
258 {
259  if(len > COOJA_RADIO_BUFSIZE) {
260  return RADIO_TX_ERR;
261  }
262  pending_data = data;
263  return 0;
264 }
265 /*---------------------------------------------------------------------------*/
266 static int
267 transmit_packet(unsigned short len)
268 {
269  int ret = RADIO_TX_ERR;
270  if(pending_data != NULL) {
271  ret = radio_send(pending_data, len);
272  }
273  return ret;
274 }
275 /*---------------------------------------------------------------------------*/
276 static int
277 receiving_packet(void)
278 {
279  return simReceiving;
280 }
281 /*---------------------------------------------------------------------------*/
282 static int
283 pending_packet(void)
284 {
285  return !simReceiving && simInSize > 0;
286 }
287 /*---------------------------------------------------------------------------*/
288 PROCESS_THREAD(cooja_radio_process, ev, data)
289 {
290  int len;
291 
292  PROCESS_BEGIN();
293 
294  while(1) {
295  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
296  if(poll_mode) {
297  continue;
298  }
299 
300  packetbuf_clear();
301  len = radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
302  if(len > 0) {
304  NETSTACK_MAC.input();
305  }
306  }
307 
308  PROCESS_END();
309 }
310 /*---------------------------------------------------------------------------*/
311 static int
312 init(void)
313 {
314  process_start(&cooja_radio_process, NULL);
315  return 1;
316 }
317 /*---------------------------------------------------------------------------*/
318 static radio_result_t
319 get_value(radio_param_t param, radio_value_t *value)
320 {
321  switch(param) {
322  case RADIO_PARAM_RX_MODE:
323  *value = 0;
324  if(addr_filter) {
326  }
327  if(auto_ack) {
328  *value |= RADIO_RX_MODE_AUTOACK;
329  }
330  if(poll_mode) {
331  *value |= RADIO_RX_MODE_POLL_MODE;
332  }
333  return RADIO_RESULT_OK;
334  case RADIO_PARAM_TX_MODE:
335  *value = 0;
336  if(send_on_cca) {
337  *value |= RADIO_TX_MODE_SEND_ON_CCA;
338  }
339  return RADIO_RESULT_OK;
340  case RADIO_PARAM_LAST_RSSI:
341  *value = simSignalStrength;
342  return RADIO_RESULT_OK;
343  case RADIO_PARAM_LAST_LINK_QUALITY:
344  *value = simLQI;
345  return RADIO_RESULT_OK;
346  case RADIO_PARAM_RSSI:
347  /* return a fixed value depending on the channel */
348  *value = -90 + simRadioChannel - 11;
349  return RADIO_RESULT_OK;
350  case RADIO_CONST_MAX_PAYLOAD_LEN:
351  *value = (radio_value_t)COOJA_RADIO_BUFSIZE;
352  return RADIO_RESULT_OK;
353  default:
354  return RADIO_RESULT_NOT_SUPPORTED;
355  }
356 }
357 /*---------------------------------------------------------------------------*/
358 static radio_result_t
359 set_value(radio_param_t param, radio_value_t value)
360 {
361  switch(param) {
362  case RADIO_PARAM_RX_MODE:
363  if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
364  RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
365  return RADIO_RESULT_INVALID_VALUE;
366  }
367 
368  /* Only disabling is acceptable for RADIO_RX_MODE_ADDRESS_FILTER */
369  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
370  return RADIO_RESULT_NOT_SUPPORTED;
371  }
372  set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
373 
374  /* Only disabling is acceptable for RADIO_RX_MODE_AUTOACK */
375  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
376  return RADIO_RESULT_NOT_SUPPORTED;
377  }
378  set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
379 
380  set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
381  return RADIO_RESULT_OK;
382  case RADIO_PARAM_TX_MODE:
383  if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
384  return RADIO_RESULT_INVALID_VALUE;
385  }
386  set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
387  return RADIO_RESULT_OK;
388  case RADIO_PARAM_CHANNEL:
389  if(value < 11 || value > 26) {
390  return RADIO_RESULT_INVALID_VALUE;
391  }
392  radio_set_channel(value);
393  return RADIO_RESULT_OK;
394  default:
395  return RADIO_RESULT_NOT_SUPPORTED;
396  }
397 }
398 /*---------------------------------------------------------------------------*/
399 static radio_result_t
400 get_object(radio_param_t param, void *dest, size_t size)
401 {
402  if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
403  if(size != sizeof(rtimer_clock_t) || !dest) {
404  return RADIO_RESULT_INVALID_VALUE;
405  }
406  *(rtimer_clock_t *)dest = (rtimer_clock_t)simLastPacketTimestamp;
407  return RADIO_RESULT_OK;
408  }
409  return RADIO_RESULT_NOT_SUPPORTED;
410 }
411 /*---------------------------------------------------------------------------*/
412 static radio_result_t
413 set_object(radio_param_t param, const void *src, size_t size)
414 {
415  return RADIO_RESULT_NOT_SUPPORTED;
416 }
417 /*---------------------------------------------------------------------------*/
418 const struct radio_driver cooja_radio_driver =
419 {
420  init,
421  prepare_packet,
422  transmit_packet,
423  radio_send,
424  radio_read,
428  radio_on,
429  radio_off,
430  get_value,
431  set_value,
432  get_object,
433  set_object
434 };
435 /*---------------------------------------------------------------------------*/
436 SIM_INTERFACE(radio_interface,
437  doInterfaceActionsBeforeTick,
438  doInterfaceActionsAfterTick);
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:328
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
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
#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
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
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
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
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:252
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
Definition: radio.h:264
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
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1107
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:334
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99