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