lpp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, 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: lpp.c,v 1.40 2010/12/02 15:55:17 dak664 Exp $
00032  */
00033 
00034 /**
00035  * \file
00036  *         Low power probing (R. Musaloiu-Elefteri, C. Liang,
00037  *         A. Terzis. Koala: Ultra-Low Power Data Retrieval in
00038  *         Wireless Sensor Networks, IPSN 2008)
00039  *
00040  * \author
00041  *         Adam Dunkels <adam@sics.se>
00042  *
00043  *
00044  * This is an implementation of the LPP (Low-Power Probing) MAC
00045  * protocol. LPP is a power-saving MAC protocol that works by sending
00046  * a probe packet each time the radio is turned on. If another node
00047  * wants to transmit a packet, it can do so after hearing the
00048  * probe. To send a packet, the sending node turns on its radio to
00049  * listen for probe packets.
00050  *
00051  */
00052 
00053 #include "dev/leds.h"
00054 #include "lib/list.h"
00055 #include "lib/memb.h"
00056 #include "lib/random.h"
00057 #include "net/rime.h"
00058 #include "net/netstack.h"
00059 #include "net/mac/mac.h"
00060 #include "net/mac/lpp.h"
00061 #include "net/packetbuf.h"
00062 #include "net/rime/announcement.h"
00063 #include "sys/compower.h"
00064 
00065 #include <stdlib.h>
00066 #include <stdio.h>
00067 #include <string.h>
00068 
00069 #define DEBUG 0
00070 #if DEBUG
00071 #include <stdio.h>
00072 #define PRINTF(...) printf(__VA_ARGS__)
00073 #else
00074 #define PRINTF(...)
00075 #endif
00076 
00077 #define WITH_ACK_OPTIMIZATION         0
00078 #define WITH_PROBE_AFTER_RECEPTION    0
00079 #define WITH_PROBE_AFTER_TRANSMISSION 0
00080 #define WITH_ENCOUNTER_OPTIMIZATION   0
00081 #define WITH_ADAPTIVE_OFF_TIME        0
00082 #define WITH_PENDING_BROADCAST        0
00083 #define WITH_STREAMING                1
00084 
00085 #define LISTEN_TIME (CLOCK_SECOND / 128)
00086 #define OFF_TIME (CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - LISTEN_TIME)
00087 
00088 #define PACKET_LIFETIME (LISTEN_TIME + OFF_TIME)
00089 #define UNICAST_TIMEOUT (1 * PACKET_LIFETIME + PACKET_LIFETIME / 2)
00090 #define PROBE_AFTER_TRANSMISSION_TIME (LISTEN_TIME * 2)
00091 
00092 #define LOWEST_OFF_TIME (CLOCK_SECOND / 8)
00093 
00094 #define ENCOUNTER_LIFETIME (16 * OFF_TIME)
00095 
00096 #ifdef QUEUEBUF_CONF_NUM
00097 #define MAX_QUEUED_PACKETS QUEUEBUF_CONF_NUM / 2
00098 #else /* QUEUEBUF_CONF_NUM */
00099 #define MAX_QUEUED_PACKETS 4
00100 #endif /* QUEUEBUF_CONF_NUM */
00101 
00102 
00103 /* If CLOCK_SECOND is less than 4, we may end up with an OFF_TIME that
00104    is 0 which will make compilation fail due to a modulo operation in
00105    the code. To ensure that OFF_TIME is greater than zero, we use the
00106    construct below. */
00107 #if OFF_TIME < 2
00108 #undef OFF_TIME
00109 #define OFF_TIME 2
00110 #endif
00111 
00112 struct announcement_data {
00113   uint16_t id;
00114   uint16_t value;
00115 };
00116 
00117 #define ANNOUNCEMENT_MSG_HEADERLEN 2
00118 struct announcement_msg {
00119   uint16_t num;
00120   struct announcement_data data[];
00121 };
00122 
00123 #define LPP_PROBE_HEADERLEN 2
00124 
00125 #define TYPE_PROBE        1
00126 #define TYPE_DATA         2
00127 struct lpp_hdr {
00128   uint16_t type;
00129   rimeaddr_t sender;
00130   rimeaddr_t receiver;
00131 };
00132 
00133 static uint8_t lpp_is_on;
00134 
00135 static struct compower_activity current_packet;
00136 
00137 static struct pt dutycycle_pt;
00138 static struct ctimer timer;
00139 
00140 static uint8_t is_listening = 0;
00141 static clock_time_t off_time_adjustment = 0;
00142 static clock_time_t off_time = OFF_TIME;
00143 
00144 struct queue_list_item {
00145   struct queue_list_item *next;
00146   struct queuebuf *packet;
00147   struct ctimer removal_timer;
00148   struct compower_activity compower;
00149   mac_callback_t sent_callback;
00150   void *sent_callback_ptr;
00151   uint8_t num_transmissions;
00152 #if WITH_PENDING_BROADCAST
00153   uint8_t broadcast_flag;
00154 #endif /* WITH_PENDING_BROADCAST */
00155 };
00156 
00157 #define BROADCAST_FLAG_NONE    0
00158 #define BROADCAST_FLAG_WAITING 1
00159 #define BROADCAST_FLAG_PENDING 2
00160 #define BROADCAST_FLAG_SEND    3
00161 
00162 LIST(pending_packets_list);
00163 LIST(queued_packets_list);
00164 MEMB(queued_packets_memb, struct queue_list_item, MAX_QUEUED_PACKETS);
00165 
00166 struct encounter {
00167   struct encounter *next;
00168   rimeaddr_t neighbor;
00169   clock_time_t time;
00170   struct ctimer remove_timer;
00171   struct ctimer turn_on_radio_timer;
00172 };
00173 
00174 #define MAX_ENCOUNTERS 4
00175 LIST(encounter_list);
00176 MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS);
00177 
00178 static uint8_t is_streaming = 0;
00179 #if WITH_STREAMING
00180 static struct ctimer stream_probe_timer, stream_off_timer;
00181 #define STREAM_PROBE_TIME CLOCK_SECOND / 128
00182 #define STREAM_OFF_TIME CLOCK_SECOND / 2
00183 #endif /* WITH_STREAMING */
00184 
00185 #ifndef MIN
00186 #define MIN(a, b) ((a) < (b)? (a) : (b))
00187 #endif /* MIN */
00188 
00189 /*---------------------------------------------------------------------------*/
00190 static void
00191 turn_radio_on(void)
00192 {
00193   NETSTACK_RADIO.on();
00194   /*  leds_on(LEDS_YELLOW);*/
00195 }
00196 /*---------------------------------------------------------------------------*/
00197 static void
00198 turn_radio_off(void)
00199 {
00200   if(lpp_is_on && is_streaming == 0) {
00201     NETSTACK_RADIO.off();
00202   }
00203   /*  leds_off(LEDS_YELLOW);*/
00204 }
00205 /*---------------------------------------------------------------------------*/
00206 static void
00207 remove_encounter(void *encounter)
00208 {
00209   struct encounter *e = encounter;
00210 
00211   ctimer_stop(&e->remove_timer);
00212   ctimer_stop(&e->turn_on_radio_timer);
00213   list_remove(encounter_list, e);
00214   memb_free(&encounter_memb, e);
00215 }
00216 /*---------------------------------------------------------------------------*/
00217 static void
00218 register_encounter(rimeaddr_t *neighbor, clock_time_t time)
00219 {
00220   struct encounter *e;
00221 
00222   /* If we have an entry for this neighbor already, we renew it. */
00223   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00224     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00225       e->time = time;
00226       ctimer_set(&e->remove_timer, ENCOUNTER_LIFETIME, remove_encounter, e);
00227       break;
00228     }
00229   }
00230   /* No matchin encounter was found, so we allocate a new one. */
00231   if(e == NULL) {
00232     e = memb_alloc(&encounter_memb);
00233     if(e == NULL) {
00234       /* We could not allocate memory for this encounter, so we just drop it. */
00235       return;
00236     }
00237     rimeaddr_copy(&e->neighbor, neighbor);
00238     e->time = time;
00239     ctimer_set(&e->remove_timer, ENCOUNTER_LIFETIME, remove_encounter, e);
00240     list_add(encounter_list, e);
00241   }
00242 }
00243 
00244 #if WITH_ENCOUNTER_OPTIMIZATION
00245 /*---------------------------------------------------------------------------*/
00246 static void
00247 turn_radio_on_callback(void *packet)
00248 {
00249   struct queue_list_item *p = packet;
00250 
00251   list_remove(pending_packets_list, p);
00252   list_add(queued_packets_list, p);
00253   turn_radio_on();
00254 
00255   /*  printf("enc\n");*/
00256 }
00257 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00258 
00259 /*---------------------------------------------------------------------------*/
00260 static void
00261 stream_off(void *dummy)
00262 {
00263   is_streaming = 0;
00264 }
00265 /*---------------------------------------------------------------------------*/
00266 /* This function goes through all encounters to see if it finds a
00267    matching neighbor. If so, we set a ctimer that will turn on the
00268    radio just before we expect the neighbor to send a probe packet. If
00269    we cannot find a matching encounter, we just turn on the radio.
00270 
00271    The outbound packet is put on either the pending_packets_list or
00272    the queued_packets_list, depending on if the packet should be sent
00273    immediately.
00274 */
00275 static void
00276 turn_radio_on_for_neighbor(rimeaddr_t *neighbor, struct queue_list_item *i)
00277 {
00278 
00279 #if WITH_STREAMING
00280   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00281      PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
00282     is_streaming = 1;
00283     turn_radio_on();
00284     list_add(queued_packets_list, i);
00285     ctimer_set(&stream_off_timer, STREAM_OFF_TIME,
00286                stream_off, NULL);
00287     return;
00288   }
00289 #endif /* WITH_STREAMING */
00290   
00291   if(rimeaddr_cmp(neighbor, &rimeaddr_null)) {
00292 #if ! WITH_PENDING_BROADCAST
00293     /* We have been asked to turn on the radio for a broadcast, so we
00294        just turn on the radio. */
00295     turn_radio_on();
00296 #endif /* ! WITH_PENDING_BROADCAST */
00297     list_add(queued_packets_list, i);
00298     return;
00299   }
00300 
00301 #if WITH_ENCOUNTER_OPTIMIZATION
00302   struct encounter *e;
00303   
00304   /* We go through the list of encounters to find if we have recorded
00305      an encounter with this particular neighbor. If so, we can compute
00306      the time for the next expected encounter and setup a ctimer to
00307      switch on the radio just before the encounter. */
00308   for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) {
00309     if(rimeaddr_cmp(neighbor, &e->neighbor)) {
00310       clock_time_t wait, now;
00311 
00312       /* We expect encounters to happen roughly every OFF_TIME time
00313          units. The next expected encounter is at time e->time +
00314          OFF_TIME. To compute a relative offset, we subtract with
00315          clock_time(). Because we are only interested in turning on
00316          the radio within the OFF_TIME period, we compute the waiting
00317          time with modulo OFF_TIME. */
00318 
00319       now = clock_time();
00320       wait = (((clock_time_t)(e->time - now)) % (OFF_TIME + LISTEN_TIME)) -
00321         2 * LISTEN_TIME;
00322 
00323       /*      printf("now %d e %d e-n %d w %d %d\n", now, e->time, e->time - now, (e->time - now) % (OFF_TIME), wait);
00324       
00325       printf("Time now %lu last encounter %lu next expected encouter %lu wait %lu/%d (%lu)\n",
00326              (1000ul * (unsigned long)now) / CLOCK_SECOND,
00327              (1000ul * (unsigned long)e->time) / CLOCK_SECOND,
00328              (1000ul * (unsigned long)(e->time + OFF_TIME)) / CLOCK_SECOND,
00329              (1000ul * (unsigned long)wait) / CLOCK_SECOND, wait,
00330              (1000ul * (unsigned long)(wait + now)) / CLOCK_SECOND);*/
00331       
00332       /*      printf("Neighbor %d.%d found encounter, waiting %d ticks\n",
00333               neighbor->u8[0], neighbor->u8[1], wait);*/
00334       
00335       ctimer_set(&e->turn_on_radio_timer, wait, turn_radio_on_callback, i);
00336       list_add(pending_packets_list, i);
00337       return;
00338     }
00339   }
00340 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
00341   
00342   /* We did not find the neighbor in the list of recent encounters, so
00343      we just turn on the radio. */
00344   /*  printf("Neighbor %d.%d not found in recent encounters\n",
00345       neighbor->u8[0], neighbor->u8[1]);*/
00346   turn_radio_on();
00347   list_add(queued_packets_list, i);
00348   return;
00349 }
00350 /*---------------------------------------------------------------------------*/
00351 static void
00352 remove_queued_packet(struct queue_list_item *i, uint8_t tx_ok)
00353 {
00354   mac_callback_t sent;
00355   void *ptr;
00356   int num_transmissions = 0;
00357   int status;
00358   
00359   PRINTF("%d.%d: removing queued packet\n",
00360          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]);
00361 
00362 
00363   queuebuf_to_packetbuf(i->packet);
00364   
00365   ctimer_stop(&i->removal_timer);
00366   queuebuf_free(i->packet);
00367   list_remove(pending_packets_list, i);
00368   list_remove(queued_packets_list, i);
00369 
00370   /* XXX potential optimization */
00371   if(list_length(queued_packets_list) == 0 && is_listening == 0) {
00372     turn_radio_off();
00373     compower_accumulate(&i->compower);
00374   }
00375 
00376   sent = i->sent_callback;
00377   ptr = i->sent_callback_ptr;
00378   num_transmissions = i->num_transmissions;
00379   memb_free(&queued_packets_memb, i);
00380   if(num_transmissions == 0 || tx_ok == 0) {
00381     status = MAC_TX_NOACK;
00382   } else {
00383     status = MAC_TX_OK;
00384   }
00385   mac_call_sent_callback(sent, ptr, status, num_transmissions);
00386 }
00387 /*---------------------------------------------------------------------------*/
00388 static void
00389 remove_queued_old_packet_callback(void *item)
00390 {
00391   remove_queued_packet(item, 0);
00392 }
00393 
00394 #if WITH_PENDING_BROADCAST
00395 /*---------------------------------------------------------------------------*/
00396 static void
00397 remove_queued_broadcast_packet_callback(void *item)
00398 {
00399   remove_queued_packet(item, 1);
00400 }
00401 /*---------------------------------------------------------------------------*/
00402 static void
00403 set_broadcast_flag(struct queue_list_item *i, uint8_t flag)
00404 {
00405   i->broadcast_flag = flag;
00406   ctimer_set(&i->removal_timer, PACKET_LIFETIME,
00407              remove_queued_broadcast_packet_callback, i);
00408 }
00409 #endif /* WITH_PENDING_BROADCAST */
00410 /*---------------------------------------------------------------------------*/
00411 static void
00412 listen_callback(int periods)
00413 {
00414   is_listening = periods;
00415   turn_radio_on();
00416 }
00417 /*---------------------------------------------------------------------------*/
00418 /**
00419  * Send a probe packet.
00420  */
00421 static void
00422 send_probe(void)
00423 {
00424   struct lpp_hdr *hdr;
00425   struct announcement_msg *adata;
00426   struct announcement *a;
00427 
00428   /* Set up the probe header. */
00429   packetbuf_clear();
00430   packetbuf_set_datalen(sizeof(struct lpp_hdr));
00431   hdr = packetbuf_dataptr();
00432   hdr->type = TYPE_PROBE;
00433   rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr);
00434   /*  rimeaddr_copy(&hdr->receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));*/
00435   rimeaddr_copy(&hdr->receiver, &rimeaddr_null);
00436 
00437   packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null);
00438   {
00439     int hdrlen = NETSTACK_FRAMER.create();
00440     if(hdrlen == 0) {
00441       /* Failed to send */
00442       return;
00443     }
00444   }
00445   
00446   /* Construct the announcements */
00447   adata = (struct announcement_msg *)((char *)hdr + sizeof(struct lpp_hdr));
00448   
00449   adata->num = 0;
00450   for(a = announcement_list(); a != NULL; a = list_item_next(a)) {
00451     adata->data[adata->num].id = a->id;
00452     adata->data[adata->num].value = a->value;
00453     adata->num++;
00454   }
00455 
00456   packetbuf_set_datalen(sizeof(struct lpp_hdr) +
00457                       ANNOUNCEMENT_MSG_HEADERLEN +
00458                       sizeof(struct announcement_data) * adata->num);
00459 
00460   /*  PRINTF("Sending probe\n");*/
00461 
00462   /*  printf("probe\n");*/
00463 
00464   if(NETSTACK_RADIO.channel_clear()) {
00465     NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00466   } else {
00467     off_time_adjustment = random_rand() % (OFF_TIME / 2);
00468   }
00469 
00470   compower_accumulate(&compower_idle_activity);
00471 }
00472 /*---------------------------------------------------------------------------*/
00473 static void
00474 send_stream_probe(void *dummy)
00475 {
00476   /* Turn on the radio for sending a probe packet and 
00477      anticipating a data packet from a neighbor. */
00478   turn_radio_on();
00479   
00480   /* Send a probe packet. */
00481   send_probe();
00482 
00483 #if WITH_STREAMING
00484   is_streaming = 1;
00485 #endif /* WITH_STREAMING */
00486 }
00487 /*---------------------------------------------------------------------------*/
00488 static int
00489 num_packets_to_send(void)
00490 {
00491 #if WITH_PENDING_BROADCAST
00492   struct queue_list_item *i;
00493   int num = 0;
00494   
00495   for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
00496     if(i->broadcast_flag == BROADCAST_FLAG_SEND ||
00497        i->broadcast_flag == BROADCAST_FLAG_NONE) {
00498       ++num;
00499     }
00500   }
00501   return num;
00502 #else /* WITH_PENDING_BROADCAST */
00503   return list_length(queued_packets_list);
00504 #endif /* WITH_PENDING_BROADCAST */
00505 }
00506 /*---------------------------------------------------------------------------*/
00507 /**
00508  * Duty cycle the radio and send probes. This function is called
00509  * repeatedly by a ctimer. The function restart_dutycycle() is used to
00510  * (re)start the duty cycling.
00511  */
00512 static int
00513 dutycycle(void *ptr)
00514 {
00515   struct ctimer *t = ptr;
00516         
00517   PT_BEGIN(&dutycycle_pt);
00518 
00519   while(1) {
00520 
00521 #if WITH_PENDING_BROADCAST
00522     {
00523         /* Before sending the probe, we mark all broadcast packets in
00524            our output queue to be pending. This means that they are
00525            ready to be sent, once we know that no neighbor is
00526            currently broadcasting. */
00527       for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) {
00528           if(p->broadcast_flag == BROADCAST_FLAG_WAITING) {
00529             PRINTF("wait -> pending\n");
00530             set_broadcast_flag(p, BROADCAST_FLAG_PENDING);
00531           }
00532         }
00533       }
00534 #endif /* WITH_PENDING_BROADCAST */
00535     
00536     /* Turn on the radio for sending a probe packet and 
00537        anticipating a data packet from a neighbor. */
00538     turn_radio_on();
00539 
00540     /* Send a probe packet. */
00541     send_probe();
00542 
00543     /* Set a timer so that we keep the radio on for LISTEN_TIME. */
00544     ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
00545     PT_YIELD(&dutycycle_pt);
00546 
00547 #if WITH_PENDING_BROADCAST
00548     {
00549       struct queue_list_item *p;
00550       /* Go through the list of packets we are waiting to send, and
00551          check if there are any pending broadcasts in the list. If
00552          there are pending broadcasts, and we did not receive any
00553          broadcast packets from a neighbor in response to our probe,
00554          we mark the broadcasts as being ready to send. */
00555       for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) {
00556         if(p->broadcast_flag == BROADCAST_FLAG_PENDING) {
00557           PRINTF("pending -> send\n");
00558           set_broadcast_flag(p, BROADCAST_FLAG_SEND);
00559           turn_radio_on();
00560         }
00561       }
00562     }
00563 #endif /* WITH_PENDING_BROADCAST */
00564 
00565     /* If we have no packets to send (indicated by the list length of
00566        queued_packets_list being zero), we should turn the radio
00567        off. Othersize, we keep the radio on. */
00568     if(num_packets_to_send() == 0) {
00569       
00570       /* If we are not listening for announcements, we turn the radio
00571          off and wait until we send the next probe. */
00572       if(is_listening == 0) {
00573         int current_off_time;
00574         if(!NETSTACK_RADIO.receiving_packet()) {
00575           turn_radio_off();
00576           compower_accumulate(&compower_idle_activity);
00577         }
00578         current_off_time = off_time - off_time_adjustment;
00579         if(current_off_time < LISTEN_TIME * 2) {
00580           current_off_time = LISTEN_TIME * 2;
00581         }
00582         off_time_adjustment = 0;
00583         ctimer_set(t, current_off_time, (void (*)(void *))dutycycle, t);
00584         PT_YIELD(&dutycycle_pt);
00585 
00586 #if WITH_ADAPTIVE_OFF_TIME
00587         off_time += LOWEST_OFF_TIME;
00588         if(off_time > OFF_TIME) {
00589           off_time = OFF_TIME;
00590         }
00591 #endif /* WITH_ADAPTIVE_OFF_TIME */
00592 
00593       } else {
00594         /* We are listening for annonucements, so we count down the
00595            listen time, and keep the radio on. */
00596         is_listening--;
00597         ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
00598         PT_YIELD(&dutycycle_pt);
00599       }
00600     } else {
00601       /* We had pending packets to send, so we do not turn the radio off. */
00602 
00603       ctimer_set(t, off_time, (void (*)(void *))dutycycle, t);
00604       PT_YIELD(&dutycycle_pt);
00605     }
00606   }
00607 
00608   PT_END(&dutycycle_pt);
00609 }
00610 /*---------------------------------------------------------------------------*/
00611 static void
00612 restart_dutycycle(clock_time_t initial_wait)
00613 {
00614   PT_INIT(&dutycycle_pt);
00615   ctimer_set(&timer, initial_wait, (void (*)(void *))dutycycle, &timer);  
00616 }
00617 /*---------------------------------------------------------------------------*/
00618 /**
00619  *
00620  * Send a packet. This function builds a complete packet with an LPP
00621  * header and queues the packet. When a probe is heard (in the
00622  * read_packet() function), and the sender of the probe matches the
00623  * receiver of the queued packet, the queued packet is sent.
00624  *
00625  * ACK packets are treated differently from other packets: if a node
00626  * sends a packet that it expects to be ACKed, the sending node keeps
00627  * its radio on for some time after sending its packet. So we do not
00628  * need to wait for a probe packet: we just transmit the ACK packet
00629  * immediately.
00630  *
00631  */
00632 static void
00633 send_packet(mac_callback_t sent, void *ptr)
00634 {
00635   struct lpp_hdr hdr;
00636   clock_time_t timeout;
00637   uint8_t is_broadcast = 0;
00638 
00639   rimeaddr_copy(&hdr.sender, &rimeaddr_node_addr);
00640   rimeaddr_copy(&hdr.receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
00641   if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
00642     is_broadcast = 1;
00643   }
00644   hdr.type = TYPE_DATA;
00645 
00646   packetbuf_hdralloc(sizeof(struct lpp_hdr));
00647   memcpy(packetbuf_hdrptr(), &hdr, sizeof(struct lpp_hdr));
00648   packetbuf_compact();
00649 
00650   packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
00651 
00652   {
00653     int hdrlen = NETSTACK_FRAMER.create();
00654     if(hdrlen == 0) {
00655       /* Failed to send */
00656       mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 0);
00657       return;
00658     }
00659   }
00660 
00661   PRINTF("%d.%d: queueing packet to %d.%d, channel %d\n",
00662          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00663          hdr.receiver.u8[0], hdr.receiver.u8[1],
00664          packetbuf_attr(PACKETBUF_ATTR_CHANNEL));
00665 #if WITH_ACK_OPTIMIZATION
00666   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) {
00667     /* Send ACKs immediately. */
00668     NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
00669     mac_call_sent_callback(sent, ptr, MAC_TX_OK, 1);
00670     return;
00671   }
00672 #endif /* WITH_ACK_OPTIMIZATION */
00673 
00674 #if WITH_ADAPTIVE_OFF_TIME
00675   off_time = LOWEST_OFF_TIME;
00676   restart_dutycycle(off_time);
00677 #endif /* WITH_ADAPTIVE_OFF_TIME */
00678 
00679   {
00680     struct queue_list_item *i;
00681     i = memb_alloc(&queued_packets_memb);
00682     if(i != NULL) {
00683       i->sent_callback = sent;
00684       i->sent_callback_ptr = ptr;
00685       i->num_transmissions = 0;
00686       i->packet = queuebuf_new_from_packetbuf();
00687       if(i->packet == NULL) {
00688         memb_free(&queued_packets_memb, i);
00689         printf("null packet\n");
00690         mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 0);
00691         return;
00692       } else {
00693         if(is_broadcast) {
00694           timeout = PACKET_LIFETIME;
00695 #if WITH_PENDING_BROADCAST
00696           /* We set the broadcast state of the packet to be
00697              waiting. This means that the packet is waiting for our
00698              next probe to be sent. Our next probe is used to check if
00699              there are any neighbors currently broadcasting a
00700              packet. If so, we will get a broadcast packet in response
00701              to our probe. If no broadcast packet is received in
00702              response to our probe, we mark the packet as ready to be
00703              sent. */
00704           set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
00705           PRINTF("-> waiting\n");
00706 #endif /* WITH_PENDING_BROADCAST */
00707         } else {
00708           timeout = UNICAST_TIMEOUT;
00709 #if WITH_PENDING_BROADCAST
00710           i->broadcast_flag = BROADCAST_FLAG_NONE;
00711 #endif /* WITH_PENDING_BROADCAST */
00712         }
00713         ctimer_set(&i->removal_timer, timeout,
00714                    remove_queued_old_packet_callback, i);
00715 
00716         /* Wait for a probe packet from a neighbor. The actual packet
00717            transmission is handled by the read_packet() function,
00718            which receives the probe from the neighbor. */
00719         turn_radio_on_for_neighbor(&hdr.receiver, i);
00720 
00721       }
00722     } else {
00723       printf("i == NULL\n");
00724       mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 0);
00725     }
00726   }
00727 }
00728 /*---------------------------------------------------------------------------*/
00729 static int
00730 detect_ack(void)
00731 {
00732 #define INTER_PACKET_INTERVAL              RTIMER_ARCH_SECOND / 5000
00733 #define ACK_LEN 3
00734 #define AFTER_ACK_DETECTECT_WAIT_TIME      RTIMER_ARCH_SECOND / 1000
00735   rtimer_clock_t wt;
00736   uint8_t ack_received = 0;
00737   
00738   wt = RTIMER_NOW();
00739   leds_on(LEDS_GREEN);
00740   while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
00741   leds_off(LEDS_GREEN);
00742   /* Check for incoming ACK. */
00743   if((NETSTACK_RADIO.receiving_packet() ||
00744       NETSTACK_RADIO.pending_packet() ||
00745       NETSTACK_RADIO.channel_clear() == 0)) {
00746     int len;
00747     uint8_t ackbuf[ACK_LEN + 2];
00748     
00749     wt = RTIMER_NOW();
00750     while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
00751     
00752     len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
00753     if(len == ACK_LEN) {
00754       ack_received = 1;
00755     }
00756   }
00757   if(ack_received) {
00758     leds_toggle(LEDS_RED);
00759   }
00760   return ack_received;
00761 }
00762 /*---------------------------------------------------------------------------*/
00763 /**
00764  * Read a packet from the underlying radio driver. If the incoming
00765  * packet is a probe packet and the sender of the probe matches the
00766  * destination address of the queued packet (if any), the queued packet
00767  * is sent.
00768  */
00769 static void
00770 input_packet(void)
00771 {
00772   struct lpp_hdr hdr;
00773   clock_time_t reception_time;
00774 
00775   reception_time = clock_time();
00776 
00777   if(!NETSTACK_FRAMER.parse()) {
00778     printf("lpp input_packet framer error\n");
00779   }
00780 
00781   memcpy(&hdr, packetbuf_dataptr(), sizeof(struct lpp_hdr));;
00782   packetbuf_hdrreduce(sizeof(struct lpp_hdr));
00783   /*    PRINTF("got packet type %d\n", hdr->type);*/
00784 
00785   if(hdr.type == TYPE_PROBE) {
00786     struct announcement_msg adata;
00787     
00788     /* Register the encounter with the sending node. We now know the
00789        neighbor's phase. */
00790     register_encounter(&hdr.sender, reception_time);
00791 
00792     /* Parse incoming announcements */
00793     memcpy(&adata, packetbuf_dataptr(),
00794            MIN(packetbuf_datalen(), sizeof(adata)));
00795 #if 0
00796     PRINTF("%d.%d: probe from %d.%d with %d announcements\n",
00797            rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00798            hdr.sender.u8[0], hdr.sender.u8[1], adata->num);
00799     
00800     if(adata.num / sizeof(struct announcement_data) > sizeof(struct announcement_msg)) {
00801       /* Sanity check. The number of announcements is too large -
00802          corrupt packet has been received. */
00803       return 0;
00804     }
00805 
00806     for(i = 0; i < adata.num; ++i) {
00807       /*          PRINTF("%d.%d: announcement %d: %d\n",
00808                   rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00809                   adata->data[i].id,
00810                   adata->data[i].value);*/
00811 
00812       announcement_heard(&hdr.sender,
00813                          adata.data[i].id,
00814                          adata.data[i].value);
00815     }
00816 #endif  /* 0 */
00817 
00818     /* Go through the list of packets to be sent to see if any of
00819        them match the sender of the probe, or if they are a
00820        broadcast packet that should be sent. */
00821     if(list_length(queued_packets_list) > 0) {
00822       struct queue_list_item *i;
00823       for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
00824         const rimeaddr_t *receiver;
00825         uint8_t sent;
00826 
00827         sent = 0;
00828  
00829         receiver = queuebuf_addr(i->packet, PACKETBUF_ADDR_RECEIVER);
00830         if(rimeaddr_cmp(receiver, &hdr.sender) ||
00831            rimeaddr_cmp(receiver, &rimeaddr_null)) {
00832           queuebuf_to_packetbuf(i->packet);
00833 
00834 #if WITH_PENDING_BROADCAST
00835           if(i->broadcast_flag == BROADCAST_FLAG_NONE ||
00836              i->broadcast_flag == BROADCAST_FLAG_SEND) {
00837             i->num_transmissions = 1;
00838             NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
00839                                 queuebuf_datalen(i->packet));
00840             sent = 1;
00841             PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
00842                    rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00843                    hdr.sender.u8[0], hdr.sender.u8[1],
00844                    receiver->u8[0], receiver->u8[1]);
00845               
00846           } else {
00847             PRINTF("%d.%d: got a probe from %d.%d, did not send packet\n",
00848                    rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00849                    hdr.sender.u8[0], hdr.sender.u8[1]);
00850           }
00851 #else /* WITH_PENDING_BROADCAST */
00852           i->num_transmissions = 1;
00853           NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
00854                                queuebuf_datalen(i->packet));
00855           PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
00856                  rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00857                  hdr.sender.u8[0], hdr.sender.u8[1],
00858                  receiver->u8[0], receiver->u8[1]);
00859 #endif /* WITH_PENDING_BROADCAST */
00860 
00861           /*          off();*/
00862 
00863           /* Attribute the energy spent on listening for the probe
00864              to this packet transmission. */
00865           compower_accumulate(&i->compower);
00866             
00867           /* If the packet was not a broadcast packet, we dequeue it
00868              now. Broadcast packets should be transmitted to all
00869              neighbors, and are dequeued by the dutycycling function
00870              instead, after the appropriate time. */
00871           if(!rimeaddr_cmp(receiver, &rimeaddr_null)) {
00872             if(detect_ack()) {
00873               remove_queued_packet(i, 1);
00874             } else {
00875               remove_queued_packet(i, 0);
00876             }
00877 
00878 #if WITH_PROBE_AFTER_TRANSMISSION
00879             /* Send a probe packet to catch any reply from the other node. */
00880             restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);
00881 #endif /* WITH_PROBE_AFTER_TRANSMISSION */
00882 
00883 #if WITH_STREAMING
00884             if(is_streaming) {
00885               ctimer_set(&stream_probe_timer, STREAM_PROBE_TIME,
00886                          send_stream_probe, NULL);
00887             }
00888 #endif /* WITH_STREAMING */
00889           }
00890 
00891           if(sent) {
00892             turn_radio_off();
00893           }
00894 
00895 #if WITH_ACK_OPTIMIZATION
00896           if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
00897              packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)) {
00898             /* We're sending a packet that needs an ACK, so we keep
00899                the radio on in anticipation of the ACK. */
00900             turn_radio_on();
00901           }
00902 #endif /* WITH_ACK_OPTIMIZATION */
00903 
00904         }
00905       }
00906     }
00907 
00908   } else if(hdr.type == TYPE_DATA) {
00909     turn_radio_off();
00910     if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
00911       if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
00912         /* Not broadcast or for us */
00913         PRINTF("%d.%d: data not for us from %d.%d\n",
00914                rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00915                hdr.sender.u8[0], hdr.sender.u8[1]);
00916         return;
00917       }
00918       packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &hdr.receiver);
00919     }
00920     packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &hdr.sender);
00921 
00922     PRINTF("%d.%d: got data from %d.%d\n",
00923            rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00924            hdr.sender.u8[0], hdr.sender.u8[1]);
00925 
00926     /* Accumulate the power consumption for the packet reception. */
00927     compower_accumulate(&current_packet);
00928     /* Convert the accumulated power consumption for the received
00929        packet to packet attributes so that the higher levels can
00930        keep track of the amount of energy spent on receiving the
00931        packet. */
00932     compower_attrconv(&current_packet);
00933       
00934     /* Clear the accumulated power consumption so that it is ready
00935        for the next packet. */
00936     compower_clear(&current_packet);
00937 
00938 #if WITH_PENDING_BROADCAST
00939     if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
00940       /* This is a broadcast packet. Check the list of pending
00941          packets to see if we are currently sending a broadcast. If
00942          so, we refrain from sending our broadcast until one sleep
00943          cycle period, so that the other broadcaster will have
00944          finished sending. */
00945         
00946       struct queue_list_item *i;
00947       for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) {
00948         /* If the packet is a broadcast packet that is not yet
00949            ready to be sent, we do not send it. */
00950         if(i->broadcast_flag == BROADCAST_FLAG_PENDING) {
00951           PRINTF("Someone else is sending, pending -> waiting\n");
00952           set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
00953         }
00954       }
00955     }
00956 #endif /* WITH_PENDING_BROADCAST */
00957 
00958 
00959 #if WITH_PROBE_AFTER_RECEPTION
00960     /* XXX send probe after receiving a packet to facilitate data
00961        streaming. We must first copy the contents of the packetbuf into
00962        a queuebuf to avoid overwriting the data with the probe packet. */
00963     if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) {
00964       struct queuebuf *q;
00965       q = queuebuf_new_from_packetbuf();
00966       if(q != NULL) {
00967         send_probe();
00968         queuebuf_to_packetbuf(q);
00969         queuebuf_free(q);
00970       }
00971     }
00972 #endif /* WITH_PROBE_AFTER_RECEPTION */
00973 
00974 #if WITH_ADAPTIVE_OFF_TIME
00975     off_time = LOWEST_OFF_TIME;
00976     restart_dutycycle(off_time);
00977 #endif /* WITH_ADAPTIVE_OFF_TIME */
00978 
00979     NETSTACK_MAC.input();
00980   }
00981 }
00982 /*---------------------------------------------------------------------------*/
00983 static int
00984 on(void)
00985 {
00986   lpp_is_on = 1;
00987   turn_radio_on();
00988   return 1;
00989 }
00990 /*---------------------------------------------------------------------------*/
00991 static int
00992 off(int keep_radio_on)
00993 {
00994   lpp_is_on = 0;
00995   if(keep_radio_on) {
00996     turn_radio_on();
00997   } else {
00998     turn_radio_off();
00999   }
01000   return 1;
01001 }
01002 /*---------------------------------------------------------------------------*/
01003 static unsigned short
01004 channel_check_interval(void)
01005 {
01006   return OFF_TIME + LISTEN_TIME;
01007 }
01008 /*---------------------------------------------------------------------------*/
01009 static void
01010 init(void)
01011 {
01012   restart_dutycycle(random_rand() % OFF_TIME);
01013 
01014   lpp_is_on = 1;
01015   
01016   announcement_register_listen_callback(listen_callback);
01017 
01018   memb_init(&queued_packets_memb);
01019   list_init(queued_packets_list);
01020   list_init(pending_packets_list);
01021 }
01022 /*---------------------------------------------------------------------------*/
01023 const struct rdc_driver lpp_driver = {
01024   "LPP",
01025   init,
01026   send_packet,
01027   input_packet,
01028   on,
01029   off,
01030   channel_check_interval,
01031 };
01032 /*---------------------------------------------------------------------------*/

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