Contiki 2.6
|
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(¤t_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(¤t_packet); 00665 00666 /* Clear the accumulated power consumption so that it is ready for 00667 the next packet. */ 00668 compower_clear(¤t_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(¤t_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(¤t_packet); 00742 00743 /* Clear the accumulated power consumption so that it is ready 00744 for the next packet. */ 00745 compower_clear(¤t_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 };