Contiki 2.5
xmac.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007, 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  * $Id: xmac.c,v 1.60 2011/01/25 14:31:09 adamdunkels Exp $
32  */
33 
34 /**
35  * \file
36  * A simple power saving MAC protocol based on X-MAC [SenSys 2006]
37  * \author
38  * Adam Dunkels <adam@sics.se>
39  * Niclas Finne <nfi@sics.se>
40  * Joakim Eriksson <joakime@sics.se>
41  */
42 
43 #include "dev/leds.h"
44 #include "dev/radio.h"
45 #include "dev/watchdog.h"
46 #include "lib/random.h"
47 #include "net/netstack.h"
48 #include "net/mac/xmac.h"
49 #include "net/rime.h"
50 #include "net/rime/timesynch.h"
51 #include "sys/compower.h"
52 #include "sys/pt.h"
53 #include "sys/rtimer.h"
54 
55 #include "contiki-conf.h"
56 
57 #ifdef EXPERIMENT_SETUP
58 #include "experiment-setup.h"
59 #endif
60 
61 #include <string.h>
62 
63 #ifndef WITH_ACK_OPTIMIZATION
64 #define WITH_ACK_OPTIMIZATION 0
65 #endif
66 #ifndef WITH_ENCOUNTER_OPTIMIZATION
67 #define WITH_ENCOUNTER_OPTIMIZATION 1
68 #endif
69 #ifndef WITH_STREAMING
70 #define WITH_STREAMING 1
71 #endif
72 #ifndef WITH_STROBE_BROADCAST
73 #define WITH_STROBE_BROADCAST 0
74 #endif
75 
76 struct announcement_data {
77  uint16_t id;
78  uint16_t value;
79 };
80 
81 /* The maximum number of announcements in a single announcement
82  message - may need to be increased in the future. */
83 #define ANNOUNCEMENT_MAX 10
84 
85 /* The structure of the announcement messages. */
86 struct announcement_msg {
87  uint16_t num;
88  struct announcement_data data[ANNOUNCEMENT_MAX];
89 };
90 
91 /* The length of the header of the announcement message, i.e., the
92  "num" field in the struct. */
93 #define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t))
94 
95 #define DISPATCH 0
96 #define TYPE_STROBE 0x10
97 /* #define TYPE_DATA 0x11 */
98 #define TYPE_ANNOUNCEMENT 0x12
99 #define TYPE_STROBE_ACK 0x13
100 
101 struct xmac_hdr {
102  uint8_t dispatch;
103  uint8_t type;
104 };
105 
106 #define MAX_STROBE_SIZE 50
107 
108 #ifdef XMAC_CONF_ON_TIME
109 #define DEFAULT_ON_TIME (XMAC_CONF_ON_TIME)
110 #else
111 #define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160)
112 #endif
113 
114 #ifdef XMAC_CONF_OFF_TIME
115 #define DEFAULT_OFF_TIME (XMAC_CONF_OFF_TIME)
116 #else
117 #define DEFAULT_OFF_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - DEFAULT_ON_TIME)
118 #endif
119 
120 #define DEFAULT_PERIOD (DEFAULT_OFF_TIME + DEFAULT_ON_TIME)
121 
122 #define WAIT_TIME_BEFORE_STROBE_ACK RTIMER_ARCH_SECOND / 1000
123 
124 /* On some platforms, we may end up with a DEFAULT_PERIOD that is 0
125  which will make compilation fail due to a modulo operation in the
126  code. To ensure that DEFAULT_PERIOD is greater than zero, we use
127  the construct below. */
128 #if DEFAULT_PERIOD == 0
129 #undef DEFAULT_PERIOD
130 #define DEFAULT_PERIOD 1
131 #endif
132 
133 /* The cycle time for announcements. */
134 #define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND
135 
136 /* The time before sending an announcement within one announcement
137  cycle. */
138 #define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD))
139 
140 #define DEFAULT_STROBE_WAIT_TIME (5 * DEFAULT_ON_TIME / 8)
141 
142 struct xmac_config xmac_config = {
143  DEFAULT_ON_TIME,
144  DEFAULT_OFF_TIME,
145  4 * DEFAULT_ON_TIME + DEFAULT_OFF_TIME,
146  DEFAULT_STROBE_WAIT_TIME
147 };
148 
149 #include <stdio.h>
150 static struct rtimer rt;
151 static struct pt pt;
152 
153 static volatile uint8_t xmac_is_on = 0;
154 
155 static volatile unsigned char waiting_for_packet = 0;
156 static volatile unsigned char someone_is_sending = 0;
157 static volatile unsigned char we_are_sending = 0;
158 static volatile unsigned char radio_is_on = 0;
159 
160 #undef LEDS_ON
161 #undef LEDS_OFF
162 #undef LEDS_TOGGLE
163 
164 #define LEDS_ON(x) leds_on(x)
165 #define LEDS_OFF(x) leds_off(x)
166 #define LEDS_TOGGLE(x) leds_toggle(x)
167 #define DEBUG 0
168 #if DEBUG
169 #include <stdio.h>
170 #define PRINTF(...) printf(__VA_ARGS__)
171 #define PRINTDEBUG(...) printf(__VA_ARGS__)
172 #else
173 #undef LEDS_ON
174 #undef LEDS_OFF
175 #undef LEDS_TOGGLE
176 #define LEDS_ON(x)
177 #define LEDS_OFF(x)
178 #define LEDS_TOGGLE(x)
179 #define PRINTF(...)
180 #define PRINTDEBUG(...)
181 #endif
182 
183 #if XMAC_CONF_ANNOUNCEMENTS
184 /* Timers for keeping track of when to send announcements. */
185 static struct ctimer announcement_cycle_ctimer, announcement_ctimer;
186 
187 static int announcement_radio_txpower;
188 #endif /* XMAC_CONF_ANNOUNCEMENTS */
189 
190 /* Flag that is used to keep track of whether or not we are listening
191  for announcements from neighbors. */
192 static uint8_t is_listening;
193 
194 #if XMAC_CONF_COMPOWER
195 static struct compower_activity current_packet;
196 #endif /* XMAC_CONF_COMPOWER */
197 
198 #if WITH_ENCOUNTER_OPTIMIZATION
199 
200 #include "lib/list.h"
201 #include "lib/memb.h"
202 
203 struct encounter {
204  struct encounter *next;
205  rimeaddr_t neighbor;
206  rtimer_clock_t time;
207 };
208 
209 #define MAX_ENCOUNTERS 4
210 LIST(encounter_list);
211 MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
212 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
213 
214 static uint8_t is_streaming;
215 static rimeaddr_t is_streaming_to, is_streaming_to_too;
216 static rtimer_clock_t stream_until;
217 #define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
218 
219 #ifndef MIN
220 #define MIN(a, b) ((a) < (b)? (a) : (b))
221 #endif /* MIN */
222 
223 struct seqno {
224  rimeaddr_t sender;
225  uint8_t seqno;
226 };
227 
228 #define MAX_SEQNOS 8
229 static struct seqno received_seqnos[MAX_SEQNOS];
230 
231 
232 /*---------------------------------------------------------------------------*/
233 static void
234 on(void)
235 {
236  if(xmac_is_on && radio_is_on == 0) {
237  radio_is_on = 1;
238  NETSTACK_RADIO.on();
239  LEDS_ON(LEDS_RED);
240  }
241 }
242 /*---------------------------------------------------------------------------*/
243 static void
244 off(void)
245 {
246  if(xmac_is_on && radio_is_on != 0 && is_listening == 0 &&
247  is_streaming == 0) {
248  radio_is_on = 0;
249  NETSTACK_RADIO.off();
250  LEDS_OFF(LEDS_RED);
251  }
252 }
253 /*---------------------------------------------------------------------------*/
254 static char powercycle(struct rtimer *t, void *ptr);
255 static void
256 schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
257 {
258  int r;
259  if(xmac_is_on) {
260  r = rtimer_set(t, RTIMER_TIME(t) + time, 1,
261  (void (*)(struct rtimer *, void *))powercycle, NULL);
262  if(r) {
263  PRINTF("schedule_powercycle: could not set rtimer\n");
264  }
265  }
266 }
267 static void
268 powercycle_turn_radio_off(void)
269 {
270  if(we_are_sending == 0 &&
271  waiting_for_packet == 0) {
272  off();
273  }
274 #if XMAC_CONF_COMPOWER
276 #endif /* XMAC_CONF_COMPOWER */
277 }
278 static void
279 powercycle_turn_radio_on(void)
280 {
281  if(we_are_sending == 0 &&
282  waiting_for_packet == 0) {
283  on();
284  }
285 }
286 static char
287 powercycle(struct rtimer *t, void *ptr)
288 {
289  if(is_streaming) {
290  if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
291  is_streaming = 0;
292  rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
293  rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
294  }
295  }
296 
297  PT_BEGIN(&pt);
298 
299  while(1) {
300  /* Only wait for some cycles to pass for someone to start sending */
301  if(someone_is_sending > 0) {
302  someone_is_sending--;
303  }
304 
305  /* If there were a strobe in the air, turn radio on */
306  powercycle_turn_radio_on();
307  schedule_powercycle(t, xmac_config.on_time);
308  PT_YIELD(&pt);
309 
310  if(xmac_config.off_time > 0 && !NETSTACK_RADIO.receiving_packet()) {
311  powercycle_turn_radio_off();
312  if(waiting_for_packet != 0) {
313  waiting_for_packet++;
314  if(waiting_for_packet > 2) {
315  /* We should not be awake for more than two consecutive
316  power cycles without having heard a packet, so we turn off
317  the radio. */
318  waiting_for_packet = 0;
319  powercycle_turn_radio_off();
320  }
321  }
322  schedule_powercycle(t, xmac_config.off_time);
323  PT_YIELD(&pt);
324  }
325  }
326 
327  PT_END(&pt);
328 }
329 /*---------------------------------------------------------------------------*/
330 #if XMAC_CONF_ANNOUNCEMENTS
331 static int
332 parse_announcements(const rimeaddr_t *from)
333 {
334  /* Parse incoming announcements */
335  struct announcement_msg adata;
336  int i;
337 
338  memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata)));
339 
340  /* printf("%d.%d: probe from %d.%d with %d announcements\n",
341  rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
342  from->u8[0], from->u8[1], adata->num);*/
343  /* for(i = 0; i < packetbuf_datalen(); ++i) {
344  printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]);
345  }
346  printf("\n");*/
347 
348  for(i = 0; i < adata.num; ++i) {
349  /* printf("%d.%d: announcement %d: %d\n",
350  rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
351  adata->data[i].id,
352  adata->data[i].value);*/
353 
354  announcement_heard(from,
355  adata.data[i].id,
356  adata.data[i].value);
357  }
358  return i;
359 }
360 /*---------------------------------------------------------------------------*/
361 static int
362 format_announcement(char *hdr)
363 {
364  struct announcement_msg adata;
365  struct announcement *a;
366 
367  /* Construct the announcements */
368  /* adata = (struct announcement_msg *)hdr;*/
369 
370  adata.num = 0;
371  for(a = announcement_list();
372  a != NULL && adata.num < ANNOUNCEMENT_MAX;
373  a = list_item_next(a)) {
374  adata.data[adata.num].id = a->id;
375  adata.data[adata.num].value = a->value;
376  adata.num++;
377  }
378 
379  memcpy(hdr, &adata, sizeof(struct announcement_msg));
380 
381  if(adata.num > 0) {
382  return ANNOUNCEMENT_MSG_HEADERLEN +
383  sizeof(struct announcement_data) * adata.num;
384  } else {
385  return 0;
386  }
387 }
388 #endif /* XMAC_CONF_ANNOUNCEMENTS */
389 /*---------------------------------------------------------------------------*/
390 #if WITH_ENCOUNTER_OPTIMIZATION
391 static void
392 register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time)
393 {
394  struct encounter *e;
395 
396  /* If we have an entry for this neighbor already, we renew it. */
397  for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
398  if(rimeaddr_cmp(neighbor, &e->neighbor)) {
399  e->time = time;
400  break;
401  }
402  }
403  /* No matching encounter was found, so we allocate a new one. */
404  if(e == NULL) {
405  e = memb_alloc(&encounter_memb);
406  if(e == NULL) {
407  /* We could not allocate memory for this encounter, so we just drop it. */
408  return;
409  }
410  rimeaddr_copy(&e->neighbor, neighbor);
411  e->time = time;
412  list_add(encounter_list, e);
413  }
414 }
415 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
416 /*---------------------------------------------------------------------------*/
417 static int
418 detect_ack(void)
419 {
420 #define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
421 #define ACK_LEN 3
422 #define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1000
423  rtimer_clock_t wt;
424  uint8_t ack_received = 0;
425 
426  wt = RTIMER_NOW();
427  leds_on(LEDS_GREEN);
428  while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
429  leds_off(LEDS_GREEN);
430  /* Check for incoming ACK. */
431  if((NETSTACK_RADIO.receiving_packet() ||
432  NETSTACK_RADIO.pending_packet() ||
433  NETSTACK_RADIO.channel_clear() == 0)) {
434  int len;
435  uint8_t ackbuf[ACK_LEN + 2];
436 
437  wt = RTIMER_NOW();
438  while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
439 
440  len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
441  if(len == ACK_LEN) {
442  ack_received = 1;
443  }
444  }
445  if(ack_received) {
446  leds_toggle(LEDS_RED);
447  }
448  return ack_received;
449 }
450 /*---------------------------------------------------------------------------*/
451 static int
452 send_packet(void)
453 {
454  rtimer_clock_t t0;
455  rtimer_clock_t t;
456  rtimer_clock_t encounter_time = 0;
457  int strobes;
458 #if 0
459  struct xmac_hdr *hdr;
460 #endif
461  uint8_t got_strobe_ack = 0;
462  uint8_t got_ack = 0;
463  uint8_t strobe[MAX_STROBE_SIZE];
464  int strobe_len, len;
465  int is_broadcast = 0;
466  int is_reliable;
467  struct encounter *e;
468  struct queuebuf *packet;
469  int is_already_streaming = 0;
470  uint8_t collisions;
471 
472  /* Create the X-MAC header for the data packet. */
473  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
474  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
475  is_broadcast = 1;
476  PRINTDEBUG("xmac: send broadcast\n");
477  } else {
478 #if UIP_CONF_IPV6
479  PRINTDEBUG("xmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
480  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
481  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1],
482  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2],
483  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3],
484  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4],
485  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5],
486  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6],
487  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]);
488 #else
489  PRINTDEBUG("xmac: send unicast to %u.%u\n",
490  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
491  packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
492 #endif /* UIP_CONF_IPV6 */
493  }
494  is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
495  packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);
496 
497  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
498  len = NETSTACK_FRAMER.create();
499  strobe_len = len + sizeof(struct xmac_hdr);
500  if(len == 0 || strobe_len > (int)sizeof(strobe)) {
501  /* Failed to send */
502  PRINTF("xmac: send failed, too large header\n");
503  return MAC_TX_ERR_FATAL;
504  }
505  memcpy(strobe, packetbuf_hdrptr(), len);
506  strobe[len] = DISPATCH; /* dispatch */
507  strobe[len + 1] = TYPE_STROBE; /* type */
508 
510  packet = queuebuf_new_from_packetbuf();
511  if(packet == NULL) {
512  /* No buffer available */
513  PRINTF("xmac: send failed, no queue buffer available (of %u)\n",
514  QUEUEBUF_CONF_NUM);
515  return MAC_TX_ERR;
516  }
517 
518 #if WITH_STREAMING
519  if(is_streaming == 1 &&
520  (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
521  &is_streaming_to) ||
522  rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
523  &is_streaming_to_too))) {
524  is_already_streaming = 1;
525  }
526  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
527  PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
528  is_streaming = 1;
529  if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
530  rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
531  } else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
532  rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
533  }
534  stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
535  }
536 #endif /* WITH_STREAMING */
537 
538  off();
539 
540 #if WITH_ENCOUNTER_OPTIMIZATION
541  /* We go through the list of encounters to find if we have recorded
542  an encounter with this particular neighbor. If so, we can compute
543  the time for the next expected encounter and setup a ctimer to
544  switch on the radio just before the encounter. */
545  for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
546  const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
547 
548  if(rimeaddr_cmp(neighbor, &e->neighbor)) {
549  rtimer_clock_t wait, now, expected;
550 
551  /* We expect encounters to happen every DEFAULT_PERIOD time
552  units. The next expected encounter is at time e->time +
553  DEFAULT_PERIOD. To compute a relative offset, we subtract
554  with clock_time(). Because we are only interested in turning
555  on the radio within the DEFAULT_PERIOD period, we compute the
556  waiting time with modulo DEFAULT_PERIOD. */
557 
558  now = RTIMER_NOW();
559  wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
560  if(wait < 2 * DEFAULT_ON_TIME) {
561  wait = DEFAULT_PERIOD;
562  }
563  expected = now + wait - 2 * DEFAULT_ON_TIME;
564 
565 #if WITH_ACK_OPTIMIZATION
566  /* Wait until the receiver is expected to be awake */
567  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
568  PACKETBUF_ATTR_PACKET_TYPE_ACK &&
569  is_streaming == 0) {
570  /* Do not wait if we are sending an ACK, because then the
571  receiver will already be awake. */
572  while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
573  }
574 #else /* WITH_ACK_OPTIMIZATION */
575  /* Wait until the receiver is expected to be awake */
576  while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
577 #endif /* WITH_ACK_OPTIMIZATION */
578  }
579  }
580 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
581 
582  /* By setting we_are_sending to one, we ensure that the rtimer
583  powercycle interrupt do not interfere with us sending the packet. */
584  we_are_sending = 1;
585 
586  t0 = RTIMER_NOW();
587  strobes = 0;
588 
589  LEDS_ON(LEDS_BLUE);
590 
591  /* Send a train of strobes until the receiver answers with an ACK. */
592 
593  /* Turn on the radio to listen for the strobe ACK. */
594  // on();
595  collisions = 0;
596  if(!is_already_streaming) {
597  watchdog_stop();
598  got_strobe_ack = 0;
599  t = RTIMER_NOW();
600  for(strobes = 0, collisions = 0;
601  got_strobe_ack == 0 && collisions == 0 &&
602  RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_time);
603  strobes++) {
604 
605  while(got_strobe_ack == 0 &&
606  RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) {
607 #if 0
608  rtimer_clock_t now = RTIMER_NOW();
609 
610  /* See if we got an ACK */
611  packetbuf_clear();
612  len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
613  if(len > 0) {
615  if(NETSTACK_FRAMER.parse()) {
616  hdr = packetbuf_dataptr();
617  if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE_ACK) {
618  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
619  &rimeaddr_node_addr)) {
620  /* We got an ACK from the receiver, so we can immediately send
621  the packet. */
622  got_strobe_ack = 1;
623  encounter_time = now;
624  } else {
625  PRINTDEBUG("xmac: strobe ack for someone else\n");
626  }
627  } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ {
628  PRINTDEBUG("xmac: strobe from someone else\n");
629  collisions++;
630  }
631  } else {
632  PRINTF("xmac: send failed to parse %u\n", len);
633  }
634  }
635 #endif /* 0 */
636  }
637 
638  t = RTIMER_NOW();
639  /* Send the strobe packet. */
640  if(got_strobe_ack == 0 && collisions == 0) {
641 
642  if(is_broadcast) {
643 #if WITH_STROBE_BROADCAST
644  NETSTACK_RADIO.send(strobe, strobe_len);
645 #else
646  /* restore the packet to send */
647  queuebuf_to_packetbuf(packet);
648  NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
649 #endif
650  off();
651  } else {
652 #if 0
653  rtimer_clock_t wt;
654 #endif
655  on();
656  NETSTACK_RADIO.send(strobe, strobe_len);
657 #if 0
658  /* Turn off the radio for a while to let the other side
659  respond. We don't need to keep our radio on when we know
660  that the other side needs some time to produce a reply. */
661  off();
662  wt = RTIMER_NOW();
663  while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
664 #endif /* 0 */
665 
666  if(detect_ack()) {
667  got_strobe_ack = 1;
668  } else {
669  off();
670  }
671  }
672  }
673  }
674  }
675 
676 #if WITH_ACK_OPTIMIZATION
677  /* If we have received the strobe ACK, and we are sending a packet
678  that will need an upper layer ACK (as signified by the
679  PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
680  if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
681  packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
682  packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
683  PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
684  on(); /* Wait for ACK packet */
685  waiting_for_packet = 1;
686  } else {
687  off();
688  }
689 #endif /* WITH_ACK_OPTIMIZATION */
690 
691  /* restore the packet to send */
692  queuebuf_to_packetbuf(packet);
693  queuebuf_free(packet);
694 
695  /* Send the data packet. */
696  if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
697  NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
698 
699  if(!is_broadcast) {
700  if(detect_ack()) {
701  got_ack = 1;
702  }
703  }
704  }
705  off();
706 
707 #if WITH_ENCOUNTER_OPTIMIZATION
708  if(got_strobe_ack && !is_streaming) {
709  register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
710  }
711 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
712  watchdog_start();
713 
714  PRINTF("xmac: send (strobes=%u,len=%u,%s), done\n", strobes,
715  packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack");
716 
717 #if XMAC_CONF_COMPOWER
718  /* Accumulate the power consumption for the packet transmission. */
719  compower_accumulate(&current_packet);
720 
721  /* Convert the accumulated power consumption for the transmitted
722  packet to packet attributes so that the higher levels can keep
723  track of the amount of energy spent on transmitting the
724  packet. */
725  compower_attrconv(&current_packet);
726 
727  /* Clear the accumulated power consumption so that it is ready for
728  the next packet. */
729  compower_clear(&current_packet);
730 #endif /* XMAC_CONF_COMPOWER */
731 
732  we_are_sending = 0;
733 
734  LEDS_OFF(LEDS_BLUE);
735  if(collisions == 0) {
736  if(is_broadcast == 0 && got_ack == 0) {
737  return MAC_TX_NOACK;
738  } else {
739  return MAC_TX_OK;
740  }
741  } else {
742  someone_is_sending++;
743  return MAC_TX_COLLISION;
744  }
745 
746 }
747 /*---------------------------------------------------------------------------*/
748 static void
749 qsend_packet(mac_callback_t sent, void *ptr)
750 {
751  int ret;
752 
753  if(someone_is_sending) {
754  PRINTF("xmac: should queue packet, now just dropping %d %d %d %d.\n",
755  waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on);
756  RIMESTATS_ADD(sendingdrop);
757  ret = MAC_TX_COLLISION;
758  } else {
759  PRINTF("xmac: send immediately.\n");
760  ret = send_packet();
761  }
762 
763  mac_call_sent_callback(sent, ptr, ret, 1);
764 }
765 /*---------------------------------------------------------------------------*/
766 static void
767 input_packet(void)
768 {
769  struct xmac_hdr *hdr;
770 
771  if(NETSTACK_FRAMER.parse()) {
772  hdr = packetbuf_dataptr();
773 
774  if(hdr->dispatch != DISPATCH) {
775  someone_is_sending = 0;
776  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
777  &rimeaddr_node_addr) ||
778  rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
779  &rimeaddr_null)) {
780  /* This is a regular packet that is destined to us or to the
781  broadcast address. */
782 
783  /* We have received the final packet, so we can go back to being
784  asleep. */
785  off();
786 
787  /* Check for duplicate packet by comparing the sequence number
788  of the incoming packet with the last few ones we saw. */
789  {
790  int i;
791  for(i = 0; i < MAX_SEQNOS; ++i) {
792  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
793  rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
794  &received_seqnos[i].sender)) {
795  /* Drop the packet. */
796  return;
797  }
798  }
799  for(i = MAX_SEQNOS - 1; i > 0; --i) {
800  memcpy(&received_seqnos[i], &received_seqnos[i - 1],
801  sizeof(struct seqno));
802  }
803  received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
804  rimeaddr_copy(&received_seqnos[0].sender,
805  packetbuf_addr(PACKETBUF_ADDR_SENDER));
806  }
807 
808 #if XMAC_CONF_COMPOWER
809  /* Accumulate the power consumption for the packet reception. */
810  compower_accumulate(&current_packet);
811  /* Convert the accumulated power consumption for the received
812  packet to packet attributes so that the higher levels can
813  keep track of the amount of energy spent on receiving the
814  packet. */
815  compower_attrconv(&current_packet);
816 
817  /* Clear the accumulated power consumption so that it is ready
818  for the next packet. */
819  compower_clear(&current_packet);
820 #endif /* XMAC_CONF_COMPOWER */
821 
822  waiting_for_packet = 0;
823 
824  PRINTDEBUG("xmac: data(%u)\n", packetbuf_datalen());
825  NETSTACK_MAC.input();
826  return;
827  } else {
828  PRINTDEBUG("xmac: data not for us\n");
829  }
830 
831  } else if(hdr->type == TYPE_STROBE) {
832  someone_is_sending = 2;
833 
834  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
835  &rimeaddr_node_addr)) {
836  /* This is a strobe packet for us. */
837 
838  /* If the sender address is someone else, we should
839  acknowledge the strobe and wait for the packet. By using
840  the same address as both sender and receiver, we flag the
841  message is a strobe ack. */
842  waiting_for_packet = 1;
843 #if 0
844  hdr->type = TYPE_STROBE_ACK;
845  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
846  packetbuf_addr(PACKETBUF_ADDR_SENDER));
847  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
849  if(NETSTACK_FRAMER.create()) {
850  /* We turn on the radio in anticipation of the incoming
851  packet. */
852  someone_is_sending = 1;
853  waiting_for_packet = 1;
854  on();
855  NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
856  PRINTDEBUG("xmac: send strobe ack %u\n", packetbuf_totlen());
857  } else {
858  PRINTF("xmac: failed to send strobe ack\n");
859  }
860 #endif /* 0 */
861  } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
862  &rimeaddr_null)) {
863  /* If the receiver address is null, the strobe is sent to
864  prepare for an incoming broadcast packet. If this is the
865  case, we turn on the radio and wait for the incoming
866  broadcast packet. */
867  waiting_for_packet = 1;
868  on();
869  } else {
870  PRINTDEBUG("xmac: strobe not for us\n");
871  }
872 
873  /* We are done processing the strobe and we therefore return
874  to the caller. */
875  return;
876 #if XMAC_CONF_ANNOUNCEMENTS
877  } else if(hdr->type == TYPE_ANNOUNCEMENT) {
878  packetbuf_hdrreduce(sizeof(struct xmac_hdr));
879  parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
880 #endif /* XMAC_CONF_ANNOUNCEMENTS */
881  } else if(hdr->type == TYPE_STROBE_ACK) {
882  PRINTDEBUG("xmac: stray strobe ack\n");
883  } else {
884  PRINTF("xmac: unknown type %u (%u/%u)\n", hdr->type,
885  packetbuf_datalen(), len);
886  }
887  } else {
888  PRINTF("xmac: failed to parse (%u)\n", packetbuf_totlen());
889  }
890 }
891 /*---------------------------------------------------------------------------*/
892 #if XMAC_CONF_ANNOUNCEMENTS
893 static void
894 send_announcement(void *ptr)
895 {
896  struct xmac_hdr *hdr;
897  int announcement_len;
898 
899  /* Set up the probe header. */
900  packetbuf_clear();
901  hdr = packetbuf_dataptr();
902 
903  announcement_len = format_announcement((char *)hdr +
904  sizeof(struct xmac_hdr));
905 
906  if(announcement_len > 0) {
907  packetbuf_set_datalen(sizeof(struct xmac_hdr) + announcement_len);
908  hdr->dispatch = DISPATCH;
909  hdr->type = TYPE_ANNOUNCEMENT;
910 
911  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
912  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
913  packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower);
914  if(NETSTACK_FRAMER.create()) {
915  NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
916  }
917  }
918 }
919 /*---------------------------------------------------------------------------*/
920 static void
921 cycle_announcement(void *ptr)
922 {
923  ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME,
924  send_announcement, NULL);
925  ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD,
926  cycle_announcement, NULL);
927  if(is_listening > 0) {
928  is_listening--;
929  /* printf("is_listening %d\n", is_listening);*/
930  }
931 }
932 /*---------------------------------------------------------------------------*/
933 static void
934 listen_callback(int periods)
935 {
936  is_listening = periods + 1;
937 }
938 #endif /* XMAC_CONF_ANNOUNCEMENTS */
939 /*---------------------------------------------------------------------------*/
940 void
941 xmac_set_announcement_radio_txpower(int txpower)
942 {
943 #if XMAC_CONF_ANNOUNCEMENTS
944  announcement_radio_txpower = txpower;
945 #endif /* XMAC_CONF_ANNOUNCEMENTS */
946 }
947 /*---------------------------------------------------------------------------*/
948 static void
949 init(void)
950 {
951  radio_is_on = 0;
952  waiting_for_packet = 0;
953  PT_INIT(&pt);
954  rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
955  (void (*)(struct rtimer *, void *))powercycle, NULL);
956 
957  xmac_is_on = 1;
958 
959 #if WITH_ENCOUNTER_OPTIMIZATION
960  list_init(encounter_list);
961  memb_init(&encounter_memb);
962 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
963 
964 #if XMAC_CONF_ANNOUNCEMENTS
965  announcement_register_listen_callback(listen_callback);
966  ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME,
967  cycle_announcement, NULL);
968 #endif /* XMAC_CONF_ANNOUNCEMENTS */
969 }
970 /*---------------------------------------------------------------------------*/
971 static int
972 turn_on(void)
973 {
974  xmac_is_on = 1;
975  rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
976  (void (*)(struct rtimer *, void *))powercycle, NULL);
977  return 1;
978 }
979 /*---------------------------------------------------------------------------*/
980 static int
981 turn_off(int keep_radio_on)
982 {
983  xmac_is_on = 0;
984  if(keep_radio_on) {
985  return NETSTACK_RADIO.on();
986  } else {
987  return NETSTACK_RADIO.off();
988  }
989 }
990 /*---------------------------------------------------------------------------*/
991 static unsigned short
992 channel_check_interval(void)
993 {
994  return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;
995 }
996 /*---------------------------------------------------------------------------*/
997 const struct rdc_driver xmac_driver =
998  {
999  "X-MAC",
1000  init,
1001  qsend_packet,
1002  input_packet,
1003  turn_on,
1004  turn_off,
1006  };