From 79f2c25dae11b966a7fdcc3a03ec8b579274ce46 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Thu, 16 Dec 2010 22:43:07 +0000 Subject: [PATCH] Rework of the phase-lock optimization mechanism. There were several bugs in the existing code, such as the phase-lock would lose synchronization when a packet was lost. --- core/net/mac/contikimac.c | 136 +++++++++++--------------------------- core/net/mac/phase.c | 23 +++---- 2 files changed, 48 insertions(+), 111 deletions(-) diff --git a/core/net/mac/contikimac.c b/core/net/mac/contikimac.c index d9cbf25f5..37572ffe0 100644 --- a/core/net/mac/contikimac.c +++ b/core/net/mac/contikimac.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * $Id: contikimac.c,v 1.44 2010/12/10 13:36:06 adamdunkels Exp $ + * $Id: contikimac.c,v 1.45 2010/12/16 22:43:07 adamdunkels Exp $ */ /** @@ -60,9 +60,6 @@ #include -#ifndef WITH_ACK_OPTIMIZATION -#define WITH_ACK_OPTIMIZATION 0 -#endif #ifndef WITH_PHASE_OPTIMIZATION #define WITH_PHASE_OPTIMIZATION 1 #endif @@ -72,6 +69,9 @@ #ifndef WITH_CONTIKIMAC_HEADER #define WITH_CONTIKIMAC_HEADER 1 #endif +#ifndef WITH_FAST_SLEEP +#define WITH_FAST_SLEEP 1 +#endif struct announcement_data { uint16_t id; @@ -111,7 +111,7 @@ struct announcement_msg { #define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE) #endif -#define MAX_PHASE_STROBE_TIME RTIMER_ARCH_SECOND / 20 +#define MAX_PHASE_STROBE_TIME RTIMER_ARCH_SECOND / 60 #define CCA_COUNT_MAX 2 #define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 @@ -168,17 +168,6 @@ static volatile unsigned char radio_is_on = 0; #define PRINTDEBUG(...) #endif -#define DEBUG_LEDS DEBUG -#undef LEDS_ON -#undef LEDS_OFF -#if DEBUG_LEDS -#define LEDS_ON(x) leds_on(x) -#define LEDS_OFF(x) leds_off(x) -#else -#define LEDS_ON(x) -#define LEDS_OFF(x) -#endif - #if CONTIKIMAC_CONF_ANNOUNCEMENTS /* Timers for keeping track of when to send announcements. */ static struct ctimer announcement_cycle_ctimer, announcement_ctimer; @@ -316,7 +305,7 @@ powercycle(struct rtimer *t, void *ptr) PT_BEGIN(&pt); cycle_start = RTIMER_NOW(); - + while(1) { static uint8_t packet_seen; static rtimer_clock_t t0; @@ -396,44 +385,36 @@ powercycle(struct rtimer *t, void *ptr) silence_periods = 0; } if(silence_periods > MAX_SILENCE_PERIODS) { - LEDS_ON(LEDS_RED); powercycle_turn_radio_off(); #if CONTIKIMAC_CONF_COMPOWER compower_accumulate(&compower_idle_activity); #endif /* CONTIKIMAC_CONF_COMPOWER */ - LEDS_OFF(LEDS_RED); break; } -#if 1 - if(periods > MAX_NONACTIVITY_PERIODIC && !(NETSTACK_RADIO.receiving_packet() || - NETSTACK_RADIO.pending_packet())) { - LEDS_ON(LEDS_GREEN); +#if WITH_FAST_SLEEP + if(periods > MAX_NONACTIVITY_PERIODIC && + !NETSTACK_RADIO.receiving_packet() && + !NETSTACK_RADIO.pending_packet()) { powercycle_turn_radio_off(); #if CONTIKIMAC_CONF_COMPOWER compower_accumulate(&compower_idle_activity); #endif /* CONTIKIMAC_CONF_COMPOWER */ - - LEDS_OFF(LEDS_GREEN); break; } -#endif /* 0 */ +#endif /* WITH_FAST_SLEEP */ if(NETSTACK_RADIO.pending_packet()) { break; } schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME); - LEDS_ON(LEDS_BLUE); PT_YIELD(&pt); - LEDS_OFF(LEDS_BLUE); } if(radio_is_on && !(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet())) { - LEDS_ON(LEDS_RED + LEDS_GREEN); powercycle_turn_radio_off(); #if CONTIKIMAC_CONF_COMPOWER compower_accumulate(&compower_idle_activity); #endif /* CONTIKIMAC_CONF_COMPOWER */ - LEDS_OFF(LEDS_RED + LEDS_GREEN); } } else { #if CONTIKIMAC_CONF_COMPOWER @@ -443,9 +424,6 @@ powercycle(struct rtimer *t, void *ptr) } while(is_snooping && RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME)); - if(is_snooping) { - LEDS_ON(LEDS_RED); - } if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME)) { /* schedule_powercycle(t, CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/ schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start); @@ -453,7 +431,6 @@ powercycle(struct rtimer *t, void *ptr) cycle_start, RTIMER_NOW(), CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/ PT_YIELD(&pt); } - LEDS_OFF(LEDS_RED); } PT_END(&pt); @@ -555,9 +532,7 @@ static int send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) { rtimer_clock_t t0; - rtimer_clock_t t; - rtimer_clock_t encounter_time = 0, last_transmission_time = 0; - uint8_t first_transmission = 1; + rtimer_clock_t encounter_time = 0, previous_txtime = 0; int strobes; uint8_t got_strobe_ack = 0; int hdrlen, len; @@ -685,31 +660,14 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) if(!is_broadcast && !is_streaming) { #if WITH_PHASE_OPTIMIZATION - if(WITH_ACK_OPTIMIZATION) { - /* Wait until the receiver is expected to be awake */ - if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != - PACKETBUF_ATTR_PACKET_TYPE_ACK) { - - ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - CYCLE_TIME, GUARD_TIME, - mac_callback, mac_callback_ptr); - if(ret == PHASE_DEFERRED) { - return MAC_TX_DEFERRED; - } - if(ret != PHASE_UNKNOWN) { - is_known_receiver = 1; - } - } - } else { - ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - CYCLE_TIME, GUARD_TIME, - mac_callback, mac_callback_ptr); - if(ret == PHASE_DEFERRED) { - return MAC_TX_DEFERRED; - } - if(ret != PHASE_UNKNOWN) { - is_known_receiver = 1; - } + ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), + CYCLE_TIME, GUARD_TIME, + mac_callback, mac_callback_ptr); + if(ret == PHASE_DEFERRED) { + return MAC_TX_DEFERRED; + } + if(ret != PHASE_UNKNOWN) { + is_known_receiver = 1; } #endif /* WITH_PHASE_OPTIMIZATION */ } @@ -750,8 +708,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) contikimac_was_on = contikimac_is_on; contikimac_is_on = 1; - if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != - PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { + if(is_streaming == 0) { /* Check if there are any transmissions by others. */ for(i = 0; i < CCA_COUNT_MAX; ++i) { t0 = RTIMER_NOW(); @@ -790,7 +747,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) watchdog_periodic(); t0 = RTIMER_NOW(); - t = RTIMER_NOW(); + #if NURTIMER for(strobes = 0, collisions = 0; got_strobe_ack == 0 && collisions == 0 && @@ -804,18 +761,19 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) watchdog_periodic(); if(is_known_receiver && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) { + PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]); break; } len = 0; - t = RTIMER_NOW(); - + previous_txtime = RTIMER_NOW(); { rtimer_clock_t wt; - rtimer_clock_t now = RTIMER_NOW(); + rtimer_clock_t txtime; int ret; + txtime = RTIMER_NOW(); ret = NETSTACK_RADIO.transmit(transmit_len); wt = RTIMER_NOW(); @@ -837,31 +795,18 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN) { got_strobe_ack = 1; - // encounter_time = last_transmission_time; - encounter_time = now; + encounter_time = previous_txtime; break; } else { PRINTF("contikimac: collisions while sending\n"); collisions++; } } - last_transmission_time = now; - first_transmission = 0; + previous_txtime = txtime; } } - if(WITH_ACK_OPTIMIZATION) { - /* If we have received the strobe ACK, and we are sending a packet - that will need an upper layer ACK (as signified by the - PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */ - if(got_strobe_ack && is_reliable) { - on(); /* Wait for ACK packet */ - } else { - off(); - } - } else { - off(); - } + off(); PRINTF("contikimac: send (strobes=%u, len=%u, %s, %s), done\n", strobes, packetbuf_totlen(), @@ -898,21 +843,16 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) } #if WITH_PHASE_OPTIMIZATION - /* if(!first_transmission)*/ { - /* COOJA_DEBUG_PRINTF("first phase 0x%02x\n", encounter_time % CYCLE_TIME);*/ - - if(WITH_ACK_OPTIMIZATION) { - if(collisions == 0 && packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != - PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { - phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, - ret); - } - } else { - if(collisions == 0 && is_streaming == 0) { - phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, - ret); - } + if(is_known_receiver && got_strobe_ack) { + PRINTF("no miss %d wake-ups %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], + strobes); + } + + if(!is_broadcast) { + if(collisions == 0 && is_streaming == 0) { + phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, + ret); } } #endif /* WITH_PHASE_OPTIMIZATION */ diff --git a/core/net/mac/phase.c b/core/net/mac/phase.c index 0cedd8cd2..735e61f45 100644 --- a/core/net/mac/phase.c +++ b/core/net/mac/phase.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * $Id: phase.c,v 1.15 2010/09/13 13:39:05 adamdunkels Exp $ + * $Id: phase.c,v 1.16 2010/12/16 22:43:07 adamdunkels Exp $ */ /** @@ -59,7 +59,7 @@ struct phase_queueitem { #define MAX_NOACKS 16 -#define MAX_NOACKS_TIME CLOCK_SECOND * 16 +#define MAX_NOACKS_TIME CLOCK_SECOND * 30 MEMB(queued_packets_memb, struct phase_queueitem, PHASE_QUEUESIZE); @@ -109,7 +109,6 @@ phase_update(const struct phase_list *list, if(mac_status == MAC_TX_OK) { e->time = time; } - /* If the neighbor didn't reply to us, it may have switched phase (rebooted). We try a number of transmissions to it before we drop it from the phase list. */ @@ -120,6 +119,7 @@ phase_update(const struct phase_list *list, timer_set(&e->noacks_timer, MAX_NOACKS_TIME); } if(e->noacks >= MAX_NOACKS || timer_expired(&e->noacks_timer)) { + printf("drop %d\n", neighbor->u8[0]); list_remove(*list->list, e); memb_free(list->memb, e); return; @@ -159,7 +159,7 @@ send_packet(void *ptr) phase_status_t phase_wait(struct phase_list *list, const rimeaddr_t *neighbor, rtimer_clock_t cycle_time, - rtimer_clock_t wait_before, + rtimer_clock_t guard_time, mac_callback_t mac_callback, void *mac_callback_ptr) { struct phase *e; @@ -170,7 +170,7 @@ phase_wait(struct phase_list *list, the radio just before the phase. */ e = find_neighbor(list, neighbor); if(e != NULL) { - rtimer_clock_t wait, now, expected, additional_wait; + rtimer_clock_t wait, now, expected; clock_time_t ctimewait; /* We expect phases to happen every CYCLE_TIME time @@ -182,9 +182,7 @@ phase_wait(struct phase_list *list, /* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1), cycle_time);*/ - - additional_wait = 2 * e->noacks * wait_before; - + /* if(e->noacks > 0) { printf("additional wait %d\n", additional_wait); }*/ @@ -192,11 +190,11 @@ phase_wait(struct phase_list *list, now = RTIMER_NOW(); wait = (rtimer_clock_t)((e->time - now) & (cycle_time - 1)); - if(wait < wait_before + additional_wait) { + if(wait < guard_time) { wait += cycle_time; } - ctimewait = (CLOCK_SECOND * (wait - wait_before - additional_wait)) / RTIMER_ARCH_SECOND; + ctimewait = (CLOCK_SECOND * (wait - guard_time)) / RTIMER_ARCH_SECOND; if(ctimewait > PHASE_DEFER_THRESHOLD) { struct phase_queueitem *p; @@ -215,11 +213,10 @@ phase_wait(struct phase_list *list, } } - expected = now + wait - wait_before - additional_wait; + expected = now + wait - guard_time; if(!RTIMER_CLOCK_LT(expected, now)) { /* Wait until the receiver is expected to be awake */ - while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)) { - } + while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); } return PHASE_SEND_NOW; }