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
59const struct simInterface radio_interface;
60
61
62
63/* The radio driver can provide Cooja these values.
64 * But at present, Cooja ignores and overrides them.
65 * */
66enum {
67 /*
68 * Tmote Sky (with CC2420 radio) gives value -100dB
69 * CC1310 gives about -110dB
70 */
71 RSSI_NO_SIGNAL = -110,
72
73 /*
74 * Tmote Sky (with CC2420 radio) gives value 105
75 * CC1310 gives about 100
76 */
77 LQI_NO_SIGNAL = 100,
78};
79
80/* COOJA */
81char simReceiving = 0;
82char simInDataBuffer[COOJA_RADIO_BUFSIZE];
83int simInSize = 0;
84rtimer_clock_t simLastPacketTimestamp = 0;
85char simOutDataBuffer[COOJA_RADIO_BUFSIZE];
86int simOutSize = 0;
87char simRadioHWOn = 1;
88int simSignalStrength = RSSI_NO_SIGNAL;
89int simLastSignalStrength = RSSI_NO_SIGNAL;
90char simPower = 100;
91int simRadioChannel = 26;
92int simLQI = LQI_NO_SIGNAL;
93int simLastLQI = LQI_NO_SIGNAL;
94
95
96
97static const void *pending_data;
98
99/* If we are in the polling mode, poll_mode is 1; otherwise 0 */
100static int poll_mode = 0; /* default 0, disabled */
101static int auto_ack = 0; /* AUTO_ACK is not supported; always 0 */
102static int addr_filter = 0; /* ADDRESS_FILTER is not supported; always 0 */
103static int send_on_cca = (COOJA_TRANSMIT_ON_CCA != 0);
104
105PROCESS(cooja_radio_process, "cooja radio process");
106/*---------------------------------------------------------------------------*/
107static void
108set_send_on_cca(uint8_t enable)
109{
110 send_on_cca = enable;
111}
112/*---------------------------------------------------------------------------*/
113static void
114set_frame_filtering(int enable)
115{
116 addr_filter = enable;
117}
118/*---------------------------------------------------------------------------*/
119static void
120set_auto_ack(int enable)
121{
122 auto_ack = enable;
123}
124/*---------------------------------------------------------------------------*/
125static void
126set_poll_mode(int enable)
127{
128 poll_mode = enable;
129}
130/*---------------------------------------------------------------------------*/
131void
132radio_set_channel(int channel)
133{
134 simRadioChannel = channel;
135}
136/*---------------------------------------------------------------------------*/
137void
138radio_set_txpower(unsigned char power)
139{
140 /* 1 - 100: Number indicating output power */
141 simPower = power;
142}
143/*---------------------------------------------------------------------------*/
144int
145radio_signal_strength_last(void)
146{
147 return simLastSignalStrength;
148}
149/*---------------------------------------------------------------------------*/
150int
151radio_signal_strength_current(void)
152{
153 return simSignalStrength;
154}
155/*---------------------------------------------------------------------------*/
156int
157radio_LQI(void)
158{
159 return simLQI;
160}
161
162static
163int radio_lqi_last(void)
164{
165 return simLastLQI;
166}
167
168/*---------------------------------------------------------------------------*/
169static int
170radio_on(void)
171{
172 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
173 simRadioHWOn = 1;
174 return 1;
175}
176/*---------------------------------------------------------------------------*/
177static int
178radio_off(void)
179{
180 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
181 simRadioHWOn = 0;
182 return 1;
183}
184/*---------------------------------------------------------------------------*/
185static void
186doInterfaceActionsBeforeTick(void)
187{
188 if(!simRadioHWOn) {
189 simInSize = 0;
190 return;
191 }
192 if(simReceiving) {
193 simLastSignalStrength = simSignalStrength;
194 simLastLQI = simLQI;
195 return;
196 }
197
198 if(simInSize > 0) {
199 process_poll(&cooja_radio_process);
200 }
201}
202/*---------------------------------------------------------------------------*/
203static void
204doInterfaceActionsAfterTick(void)
205{
206}
207/*---------------------------------------------------------------------------*/
208static int
209radio_read(void *buf, unsigned short bufsize)
210{
211 int tmp = simInSize;
212
213 if(simInSize == 0) {
214 return 0;
215 }
216 if(bufsize < simInSize) {
217 simInSize = 0; /* rx flush */
218 return 0;
219 }
220
221 memcpy(buf, simInDataBuffer, simInSize);
222 simInSize = 0;
223 if(!poll_mode) {
224 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_signal_strength_last());
225 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_lqi_last() );
226 }
227
228 return tmp;
229}
230/*---------------------------------------------------------------------------*/
231static int
232channel_clear(void)
233{
234 if(simSignalStrength > CCA_SS_THRESHOLD) {
235 return 0;
236 }
237 return 1;
238}
239/*---------------------------------------------------------------------------*/
240static int
241radio_send(const void *payload, unsigned short payload_len)
242{
243 int result;
244 int radio_was_on = simRadioHWOn;
245
246 if(payload_len > COOJA_RADIO_BUFSIZE) {
247 return RADIO_TX_ERR;
248 }
249 if(payload_len == 0) {
250 return RADIO_TX_ERR;
251 }
252 if(simOutSize > 0) {
253 return RADIO_TX_ERR;
254 }
255
256 if(radio_was_on) {
257 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
258 } else {
259 /* Turn on radio temporarily */
260 simRadioHWOn = 1;
261 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
262 }
263
264#if COOJA_SIMULATE_TURNAROUND
265 simProcessRunValue = 1;
266 cooja_mt_yield();
267 if(payload_len > 3) {
268 simProcessRunValue = 1;
269 cooja_mt_yield();
270 }
271#endif /* COOJA_SIMULATE_TURNAROUND */
272
273 /* Transmit on CCA */
274 if(COOJA_TRANSMIT_ON_CCA && send_on_cca && !channel_clear()) {
275 result = RADIO_TX_COLLISION;
276 } else {
277 /* Copy packet data to temporary storage */
278 memcpy(simOutDataBuffer, payload, payload_len);
279 simOutSize = payload_len;
280
281 /* Transmit */
282 while(simOutSize > 0) {
283 cooja_mt_yield();
284 }
285
286 result = RADIO_TX_OK;
287 }
288
289 if(radio_was_on) {
290 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
291 } else {
292 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
293 }
294
295 simRadioHWOn = radio_was_on;
296 return result;
297}
298/*---------------------------------------------------------------------------*/
299static int
300prepare_packet(const void *data, unsigned short len)
301{
302 if(len > COOJA_RADIO_BUFSIZE) {
303 return RADIO_TX_ERR;
304 }
305 pending_data = data;
306 return 0;
307}
308/*---------------------------------------------------------------------------*/
309static int
310transmit_packet(unsigned short len)
311{
312 int ret = RADIO_TX_ERR;
313 if(pending_data != NULL) {
314 ret = radio_send(pending_data, len);
315 }
316 return ret;
317}
318/*---------------------------------------------------------------------------*/
319static int
320receiving_packet(void)
321{
322 return simReceiving;
323}
324/*---------------------------------------------------------------------------*/
325static int
326pending_packet(void)
327{
328 return !simReceiving && simInSize > 0;
329}
330/*---------------------------------------------------------------------------*/
331PROCESS_THREAD(cooja_radio_process, ev, data)
332{
333 int len;
334
336
337 while(1) {
338 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
339 if(poll_mode) {
340 continue;
341 }
342
344 len = radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
345 if(len > 0) {
347 NETSTACK_MAC.input();
348 }
349 }
350
351 PROCESS_END();
352}
353/*---------------------------------------------------------------------------*/
354static int
355init(void)
356{
357 process_start(&cooja_radio_process, NULL);
358 return 1;
359}
360/*---------------------------------------------------------------------------*/
361static radio_result_t
362get_value(radio_param_t param, radio_value_t *value)
363{
364 switch(param) {
366 *value = 0;
367 if(addr_filter) {
369 }
370 if(auto_ack) {
371 *value |= RADIO_RX_MODE_AUTOACK;
372 }
373 if(poll_mode) {
374 *value |= RADIO_RX_MODE_POLL_MODE;
375 }
376 return RADIO_RESULT_OK;
378 *value = 0;
379 if(send_on_cca) {
381 }
382 return RADIO_RESULT_OK;
384 *value = radio_signal_strength_last();
385 return RADIO_RESULT_OK;
386
388 *value = radio_lqi_last();
389 return RADIO_RESULT_OK;
390
391 case RADIO_PARAM_RSSI:
392 *value = radio_signal_strength_current();
393 return RADIO_RESULT_OK;
394
395 case RADIO_CONST_MAX_PAYLOAD_LEN:
396 *value = (radio_value_t)COOJA_RADIO_BUFSIZE;
397 return RADIO_RESULT_OK;
398 default:
400 }
401}
402/*---------------------------------------------------------------------------*/
403static radio_result_t
404set_value(radio_param_t param, radio_value_t value)
405{
406 switch(param) {
408 if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
411 }
412
413 /* Only disabling is acceptable for RADIO_RX_MODE_ADDRESS_FILTER */
414 if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
416 }
417 set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
418
419 /* Only disabling is acceptable for RADIO_RX_MODE_AUTOACK */
420 if ((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0) {
422 }
423 set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
424
425 set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
426 return RADIO_RESULT_OK;
428 if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
430 }
431 set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
432 return RADIO_RESULT_OK;
434 /* With channel value < 0 Cooja matches any channels:
435 * - send packets on a negative channel -> to any receiver's channels.
436 * - receive on a negative channel <- get packets from any sender's channels.
437 * So, negative channel are useful for wide-band noise generation.
438 * Or for wide-band sniffing.
439 * */
440 radio_set_channel(value);
441 return RADIO_RESULT_OK;
442 default:
444 }
445}
446/*---------------------------------------------------------------------------*/
447static radio_result_t
448get_object(radio_param_t param, void *dest, size_t size)
449{
451 if(size != sizeof(rtimer_clock_t) || !dest) {
453 }
454 *(rtimer_clock_t *)dest = (rtimer_clock_t)simLastPacketTimestamp;
455 return RADIO_RESULT_OK;
456 }
458}
459/*---------------------------------------------------------------------------*/
460static radio_result_t
461set_object(radio_param_t param, const void *src, size_t size)
462{
464}
465/*---------------------------------------------------------------------------*/
466const struct radio_driver cooja_radio_driver =
467{
468 init,
469 prepare_packet,
470 transmit_packet,
471 radio_send,
472 radio_read,
476 radio_on,
477 radio_off,
478 get_value,
479 set_value,
482};
483/*---------------------------------------------------------------------------*/
484SIM_INTERFACE(radio_interface,
485 doInterfaceActionsBeforeTick,
486 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:1110
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:443
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Definition: radio.h:453
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition: radio.h:466
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:448
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
Definition: radio.h:473
@ RADIO_RESULT_INVALID_VALUE
The value argument was incorrect.
Definition: radio.h:474
@ RADIO_RESULT_OK
The parameter was set/read successfully.
Definition: radio.h:472
@ 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:278
@ 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:236
@ 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:503
@ RADIO_TX_ERR
An error occurred during transmission.
Definition: radio.h:498
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
Definition: radio.h:490
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:526
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:762
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:748
int(* init)(void)
Initialise the radio hardware.
Definition: radio.h:547
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:676
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:779
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
Definition: radio.h:689
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:733
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