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