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  * $Id: xmac.c,v 1.60 2011/01/25 14:31:09 adamdunkels Exp $
00032  */
00033 
00034 /**
00035  * \file
00036  *         A simple power saving MAC protocol based on X-MAC [SenSys 2006]
00037  * \author
00038  *         Adam Dunkels <adam@sics.se>
00039  *         Niclas Finne <nfi@sics.se>
00040  *         Joakim Eriksson <joakime@sics.se>
00041  */
00042 
00043 #include "dev/leds.h"
00044 #include "dev/radio.h"
00045 #include "dev/watchdog.h"
00046 #include "lib/random.h"
00047 #include "net/netstack.h"
00048 #include "net/mac/xmac.h"
00049 #include "net/rime.h"
00050 #include "net/rime/timesynch.h"
00051 #include "sys/compower.h"
00052 #include "sys/pt.h"
00053 #include "sys/rtimer.h"
00054 
00055 #include "contiki-conf.h"
00056 
00057 #ifdef EXPERIMENT_SETUP
00058 #include "experiment-setup.h"
00059 #endif
00060 
00061 #include <string.h>
00062 
00063 #ifndef WITH_ACK_OPTIMIZATION
00064 #define WITH_ACK_OPTIMIZATION        0
00065 #endif
00066 #ifndef WITH_ENCOUNTER_OPTIMIZATION
00067 #define WITH_ENCOUNTER_OPTIMIZATION  1
00068 #endif
00069 #ifndef WITH_STREAMING
00070 #define WITH_STREAMING               1
00071 #endif
00072 #ifndef WITH_STROBE_BROADCAST
00073 #define WITH_STROBE_BROADCAST        0
00074 #endif
00075 
00076 struct announcement_data {
00077   uint16_t id;
00078   uint16_t value;
00079 };
00080 
00081 /* The maximum number of announcements in a single announcement
00082    message - may need to be increased in the future. */
00083 #define ANNOUNCEMENT_MAX 10
00084 
00085 /* The structure of the announcement messages. */
00086 struct announcement_msg {
00087   uint16_t num;
00088   struct announcement_data data[ANNOUNCEMENT_MAX];
00089 };
00090 
00091 /* The length of the header of the announcement message, i.e., the
00092    "num" field in the struct. */
00093 #define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t))
00094 
00095 #define DISPATCH          0
00096 #define TYPE_STROBE       0x10
00097 /* #define TYPE_DATA         0x11 */
00098 #define TYPE_ANNOUNCEMENT 0x12
00099 #define TYPE_STROBE_ACK   0x13
00100 
00101 struct xmac_hdr {
00102   uint8_t dispatch;
00103   uint8_t type;
00104 };
00105 
00106 #define MAX_STROBE_SIZE 50
00107 
00108 #ifdef XMAC_CONF_ON_TIME
00109 #define DEFAULT_ON_TIME (XMAC_CONF_ON_TIME)
00110 #else
00111 #define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160)
00112 #endif
00113 
00114 #ifdef XMAC_CONF_OFF_TIME
00115 #define DEFAULT_OFF_TIME (XMAC_CONF_OFF_TIME)
00116 #else
00117 #define DEFAULT_OFF_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - DEFAULT_ON_TIME)
00118 #endif
00119 
00120 #define DEFAULT_PERIOD (DEFAULT_OFF_TIME + DEFAULT_ON_TIME)
00121 
00122 #define WAIT_TIME_BEFORE_STROBE_ACK RTIMER_ARCH_SECOND / 1000
00123 
00124 /* On some platforms, we may end up with a DEFAULT_PERIOD that is 0
00125    which will make compilation fail due to a modulo operation in the
00126    code. To ensure that DEFAULT_PERIOD is greater than zero, we use
00127    the construct below. */
00128 #if DEFAULT_PERIOD == 0
00129 #undef DEFAULT_PERIOD
00130 #define DEFAULT_PERIOD 1
00131 #endif
00132 
00133 /* The cycle time for announcements. */
00134 #define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND
00135 
00136 /* The time before sending an announcement within one announcement
00137    cycle. */
00138 #define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD))
00139 
00140 #define DEFAULT_STROBE_WAIT_TIME (5 * DEFAULT_ON_TIME / 8)
00141 
00142 struct xmac_config xmac_config = {
00143   DEFAULT_ON_TIME,
00144   DEFAULT_OFF_TIME,
00145   4 * DEFAULT_ON_TIME + DEFAULT_OFF_TIME,
00146   DEFAULT_STROBE_WAIT_TIME
00147 };
00148 
00149 #include <stdio.h>
00150 static struct rtimer rt;
00151 static struct pt pt;
00152 
00153 static volatile uint8_t xmac_is_on = 0;
00154 
00155 static volatile unsigned char waiting_for_packet = 0;
00156 static volatile unsigned char someone_is_sending = 0;
00157 static volatile unsigned char we_are_sending = 0;
00158 static volatile unsigned char radio_is_on = 0;
00159 
00160 #undef LEDS_ON
00161 #undef LEDS_OFF
00162 #undef LEDS_TOGGLE
00163 
00164 #define LEDS_ON(x) leds_on(x)
00165 #define LEDS_OFF(x) leds_off(x)
00166 #define LEDS_TOGGLE(x) leds_toggle(x)
00167 #define DEBUG 0
00168 #if DEBUG
00169 #include <stdio.h>
00170 #define PRINTF(...) printf(__VA_ARGS__)
00171 #define PRINTDEBUG(...) printf(__VA_ARGS__)
00172 #else
00173 #undef LEDS_ON
00174 #undef LEDS_OFF
00175 #undef LEDS_TOGGLE
00176 #define LEDS_ON(x)
00177 #define LEDS_OFF(x)
00178 #define LEDS_TOGGLE(x)
00179 #define PRINTF(...)
00180 #define PRINTDEBUG(...)
00181 #endif
00182 
00183 #if XMAC_CONF_ANNOUNCEMENTS
00184 /* Timers for keeping track of when to send announcements. */
00185 static struct ctimer announcement_cycle_ctimer, announcement_ctimer;
00186 
00187 static int announcement_radio_txpower;
00188 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00189 
00190 /* Flag that is used to keep track of whether or not we are listening
00191    for announcements from neighbors. */
00192 static uint8_t is_listening;
00193 
00194 #if XMAC_CONF_COMPOWER
00195 static struct compower_activity current_packet;
00196 #endif /* XMAC_CONF_COMPOWER */
00197 
00198 #if WITH_ENCOUNTER_OPTIMIZATION
00199 
00200 #include "lib/list.h"
00201 #include "lib/memb.h"
00202 
00203 struct encounter {
00204   struct encounter *next;
00205   rimeaddr_t neighbor;
00206   rtimer_clock_t time;
00207 };
00208 
00209 #define MAX_ENCOUNTERS 4
00210 LIST(encounter_list);
00211 MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
00212 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00213 
00214 static uint8_t is_streaming;
00215 static rimeaddr_t is_streaming_to, is_streaming_to_too;
00216 static rtimer_clock_t stream_until;
00217 #define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
00218 
00219 #ifndef MIN
00220 #define MIN(a, b) ((a) < (b)? (a) : (b))
00221 #endif /* MIN */
00222 
00223 struct seqno {
00224   rimeaddr_t sender;
00225   uint8_t seqno;
00226 };
00227 
00228 #define MAX_SEQNOS 8
00229 static struct seqno received_seqnos[MAX_SEQNOS];
00230 
00231 
00232 /*---------------------------------------------------------------------------*/
00233 static void
00234 on(void)
00235 {
00236   if(xmac_is_on && radio_is_on == 0) {
00237     radio_is_on = 1;
00238     NETSTACK_RADIO.on();
00239     LEDS_ON(LEDS_RED);
00240   }
00241 }
00242 /*---------------------------------------------------------------------------*/
00243 static void
00244 off(void)
00245 {
00246   if(xmac_is_on && radio_is_on != 0 && is_listening == 0 &&
00247      is_streaming == 0) {
00248     radio_is_on = 0;
00249     NETSTACK_RADIO.off();
00250     LEDS_OFF(LEDS_RED);
00251   }
00252 }
00253 /*---------------------------------------------------------------------------*/
00254 static char powercycle(struct rtimer *t, void *ptr);
00255 static void
00256 schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
00257 {
00258   int r;
00259   if(xmac_is_on) {
00260     r = rtimer_set(t, RTIMER_TIME(t) + time, 1,
00261                    (void (*)(struct rtimer *, void *))powercycle, NULL);
00262     if(r) {
00263       PRINTF("schedule_powercycle: could not set rtimer\n");
00264     }
00265   }
00266 }
00267 static void
00268 powercycle_turn_radio_off(void)
00269 {
00270   if(we_are_sending == 0 &&
00271      waiting_for_packet == 0) {
00272     off();
00273   }
00274 #if XMAC_CONF_COMPOWER
00275   compower_accumulate(&compower_idle_activity);
00276 #endif /* XMAC_CONF_COMPOWER */
00277 }
00278 static void
00279 powercycle_turn_radio_on(void)
00280 {
00281   if(we_are_sending == 0 &&
00282      waiting_for_packet == 0) {
00283     on();
00284   }
00285 }
00286 static char
00287 powercycle(struct rtimer *t, void *ptr)
00288 {
00289   if(is_streaming) {
00290     if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
00291       is_streaming = 0;
00292       rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
00293       rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
00294     }
00295   }
00296 
00297   PT_BEGIN(&pt);
00298 
00299   while(1) {
00300     /* Only wait for some cycles to pass for someone to start sending */
00301     if(someone_is_sending > 0) {
00302       someone_is_sending--;
00303     }
00304 
00305     /* If there were a strobe in the air, turn radio on */
00306     powercycle_turn_radio_on();
00307     schedule_powercycle(t, xmac_config.on_time);
00308     PT_YIELD(&pt);
00309 
00310     if(xmac_config.off_time > 0 && !NETSTACK_RADIO.receiving_packet()) {
00311       powercycle_turn_radio_off();
00312       if(waiting_for_packet != 0) {
00313         waiting_for_packet++;
00314         if(waiting_for_packet > 2) {
00315           /* We should not be awake for more than two consecutive
00316              power cycles without having heard a packet, so we turn off
00317              the radio. */
00318           waiting_for_packet = 0;
00319           powercycle_turn_radio_off();
00320         }
00321       }
00322       schedule_powercycle(t, xmac_config.off_time);
00323       PT_YIELD(&pt);
00324     }
00325   }
00326 
00327   PT_END(&pt);
00328 }
00329 /*---------------------------------------------------------------------------*/
00330 #if XMAC_CONF_ANNOUNCEMENTS
00331 static int
00332 parse_announcements(const rimeaddr_t *from)
00333 {
00334   /* Parse incoming announcements */
00335   struct announcement_msg adata;
00336   int i;
00337 
00338   memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata)));
00339 
00340   /*  printf("%d.%d: probe from %d.%d with %d announcements\n",
00341          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00342          from->u8[0], from->u8[1], adata->num);*/
00343   /*  for(i = 0; i < packetbuf_datalen(); ++i) {
00344     printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]);
00345   }
00346   printf("\n");*/
00347 
00348   for(i = 0; i < adata.num; ++i) {
00349     /*   printf("%d.%d: announcement %d: %d\n",
00350           rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00351           adata->data[i].id,
00352           adata->data[i].value);*/
00353 
00354     announcement_heard(from,
00355                        adata.data[i].id,
00356                        adata.data[i].value);
00357   }
00358   return i;
00359 }
00360 /*---------------------------------------------------------------------------*/
00361 static int
00362 format_announcement(char *hdr)
00363 {
00364   struct announcement_msg adata;
00365   struct announcement *a;
00366 
00367   /* Construct the announcements */
00368   /*  adata = (struct announcement_msg *)hdr;*/
00369 
00370   adata.num = 0;
00371   for(a = announcement_list();
00372       a != NULL && adata.num < ANNOUNCEMENT_MAX;
00373       a = list_item_next(a)) {
00374     adata.data[adata.num].id = a->id;
00375     adata.data[adata.num].value = a->value;
00376     adata.num++;
00377   }
00378 
00379   memcpy(hdr, &adata, sizeof(struct announcement_msg));
00380 
00381   if(adata.num > 0) {
00382     return ANNOUNCEMENT_MSG_HEADERLEN +
00383       sizeof(struct announcement_data) * adata.num;
00384   } else {
00385     return 0;
00386   }
00387 }
00388 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00389 /*---------------------------------------------------------------------------*/
00390 #if WITH_ENCOUNTER_OPTIMIZATION
00391 static void
00392 register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time)
00393 {
00394   struct encounter *e;
00395 
00396   /* If we have an entry for this neighbor already, we renew it. */
00397   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00398     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00399       e->time = time;
00400       break;
00401     }
00402   }
00403   /* No matching encounter was found, so we allocate a new one. */
00404   if(e == NULL) {
00405     e = memb_alloc(&encounter_memb);
00406     if(e == NULL) {
00407       /* We could not allocate memory for this encounter, so we just drop it. */
00408       return;
00409     }
00410     rimeaddr_copy(&e->neighbor, neighbor);
00411     e->time = time;
00412     list_add(encounter_list, e);
00413   }
00414 }
00415 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00416 /*---------------------------------------------------------------------------*/
00417 static int
00418 detect_ack(void)
00419 {
00420 #define INTER_PACKET_INTERVAL              RTIMER_ARCH_SECOND / 5000
00421 #define ACK_LEN 3
00422 #define AFTER_ACK_DETECTECT_WAIT_TIME      RTIMER_ARCH_SECOND / 1000
00423   rtimer_clock_t wt;
00424   uint8_t ack_received = 0;
00425   
00426   wt = RTIMER_NOW();
00427   leds_on(LEDS_GREEN);
00428   while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
00429   leds_off(LEDS_GREEN);
00430   /* Check for incoming ACK. */
00431   if((NETSTACK_RADIO.receiving_packet() ||
00432       NETSTACK_RADIO.pending_packet() ||
00433       NETSTACK_RADIO.channel_clear() == 0)) {
00434     int len;
00435     uint8_t ackbuf[ACK_LEN + 2];
00436     
00437     wt = RTIMER_NOW();
00438     while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
00439     
00440     len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
00441     if(len == ACK_LEN) {
00442       ack_received = 1;
00443     }
00444   }
00445   if(ack_received) {
00446     leds_toggle(LEDS_RED);
00447   }
00448   return ack_received;
00449 }
00450 /*---------------------------------------------------------------------------*/
00451 static int
00452 send_packet(void)
00453 {
00454   rtimer_clock_t t0;
00455   rtimer_clock_t t;
00456   rtimer_clock_t encounter_time = 0;
00457   int strobes;
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()) {
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           NETSTACK_RADIO.send(strobe, strobe_len);
00645 #else
00646           /* restore the packet to send */
00647           queuebuf_to_packetbuf(packet);
00648           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           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 
00666           if(detect_ack()) {
00667             got_strobe_ack = 1;
00668           } else {
00669             off();
00670           }
00671         }
00672       }
00673     }
00674   }
00675 
00676 #if WITH_ACK_OPTIMIZATION
00677   /* If we have received the strobe ACK, and we are sending a packet
00678      that will need an upper layer ACK (as signified by the
00679      PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
00680   if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00681                         packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
00682                         packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00683                         PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
00684     on(); /* Wait for ACK packet */
00685     waiting_for_packet = 1;
00686   } else {
00687     off();
00688   }
00689 #endif /* WITH_ACK_OPTIMIZATION */
00690 
00691   /* restore the packet to send */
00692   queuebuf_to_packetbuf(packet);
00693   queuebuf_free(packet);
00694 
00695   /* Send the data packet. */
00696   if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
00697     NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00698 
00699     if(!is_broadcast) {
00700       if(detect_ack()) {
00701         got_ack = 1;
00702       }
00703     }
00704   }
00705   off();
00706 
00707 #if WITH_ENCOUNTER_OPTIMIZATION
00708   if(got_strobe_ack && !is_streaming) {
00709     register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
00710   }
00711 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00712   watchdog_start();
00713 
00714   PRINTF("xmac: send (strobes=%u,len=%u,%s), done\n", strobes,
00715          packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack");
00716 
00717 #if XMAC_CONF_COMPOWER
00718   /* Accumulate the power consumption for the packet transmission. */
00719   compower_accumulate(&current_packet);
00720 
00721   /* Convert the accumulated power consumption for the transmitted
00722      packet to packet attributes so that the higher levels can keep
00723      track of the amount of energy spent on transmitting the
00724      packet. */
00725   compower_attrconv(&current_packet);
00726 
00727   /* Clear the accumulated power consumption so that it is ready for
00728      the next packet. */
00729   compower_clear(&current_packet);
00730 #endif /* XMAC_CONF_COMPOWER */
00731 
00732   we_are_sending = 0;
00733 
00734   LEDS_OFF(LEDS_BLUE);
00735   if(collisions == 0) {
00736     if(is_broadcast == 0 && got_ack == 0) {
00737       return MAC_TX_NOACK;
00738     } else {
00739       return MAC_TX_OK;
00740     }
00741   } else {
00742     someone_is_sending++;
00743     return MAC_TX_COLLISION;
00744   }
00745 
00746 }
00747 /*---------------------------------------------------------------------------*/
00748 static void
00749 qsend_packet(mac_callback_t sent, void *ptr)
00750 {
00751   int ret;
00752   
00753   if(someone_is_sending) {
00754     PRINTF("xmac: should queue packet, now just dropping %d %d %d %d.\n",
00755            waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on);
00756     RIMESTATS_ADD(sendingdrop);
00757     ret = MAC_TX_COLLISION;
00758   } else {
00759     PRINTF("xmac: send immediately.\n");
00760     ret = send_packet();
00761   }
00762 
00763   mac_call_sent_callback(sent, ptr, ret, 1);
00764 }
00765 /*---------------------------------------------------------------------------*/
00766 static void
00767 input_packet(void)
00768 {
00769   struct xmac_hdr *hdr;
00770 
00771   if(NETSTACK_FRAMER.parse()) {
00772     hdr = packetbuf_dataptr();
00773 
00774     if(hdr->dispatch != DISPATCH) {
00775       someone_is_sending = 0;
00776       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00777                                      &rimeaddr_node_addr) ||
00778          rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00779                       &rimeaddr_null)) {
00780         /* This is a regular packet that is destined to us or to the
00781            broadcast address. */
00782 
00783         /* We have received the final packet, so we can go back to being
00784            asleep. */
00785         off();
00786 
00787         /* Check for duplicate packet by comparing the sequence number
00788            of the incoming packet with the last few ones we saw. */
00789         {
00790           int i;
00791           for(i = 0; i < MAX_SEQNOS; ++i) {
00792             if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
00793                rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
00794                             &received_seqnos[i].sender)) {
00795               /* Drop the packet. */
00796               return;
00797             }
00798           }
00799           for(i = MAX_SEQNOS - 1; i > 0; --i) {
00800             memcpy(&received_seqnos[i], &received_seqnos[i - 1],
00801                    sizeof(struct seqno));
00802           }
00803           received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
00804           rimeaddr_copy(&received_seqnos[0].sender,
00805                         packetbuf_addr(PACKETBUF_ADDR_SENDER));
00806         }
00807 
00808 #if XMAC_CONF_COMPOWER
00809         /* Accumulate the power consumption for the packet reception. */
00810         compower_accumulate(&current_packet);
00811         /* Convert the accumulated power consumption for the received
00812            packet to packet attributes so that the higher levels can
00813            keep track of the amount of energy spent on receiving the
00814            packet. */
00815         compower_attrconv(&current_packet);
00816 
00817         /* Clear the accumulated power consumption so that it is ready
00818            for the next packet. */
00819         compower_clear(&current_packet);
00820 #endif /* XMAC_CONF_COMPOWER */
00821 
00822         waiting_for_packet = 0;
00823 
00824         PRINTDEBUG("xmac: data(%u)\n", packetbuf_datalen());
00825         NETSTACK_MAC.input();
00826         return;
00827       } else {
00828         PRINTDEBUG("xmac: data not for us\n");
00829       }
00830 
00831     } else if(hdr->type == TYPE_STROBE) {
00832       someone_is_sending = 2;
00833 
00834       if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00835                       &rimeaddr_node_addr)) {
00836         /* This is a strobe packet for us. */
00837 
00838         /* If the sender address is someone else, we should
00839            acknowledge the strobe and wait for the packet. By using
00840            the same address as both sender and receiver, we flag the
00841            message is a strobe ack. */
00842         waiting_for_packet = 1;
00843 #if 0
00844         hdr->type = TYPE_STROBE_ACK;
00845         packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
00846                            packetbuf_addr(PACKETBUF_ADDR_SENDER));
00847         packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00848         packetbuf_compact();
00849         if(NETSTACK_FRAMER.create()) {
00850           /* We turn on the radio in anticipation of the incoming
00851              packet. */
00852           someone_is_sending = 1;
00853           waiting_for_packet = 1;
00854           on();
00855           NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00856           PRINTDEBUG("xmac: send strobe ack %u\n", packetbuf_totlen());
00857         } else {
00858           PRINTF("xmac: failed to send strobe ack\n");
00859         }
00860 #endif /* 0 */
00861       } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00862                              &rimeaddr_null)) {
00863         /* If the receiver address is null, the strobe is sent to
00864            prepare for an incoming broadcast packet. If this is the
00865            case, we turn on the radio and wait for the incoming
00866            broadcast packet. */
00867         waiting_for_packet = 1;
00868         on();
00869       } else {
00870         PRINTDEBUG("xmac: strobe not for us\n");
00871       }
00872       
00873       /* We are done processing the strobe and we therefore return
00874          to the caller. */
00875       return;
00876 #if XMAC_CONF_ANNOUNCEMENTS
00877     } else if(hdr->type == TYPE_ANNOUNCEMENT) {
00878       packetbuf_hdrreduce(sizeof(struct xmac_hdr));
00879       parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
00880 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00881     } else if(hdr->type == TYPE_STROBE_ACK) {
00882       PRINTDEBUG("xmac: stray strobe ack\n");
00883     } else {
00884       PRINTF("xmac: unknown type %u (%u/%u)\n", hdr->type,
00885              packetbuf_datalen(), len);
00886     }
00887   } else {
00888     PRINTF("xmac: failed to parse (%u)\n", packetbuf_totlen());
00889   }
00890 }
00891 /*---------------------------------------------------------------------------*/
00892 #if XMAC_CONF_ANNOUNCEMENTS
00893 static void
00894 send_announcement(void *ptr)
00895 {
00896   struct xmac_hdr *hdr;
00897   int announcement_len;
00898 
00899   /* Set up the probe header. */
00900   packetbuf_clear();
00901   hdr = packetbuf_dataptr();
00902 
00903   announcement_len = format_announcement((char *)hdr +
00904                                          sizeof(struct xmac_hdr));
00905 
00906   if(announcement_len > 0) {
00907     packetbuf_set_datalen(sizeof(struct xmac_hdr) + announcement_len);
00908     hdr->dispatch = DISPATCH;
00909     hdr->type = TYPE_ANNOUNCEMENT;
00910 
00911     packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00912     packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
00913     packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower);
00914     if(NETSTACK_FRAMER.create()) {
00915       NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00916     }
00917   }
00918 }
00919 /*---------------------------------------------------------------------------*/
00920 static void
00921 cycle_announcement(void *ptr)
00922 {
00923   ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME,
00924              send_announcement, NULL);
00925   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD,
00926              cycle_announcement, NULL);
00927   if(is_listening > 0) {
00928     is_listening--;
00929     /*    printf("is_listening %d\n", is_listening);*/
00930   }
00931 }
00932 /*---------------------------------------------------------------------------*/
00933 static void
00934 listen_callback(int periods)
00935 {
00936   is_listening = periods + 1;
00937 }
00938 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00939 /*---------------------------------------------------------------------------*/
00940 void
00941 xmac_set_announcement_radio_txpower(int txpower)
00942 {
00943 #if XMAC_CONF_ANNOUNCEMENTS
00944   announcement_radio_txpower = txpower;
00945 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00946 }
00947 /*---------------------------------------------------------------------------*/
00948 static void
00949 init(void)
00950 {
00951   radio_is_on = 0;
00952   waiting_for_packet = 0;
00953   PT_INIT(&pt);
00954   rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
00955              (void (*)(struct rtimer *, void *))powercycle, NULL);
00956 
00957   xmac_is_on = 1;
00958 
00959 #if WITH_ENCOUNTER_OPTIMIZATION
00960   list_init(encounter_list);
00961   memb_init(&encounter_memb);
00962 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00963 
00964 #if XMAC_CONF_ANNOUNCEMENTS
00965   announcement_register_listen_callback(listen_callback);
00966   ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME,
00967              cycle_announcement, NULL);
00968 #endif /* XMAC_CONF_ANNOUNCEMENTS */
00969 }
00970 /*---------------------------------------------------------------------------*/
00971 static int
00972 turn_on(void)
00973 {
00974   xmac_is_on = 1;
00975   rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1,
00976              (void (*)(struct rtimer *, void *))powercycle, NULL);
00977   return 1;
00978 }
00979 /*---------------------------------------------------------------------------*/
00980 static int
00981 turn_off(int keep_radio_on)
00982 {
00983   xmac_is_on = 0;
00984   if(keep_radio_on) {
00985     return NETSTACK_RADIO.on();
00986   } else {
00987     return NETSTACK_RADIO.off();
00988   }
00989 }
00990 /*---------------------------------------------------------------------------*/
00991 static unsigned short
00992 channel_check_interval(void)
00993 {
00994   return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;
00995 }
00996 /*---------------------------------------------------------------------------*/
00997 const struct rdc_driver xmac_driver =
00998   {
00999     "X-MAC",
01000     init,
01001     qsend_packet,
01002     input_packet,
01003     turn_on,
01004     turn_off,
01005     channel_check_interval,
01006   };

Generated on Mon Apr 11 14:23:29 2011 for Contiki 2.5 by  doxygen 1.6.1