Contiki 3.x
nullrdc.c
Go to the documentation of this file.
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  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * A null RDC implementation that uses framer for headers.
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  * Niclas Finne <nfi@sics.se>
39  */
40 
41 #include "net/mac/mac-sequence.h"
42 #include "net/mac/nullrdc.h"
43 #include "net/packetbuf.h"
44 #include "net/queuebuf.h"
45 #include "net/netstack.h"
46 #include "net/rime/rimestats.h"
47 #include <string.h>
48 
49 #if CONTIKI_TARGET_COOJA
50 #include "lib/simEnvChange.h"
51 #endif /* CONTIKI_TARGET_COOJA */
52 
53 #define DEBUG 0
54 #if DEBUG
55 #include <stdio.h>
56 #define PRINTF(...) printf(__VA_ARGS__)
57 #else
58 #define PRINTF(...)
59 #endif
60 
61 #ifdef NULLRDC_CONF_ADDRESS_FILTER
62 #define NULLRDC_ADDRESS_FILTER NULLRDC_CONF_ADDRESS_FILTER
63 #else
64 #define NULLRDC_ADDRESS_FILTER 1
65 #endif /* NULLRDC_CONF_ADDRESS_FILTER */
66 
67 #ifndef NULLRDC_802154_AUTOACK
68 #ifdef NULLRDC_CONF_802154_AUTOACK
69 #define NULLRDC_802154_AUTOACK NULLRDC_CONF_802154_AUTOACK
70 #else
71 #define NULLRDC_802154_AUTOACK 0
72 #endif /* NULLRDC_CONF_802154_AUTOACK */
73 #endif /* NULLRDC_802154_AUTOACK */
74 
75 #ifndef NULLRDC_802154_AUTOACK_HW
76 #ifdef NULLRDC_CONF_802154_AUTOACK_HW
77 #define NULLRDC_802154_AUTOACK_HW NULLRDC_CONF_802154_AUTOACK_HW
78 #else
79 #define NULLRDC_802154_AUTOACK_HW 0
80 #endif /* NULLRDC_CONF_802154_AUTOACK_HW */
81 #endif /* NULLRDC_802154_AUTOACK_HW */
82 
83 #if NULLRDC_802154_AUTOACK
84 #include "sys/rtimer.h"
85 #include "dev/watchdog.h"
86 
87 #ifdef NULLRDC_CONF_ACK_WAIT_TIME
88 #define ACK_WAIT_TIME NULLRDC_CONF_ACK_WAIT_TIME
89 #else /* NULLRDC_CONF_ACK_WAIT_TIME */
90 #define ACK_WAIT_TIME RTIMER_SECOND / 2500
91 #endif /* NULLRDC_CONF_ACK_WAIT_TIME */
92 #ifdef NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
93 #define AFTER_ACK_DETECTED_WAIT_TIME NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
94 #else /* NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME */
95 #define AFTER_ACK_DETECTED_WAIT_TIME RTIMER_SECOND / 1500
96 #endif /* NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME */
97 #endif /* NULLRDC_802154_AUTOACK */
98 
99 #ifdef NULLRDC_CONF_SEND_802154_ACK
100 #define NULLRDC_SEND_802154_ACK NULLRDC_CONF_SEND_802154_ACK
101 #else /* NULLRDC_CONF_SEND_802154_ACK */
102 #define NULLRDC_SEND_802154_ACK 0
103 #endif /* NULLRDC_CONF_SEND_802154_ACK */
104 
105 #if NULLRDC_SEND_802154_ACK
106 #include "net/mac/frame802154.h"
107 #endif /* NULLRDC_SEND_802154_ACK */
108 
109 #define ACK_LEN 3
110 
111 /*---------------------------------------------------------------------------*/
112 static int
113 send_one_packet(mac_callback_t sent, void *ptr)
114 {
115  int ret;
116  int last_sent_ok = 0;
117 
118  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
119 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
120  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
121 #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */
122 
123  if(NETSTACK_FRAMER.create_and_secure() < 0) {
124  /* Failed to allocate space for headers */
125  PRINTF("nullrdc: send failed, too large header\n");
126  ret = MAC_TX_ERR_FATAL;
127  } else {
128 #if NULLRDC_802154_AUTOACK
129  int is_broadcast;
130  uint8_t dsn;
131  dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;
132 
133  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());
134 
135  is_broadcast = linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
136  &linkaddr_null);
137 
138  if(NETSTACK_RADIO.receiving_packet() ||
139  (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
140 
141  /* Currently receiving a packet over air or the radio has
142  already received a packet that needs to be read before
143  sending with auto ack. */
144  ret = MAC_TX_COLLISION;
145  } else {
146  if(!is_broadcast) {
147  RIMESTATS_ADD(reliabletx);
148  }
149 
150  switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) {
151  case RADIO_TX_OK:
152  if(is_broadcast) {
153  ret = MAC_TX_OK;
154  } else {
155  rtimer_clock_t wt;
156 
157  /* Check for ack */
158  wt = RTIMER_NOW();
160  while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) {
161 #if CONTIKI_TARGET_COOJA
162  simProcessRunValue = 1;
163  cooja_mt_yield();
164 #endif /* CONTIKI_TARGET_COOJA */
165  }
166 
167  ret = MAC_TX_NOACK;
168  if(NETSTACK_RADIO.receiving_packet() ||
169  NETSTACK_RADIO.pending_packet() ||
170  NETSTACK_RADIO.channel_clear() == 0) {
171  int len;
172  uint8_t ackbuf[ACK_LEN];
173 
174  if(AFTER_ACK_DETECTED_WAIT_TIME > 0) {
175  wt = RTIMER_NOW();
177  while(RTIMER_CLOCK_LT(RTIMER_NOW(),
178  wt + AFTER_ACK_DETECTED_WAIT_TIME)) {
179  #if CONTIKI_TARGET_COOJA
180  simProcessRunValue = 1;
181  cooja_mt_yield();
182  #endif /* CONTIKI_TARGET_COOJA */
183  }
184  }
185 
186  if(NETSTACK_RADIO.pending_packet()) {
187  len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
188  if(len == ACK_LEN && ackbuf[2] == dsn) {
189  /* Ack received */
190  RIMESTATS_ADD(ackrx);
191  ret = MAC_TX_OK;
192  } else {
193  /* Not an ack or ack not for us: collision */
194  ret = MAC_TX_COLLISION;
195  }
196  }
197  } else {
198  PRINTF("nullrdc tx noack\n");
199  }
200  }
201  break;
202  case RADIO_TX_COLLISION:
203  ret = MAC_TX_COLLISION;
204  break;
205  default:
206  ret = MAC_TX_ERR;
207  break;
208  }
209  }
210 
211 #else /* ! NULLRDC_802154_AUTOACK */
212 
213  switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
214  case RADIO_TX_OK:
215  ret = MAC_TX_OK;
216  break;
217  case RADIO_TX_COLLISION:
218  ret = MAC_TX_COLLISION;
219  break;
220  case RADIO_TX_NOACK:
221  ret = MAC_TX_NOACK;
222  break;
223  default:
224  ret = MAC_TX_ERR;
225  break;
226  }
227 
228 #endif /* ! NULLRDC_802154_AUTOACK */
229  }
230  if(ret == MAC_TX_OK) {
231  last_sent_ok = 1;
232  }
233  mac_call_sent_callback(sent, ptr, ret, 1);
234  return last_sent_ok;
235 }
236 /*---------------------------------------------------------------------------*/
237 static void
238 send_packet(mac_callback_t sent, void *ptr)
239 {
240  send_one_packet(sent, ptr);
241 }
242 /*---------------------------------------------------------------------------*/
243 static void
244 send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
245 {
246  while(buf_list != NULL) {
247  /* We backup the next pointer, as it may be nullified by
248  * mac_call_sent_callback() */
249  struct rdc_buf_list *next = buf_list->next;
250  int last_sent_ok;
251 
252  queuebuf_to_packetbuf(buf_list->buf);
253  last_sent_ok = send_one_packet(sent, ptr);
254 
255  /* If packet transmission was not successful, we should back off and let
256  * upper layers retransmit, rather than potentially sending out-of-order
257  * packet fragments. */
258  if(!last_sent_ok) {
259  return;
260  }
261  buf_list = next;
262  }
263 }
264 /*---------------------------------------------------------------------------*/
265 static void
266 packet_input(void)
267 {
268  int original_datalen;
269  uint8_t *original_dataptr;
270 
271  original_datalen = packetbuf_datalen();
272  original_dataptr = packetbuf_dataptr();
273 
274 #if NULLRDC_802154_AUTOACK
275  if(packetbuf_datalen() == ACK_LEN) {
276  /* Ignore ack packets */
277  PRINTF("nullrdc: ignored ack\n");
278  } else
279 #endif /* NULLRDC_802154_AUTOACK */
280  if(NETSTACK_FRAMER.parse() < 0) {
281  PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen());
282 #if NULLRDC_ADDRESS_FILTER
283  } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
284  &linkaddr_node_addr) &&
285  !linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
286  &linkaddr_null)) {
287  PRINTF("nullrdc: not for us\n");
288 #endif /* NULLRDC_ADDRESS_FILTER */
289  } else {
290  int duplicate = 0;
291 
292 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
293 #if RDC_WITH_DUPLICATE_DETECTION
294  /* Check for duplicate packet. */
295  duplicate = mac_sequence_is_duplicate();
296  if(duplicate) {
297  /* Drop the packet. */
298  PRINTF("nullrdc: drop duplicate link layer packet %u\n",
299  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
300  } else {
302  }
303 #endif /* RDC_WITH_DUPLICATE_DETECTION */
304 #endif /* NULLRDC_802154_AUTOACK */
305 
306 /* TODO We may want to acknowledge only authentic frames */
307 #if NULLRDC_SEND_802154_ACK
308  {
309  frame802154_t info154;
310  frame802154_parse(original_dataptr, original_datalen, &info154);
311  if(info154.fcf.frame_type == FRAME802154_DATAFRAME &&
312  info154.fcf.ack_required != 0 &&
313  linkaddr_cmp((linkaddr_t *)&info154.dest_addr,
314  &linkaddr_node_addr)) {
315  uint8_t ackdata[ACK_LEN] = {0, 0, 0};
316 
317  ackdata[0] = FRAME802154_ACKFRAME;
318  ackdata[1] = 0;
319  ackdata[2] = info154.seq;
320  NETSTACK_RADIO.send(ackdata, ACK_LEN);
321  }
322  }
323 #endif /* NULLRDC_SEND_ACK */
324  if(!duplicate) {
325  NETSTACK_MAC.input();
326  }
327  }
328 }
329 /*---------------------------------------------------------------------------*/
330 static int
331 on(void)
332 {
333  return NETSTACK_RADIO.on();
334 }
335 /*---------------------------------------------------------------------------*/
336 static int
337 off(int keep_radio_on)
338 {
339  if(keep_radio_on) {
340  return NETSTACK_RADIO.on();
341  } else {
342  return NETSTACK_RADIO.off();
343  }
344 }
345 /*---------------------------------------------------------------------------*/
346 static unsigned short
347 channel_check_interval(void)
348 {
349  return 0;
350 }
351 /*---------------------------------------------------------------------------*/
352 static void
353 init(void)
354 {
355  on();
356 }
357 /*---------------------------------------------------------------------------*/
358 const struct rdc_driver nullrdc_driver = {
359  "nullrdc",
360  init,
361  send_packet,
362  send_list,
363  packet_input,
364  on,
365  off,
367 };
368 /*---------------------------------------------------------------------------*/
int mac_sequence_is_duplicate(void)
Tell whether the packetbuf is a duplicate packet.
Definition: mac-sequence.c:66
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
802.15.4 frame creation and parsing functions
uint8_t ack_required
1 bit.
Definition: frame802154.h:137
const linkaddr_t linkaddr_null
The null Rime address.
The MAC layer deferred the transmission for a later time.
Definition: mac.h:86
uint8_t frame_type
3 bit.
Definition: frame802154.h:134
Header file for the Rime buffer (packetbuf) management
#define NULL
The null pointer.
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:93
Header file for MAC sequence numbers management
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:260
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:239
Parameters used by the frame802154_create() function.
Definition: frame802154.h:175
uint8_t seq
Sequence number.
Definition: frame802154.h:182
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:213
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:64
Header file for the real-time timer module.
void mac_sequence_register_seqno(void)
Register the sequence number of the packetbuf.
Definition: mac-sequence.c:88
int(* off)(int keep_radio_on)
Turn the MAC layer off.
Definition: rdc.h:86
Header file for the Rime queue buffer management
uint8_t dest_addr[8]
Destination address.
Definition: frame802154.h:179
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
Definition: rdc.h:89
The structure of a RDC (radio duty cycling) driver in Contiki.
Definition: rdc.h:67
void(* init)(void)
Initialize the RDC driver.
Definition: rdc.h:71
The MAC layer transmission was OK.
Definition: mac.h:79
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:133
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:270
A null RDC implementation that uses framer for headers.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
int(* on)(void)
Turn the MAC layer on.
Definition: rdc.h:83
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:83
Header file for Rime statistics
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:181
void(* send_list)(mac_callback_t sent_callback, void *ptr, struct rdc_buf_list *list)
Send a packet list.
Definition: rdc.h:77
Include file for the Contiki low-layer network stack (NETSTACK)