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 PACKETBUF_SIZE
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  pending_data = data;
250  return 0;
251 }
252 /*---------------------------------------------------------------------------*/
253 static int
254 transmit_packet(unsigned short len)
255 {
256  int ret = RADIO_TX_ERR;
257  if(pending_data != NULL) {
258  ret = radio_send(pending_data, len);
259  }
260  return ret;
261 }
262 /*---------------------------------------------------------------------------*/
263 static int
264 receiving_packet(void)
265 {
266  return simReceiving;
267 }
268 /*---------------------------------------------------------------------------*/
269 static int
270 pending_packet(void)
271 {
272  return !simReceiving && simInSize > 0;
273 }
274 /*---------------------------------------------------------------------------*/
275 PROCESS_THREAD(cooja_radio_process, ev, data)
276 {
277  int len;
278 
279  PROCESS_BEGIN();
280 
281  while(1) {
282  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
283  if(poll_mode) {
284  continue;
285  }
286 
287  packetbuf_clear();
288  len = radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
289  if(len > 0) {
291  NETSTACK_MAC.input();
292  }
293  }
294 
295  PROCESS_END();
296 }
297 /*---------------------------------------------------------------------------*/
298 static int
299 init(void)
300 {
301  process_start(&cooja_radio_process, NULL);
302  return 1;
303 }
304 /*---------------------------------------------------------------------------*/
305 static radio_result_t
306 get_value(radio_param_t param, radio_value_t *value)
307 {
308  switch(param) {
309  case RADIO_PARAM_RX_MODE:
310  *value = 0;
311  if(addr_filter) {
313  }
314  if(auto_ack) {
315  *value |= RADIO_RX_MODE_AUTOACK;
316  }
317  if(poll_mode) {
318  *value |= RADIO_RX_MODE_POLL_MODE;
319  }
320  return RADIO_RESULT_OK;
321  case RADIO_PARAM_TX_MODE:
322  *value = 0;
323  if(send_on_cca) {
324  *value |= RADIO_TX_MODE_SEND_ON_CCA;
325  }
326  return RADIO_RESULT_OK;
327  case RADIO_PARAM_LAST_RSSI:
328  *value = simSignalStrength;
329  return RADIO_RESULT_OK;
330  case RADIO_PARAM_LAST_LINK_QUALITY:
331  *value = simLQI;
332  return RADIO_RESULT_OK;
333  case RADIO_PARAM_RSSI:
334  /* return a fixed value depending on the channel */
335  *value = -90 + simRadioChannel - 11;
336  return RADIO_RESULT_OK;
337  default:
338  return RADIO_RESULT_NOT_SUPPORTED;
339  }
340 }
341 /*---------------------------------------------------------------------------*/
342 static radio_result_t
343 set_value(radio_param_t param, radio_value_t value)
344 {
345  switch(param) {
346  case RADIO_PARAM_RX_MODE:
347  if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
348  RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
349  return RADIO_RESULT_INVALID_VALUE;
350  }
351 
352  /* Only disabling is acceptable for RADIO_RX_MODE_ADDRESS_FILTER */
353  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
354  return RADIO_RESULT_NOT_SUPPORTED;
355  }
356  set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
357 
358  /* Only disabling is acceptable for RADIO_RX_MODE_AUTOACK */
359  if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
360  return RADIO_RESULT_NOT_SUPPORTED;
361  }
362  set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
363 
364  set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
365  return RADIO_RESULT_OK;
366  case RADIO_PARAM_TX_MODE:
367  if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
368  return RADIO_RESULT_INVALID_VALUE;
369  }
370  set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
371  return RADIO_RESULT_OK;
372  case RADIO_PARAM_CHANNEL:
373  if(value < 11 || value > 26) {
374  return RADIO_RESULT_INVALID_VALUE;
375  }
376  radio_set_channel(value);
377  return RADIO_RESULT_OK;
378  default:
379  return RADIO_RESULT_NOT_SUPPORTED;
380  }
381 }
382 /*---------------------------------------------------------------------------*/
383 static radio_result_t
384 get_object(radio_param_t param, void *dest, size_t size)
385 {
386  if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
387  if(size != sizeof(rtimer_clock_t) || !dest) {
388  return RADIO_RESULT_INVALID_VALUE;
389  }
390  *(rtimer_clock_t *)dest = (rtimer_clock_t)simLastPacketTimestamp;
391  return RADIO_RESULT_OK;
392  }
393  return RADIO_RESULT_NOT_SUPPORTED;
394 }
395 /*---------------------------------------------------------------------------*/
396 static radio_result_t
397 set_object(radio_param_t param, const void *src, size_t size)
398 {
399  return RADIO_RESULT_NOT_SUPPORTED;
400 }
401 /*---------------------------------------------------------------------------*/
402 const struct radio_driver cooja_radio_driver =
403 {
404  init,
405  prepare_packet,
406  transmit_packet,
407  radio_send,
408  radio_read,
412  radio_on,
413  radio_off,
414  get_value,
415  set_value,
416  get_object,
417  set_object
418 };
419 /*---------------------------------------------------------------------------*/
420 SIM_INTERFACE(radio_interface,
421  doInterfaceActionsBeforeTick,
422  doInterfaceActionsAfterTick);
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:290
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:268
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:283
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
Definition: radio.h:271
The structure of a device driver for a radio in Contiki.
Definition: radio.h:247
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:265
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:66
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:214
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
Definition: radio.h:226
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:280
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1035
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:296
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