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 #include "sys/cooja_mt.h"
52 #endif /* CONTIKI_TARGET_COOJA */
53 
54 #define DEBUG 0
55 #if DEBUG
56 #include <stdio.h>
57 #define PRINTF(...) printf(__VA_ARGS__)
58 #else
59 #define PRINTF(...)
60 #endif
61 
62 #ifdef NULLRDC_CONF_ADDRESS_FILTER
63 #define NULLRDC_ADDRESS_FILTER NULLRDC_CONF_ADDRESS_FILTER
64 #else
65 #define NULLRDC_ADDRESS_FILTER 1
66 #endif /* NULLRDC_CONF_ADDRESS_FILTER */
67 
68 #ifndef NULLRDC_802154_AUTOACK
69 #ifdef NULLRDC_CONF_802154_AUTOACK
70 #define NULLRDC_802154_AUTOACK NULLRDC_CONF_802154_AUTOACK
71 #else
72 #define NULLRDC_802154_AUTOACK 0
73 #endif /* NULLRDC_CONF_802154_AUTOACK */
74 #endif /* NULLRDC_802154_AUTOACK */
75 
76 #ifndef NULLRDC_802154_AUTOACK_HW
77 #ifdef NULLRDC_CONF_802154_AUTOACK_HW
78 #define NULLRDC_802154_AUTOACK_HW NULLRDC_CONF_802154_AUTOACK_HW
79 #else
80 #define NULLRDC_802154_AUTOACK_HW 0
81 #endif /* NULLRDC_CONF_802154_AUTOACK_HW */
82 #endif /* NULLRDC_802154_AUTOACK_HW */
83 
84 #if NULLRDC_802154_AUTOACK
85 #include "sys/rtimer.h"
86 #include "dev/watchdog.h"
87 
88 #ifdef NULLRDC_CONF_ACK_WAIT_TIME
89 #define ACK_WAIT_TIME NULLRDC_CONF_ACK_WAIT_TIME
90 #else /* NULLRDC_CONF_ACK_WAIT_TIME */
91 #define ACK_WAIT_TIME RTIMER_SECOND / 2500
92 #endif /* NULLRDC_CONF_ACK_WAIT_TIME */
93 #ifdef NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
94 #define AFTER_ACK_DETECTED_WAIT_TIME NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
95 #else /* NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME */
96 #define AFTER_ACK_DETECTED_WAIT_TIME RTIMER_SECOND / 1500
97 #endif /* NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME */
98 #endif /* NULLRDC_802154_AUTOACK */
99 
100 #ifdef NULLRDC_CONF_SEND_802154_ACK
101 #define NULLRDC_SEND_802154_ACK NULLRDC_CONF_SEND_802154_ACK
102 #else /* NULLRDC_CONF_SEND_802154_ACK */
103 #define NULLRDC_SEND_802154_ACK 0
104 #endif /* NULLRDC_CONF_SEND_802154_ACK */
105 
106 #if NULLRDC_SEND_802154_ACK
107 #include "net/mac/frame802154.h"
108 #endif /* NULLRDC_SEND_802154_ACK */
109 
110 #define ACK_LEN 3
111 
112 /*---------------------------------------------------------------------------*/
113 static int
114 send_one_packet(mac_callback_t sent, void *ptr)
115 {
116  int ret;
117  int last_sent_ok = 0;
118 
119  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
120 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
121  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
122 #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */
123 
124  if(NETSTACK_FRAMER.create() < 0) {
125  /* Failed to allocate space for headers */
126  PRINTF("nullrdc: send failed, too large header\n");
127  ret = MAC_TX_ERR_FATAL;
128  } else {
129 #if NULLRDC_802154_AUTOACK
130  int is_broadcast;
131  uint8_t dsn;
132  dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;
133 
134  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());
135 
136  is_broadcast = packetbuf_holds_broadcast();
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 #if NULLRDC_SEND_802154_ACK
269  int original_datalen;
270  uint8_t *original_dataptr;
271 
272  original_datalen = packetbuf_datalen();
273  original_dataptr = packetbuf_dataptr();
274 #endif
275 
276 #if NULLRDC_802154_AUTOACK
277  if(packetbuf_datalen() == ACK_LEN) {
278  /* Ignore ack packets */
279  PRINTF("nullrdc: ignored ack\n");
280  } else
281 #endif /* NULLRDC_802154_AUTOACK */
282  if(NETSTACK_FRAMER.parse() < 0) {
283  PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen());
284 #if NULLRDC_ADDRESS_FILTER
285  } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
286  &linkaddr_node_addr) &&
288  PRINTF("nullrdc: not for us\n");
289 #endif /* NULLRDC_ADDRESS_FILTER */
290  } else {
291  int duplicate = 0;
292 
293 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
294 #if RDC_WITH_DUPLICATE_DETECTION
295  /* Check for duplicate packet. */
296  duplicate = mac_sequence_is_duplicate();
297  if(duplicate) {
298  /* Drop the packet. */
299  PRINTF("nullrdc: drop duplicate link layer packet %u\n",
300  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
301  } else {
303  }
304 #endif /* RDC_WITH_DUPLICATE_DETECTION */
305 #endif /* NULLRDC_802154_AUTOACK */
306 
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 /*---------------------------------------------------------------------------*/
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:158
void(* send_list)(mac_callback_t sent_callback, void *ptr, struct rdc_buf_list *list)
Send a packet list.
Definition: rdc.h:78
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
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
Definition: rdc.h:90
uint8_t dest_addr[8]
Destination address.
Definition: frame802154.h:196
The MAC layer deferred the transmission for a later time.
Definition: mac.h:86
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:83
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:198
int(* off)(int keep_radio_on)
Turn the MAC layer off.
Definition: rdc.h:87
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
int(* on)(void)
Turn the MAC layer on.
Definition: rdc.h:84
uint8_t seq
Sequence number.
Definition: frame802154.h:199
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:182
Header file for MAC sequence numbers management
int packetbuf_holds_broadcast(void)
Checks whether the current packet is a broadcast.
Definition: packetbuf.c:242
int mac_sequence_is_duplicate(void)
Tell whether the packetbuf is a duplicate packet.
Definition: mac-sequence.c:66
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:164
Header file for the Rime buffer (packetbuf) management
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:93
void(* init)(void)
Initialize the RDC driver.
Definition: rdc.h:72
The MAC layer transmission was OK.
Definition: mac.h:79
#define NULL
The null pointer.
uint8_t frame_type
3 bit.
Definition: frame802154.h:147
802.15.4 frame creation and parsing functions
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:64
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:465
The structure of a RDC (radio duty cycling) driver in Contiki.
Definition: rdc.h:68
uint8_t ack_required
1 bit.
Definition: frame802154.h:150
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:170
Header file for Rime statistics
Header file for the Rime queue buffer management
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
A null RDC implementation that uses framer for headers.
Parameters used by the frame802154_create() function.
Definition: frame802154.h:192
Include file for the Contiki low-layer network stack (NETSTACK)