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