Contiki-Inga 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() < 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 
129 #ifdef NETSTACK_ENCRYPT
130  NETSTACK_ENCRYPT();
131 #endif /* NETSTACK_ENCRYPT */
132 
133 #if NULLRDC_802154_AUTOACK
134  int is_broadcast;
135  uint8_t dsn;
136  dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;
137 
138  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());
139 
140  is_broadcast = linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
141  &linkaddr_null);
142 
143  if(NETSTACK_RADIO.receiving_packet() ||
144  (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
145 
146  /* Currently receiving a packet over air or the radio has
147  already received a packet that needs to be read before
148  sending with auto ack. */
149  ret = MAC_TX_COLLISION;
150  } else {
151  if(!is_broadcast) {
152  RIMESTATS_ADD(reliabletx);
153  }
154 
155  switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) {
156  case RADIO_TX_OK:
157  if(is_broadcast) {
158  ret = MAC_TX_OK;
159  } else {
160  rtimer_clock_t wt;
161 
162  /* Check for ack */
163  wt = RTIMER_NOW();
165  while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) {
166 #if CONTIKI_TARGET_COOJA
167  simProcessRunValue = 1;
168  cooja_mt_yield();
169 #endif /* CONTIKI_TARGET_COOJA */
170  }
171 
172  ret = MAC_TX_NOACK;
173  if(NETSTACK_RADIO.receiving_packet() ||
174  NETSTACK_RADIO.pending_packet() ||
175  NETSTACK_RADIO.channel_clear() == 0) {
176  int len;
177  uint8_t ackbuf[ACK_LEN];
178 
179  if(AFTER_ACK_DETECTED_WAIT_TIME > 0) {
180  wt = RTIMER_NOW();
182  while(RTIMER_CLOCK_LT(RTIMER_NOW(),
183  wt + AFTER_ACK_DETECTED_WAIT_TIME)) {
184  #if CONTIKI_TARGET_COOJA
185  simProcessRunValue = 1;
186  cooja_mt_yield();
187  #endif /* CONTIKI_TARGET_COOJA */
188  }
189  }
190 
191  if(NETSTACK_RADIO.pending_packet()) {
192  len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
193  if(len == ACK_LEN && ackbuf[2] == dsn) {
194  /* Ack received */
195  RIMESTATS_ADD(ackrx);
196  ret = MAC_TX_OK;
197  } else {
198  /* Not an ack or ack not for us: collision */
199  ret = MAC_TX_COLLISION;
200  }
201  }
202  } else {
203  PRINTF("nullrdc tx noack\n");
204  }
205  }
206  break;
207  case RADIO_TX_COLLISION:
208  ret = MAC_TX_COLLISION;
209  break;
210  default:
211  ret = MAC_TX_ERR;
212  break;
213  }
214  }
215 
216 #else /* ! NULLRDC_802154_AUTOACK */
217 
218  switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
219  case RADIO_TX_OK:
220  ret = MAC_TX_OK;
221  break;
222  case RADIO_TX_COLLISION:
223  ret = MAC_TX_COLLISION;
224  break;
225  case RADIO_TX_NOACK:
226  ret = MAC_TX_NOACK;
227  break;
228  default:
229  ret = MAC_TX_ERR;
230  break;
231  }
232 
233 #endif /* ! NULLRDC_802154_AUTOACK */
234  }
235  if(ret == MAC_TX_OK) {
236  last_sent_ok = 1;
237  }
238  mac_call_sent_callback(sent, ptr, ret, 1);
239  return last_sent_ok;
240 }
241 /*---------------------------------------------------------------------------*/
242 static void
243 send_packet(mac_callback_t sent, void *ptr)
244 {
245  send_one_packet(sent, ptr);
246 }
247 /*---------------------------------------------------------------------------*/
248 static void
249 send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
250 {
251  while(buf_list != NULL) {
252  /* We backup the next pointer, as it may be nullified by
253  * mac_call_sent_callback() */
254  struct rdc_buf_list *next = buf_list->next;
255  int last_sent_ok;
256 
257  queuebuf_to_packetbuf(buf_list->buf);
258  last_sent_ok = send_one_packet(sent, ptr);
259 
260  /* If packet transmission was not successful, we should back off and let
261  * upper layers retransmit, rather than potentially sending out-of-order
262  * packet fragments. */
263  if(!last_sent_ok) {
264  return;
265  }
266  buf_list = next;
267  }
268 }
269 /*---------------------------------------------------------------------------*/
270 static void
271 packet_input(void)
272 {
273  int original_datalen;
274  uint8_t *original_dataptr;
275 
276  original_datalen = packetbuf_datalen();
277  original_dataptr = packetbuf_dataptr();
278 #ifdef NETSTACK_DECRYPT
279  NETSTACK_DECRYPT();
280 #endif /* NETSTACK_DECRYPT */
281 
282 #if NULLRDC_802154_AUTOACK
283  if(packetbuf_datalen() == ACK_LEN) {
284  /* Ignore ack packets */
285  PRINTF("nullrdc: ignored ack\n");
286  } else
287 #endif /* NULLRDC_802154_AUTOACK */
288  if(NETSTACK_FRAMER.parse() < 0) {
289  PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen());
290 #if NULLRDC_ADDRESS_FILTER
291  } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
292  &linkaddr_node_addr) &&
293  !linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
294  &linkaddr_null)) {
295  PRINTF("nullrdc: not for us\n");
296 #endif /* NULLRDC_ADDRESS_FILTER */
297  } else {
298  int duplicate = 0;
299 
300 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
301  /* Check for duplicate packet. */
302  duplicate = mac_sequence_is_duplicate();
303  if(duplicate) {
304  /* Drop the packet. */
305  PRINTF("nullrdc: drop duplicate link layer packet %u\n",
306  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
307  } else {
309  }
310 #endif /* NULLRDC_802154_AUTOACK */
311 
312 #if NULLRDC_SEND_802154_ACK
313  {
314  frame802154_t info154;
315  frame802154_parse(original_dataptr, original_datalen, &info154);
316  if(info154.fcf.frame_type == FRAME802154_DATAFRAME &&
317  info154.fcf.ack_required != 0 &&
318  linkaddr_cmp((linkaddr_t *)&info154.dest_addr,
319  &linkaddr_node_addr)) {
320  uint8_t ackdata[ACK_LEN] = {0, 0, 0};
321 
322  ackdata[0] = FRAME802154_ACKFRAME;
323  ackdata[1] = 0;
324  ackdata[2] = info154.seq;
325  NETSTACK_RADIO.send(ackdata, ACK_LEN);
326  }
327  }
328 #endif /* NULLRDC_SEND_ACK */
329  if(!duplicate) {
330  NETSTACK_MAC.input();
331  }
332  }
333 }
334 /*---------------------------------------------------------------------------*/
335 static int
336 on(void)
337 {
338  return NETSTACK_RADIO.on();
339 }
340 /*---------------------------------------------------------------------------*/
341 static int
342 off(int keep_radio_on)
343 {
344  if(keep_radio_on) {
345  return NETSTACK_RADIO.on();
346  } else {
347  return NETSTACK_RADIO.off();
348  }
349 }
350 /*---------------------------------------------------------------------------*/
351 static unsigned short
352 channel_check_interval(void)
353 {
354  return 0;
355 }
356 /*---------------------------------------------------------------------------*/
357 static void
358 init(void)
359 {
360  on();
361 }
362 /*---------------------------------------------------------------------------*/
363 const struct rdc_driver nullrdc_driver = {
364  "nullrdc",
365  init,
366  send_packet,
367  send_list,
368  packet_input,
369  on,
370  off,
372 };
373 /*---------------------------------------------------------------------------*/