Contiki 2.6

xmac.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007, Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  */
00032 
00033 /**
00034  * \file
00035  *         A simple power saving MAC protocol based on X-MAC [SenSys 2006]
00036  * \author
00037  *         Adam Dunkels <adam@sics.se>
00038  *         Niclas Finne <nfi@sics.se>
00039  *         Joakim Eriksson <joakime@sics.se>
00040  */
00041 
00042 #include "dev/leds.h"
00043 #include "dev/radio.h"
00044 #include "dev/watchdog.h"
00045 #include "lib/random.h"
00046 #include "net/netstack.h"
00047 #include "net/mac/xmac.h"
00048 #include "net/rime.h"
00049 #include "net/rime/timesynch.h"
00050 #include "sys/compower.h"
00051 #include "sys/pt.h"
00052 #include "sys/rtimer.h"
00053 
00054 #include "contiki-conf.h"
00055 
00056 #ifdef EXPERIMENT_SETUP
00057 #include "experiment-setup.h"
00058 #endif
00059 
00060 #include <string.h>
00061 
00062 #ifndef WITH_ACK_OPTIMIZATION
00063 #define WITH_ACK_OPTIMIZATION        0
00064 #endif
00065 #ifndef WITH_ENCOUNTER_OPTIMIZATION
00066 #define WITH_ENCOUNTER_OPTIMIZATION  1
00067 #endif
00068 #ifndef WITH_STREAMING
00069 #define WITH_STREAMING               1
00070 #endif
00071 #ifndef WITH_STROBE_BROADCAST
00072 #define WITH_STROBE_BROADCAST        0
00073 #endif
00074 
00075 struct announcement_data {
00076   uint16_t id;
00077   uint16_t value;
00078 };
00079 
00080 /* The maximum number of announcements in a single announcement
00081    message - may need to be increased in the future. */
00082 #define ANNOUNCEMENT_MAX 10
00083 
00084 /* The structure of the announcement messages. */
00085 struct announcement_msg {
00086   uint16_t num;
00087   struct announcement_data data[ANNOUNCEMENT_MAX];
00088 };
00089 
00090 /* The length of the header of the announcement message, i.e., the
00091    "num" field in the struct. */
00092 #define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t))
00093 
00094 #define DISPATCH          0
00095 #define TYPE_STROBE       0x10
00096 /* #define TYPE_DATA         0x11 */
00097 #define TYPE_ANNOUNCEMENT 0x12
00098 #define TYPE_STROBE_ACK   0x13
00099 
00100 struct xmac_hdr {
00101   uint8_t dispatch;
00102   uint8_t type;
00103 };
00104 
00105 #define MAX_STROBE_SIZE 50
00106 
00107 #ifdef XMAC_CONF_ON_TIME
00108 #define DEFAULT_ON_TIME (XMAC_CONF_ON_TIME)
00109 #else
00110 #define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160)
00111 #endif
00112 
00113 #ifdef XMAC_CONF_OFF_TIME
00114 #define DEFAULT_OFF_TIME (XMAC_CONF_OFF_TIME)
00115 #else
00116 #define DEFAULT_OFF_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - DEFAULT_ON_TIME)
00117 #endif
00118 
00119 #define DEFAULT_PERIOD (DEFAULT_OFF_TIME + DEFAULT_ON_TIME)
00120 
00121 #define WAIT_TIME_BEFORE_STROBE_ACK RTIMER_ARCH_SECOND / 1000
00122 
00123 /* On some platforms, we may end up with a DEFAULT_PERIOD that is 0
00124    which will make compilation fail due to a modulo operation in the
00125    code. To ensure that DEFAULT_PERIOD is greater than zero, we use
00126    the construct below. */
00127 #if DEFAULT_PERIOD == 0
00128 #undef DEFAULT_PERIOD
00129 #define DEFAULT_PERIOD 1
00130 #endif
00131 
00132 /* The cycle time for announcements. */
00133 #define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND
00134 
00135 /* The time before sending an announcement within one announcement
00136    cycle. */
00137 #define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD))
00138 
00139 #define DEFAULT_STROBE_WAIT_TIME (5 * DEFAULT_ON_TIME / 8)
00140 
00141 struct xmac_config xmac_config = {
00142   DEFAULT_ON_TIME,
00143   DEFAULT_OFF_TIME,
00144   4 * DEFAULT_ON_TIME + DEFAULT_OFF_TIME,
00145   DEFAULT_STROBE_WAIT_TIME
00146 };
00147 
00148 #include <stdio.h>
00149 static struct rtimer rt;
00150 static struct pt pt;
00151 
00152 static volatile uint8_t xmac_is_on = 0;
00153 
00154 static volatile unsigned char waiting_for_packet = 0;
00155 static volatile unsigned char someone_is_sending = 0;
00156 static volatile unsigned char we_are_sending = 0;
00157 static volatile unsigned char radio_is_on = 0;
00158 
00159 #undef LEDS_ON
00160 #undef LEDS_OFF
00161 #undef LEDS_TOGGLE
00162 
00163 #define LEDS_ON(x) leds_on(x)
00164 #define LEDS_OFF(x) leds_off(x)
00165 #define LEDS_TOGGLE(x) leds_toggle(x)
00166 #define DEBUG 0
00167 #if DEBUG
00168 #include <stdio.h>
00169 #define PRINTF(...) printf(__VA_ARGS__)
00170 #define PRINTDEBUG(...) printf(__VA_ARGS__)
00171 #else
00172 #undef LEDS_ON
00173 #undef LEDS_OFF
00174 #undef LEDS_TOGGLE
00175 #define LEDS_ON(x)
00176 #define LEDS_OFF(x)
00177 #define LEDS_TOGGLE(x)
00178 #define PRINTF(...)
00179 #define PRINTDEBUG(...)
00180 #endif
00181 
00182 #if XMAC_CONF_ANNOUNCEMENTS
00183 /* Timers for keeping track of when to send announcements. */
00184 static struct ctimer announcement_cycle_ctimer, announcement_ctimer;
00185 
00186 static int announcement_radio_txpower;
00187 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00188 
00189 /* Flag that is used to keep track of whether or not we are listening
00190    for announcements from neighbors. */
00191 static uint8_t is_listening;
00192 
00193 #if XMAC_CONF_COMPOWER
00194 static struct compower_activity current_packet;
00195 #endif /* XMAC_CONF_COMPOWER */
00196 
00197 #if WITH_ENCOUNTER_OPTIMIZATION
00198 
00199 #include "lib/list.h"
00200 #include "lib/memb.h"
00201 
00202 struct encounter {
00203   struct encounter *next;
00204   rimeaddr_t neighbor;
00205   rtimer_clock_t time;
00206 };
00207 
00208 #define MAX_ENCOUNTERS 4
00209 LIST(encounter_list);
00210 MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
00211 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00212 
00213 static uint8_t is_streaming;
00214 static rimeaddr_t is_streaming_to, is_streaming_to_too;
00215 static rtimer_clock_t stream_until;
00216 #define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
00217 
00218 #ifndef MIN
00219 #define MIN(a, b) ((a) < (b)? (a) : (b))
00220 #endif /* MIN */
00221 
00222 struct seqno {
00223   rimeaddr_t sender;
00224   uint8_t seqno;
00225 };
00226 
00227 #define MAX_SEQNOS 8
00228 static struct seqno received_seqnos[MAX_SEQNOS];
00229 
00230 
00231 /*---------------------------------------------------------------------------*/
00232 static void
00233 on(void)
00234 {
00235   if(xmac_is_on && radio_is_on == 0) {
00236     radio_is_on = 1;
00237     NETSTACK_RADIO.on();
00238     LEDS_ON(LEDS_RED);
00239   }
00240 }
00241 /*---------------------------------------------------------------------------*/
00242 static void
00243 off(void)
00244 {
00245   if(xmac_is_on && radio_is_on != 0 && is_listening == 0 &&
00246      is_streaming == 0) {
00247     radio_is_on = 0;
00248     NETSTACK_RADIO.off();
00249     LEDS_OFF(LEDS_RED);
00250   }
00251 }
00252 /*---------------------------------------------------------------------------*/
00253 static char powercycle(struct rtimer *t, void *ptr);
00254 static void
00255 schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
00256 {
00257   int r;
00258   if(xmac_is_on) {
00259     r = rtimer_set(t, RTIMER_TIME(t) + time, 1,
00260                    (void (*)(struct rtimer *, void *))powercycle, NULL);
00261     if(r) {
00262       PRINTF("schedule_powercycle: could not set rtimer\n");
00263     }
00264   }
00265 }
00266 static void
00267 powercycle_turn_radio_off(void)
00268 {
00269   if(we_are_sending == 0 &&
00270      waiting_for_packet == 0) {
00271     off();
00272   }
00273 #if XMAC_CONF_COMPOWER
00274   compower_accumulate(&compower_idle_activity);
00275 #endif /* XMAC_CONF_COMPOWER */
00276 }
00277 static void
00278 powercycle_turn_radio_on(void)
00279 {
00280   if(we_are_sending == 0 &&
00281      waiting_for_packet == 0) {
00282     on();
00283   }
00284 }
00285 static char
00286 powercycle(struct rtimer *t, void *ptr)
00287 {
00288   if(is_streaming) {
00289     if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
00290       is_streaming = 0;
00291       rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
00292       rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
00293     }
00294   }
00295 
00296   PT_BEGIN(&pt);
00297 
00298   while(1) {
00299     /* Only wait for some cycles to pass for someone to start sending */
00300     if(someone_is_sending > 0) {
00301       someone_is_sending--;
00302     }
00303 
00304     /* If there were a strobe in the air, turn radio on */
00305     powercycle_turn_radio_on();
00306     schedule_powercycle(t, xmac_config.on_time);
00307     PT_YIELD(&pt);
00308 
00309     if(xmac_config.off_time > 0 && !NETSTACK_RADIO.receiving_packet()) {
00310       powercycle_turn_radio_off();
00311       if(waiting_for_packet != 0) {
00312         waiting_for_packet++;
00313         if(waiting_for_packet > 2) {
00314           /* We should not be awake for more than two consecutive
00315              power cycles without having heard a packet, so we turn off
00316              the radio. */
00317           waiting_for_packet = 0;
00318           powercycle_turn_radio_off();
00319         }
00320       }
00321       schedule_powercycle(t, xmac_config.off_time);
00322       PT_YIELD(&pt);
00323     }
00324   }
00325 
00326   PT_END(&pt);
00327 }
00328 /*---------------------------------------------------------------------------*/
00329 #if XMAC_CONF_ANNOUNCEMENTS
00330 static int
00331 parse_announcements(const rimeaddr_t *from)
00332 {
00333   /* Parse incoming announcements */
00334   struct announcement_msg adata;
00335   int i;
00336 
00337   memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata)));
00338 
00339   /*  printf("%d.%d: probe from %d.%d with %d announcements\n",
00340          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00341          from->u8[0], from->u8[1], adata->num);*/
00342   /*  for(i = 0; i < packetbuf_datalen(); ++i) {
00343     printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]);
00344   }
00345   printf("\n");*/
00346 
00347   for(i = 0; i < adata.num; ++i) {
00348     /*   printf("%d.%d: announcement %d: %d\n",
00349           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00350           adata->data[i].id,
00351           adata->data[i].value);*/
00352 
00353     announcement_heard(from,
00354                        adata.data[i].id,
00355                        adata.data[i].value);
00356   }
00357   return i;
00358 }
00359 /*---------------------------------------------------------------------------*/
00360 static int
00361 format_announcement(char *hdr)
00362 {
00363   struct announcement_msg adata;
00364   struct announcement *a;
00365 
00366   /* Construct the announcements */
00367   /*  adata = (struct announcement_msg *)hdr;*/
00368 
00369   adata.num = 0;
00370   for(a = announcement_list();
00371       a != NULL && adata.num < ANNOUNCEMENT_MAX;
00372       a = list_item_next(a)) {
00373     adata.data[adata.num].id = a->id;
00374     adata.data[adata.num].value = a->value;
00375     adata.num++;
00376   }
00377 
00378   memcpy(hdr, &adata, sizeof(struct announcement_msg));
00379 
00380   if(adata.num > 0) {
00381     return ANNOUNCEMENT_MSG_HEADERLEN +
00382       sizeof(struct announcement_data) * adata.num;
00383   } else {
00384     return 0;
00385   }
00386 }
00387 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00388 /*---------------------------------------------------------------------------*/
00389 #if WITH_ENCOUNTER_OPTIMIZATION
00390 static void
00391 register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time)
00392 {
00393   struct encounter *e;
00394 
00395   /* If we have an entry for this neighbor already, we renew it. */
00396   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00397     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00398       e->time = time;
00399       break;
00400     }
00401   }
00402   /* No matching encounter was found, so we allocate a new one. */
00403   if(e == NULL) {
00404     e = memb_alloc(&encounter_memb);
00405     if(e == NULL) {
00406       /* We could not allocate memory for this encounter, so we just drop it. */
00407       return;
00408     }
00409     rimeaddr_copy(&e->neighbor, neighbor);
00410     e->time = time;
00411     list_add(encounter_list, e);
00412   }
00413 }
00414 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00415 /*---------------------------------------------------------------------------*/
00416 static int
00417 detect_ack(void)
00418 {
00419 #define INTER_PACKET_INTERVAL              RTIMER_ARCH_SECOND / 5000
00420 #define ACK_LEN 3
00421 #define AFTER_ACK_DETECTECT_WAIT_TIME      RTIMER_ARCH_SECOND / 1000
00422   rtimer_clock_t wt;
00423   uint8_t ack_received = 0;
00424   
00425   wt = RTIMER_NOW();
00426   leds_on(LEDS_GREEN);
00427   while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
00428   leds_off(LEDS_GREEN);
00429   /* Check for incoming ACK. */
00430   if((NETSTACK_RADIO.receiving_packet() ||
00431       NETSTACK_RADIO.pending_packet() ||
00432       NETSTACK_RADIO.channel_clear() == 0)) {
00433     int len;
00434     uint8_t ackbuf[ACK_LEN + 2];
00435     
00436     wt = RTIMER_NOW();
00437     while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
00438     
00439     len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
00440     if(len == ACK_LEN) {
00441       ack_received = 1;
00442     }
00443   }
00444   if(ack_received) {
00445     leds_toggle(LEDS_RED);
00446   }
00447   return ack_received;
00448 }
00449 /*---------------------------------------------------------------------------*/
00450 static int
00451 send_packet(void)
00452 {
00453   rtimer_clock_t t0;
00454   rtimer_clock_t t;
00455   rtimer_clock_t encounter_time = 0;
00456   int strobes;
00457   int ret;
00458 #if 0
00459   struct xmac_hdr *hdr;
00460 #endif
00461   uint8_t got_strobe_ack = 0;
00462   uint8_t got_ack = 0;
00463   uint8_t strobe[MAX_STROBE_SIZE];
00464   int strobe_len, len;
00465   int is_broadcast = 0;
00466 /*int is_reliable; */
00467   struct encounter *e;
00468   struct queuebuf *packet;
00469   int is_already_streaming = 0;
00470   uint8_t collisions;
00471 
00472   /* Create the X-MAC header for the data packet. */
00473   packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00474   if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
00475     is_broadcast = 1;
00476     PRINTDEBUG("xmac: send broadcast\n");
00477   } else {
00478 #if UIP_CONF_IPV6
00479     PRINTDEBUG("xmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
00480            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
00481            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1],
00482            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2],
00483            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3],
00484            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4],
00485            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5],
00486            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6],
00487            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]);
00488 #else
00489     PRINTDEBUG("xmac: send unicast to %u.%u\n",
00490            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
00491            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
00492 #endif /* UIP_CONF_IPV6 */
00493   }
00494 /*  is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00495     packetbuf_attr(PACKETBUF_ATTR_ERELIABLE); */
00496 
00497   packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
00498   len = NETSTACK_FRAMER.create();
00499   strobe_len = len + sizeof(struct xmac_hdr);
00500   if(len < 0 || strobe_len > (int)sizeof(strobe)) {
00501     /* Failed to send */
00502    PRINTF("xmac: send failed, too large header\n");
00503     return MAC_TX_ERR_FATAL;
00504   }
00505   memcpy(strobe, packetbuf_hdrptr(), len);
00506   strobe[len] = DISPATCH; /* dispatch */
00507   strobe[len + 1] = TYPE_STROBE; /* type */
00508 
00509   packetbuf_compact();
00510   packet = queuebuf_new_from_packetbuf();
00511   if(packet == NULL) {
00512     /* No buffer available */
00513     PRINTF("xmac: send failed, no queue buffer available (of %u)\n",
00514            QUEUEBUF_CONF_NUM);
00515     return MAC_TX_ERR;
00516   }
00517 
00518 #if WITH_STREAMING
00519   if(is_streaming == 1 &&
00520      (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00521                    &is_streaming_to) ||
00522       rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00523                    &is_streaming_to_too))) {
00524     is_already_streaming = 1;
00525   }
00526   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00527      PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
00528     is_streaming = 1;
00529     if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
00530       rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
00531     } else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
00532       rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
00533     }
00534     stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
00535   }
00536 #endif /* WITH_STREAMING */
00537 
00538   off();
00539 
00540 #if WITH_ENCOUNTER_OPTIMIZATION
00541   /* We go through the list of encounters to find if we have recorded
00542      an encounter with this particular neighbor. If so, we can compute
00543      the time for the next expected encounter and setup a ctimer to
00544      switch on the radio just before the encounter. */
00545   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00546     const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
00547 
00548     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00549       rtimer_clock_t wait, now, expected;
00550 
00551       /* We expect encounters to happen every DEFAULT_PERIOD time
00552          units. The next expected encounter is at time e->time +
00553          DEFAULT_PERIOD. To compute a relative offset, we subtract
00554          with clock_time(). Because we are only interested in turning
00555          on the radio within the DEFAULT_PERIOD period, we compute the
00556          waiting time with modulo DEFAULT_PERIOD. */
00557 
00558       now = RTIMER_NOW();
00559       wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
00560       if(wait < 2 * DEFAULT_ON_TIME) {
00561         wait = DEFAULT_PERIOD;
00562       }
00563       expected = now + wait - 2 * DEFAULT_ON_TIME;
00564 
00565 #if WITH_ACK_OPTIMIZATION
00566       /* Wait until the receiver is expected to be awake */
00567       if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
00568          PACKETBUF_ATTR_PACKET_TYPE_ACK &&
00569          is_streaming == 0) {
00570         /* Do not wait if we are sending an ACK, because then the
00571            receiver will already be awake. */
00572         while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
00573       }
00574 #else /* WITH_ACK_OPTIMIZATION */
00575       /* Wait until the receiver is expected to be awake */
00576       while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
00577 #endif /* WITH_ACK_OPTIMIZATION */
00578     }
00579   }
00580 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00581 
00582   /* By setting we_are_sending to one, we ensure that the rtimer
00583      powercycle interrupt do not interfere with us sending the packet. */
00584   we_are_sending = 1;
00585   
00586   t0 = RTIMER_NOW();
00587   strobes = 0;
00588 
00589   LEDS_ON(LEDS_BLUE);
00590 
00591   /* Send a train of strobes until the receiver answers with an ACK. */
00592 
00593   /* Turn on the radio to listen for the strobe ACK. */
00594   //  on();
00595   collisions = 0;
00596   if(!is_already_streaming) {
00597     watchdog_stop();
00598     got_strobe_ack = 0;
00599     t = RTIMER_NOW();
00600     for(strobes = 0, collisions = 0;
00601         got_strobe_ack == 0 && collisions == 0 &&
00602           RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_time);
00603         strobes++) {
00604 
00605       while(got_strobe_ack == 0 &&
00606             RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) {
00607 #if 0
00608         rtimer_clock_t now = RTIMER_NOW();
00609 
00610         /* See if we got an ACK */
00611         packetbuf_clear();
00612         len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
00613         if(len > 0) {
00614           packetbuf_set_datalen(len);
00615           if(NETSTACK_FRAMER.parse() >= 0) {
00616             hdr = packetbuf_dataptr();
00617             if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE_ACK) {
00618               if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00619                               &rimeaddr_node_addr)) {
00620                 /* We got an ACK from the receiver, so we can immediately send
00621                    the packet. */
00622                 got_strobe_ack = 1;
00623                 encounter_time = now;
00624               } else {
00625                 PRINTDEBUG("xmac: strobe ack for someone else\n");
00626               }
00627             } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ {
00628               PRINTDEBUG("xmac: strobe from someone else\n");
00629               collisions++;
00630             }
00631           } else {
00632             PRINTF("xmac: send failed to parse %u\n", len);
00633           }
00634         }
00635 #endif /* 0 */
00636       }
00637       
00638       t = RTIMER_NOW();
00639             /* Send the strobe packet. */
00640       if(got_strobe_ack == 0 && collisions == 0) {
00641 
00642         if(is_broadcast) {
00643 #if WITH_STROBE_BROADCAST
00644           ret = NETSTACK_RADIO.send(strobe, strobe_len);
00645 #else
00646           /* restore the packet to send */
00647           queuebuf_to_packetbuf(packet);
00648           ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00649 #endif
00650           off();
00651         } else {
00652 #if 0
00653           rtimer_clock_t wt;
00654 #endif
00655           on();
00656           ret = NETSTACK_RADIO.send(strobe, strobe_len);
00657 #if 0
00658           /* Turn off the radio for a while to let the other side
00659              respond. We don't need to keep our radio on when we know
00660              that the other side needs some time to produce a reply. */
00661           off();
00662           wt = RTIMER_NOW();
00663           while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
00664 #endif /* 0 */
00665 #if RDC_CONF_HARDWARE_ACK
00666           if(ret == RADIO_TX_OK) {
00667             got_strobe_ack = 1;
00668           } else {
00669             off();
00670           }
00671 #else
00672           if(detect_ack()) {
00673             got_strobe_ack = 1;
00674           } else {
00675             off();
00676           }
00677 #endif /* RDC_CONF_HARDWARE_ACK */
00678 
00679         }
00680       }
00681     }
00682   }
00683 
00684 #if WITH_ACK_OPTIMIZATION
00685   /* If we have received the strobe ACK, and we are sending a packet
00686      that will need an upper layer ACK (as signified by the
00687      PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
00688   if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00689                         packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
00690                         packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00691                         PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
00692     on(); /* Wait for ACK packet */
00693     waiting_for_packet = 1;
00694   } else {
00695     off();
00696   }
00697 #endif /* WITH_ACK_OPTIMIZATION */
00698 
00699   /* restore the packet to send */
00700   queuebuf_to_packetbuf(packet);
00701   queuebuf_free(packet);
00702 
00703   /* Send the data packet. */
00704   if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
00705     ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00706 
00707     if(!is_broadcast) {
00708 #if RDC_CONF_HARDWARE_ACK
00709       if(ret == RADIO_TX_OK) {
00710         got_ack = 1;
00711       }
00712 #else
00713       if(detect_ack()) {
00714         got_ack = 1;
00715       }
00716 #endif /* RDC_CONF_HARDWARE_ACK */
00717     }
00718   }
00719   off();
00720 
00721 #if WITH_ENCOUNTER_OPTIMIZATION
00722   if(got_strobe_ack && !is_streaming) {
00723     register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
00724   }
00725 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00726   watchdog_start();
00727 
00728   PRINTF("xmac: send (strobes=%u,len=%u,%s), done\n", strobes,
00729          packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack");
00730 
00731 #if XMAC_CONF_COMPOWER
00732   /* Accumulate the power consumption for the packet transmission. */
00733   compower_accumulate(&current_packet);
00734 
00735   /* Convert the accumulated power consumption for the transmitted
00736      packet to packet attributes so that the higher levels can keep
00737      track of the amount of energy spent on transmitting the
00738      packet. */
00739   compower_attrconv(&current_packet);
00740 
00741   /* Clear the accumulated power consumption so that it is ready for
00742      the next packet. */
00743   compower_clear(&current_packet);
00744 #endif /* XMAC_CONF_COMPOWER */
00745 
00746   we_are_sending = 0;
00747 
00748   LEDS_OFF(LEDS_BLUE);
00749   if(collisions == 0) {
00750     if(is_broadcast == 0 && got_ack == 0) {
00751       return MAC_TX_NOACK;
00752     } else {
00753       return MAC_TX_OK;
00754     }
00755   } else {
00756     someone_is_sending++;
00757     return MAC_TX_COLLISION;
00758   }
00759 
00760 }
00761 /*---------------------------------------------------------------------------*/
00762 static void
00763 qsend_packet(mac_callback_t sent, void *ptr)
00764 {
00765   int ret;
00766   
00767   if(someone_is_sending) {
00768     PRINTF("xmac: should queue packet, now just dropping %d %d %d %d.\n",
00769            waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on);
00770     RIMESTATS_ADD(sendingdrop);
00771     ret = MAC_TX_COLLISION;
00772   } else {
00773     PRINTF("xmac: send immediately.\n");
00774     ret = send_packet();
00775   }
00776 
00777   mac_call_sent_callback(sent, ptr, ret, 1);
00778 }
00779 /*---------------------------------------------------------------------------*/
00780 static void
00781 qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
00782 {
00783   if(buf_list != NULL) {
00784     queuebuf_to_packetbuf(buf_list->buf);
00785     qsend_packet(sent, ptr);
00786   }
00787 }
00788 /*---------------------------------------------------------------------------*/
00789 static void
00790 input_packet(void)
00791 {
00792   struct xmac_hdr *hdr;
00793 
00794   if(NETSTACK_FRAMER.parse() >= 0) {
00795     hdr = packetbuf_dataptr();
00796 
00797     if(hdr->dispatch != DISPATCH) {
00798       someone_is_sending = 0;
00799       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00800                                      &rimeaddr_node_addr) ||
00801          rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00802                       &rimeaddr_null)) {
00803         /* This is a regular packet that is destined to us or to the
00804            broadcast address. */
00805 
00806         /* We have received the final packet, so we can go back to being
00807            asleep. */
00808         off();
00809 
00810         /* Check for duplicate packet by comparing the sequence number
00811            of the incoming packet with the last few ones we saw. */
00812         {
00813           int i;
00814           for(i = 0; i < MAX_SEQNOS; ++i) {
00815             if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
00816                rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
00817                             &received_seqnos[i].sender)) {
00818               /* Drop the packet. */
00819               return;
00820             }
00821           }
00822           for(i = MAX_SEQNOS - 1; i > 0; --i) {
00823             memcpy(&received_seqnos[i], &received_seqnos[i - 1],
00824                    sizeof(struct seqno));
00825           }
00826           received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
00827           rimeaddr_copy(&received_seqnos[0].sender,
00828                         packetbuf_addr(PACKETBUF_ADDR_SENDER));
00829         }
00830 
00831 #if XMAC_CONF_COMPOWER
00832         /* Accumulate the power consumption for the packet reception. */
00833         compower_accumulate(&current_packet);
00834         /* Convert the accumulated power consumption for the received
00835            packet to packet attributes so that the higher levels can
00836            keep track of the amount of energy spent on receiving the
00837            packet. */
00838         compower_attrconv(&current_packet);
00839 
00840         /* Clear the accumulated power consumption so that it is ready
00841            for the next packet. */
00842         compower_clear(&current_packet);
00843 #endif /* XMAC_CONF_COMPOWER */
00844 
00845         waiting_for_packet = 0;
00846 
00847         PRINTDEBUG("xmac: data(%u)\n", packetbuf_datalen());
00848         NETSTACK_MAC.input();
00849         return;
00850       } else {
00851         PRINTDEBUG("xmac: data not for us\n");
00852       }
00853 
00854     } else if(hdr->type == TYPE_STROBE) {
00855       someone_is_sending = 2;
00856 
00857       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00858                       &rimeaddr_node_addr)) {
00859         /* This is a strobe packet for us. */
00860 
00861         /* If the sender address is someone else, we should
00862            acknowledge the strobe and wait for the packet. By using
00863            the same address as both sender and receiver, we flag the
00864            message is a strobe ack. */
00865         waiting_for_packet = 1;
00866 #if 0
00867         hdr->type = TYPE_STROBE_ACK;
00868         packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
00869                            packetbuf_addr(PACKETBUF_ADDR_SENDER));
00870         packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00871         packetbuf_compact();
00872         if(NETSTACK_FRAMER.create() >= 0) {
00873           /* We turn on the radio in anticipation of the incoming
00874              packet. */
00875           someone_is_sending = 1;
00876           waiting_for_packet = 1;
00877           on();
00878           NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00879           PRINTDEBUG("xmac: send strobe ack %u\n", packetbuf_totlen());
00880         } else {
00881           PRINTF("xmac: failed to send strobe ack\n");
00882         }
00883 #endif /* 0 */
00884       } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00885                              &rimeaddr_null)) {
00886         /* If the receiver address is null, the strobe is sent to
00887            prepare for an incoming broadcast packet. If this is the
00888            case, we turn on the radio and wait for the incoming
00889            broadcast packet. */
00890         waiting_for_packet = 1;
00891         on();
00892       } else {
00893         PRINTDEBUG("xmac: strobe not for us\n");
00894       }
00895       
00896       /* We are done processing the strobe and we therefore return
00897          to the caller. */
00898       return;
00899 #if XMAC_CONF_ANNOUNCEMENTS
00900     } else if(hdr->type == TYPE_ANNOUNCEMENT) {
00901       packetbuf_hdrreduce(sizeof(struct xmac_hdr));
00902       parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
00903 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00904     } else if(hdr->type == TYPE_STROBE_ACK) {
00905       PRINTDEBUG("xmac: stray strobe ack\n");
00906     } else {
00907       PRINTF("xmac: unknown type %u (%u/%u)\n", hdr->type,
00908              packetbuf_datalen(), len);
00909     }
00910   } else {
00911     PRINTF("xmac: failed to parse (%u)\n", packetbuf_totlen());
00912   }
00913 }
00914 /*---------------------------------------------------------------------------*/
00915 #if XMAC_CONF_ANNOUNCEMENTS
00916 static void
00917 send_announcement(void *ptr)
00918 {
00919   struct xmac_hdr *hdr;
00920   int announcement_len;
00921 
00922   /* Set up the probe header. */
00923   packetbuf_clear();
00924   hdr = packetbuf_dataptr();
00925 
00926   announcement_len = format_announcement((char *)hdr +
00927                                          sizeof(struct xmac_hdr));
00928 
00929   if(announcement_len > 0) {
00930     packetbuf_set_datalen(sizeof(struct xmac_hdr) + announcement_len);
00931     hdr->dispatch = DISPATCH;
00932     hdr->type = TYPE_ANNOUNCEMENT;
00933 
00934     packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00935     packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
00936     packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower);
00937     if(NETSTACK_FRAMER.create() >= 0) {
00938       NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00939     }
00940   }
00941 }
00942 /*---------------------------------------------------------------------------*/
00943 static void
00944 cycle_announcement(void *ptr)
00945 {
00946   ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME,
00947              send_announcement, NULL);
00948   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD,
00949              cycle_announcement, NULL);
00950   if(is_listening > 0) {
00951     is_listening--;
00952     /*    printf("is_listening %d\n", is_listening);*/
00953   }
00954 }
00955 /*---------------------------------------------------------------------------*/
00956 static void
00957 listen_callback(int periods)
00958 {
00959   is_listening = periods + 1;
00960 }
00961 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00962 /*---------------------------------------------------------------------------*/
00963 void
00964 xmac_set_announcement_radio_txpower(int txpower)
00965 {
00966 #if XMAC_CONF_ANNOUNCEMENTS
00967   announcement_radio_txpower = txpower;
00968 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00969 }
00970 /*---------------------------------------------------------------------------*/
00971 static void
00972 init(void)
00973 {
00974   radio_is_on = 0;
00975   waiting_for_packet = 0;
00976   PT_INIT(&pt);
00977   rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
00978              (void (*)(struct rtimer *, void *))powercycle, NULL);
00979 
00980   xmac_is_on = 1;
00981 
00982 #if WITH_ENCOUNTER_OPTIMIZATION
00983   list_init(encounter_list);
00984   memb_init(&encounter_memb);
00985 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00986 
00987 #if XMAC_CONF_ANNOUNCEMENTS
00988   announcement_register_listen_callback(listen_callback);
00989   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME,
00990              cycle_announcement, NULL);
00991 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00992 }
00993 /*---------------------------------------------------------------------------*/
00994 static int
00995 turn_on(void)
00996 {
00997   xmac_is_on = 1;
00998   rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
00999              (void (*)(struct rtimer *, void *))powercycle, NULL);
01000   return 1;
01001 }
01002 /*---------------------------------------------------------------------------*/
01003 static int
01004 turn_off(int keep_radio_on)
01005 {
01006   xmac_is_on = 0;
01007   if(keep_radio_on) {
01008     return NETSTACK_RADIO.on();
01009   } else {
01010     return NETSTACK_RADIO.off();
01011   }
01012 }
01013 /*---------------------------------------------------------------------------*/
01014 static unsigned short
01015 channel_check_interval(void)
01016 {
01017   return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;
01018 }
01019 /*---------------------------------------------------------------------------*/
01020 const struct rdc_driver xmac_driver =
01021   {
01022     "X-MAC",
01023     init,
01024     qsend_packet,
01025     qsend_list,
01026     input_packet,
01027     turn_on,
01028     turn_off,
01029     channel_check_interval,
01030   };