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 MIN_CHANNEL 11
58#define MAX_CHANNEL 26
59#define CCA_SS_THRESHOLD -95
60
61const struct simInterface radio_interface;
62
63
64
65/* The radio driver can provide Cooja these values.
66 * But at present, Cooja ignores and overrides them.
67 * */
68enum {
69 /*
70 * Tmote Sky (with CC2420 radio) gives value -100dB
71 * CC1310 gives about -110dB
72 */
73 RSSI_NO_SIGNAL = -110,
74
75 /*
76 * Tmote Sky (with CC2420 radio) gives value 105
77 * CC1310 gives about 100
78 */
79 LQI_NO_SIGNAL = 100,
80};
81
82/* COOJA */
83char simReceiving = 0;
84char simInDataBuffer[COOJA_RADIO_BUFSIZE];
85int simInSize = 0;
86rtimer_clock_t simLastPacketTimestamp = 0;
87char simOutDataBuffer[COOJA_RADIO_BUFSIZE];
88int simOutSize = 0;
89char simRadioHWOn = 1;
90int simSignalStrength = RSSI_NO_SIGNAL;
91int simLastSignalStrength = RSSI_NO_SIGNAL;
92char simPower = 100;
93int simRadioChannel = MAX_CHANNEL;
94int simLQI = LQI_NO_SIGNAL;
95int simLastLQI = LQI_NO_SIGNAL;
96
97
98
99static const void *pending_data;
100
101/* If we are in the polling mode, poll_mode is 1; otherwise 0 */
102static int poll_mode = 0; /* default 0, disabled */
103static int auto_ack = 0; /* AUTO_ACK is not supported; always 0 */
104static int addr_filter = 0; /* ADDRESS_FILTER is not supported; always 0 */
105static int send_on_cca = (COOJA_TRANSMIT_ON_CCA != 0);
106
107PROCESS(cooja_radio_process, "cooja radio process");
108/*---------------------------------------------------------------------------*/
109static void
110set_send_on_cca(uint8_t enable)
111{
112 send_on_cca = enable;
113}
114/*---------------------------------------------------------------------------*/
115static void
116set_frame_filtering(int enable)
117{
118 addr_filter = enable;
119}
120/*---------------------------------------------------------------------------*/
121static void
122set_auto_ack(int enable)
123{
124 auto_ack = enable;
125}
126/*---------------------------------------------------------------------------*/
127static void
128set_poll_mode(int enable)
129{
130 poll_mode = enable;
131}
132/*---------------------------------------------------------------------------*/
133void
134radio_set_channel(int channel)
135{
136 simRadioChannel = channel;
137}
138/*---------------------------------------------------------------------------*/
139void
140radio_set_txpower(unsigned char power)
141{
142 /* 1 - 100: Number indicating output power */
143 simPower = power;
144}
145/*---------------------------------------------------------------------------*/
146int
147radio_signal_strength_last(void)
148{
149 return simLastSignalStrength;
150}
151/*---------------------------------------------------------------------------*/
152int
153radio_signal_strength_current(void)
154{
155 return simSignalStrength;
156}
157/*---------------------------------------------------------------------------*/
158int
159radio_LQI(void)
160{
161 return simLQI;
162}
163
164static
165int radio_lqi_last(void)
166{
167 return simLastLQI;
168}
169
170/*---------------------------------------------------------------------------*/
171static int
172radio_on(void)
173{
174 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
175 simRadioHWOn = 1;
176 return 1;
177}
178/*---------------------------------------------------------------------------*/
179static int
180radio_off(void)
181{
182 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
183 simRadioHWOn = 0;
184 return 1;
185}
186/*---------------------------------------------------------------------------*/
187static void
188doInterfaceActionsBeforeTick(void)
189{
190 if(!simRadioHWOn) {
191 simInSize = 0;
192 return;
193 }
194 if(simReceiving) {
195 simLastSignalStrength = simSignalStrength;
196 simLastLQI = simLQI;
197 return;
198 }
199
200 if(simInSize > 0) {
201 process_poll(&cooja_radio_process);
202 }
203}
204/*---------------------------------------------------------------------------*/
205static void
206doInterfaceActionsAfterTick(void)
207{
208}
209/*---------------------------------------------------------------------------*/
210static int
211radio_read(void *buf, unsigned short bufsize)
212{
213 int tmp = simInSize;
214
215 if(simInSize == 0) {
216 return 0;
217 }
218 if(bufsize < simInSize) {
219 simInSize = 0; /* rx flush */
220 return 0;
221 }
222
223 memcpy(buf, simInDataBuffer, simInSize);
224 simInSize = 0;
225 if(!poll_mode) {
226 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_signal_strength_last());
227 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_lqi_last() );
228 }
229
230 return tmp;
231}
232/*---------------------------------------------------------------------------*/
233static int
234channel_clear(void)
235{
236 if(simSignalStrength > CCA_SS_THRESHOLD) {
237 return 0;
238 }
239 return 1;
240}
241/*---------------------------------------------------------------------------*/
242static int
243radio_send(const void *payload, unsigned short payload_len)
244{
245 int result;
246 int radio_was_on = simRadioHWOn;
247
248 if(payload_len > COOJA_RADIO_BUFSIZE) {
249 return RADIO_TX_ERR;
250 }
251 if(payload_len == 0) {
252 return RADIO_TX_ERR;
253 }
254 if(simOutSize > 0) {
255 return RADIO_TX_ERR;
256 }
257
258 if(radio_was_on) {
259 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
260 } else {
261 /* Turn on radio temporarily */
262 simRadioHWOn = 1;
263 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
264 }
265
266#if COOJA_SIMULATE_TURNAROUND
267 simProcessRunValue = 1;
268 cooja_mt_yield();
269 if(payload_len > 3) {
270 simProcessRunValue = 1;
271 cooja_mt_yield();
272 }
273#endif /* COOJA_SIMULATE_TURNAROUND */
274
275 /* Transmit on CCA */
276 if(COOJA_TRANSMIT_ON_CCA && send_on_cca && !channel_clear()) {
277 result = RADIO_TX_COLLISION;
278 } else {
279 /* Copy packet data to temporary storage */
280 memcpy(simOutDataBuffer, payload, payload_len);
281 simOutSize = payload_len;
282
283 /* Transmit */
284 while(simOutSize > 0) {
285 cooja_mt_yield();
286 }
287
288 result = RADIO_TX_OK;
289 }
290
291 if(radio_was_on) {
292 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
293 } else {
294 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
295 }
296
297 simRadioHWOn = radio_was_on;
298 return result;
299}
300/*---------------------------------------------------------------------------*/
301static int
302prepare_packet(const void *data, unsigned short len)
303{
304 if(len > COOJA_RADIO_BUFSIZE) {
305 return RADIO_TX_ERR;
306 }
307 pending_data = data;
308 return 0;
309}
310/*---------------------------------------------------------------------------*/
311static int
312transmit_packet(unsigned short len)
313{
314 int ret = RADIO_TX_ERR;
315 if(pending_data != NULL) {
316 ret = radio_send(pending_data, len);
317 }
318 return ret;
319}
320/*---------------------------------------------------------------------------*/
321static int
322receiving_packet(void)
323{
324 return simReceiving;
325}
326/*---------------------------------------------------------------------------*/
327static int
328pending_packet(void)
329{
330 return !simReceiving && simInSize > 0;
331}
332/*---------------------------------------------------------------------------*/
333PROCESS_THREAD(cooja_radio_process, ev, data)
334{
335 int len;
336
338
339 while(1) {
340 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
341 if(poll_mode) {
342 continue;
343 }
344
346 len = radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
347 if(len > 0) {
349 NETSTACK_MAC.input();
350 }
351 }
352
353 PROCESS_END();
354}
355/*---------------------------------------------------------------------------*/
356static int
357init(void)
358{
359 process_start(&cooja_radio_process, NULL);
360 return 1;
361}
362/*---------------------------------------------------------------------------*/
363static radio_result_t
364get_value(radio_param_t param, radio_value_t *value)
365{
366 switch(param) {
368 *value = 0;
369 if(addr_filter) {
371 }
372 if(auto_ack) {
373 *value |= RADIO_RX_MODE_AUTOACK;
374 }
375 if(poll_mode) {
376 *value |= RADIO_RX_MODE_POLL_MODE;
377 }
378 return RADIO_RESULT_OK;
380 *value = 0;
381 if(send_on_cca) {
383 }
384 return RADIO_RESULT_OK;
386 *value = radio_signal_strength_last();
387 return RADIO_RESULT_OK;
388
390 *value = radio_lqi_last();
391 return RADIO_RESULT_OK;
392
393 case RADIO_PARAM_RSSI:
394 *value = radio_signal_strength_current();
395 return RADIO_RESULT_OK;
396
397 case RADIO_CONST_MAX_PAYLOAD_LEN:
398 *value = (radio_value_t)COOJA_RADIO_BUFSIZE;
399 return RADIO_RESULT_OK;
401 *value = simRadioChannel;
402 return RADIO_RESULT_OK;
404 *value = MIN_CHANNEL;
405 return RADIO_RESULT_OK;
407 *value = MAX_CHANNEL;
408 return RADIO_RESULT_OK;
409 default:
411 }
412}
413/*---------------------------------------------------------------------------*/
414static radio_result_t
415set_value(radio_param_t param, radio_value_t value)
416{
417 switch(param) {
419 if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
422 }
423
424 /* Only disabling is acceptable for RADIO_RX_MODE_ADDRESS_FILTER */
425 if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
427 }
428 set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
429
430 /* Only disabling is acceptable for RADIO_RX_MODE_AUTOACK */
431 if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
433 }
434 set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
435
436 set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
437 return RADIO_RESULT_OK;
439 if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
441 }
442 set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
443 return RADIO_RESULT_OK;
445 /* With channel value < 0 Cooja matches any channels:
446 * - send packets on a negative channel -> to any receiver's channels.
447 * - receive on a negative channel <- get packets from any sender's channels.
448 * So, negative channel are useful for wide-band noise generation.
449 * Or for wide-band sniffing.
450 * */
451 radio_set_channel(value);
452 return RADIO_RESULT_OK;
453 default:
455 }
456}
457/*---------------------------------------------------------------------------*/
458static radio_result_t
459get_object(radio_param_t param, void *dest, size_t size)
460{
462 if(size != sizeof(rtimer_clock_t) || !dest) {
464 }
465 *(rtimer_clock_t *)dest = (rtimer_clock_t)simLastPacketTimestamp;
466 return RADIO_RESULT_OK;
467 }
469}
470/*---------------------------------------------------------------------------*/
471static radio_result_t
472set_object(radio_param_t param, const void *src, size_t size)
473{
475}
476/*---------------------------------------------------------------------------*/
477const struct radio_driver cooja_radio_driver =
478{
479 init,
480 prepare_packet,
481 transmit_packet,
482 radio_send,
483 radio_read,
487 radio_on,
488 radio_off,
489 get_value,
490 set_value,
493};
494/*---------------------------------------------------------------------------*/
495SIM_INTERFACE(radio_interface,
496 doInterfaceActionsBeforeTick,
497 doInterfaceActionsAfterTick);
Header file for the energy estimation mechanism.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#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
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
Definition: radio.h:451
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Definition: radio.h:461
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition: radio.h:474
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
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
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
Definition: radio.h:456
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
Definition: radio.h:481
@ RADIO_RESULT_INVALID_VALUE
The value argument was incorrect.
Definition: radio.h:482
@ RADIO_RESULT_OK
The parameter was set/read successfully.
Definition: radio.h:480
@ RADIO_PARAM_RSSI
Received signal strength indicator in dBm.
Definition: radio.h:218
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
Definition: radio.h:286
@ RADIO_PARAM_LAST_RSSI
The RSSI value of the last received packet.
Definition: radio.h:226
@ RADIO_PARAM_RX_MODE
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
Definition: radio.h:173
@ RADIO_PARAM_CHANNEL
Channel used for radio communication.
Definition: radio.h:134
@ RADIO_PARAM_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
Definition: radio.h:244
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
Definition: radio.h:316
@ RADIO_CONST_CHANNEL_MIN
The lowest radio channel number.
Definition: radio.h:311
@ RADIO_PARAM_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
Definition: radio.h:180
@ RADIO_TX_COLLISION
TX failed due to a collision.
Definition: radio.h:511
@ RADIO_TX_ERR
An error occurred during transmission.
Definition: radio.h:506
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
Definition: radio.h:498
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the radio API.
void(* input)(void)
Callback for getting notified of incoming packet.
Definition: mac.h:72
The structure of a Contiki-NG radio device driver.
Definition: radio.h:534
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:770
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:756
int(* init)(void)
Initialise the radio hardware.
Definition: radio.h:555
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:684
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:787
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
Definition: radio.h:697
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:741
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:672