Contiki 2.6

cxmac.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 "net/netstack.h"
00046 #include "lib/random.h"
00047 #include "net/mac/cxmac.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        1
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 cxmac_hdr {
00101   uint8_t dispatch;
00102   uint8_t type;
00103 };
00104 
00105 #define MAX_STROBE_SIZE 50
00106 
00107 #ifdef CXMAC_CONF_ON_TIME
00108 #define DEFAULT_ON_TIME (CXMAC_CONF_ON_TIME)
00109 #else
00110 #define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160)
00111 #endif
00112 
00113 #ifdef CXMAC_CONF_OFF_TIME
00114 #define DEFAULT_OFF_TIME (CXMAC_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 (7 * DEFAULT_ON_TIME / 8)
00140 
00141 struct cxmac_config cxmac_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 
00150 static struct pt pt;
00151 
00152 static volatile uint8_t cxmac_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 CXMAC_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 /* CXMAC_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 CXMAC_CONF_COMPOWER
00194 static struct compower_activity current_packet;
00195 #endif /* CXMAC_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 /*---------------------------------------------------------------------------*/
00223 static void
00224 on(void)
00225 {
00226   if(cxmac_is_on && radio_is_on == 0) {
00227     radio_is_on = 1;
00228     NETSTACK_RADIO.on();
00229     LEDS_ON(LEDS_RED);
00230   }
00231 }
00232 /*---------------------------------------------------------------------------*/
00233 static void
00234 off(void)
00235 {
00236   if(cxmac_is_on && radio_is_on != 0 && is_listening == 0 &&
00237      is_streaming == 0) {
00238     radio_is_on = 0;
00239     NETSTACK_RADIO.off();
00240     LEDS_OFF(LEDS_RED);
00241   }
00242 }
00243 /*---------------------------------------------------------------------------*/
00244 static void
00245 powercycle_turn_radio_off(void)
00246 {
00247   if(we_are_sending == 0 &&
00248      waiting_for_packet == 0) {
00249     off();
00250   }
00251 #if CXMAC_CONF_COMPOWER
00252   compower_accumulate(&compower_idle_activity);
00253 #endif /* CXMAC_CONF_COMPOWER */
00254 }
00255 static void
00256 powercycle_turn_radio_on(void)
00257 {
00258   if(we_are_sending == 0 &&
00259      waiting_for_packet == 0) {
00260     on();
00261   }
00262 }
00263 /*---------------------------------------------------------------------------*/
00264 static struct ctimer cpowercycle_ctimer;
00265 #define CSCHEDULE_POWERCYCLE(rtime) cschedule_powercycle((1ul * CLOCK_SECOND * (rtime)) / RTIMER_ARCH_SECOND)
00266 static char cpowercycle(void *ptr);
00267 static void
00268 cschedule_powercycle(clock_time_t time)
00269 {
00270 
00271   if(cxmac_is_on) {
00272     if(time == 0) {
00273       time = 1;
00274     }
00275     ctimer_set(&cpowercycle_ctimer, time,
00276                (void (*)(void *))cpowercycle, NULL);
00277   }
00278 }
00279 /*---------------------------------------------------------------------------*/
00280 static char
00281 cpowercycle(void *ptr)
00282 {
00283   if(is_streaming) {
00284     if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
00285       is_streaming = 0;
00286       rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
00287       rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
00288     }
00289   }
00290 
00291   PT_BEGIN(&pt);
00292 
00293   while(1) {
00294     /* Only wait for some cycles to pass for someone to start sending */
00295     if(someone_is_sending > 0) {
00296       someone_is_sending--;
00297     }
00298 
00299     /* If there were a strobe in the air, turn radio on */
00300     powercycle_turn_radio_on();
00301     CSCHEDULE_POWERCYCLE(DEFAULT_ON_TIME);
00302     PT_YIELD(&pt);
00303 
00304     if(cxmac_config.off_time > 0) {
00305       powercycle_turn_radio_off();
00306       if(waiting_for_packet != 0) {
00307         waiting_for_packet++;
00308         if(waiting_for_packet > 2) {
00309           /* We should not be awake for more than two consecutive
00310              power cycles without having heard a packet, so we turn off
00311              the radio. */
00312           waiting_for_packet = 0;
00313           powercycle_turn_radio_off();
00314         }
00315       }
00316       CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
00317       PT_YIELD(&pt);
00318     }
00319   }
00320 
00321   PT_END(&pt);
00322 }
00323 /*---------------------------------------------------------------------------*/
00324 #if CXMAC_CONF_ANNOUNCEMENTS
00325 static int
00326 parse_announcements(const rimeaddr_t *from)
00327 {
00328   /* Parse incoming announcements */
00329   struct announcement_msg adata;
00330   int i;
00331 
00332   memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata)));
00333 
00334   /*  printf("%d.%d: probe from %d.%d with %d announcements\n",
00335          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00336          from->u8[0], from->u8[1], adata->num);*/
00337   /*  for(i = 0; i < packetbuf_datalen(); ++i) {
00338     printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]);
00339   }
00340   printf("\n");*/
00341 
00342   for(i = 0; i < adata.num; ++i) {
00343     /*   printf("%d.%d: announcement %d: %d\n",
00344           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00345           adata->data[i].id,
00346           adata->data[i].value);*/
00347 
00348     announcement_heard(from,
00349                        adata.data[i].id,
00350                        adata.data[i].value);
00351   }
00352   return i;
00353 }
00354 /*---------------------------------------------------------------------------*/
00355 static int
00356 format_announcement(char *hdr)
00357 {
00358   struct announcement_msg adata;
00359   struct announcement *a;
00360 
00361   /* Construct the announcements */
00362   /*  adata = (struct announcement_msg *)hdr;*/
00363 
00364   adata.num = 0;
00365   for(a = announcement_list();
00366       a != NULL && adata.num < ANNOUNCEMENT_MAX;
00367       a = list_item_next(a)) {
00368     adata.data[adata.num].id = a->id;
00369     adata.data[adata.num].value = a->value;
00370     adata.num++;
00371   }
00372 
00373   memcpy(hdr, &adata, sizeof(struct announcement_msg));
00374 
00375   if(adata.num > 0) {
00376     return ANNOUNCEMENT_MSG_HEADERLEN +
00377       sizeof(struct announcement_data) * adata.num;
00378   } else {
00379     return 0;
00380   }
00381 }
00382 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
00383 /*---------------------------------------------------------------------------*/
00384 #if WITH_ENCOUNTER_OPTIMIZATION
00385 static void
00386 register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time)
00387 {
00388   struct encounter *e;
00389 
00390   /* If we have an entry for this neighbor already, we renew it. */
00391   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00392     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00393       e->time = time;
00394       break;
00395     }
00396   }
00397   /* No matching encounter was found, so we allocate a new one. */
00398   if(e == NULL) {
00399     e = memb_alloc(&encounter_memb);
00400     if(e == NULL) {
00401       /* We could not allocate memory for this encounter, so we just drop it. */
00402       return;
00403     }
00404     rimeaddr_copy(&e->neighbor, neighbor);
00405     e->time = time;
00406     list_add(encounter_list, e);
00407   }
00408 }
00409 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00410 /*---------------------------------------------------------------------------*/
00411 static int
00412 send_packet(void)
00413 {
00414   rtimer_clock_t t0;
00415   rtimer_clock_t t;
00416   rtimer_clock_t encounter_time = 0;
00417   int strobes;
00418   struct cxmac_hdr *hdr;
00419   int got_strobe_ack = 0;
00420   uint8_t strobe[MAX_STROBE_SIZE];
00421   int strobe_len, len;
00422   int is_broadcast = 0;
00423   int is_dispatch, is_strobe_ack;
00424   /*int is_reliable;*/
00425   struct encounter *e;
00426   struct queuebuf *packet;
00427   int is_already_streaming = 0;
00428   uint8_t collisions;
00429 
00430 
00431   /* Create the X-MAC header for the data packet. */
00432   packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00433   if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
00434     is_broadcast = 1;
00435     PRINTDEBUG("cxmac: send broadcast\n");
00436   } else {
00437 #if UIP_CONF_IPV6
00438     PRINTDEBUG("cxmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
00439            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
00440            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1],
00441            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2],
00442            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3],
00443            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4],
00444            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5],
00445            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6],
00446            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]);
00447 #else
00448     PRINTDEBUG("cxmac: send unicast to %u.%u\n",
00449            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
00450            packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
00451 #endif /* UIP_CONF_IPV6 */
00452   }
00453 /* is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00454     packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);*/
00455   len = NETSTACK_FRAMER.create();
00456   strobe_len = len + sizeof(struct cxmac_hdr);
00457   if(len < 0 || strobe_len > (int)sizeof(strobe)) {
00458     /* Failed to send */
00459    PRINTF("cxmac: send failed, too large header\n");
00460     return MAC_TX_ERR_FATAL;
00461   }
00462   memcpy(strobe, packetbuf_hdrptr(), len);
00463   strobe[len] = DISPATCH; /* dispatch */
00464   strobe[len + 1] = TYPE_STROBE; /* type */
00465 
00466   packetbuf_compact();
00467   packet = queuebuf_new_from_packetbuf();
00468   if(packet == NULL) {
00469     /* No buffer available */
00470     PRINTF("cxmac: send failed, no queue buffer available (of %u)\n",
00471            QUEUEBUF_CONF_NUM);
00472     return MAC_TX_ERR;
00473   }
00474 
00475 #if WITH_STREAMING
00476   if(is_streaming == 1 &&
00477      (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00478                    &is_streaming_to) ||
00479       rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00480                    &is_streaming_to_too))) {
00481     is_already_streaming = 1;
00482   }
00483   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00484      PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
00485     is_streaming = 1;
00486     if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
00487       rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
00488     } else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
00489       rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
00490     }
00491     stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
00492   }
00493 #endif /* WITH_STREAMING */
00494 
00495   off();
00496 
00497 #if WITH_ENCOUNTER_OPTIMIZATION
00498   /* We go through the list of encounters to find if we have recorded
00499      an encounter with this particular neighbor. If so, we can compute
00500      the time for the next expected encounter and setup a ctimer to
00501      switch on the radio just before the encounter. */
00502   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00503     const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
00504 
00505     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00506       rtimer_clock_t wait, now, expected;
00507 
00508       /* We expect encounters to happen every DEFAULT_PERIOD time
00509          units. The next expected encounter is at time e->time +
00510          DEFAULT_PERIOD. To compute a relative offset, we subtract
00511          with clock_time(). Because we are only interested in turning
00512          on the radio within the DEFAULT_PERIOD period, we compute the
00513          waiting time with modulo DEFAULT_PERIOD. */
00514 
00515       now = RTIMER_NOW();
00516       wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
00517       expected = now + wait - 2 * DEFAULT_ON_TIME;
00518 
00519 #if WITH_ACK_OPTIMIZATION
00520       /* Wait until the receiver is expected to be awake */
00521       if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
00522          PACKETBUF_ATTR_PACKET_TYPE_ACK &&
00523          is_streaming == 0) {
00524         /* Do not wait if we are sending an ACK, because then the
00525            receiver will already be awake. */
00526         while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
00527       }
00528 #else /* WITH_ACK_OPTIMIZATION */
00529       /* Wait until the receiver is expected to be awake */
00530       while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
00531 #endif /* WITH_ACK_OPTIMIZATION */
00532     }
00533   }
00534 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00535 
00536   /* By setting we_are_sending to one, we ensure that the rtimer
00537      powercycle interrupt do not interfere with us sending the packet. */
00538   we_are_sending = 1;
00539   
00540   t0 = RTIMER_NOW();
00541   strobes = 0;
00542 
00543   LEDS_ON(LEDS_BLUE);
00544 
00545   /* Send a train of strobes until the receiver answers with an ACK. */
00546 
00547   /* Turn on the radio to listen for the strobe ACK. */
00548   on();
00549   collisions = 0;
00550   if(!is_already_streaming) {
00551     watchdog_stop();
00552     got_strobe_ack = 0;
00553     t = RTIMER_NOW();
00554     for(strobes = 0, collisions = 0;
00555         got_strobe_ack == 0 && collisions == 0 &&
00556           RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + cxmac_config.strobe_time);
00557         strobes++) {
00558 
00559       while(got_strobe_ack == 0 &&
00560             RTIMER_CLOCK_LT(RTIMER_NOW(), t + cxmac_config.strobe_wait_time)) {
00561         rtimer_clock_t now = RTIMER_NOW();
00562 
00563         /* See if we got an ACK */
00564         packetbuf_clear();
00565         len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
00566         if(len > 0) {
00567           packetbuf_set_datalen(len);
00568           if(NETSTACK_FRAMER.parse() >= 0) {
00569             hdr = packetbuf_dataptr();
00570             is_dispatch = hdr->dispatch == DISPATCH;
00571             is_strobe_ack = hdr->type == TYPE_STROBE_ACK;
00572             if(is_dispatch && is_strobe_ack) {
00573               if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00574                               &rimeaddr_node_addr)) {
00575                 /* We got an ACK from the receiver, so we can immediately send
00576                    the packet. */
00577                 got_strobe_ack = 1;
00578                 encounter_time = now;
00579               } else {
00580                 PRINTDEBUG("cxmac: strobe ack for someone else\n");
00581               }
00582             } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ {
00583               PRINTDEBUG("cxmac: strobe from someone else\n");
00584               collisions++;
00585             }
00586           } else {
00587             PRINTF("cxmac: send failed to parse %u\n", len);
00588           }
00589         }
00590       }
00591 
00592       t = RTIMER_NOW();
00593       /* Send the strobe packet. */
00594       if(got_strobe_ack == 0 && collisions == 0) {
00595         if(is_broadcast) {
00596 #if WITH_STROBE_BROADCAST
00597           NETSTACK_RADIO.send(strobe, strobe_len);
00598 #else
00599           /* restore the packet to send */
00600           queuebuf_to_packetbuf(packet);
00601           NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00602 #endif
00603           off();
00604         } else {
00605           NETSTACK_RADIO.send(strobe, strobe_len);
00606 #if 0
00607           /* Turn off the radio for a while to let the other side
00608              respond. We don't need to keep our radio on when we know
00609              that the other side needs some time to produce a reply. */
00610           off();
00611           rtimer_clock_t wt = RTIMER_NOW();
00612           while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
00613 #endif /* 0 */
00614           on();
00615         }
00616       }
00617     }
00618   }
00619 
00620 #if WITH_ACK_OPTIMIZATION
00621   /* If we have received the strobe ACK, and we are sending a packet
00622      that will need an upper layer ACK (as signified by the
00623      PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
00624   if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00625                         packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
00626                         packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00627                         PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
00628     on(); /* Wait for ACK packet */
00629     waiting_for_packet = 1;
00630   } else {
00631     off();
00632   }
00633 #else /* WITH_ACK_OPTIMIZATION */
00634   off();
00635 #endif /* WITH_ACK_OPTIMIZATION */
00636 
00637   /* restore the packet to send */
00638   queuebuf_to_packetbuf(packet);
00639   queuebuf_free(packet);
00640 
00641   /* Send the data packet. */
00642   if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
00643     NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00644   }
00645 
00646 #if WITH_ENCOUNTER_OPTIMIZATION
00647   if(got_strobe_ack && !is_streaming) {
00648     register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
00649   }
00650 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00651   watchdog_start();
00652 
00653   PRINTF("cxmac: send (strobes=%u,len=%u,%s), done\n", strobes,
00654          packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack");
00655 
00656 #if CXMAC_CONF_COMPOWER
00657   /* Accumulate the power consumption for the packet transmission. */
00658   compower_accumulate(&current_packet);
00659 
00660   /* Convert the accumulated power consumption for the transmitted
00661      packet to packet attributes so that the higher levels can keep
00662      track of the amount of energy spent on transmitting the
00663      packet. */
00664   compower_attrconv(&current_packet);
00665 
00666   /* Clear the accumulated power consumption so that it is ready for
00667      the next packet. */
00668   compower_clear(&current_packet);
00669 #endif /* CXMAC_CONF_COMPOWER */
00670 
00671   we_are_sending = 0;
00672 
00673   LEDS_OFF(LEDS_BLUE);
00674   if(collisions == 0) {
00675     if(!is_broadcast && !got_strobe_ack) {
00676       return MAC_TX_NOACK;
00677     } else {
00678       return MAC_TX_OK;
00679     }
00680   } else {
00681     someone_is_sending++;
00682     return MAC_TX_COLLISION;
00683   }
00684 
00685 }
00686 /*---------------------------------------------------------------------------*/
00687 static void
00688 qsend_packet(mac_callback_t sent, void *ptr)
00689 {
00690   int ret;
00691   if(someone_is_sending) {
00692     PRINTF("cxmac: should queue packet, now just dropping %d %d %d %d.\n",
00693            waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on);
00694     RIMESTATS_ADD(sendingdrop);
00695     ret = MAC_TX_COLLISION;
00696   } else {
00697     PRINTF("cxmac: send immediately.\n");
00698     ret = send_packet();
00699   }
00700 
00701   mac_call_sent_callback(sent, ptr, ret, 1);
00702 }
00703 /*---------------------------------------------------------------------------*/
00704 static void
00705 qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
00706 {
00707   if(buf_list != NULL) {
00708     queuebuf_to_packetbuf(buf_list->buf);
00709     qsend_packet(sent, ptr);
00710   }
00711 }
00712 /*---------------------------------------------------------------------------*/
00713 static void
00714 input_packet(void)
00715 {
00716   struct cxmac_hdr *hdr;
00717 
00718   if(NETSTACK_FRAMER.parse() >= 0) {
00719     hdr = packetbuf_dataptr();
00720 
00721     if(hdr->dispatch != DISPATCH) {
00722       someone_is_sending = 0;
00723       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00724                                      &rimeaddr_node_addr) ||
00725          rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00726                       &rimeaddr_null)) {
00727         /* This is a regular packet that is destined to us or to the
00728            broadcast address. */
00729 
00730         /* We have received the final packet, so we can go back to being
00731            asleep. */
00732         off();
00733 
00734 #if CXMAC_CONF_COMPOWER
00735         /* Accumulate the power consumption for the packet reception. */
00736         compower_accumulate(&current_packet);
00737         /* Convert the accumulated power consumption for the received
00738            packet to packet attributes so that the higher levels can
00739            keep track of the amount of energy spent on receiving the
00740            packet. */
00741         compower_attrconv(&current_packet);
00742 
00743         /* Clear the accumulated power consumption so that it is ready
00744            for the next packet. */
00745         compower_clear(&current_packet);
00746 #endif /* CXMAC_CONF_COMPOWER */
00747 
00748         waiting_for_packet = 0;
00749 
00750         PRINTDEBUG("cxmac: data(%u)\n", packetbuf_datalen());
00751         NETSTACK_MAC.input();
00752         return;
00753       } else {
00754         PRINTDEBUG("cxmac: data not for us\n");
00755       }
00756 
00757     } else if(hdr->type == TYPE_STROBE) {
00758       someone_is_sending = 2;
00759 
00760       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00761                       &rimeaddr_node_addr)) {
00762         /* This is a strobe packet for us. */
00763 
00764         /* If the sender address is someone else, we should
00765            acknowledge the strobe and wait for the packet. By using
00766            the same address as both sender and receiver, we flag the
00767            message is a strobe ack. */
00768         hdr->type = TYPE_STROBE_ACK;
00769         packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
00770                            packetbuf_addr(PACKETBUF_ADDR_SENDER));
00771         packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00772         packetbuf_compact();
00773         if(NETSTACK_FRAMER.create() >= 0) {
00774           /* We turn on the radio in anticipation of the incoming
00775              packet. */
00776           someone_is_sending = 1;
00777           waiting_for_packet = 1;
00778           on();
00779           NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00780           PRINTDEBUG("cxmac: send strobe ack %u\n", packetbuf_totlen());
00781         } else {
00782           PRINTF("cxmac: failed to send strobe ack\n");
00783         }
00784       } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00785                              &rimeaddr_null)) {
00786         /* If the receiver address is null, the strobe is sent to
00787            prepare for an incoming broadcast packet. If this is the
00788            case, we turn on the radio and wait for the incoming
00789            broadcast packet. */
00790         waiting_for_packet = 1;
00791         on();
00792       } else {
00793         PRINTDEBUG("cxmac: strobe not for us\n");
00794       }
00795 
00796       /* We are done processing the strobe and we therefore return
00797          to the caller. */
00798       return;
00799 #if CXMAC_CONF_ANNOUNCEMENTS
00800     } else if(hdr->type == TYPE_ANNOUNCEMENT) {
00801       packetbuf_hdrreduce(sizeof(struct cxmac_hdr));
00802       parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
00803 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
00804     } else if(hdr->type == TYPE_STROBE_ACK) {
00805       PRINTDEBUG("cxmac: stray strobe ack\n");
00806     } else {
00807       PRINTF("cxmac: unknown type %u (%u)\n", hdr->type,
00808              packetbuf_datalen());
00809     }
00810   } else {
00811     PRINTF("cxmac: failed to parse (%u)\n", packetbuf_totlen());
00812   }
00813 }
00814 /*---------------------------------------------------------------------------*/
00815 #if CXMAC_CONF_ANNOUNCEMENTS
00816 static void
00817 send_announcement(void *ptr)
00818 {
00819   struct cxmac_hdr *hdr;
00820   int announcement_len;
00821 
00822   /* Set up the probe header. */
00823   packetbuf_clear();
00824   hdr = packetbuf_dataptr();
00825 
00826   announcement_len = format_announcement((char *)hdr +
00827                                          sizeof(struct cxmac_hdr));
00828 
00829   if(announcement_len > 0) {
00830     packetbuf_set_datalen(sizeof(struct cxmac_hdr) + announcement_len);
00831     hdr->dispatch = DISPATCH;
00832     hdr->type = TYPE_ANNOUNCEMENT;
00833 
00834     packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00835     packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
00836     packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower);
00837     if(NETSTACK_FRAMER.create() >= 0) {
00838       NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00839     }
00840   }
00841 }
00842 /*---------------------------------------------------------------------------*/
00843 static void
00844 cycle_announcement(void *ptr)
00845 {
00846   ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME,
00847              send_announcement, NULL);
00848   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD,
00849              cycle_announcement, NULL);
00850   if(is_listening > 0) {
00851     is_listening--;
00852     /*    printf("is_listening %d\n", is_listening);*/
00853   }
00854 }
00855 /*---------------------------------------------------------------------------*/
00856 static void
00857 listen_callback(int periods)
00858 {
00859   is_listening = periods + 1;
00860 }
00861 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
00862 /*---------------------------------------------------------------------------*/
00863 void
00864 cxmac_set_announcement_radio_txpower(int txpower)
00865 {
00866 #if CXMAC_CONF_ANNOUNCEMENTS
00867   announcement_radio_txpower = txpower;
00868 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
00869 }
00870 /*---------------------------------------------------------------------------*/
00871 void
00872 cxmac_init(void)
00873 {
00874   radio_is_on = 0;
00875   waiting_for_packet = 0;
00876   PT_INIT(&pt);
00877   /*  rtimer_set(&rt, RTIMER_NOW() + cxmac_config.off_time, 1,
00878       (void (*)(struct rtimer *, void *))powercycle, NULL);*/
00879 
00880   cxmac_is_on = 1;
00881 
00882 #if WITH_ENCOUNTER_OPTIMIZATION
00883   list_init(encounter_list);
00884   memb_init(&encounter_memb);
00885 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00886 
00887 #if CXMAC_CONF_ANNOUNCEMENTS
00888   announcement_register_listen_callback(listen_callback);
00889   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME,
00890              cycle_announcement, NULL);
00891 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
00892 
00893   CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
00894 }
00895 /*---------------------------------------------------------------------------*/
00896 static int
00897 turn_on(void)
00898 {
00899   cxmac_is_on = 1;
00900   /*  rtimer_set(&rt, RTIMER_NOW() + cxmac_config.off_time, 1,
00901       (void (*)(struct rtimer *, void *))powercycle, NULL);*/
00902   CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
00903   return 1;
00904 }
00905 /*---------------------------------------------------------------------------*/
00906 static int
00907 turn_off(int keep_radio_on)
00908 {
00909   cxmac_is_on = 0;
00910   if(keep_radio_on) {
00911     return NETSTACK_RADIO.on();
00912   } else {
00913     return NETSTACK_RADIO.off();
00914   }
00915 }
00916 /*---------------------------------------------------------------------------*/
00917 static unsigned short
00918 channel_check_interval(void)
00919 {
00920   return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;
00921 }
00922 /*---------------------------------------------------------------------------*/
00923 const struct rdc_driver cxmac_driver =
00924   {
00925     "CX-MAC",
00926     cxmac_init,
00927     qsend_packet,
00928     qsend_list,
00929     input_packet,
00930     turn_on,
00931     turn_off,
00932     channel_check_interval,
00933   };