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.

This commit is contained in:
adamdunkels 2010-12-16 22:43:07 +00:00
parent 01c28ab502
commit 79f2c25dae
2 changed files with 48 additions and 111 deletions

View file

@ -28,7 +28,7 @@
* *
* This file is part of the Contiki operating system. * 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 <string.h> #include <string.h>
#ifndef WITH_ACK_OPTIMIZATION
#define WITH_ACK_OPTIMIZATION 0
#endif
#ifndef WITH_PHASE_OPTIMIZATION #ifndef WITH_PHASE_OPTIMIZATION
#define WITH_PHASE_OPTIMIZATION 1 #define WITH_PHASE_OPTIMIZATION 1
#endif #endif
@ -72,6 +69,9 @@
#ifndef WITH_CONTIKIMAC_HEADER #ifndef WITH_CONTIKIMAC_HEADER
#define WITH_CONTIKIMAC_HEADER 1 #define WITH_CONTIKIMAC_HEADER 1
#endif #endif
#ifndef WITH_FAST_SLEEP
#define WITH_FAST_SLEEP 1
#endif
struct announcement_data { struct announcement_data {
uint16_t id; uint16_t id;
@ -111,7 +111,7 @@ struct announcement_msg {
#define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE) #define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE)
#endif #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_COUNT_MAX 2
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 #define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192
@ -168,17 +168,6 @@ static volatile unsigned char radio_is_on = 0;
#define PRINTDEBUG(...) #define PRINTDEBUG(...)
#endif #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 #if CONTIKIMAC_CONF_ANNOUNCEMENTS
/* Timers for keeping track of when to send announcements. */ /* Timers for keeping track of when to send announcements. */
static struct ctimer announcement_cycle_ctimer, announcement_ctimer; static struct ctimer announcement_cycle_ctimer, announcement_ctimer;
@ -396,44 +385,36 @@ powercycle(struct rtimer *t, void *ptr)
silence_periods = 0; silence_periods = 0;
} }
if(silence_periods > MAX_SILENCE_PERIODS) { if(silence_periods > MAX_SILENCE_PERIODS) {
LEDS_ON(LEDS_RED);
powercycle_turn_radio_off(); powercycle_turn_radio_off();
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
compower_accumulate(&compower_idle_activity); compower_accumulate(&compower_idle_activity);
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
LEDS_OFF(LEDS_RED);
break; break;
} }
#if 1 #if WITH_FAST_SLEEP
if(periods > MAX_NONACTIVITY_PERIODIC && !(NETSTACK_RADIO.receiving_packet() || if(periods > MAX_NONACTIVITY_PERIODIC &&
NETSTACK_RADIO.pending_packet())) { !NETSTACK_RADIO.receiving_packet() &&
LEDS_ON(LEDS_GREEN); !NETSTACK_RADIO.pending_packet()) {
powercycle_turn_radio_off(); powercycle_turn_radio_off();
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
compower_accumulate(&compower_idle_activity); compower_accumulate(&compower_idle_activity);
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
LEDS_OFF(LEDS_GREEN);
break; break;
} }
#endif /* 0 */ #endif /* WITH_FAST_SLEEP */
if(NETSTACK_RADIO.pending_packet()) { if(NETSTACK_RADIO.pending_packet()) {
break; break;
} }
schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME); schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
LEDS_ON(LEDS_BLUE);
PT_YIELD(&pt); PT_YIELD(&pt);
LEDS_OFF(LEDS_BLUE);
} }
if(radio_is_on && !(NETSTACK_RADIO.receiving_packet() || if(radio_is_on && !(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) { NETSTACK_RADIO.pending_packet())) {
LEDS_ON(LEDS_RED + LEDS_GREEN);
powercycle_turn_radio_off(); powercycle_turn_radio_off();
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
compower_accumulate(&compower_idle_activity); compower_accumulate(&compower_idle_activity);
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
LEDS_OFF(LEDS_RED + LEDS_GREEN);
} }
} else { } else {
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
@ -443,9 +424,6 @@ powercycle(struct rtimer *t, void *ptr)
} while(is_snooping && } while(is_snooping &&
RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME)); 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)) { if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME)) {
/* schedule_powercycle(t, CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/ /* schedule_powercycle(t, CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/
schedule_powercycle_fixed(t, CYCLE_TIME + 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));*/ cycle_start, RTIMER_NOW(), CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/
PT_YIELD(&pt); PT_YIELD(&pt);
} }
LEDS_OFF(LEDS_RED);
} }
PT_END(&pt); PT_END(&pt);
@ -555,9 +532,7 @@ static int
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
{ {
rtimer_clock_t t0; rtimer_clock_t t0;
rtimer_clock_t t; rtimer_clock_t encounter_time = 0, previous_txtime = 0;
rtimer_clock_t encounter_time = 0, last_transmission_time = 0;
uint8_t first_transmission = 1;
int strobes; int strobes;
uint8_t got_strobe_ack = 0; uint8_t got_strobe_ack = 0;
int hdrlen, len; int hdrlen, len;
@ -685,31 +660,14 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
if(!is_broadcast && !is_streaming) { if(!is_broadcast && !is_streaming) {
#if WITH_PHASE_OPTIMIZATION #if WITH_PHASE_OPTIMIZATION
if(WITH_ACK_OPTIMIZATION) { ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
/* Wait until the receiver is expected to be awake */ CYCLE_TIME, GUARD_TIME,
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != mac_callback, mac_callback_ptr);
PACKETBUF_ATTR_PACKET_TYPE_ACK) { if(ret == PHASE_DEFERRED) {
return MAC_TX_DEFERRED;
ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), }
CYCLE_TIME, GUARD_TIME, if(ret != PHASE_UNKNOWN) {
mac_callback, mac_callback_ptr); is_known_receiver = 1;
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;
}
} }
#endif /* WITH_PHASE_OPTIMIZATION */ #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_was_on = contikimac_is_on;
contikimac_is_on = 1; contikimac_is_on = 1;
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != if(is_streaming == 0) {
PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) {
/* Check if there are any transmissions by others. */ /* Check if there are any transmissions by others. */
for(i = 0; i < CCA_COUNT_MAX; ++i) { for(i = 0; i < CCA_COUNT_MAX; ++i) {
t0 = RTIMER_NOW(); t0 = RTIMER_NOW();
@ -790,7 +747,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
watchdog_periodic(); watchdog_periodic();
t0 = RTIMER_NOW(); t0 = RTIMER_NOW();
t = RTIMER_NOW();
#if NURTIMER #if NURTIMER
for(strobes = 0, collisions = 0; for(strobes = 0, collisions = 0;
got_strobe_ack == 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(); watchdog_periodic();
if(is_known_receiver && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) { 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; break;
} }
len = 0; len = 0;
t = RTIMER_NOW(); previous_txtime = RTIMER_NOW();
{ {
rtimer_clock_t wt; rtimer_clock_t wt;
rtimer_clock_t now = RTIMER_NOW(); rtimer_clock_t txtime;
int ret; int ret;
txtime = RTIMER_NOW();
ret = NETSTACK_RADIO.transmit(transmit_len); ret = NETSTACK_RADIO.transmit(transmit_len);
wt = RTIMER_NOW(); 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); len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
if(len == ACK_LEN) { if(len == ACK_LEN) {
got_strobe_ack = 1; got_strobe_ack = 1;
// encounter_time = last_transmission_time; encounter_time = previous_txtime;
encounter_time = now;
break; break;
} else { } else {
PRINTF("contikimac: collisions while sending\n"); PRINTF("contikimac: collisions while sending\n");
collisions++; collisions++;
} }
} }
last_transmission_time = now; previous_txtime = txtime;
first_transmission = 0;
} }
} }
if(WITH_ACK_OPTIMIZATION) { off();
/* 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();
}
PRINTF("contikimac: send (strobes=%u, len=%u, %s, %s), done\n", strobes, PRINTF("contikimac: send (strobes=%u, len=%u, %s, %s), done\n", strobes,
packetbuf_totlen(), packetbuf_totlen(),
@ -898,21 +843,16 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
} }
#if WITH_PHASE_OPTIMIZATION #if WITH_PHASE_OPTIMIZATION
/* if(!first_transmission)*/ {
/* COOJA_DEBUG_PRINTF("first phase 0x%02x\n", encounter_time % CYCLE_TIME);*/ if(is_known_receiver && got_strobe_ack) {
PRINTF("no miss %d wake-ups %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
strobes);
}
if(WITH_ACK_OPTIMIZATION) { if(!is_broadcast) {
if(collisions == 0 && packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != if(collisions == 0 && is_streaming == 0) {
PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, ret);
ret);
}
} else {
if(collisions == 0 && is_streaming == 0) {
phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
ret);
}
} }
} }
#endif /* WITH_PHASE_OPTIMIZATION */ #endif /* WITH_PHASE_OPTIMIZATION */

View file

@ -28,7 +28,7 @@
* *
* This file is part of the Contiki operating system. * 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 16
#define MAX_NOACKS_TIME CLOCK_SECOND * 16 #define MAX_NOACKS_TIME CLOCK_SECOND * 30
MEMB(queued_packets_memb, struct phase_queueitem, PHASE_QUEUESIZE); 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) { if(mac_status == MAC_TX_OK) {
e->time = time; e->time = time;
} }
/* If the neighbor didn't reply to us, it may have switched /* If the neighbor didn't reply to us, it may have switched
phase (rebooted). We try a number of transmissions to it phase (rebooted). We try a number of transmissions to it
before we drop it from the phase list. */ 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); timer_set(&e->noacks_timer, MAX_NOACKS_TIME);
} }
if(e->noacks >= MAX_NOACKS || timer_expired(&e->noacks_timer)) { if(e->noacks >= MAX_NOACKS || timer_expired(&e->noacks_timer)) {
printf("drop %d\n", neighbor->u8[0]);
list_remove(*list->list, e); list_remove(*list->list, e);
memb_free(list->memb, e); memb_free(list->memb, e);
return; return;
@ -159,7 +159,7 @@ send_packet(void *ptr)
phase_status_t phase_status_t
phase_wait(struct phase_list *list, phase_wait(struct phase_list *list,
const rimeaddr_t *neighbor, rtimer_clock_t cycle_time, 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) mac_callback_t mac_callback, void *mac_callback_ptr)
{ {
struct phase *e; struct phase *e;
@ -170,7 +170,7 @@ phase_wait(struct phase_list *list,
the radio just before the phase. */ the radio just before the phase. */
e = find_neighbor(list, neighbor); e = find_neighbor(list, neighbor);
if(e != NULL) { if(e != NULL) {
rtimer_clock_t wait, now, expected, additional_wait; rtimer_clock_t wait, now, expected;
clock_time_t ctimewait; clock_time_t ctimewait;
/* We expect phases to happen every CYCLE_TIME time /* We expect phases to happen every CYCLE_TIME time
@ -183,8 +183,6 @@ phase_wait(struct phase_list *list,
/* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1), /* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1),
cycle_time);*/ cycle_time);*/
additional_wait = 2 * e->noacks * wait_before;
/* if(e->noacks > 0) { /* if(e->noacks > 0) {
printf("additional wait %d\n", additional_wait); printf("additional wait %d\n", additional_wait);
}*/ }*/
@ -192,11 +190,11 @@ phase_wait(struct phase_list *list,
now = RTIMER_NOW(); now = RTIMER_NOW();
wait = (rtimer_clock_t)((e->time - now) & wait = (rtimer_clock_t)((e->time - now) &
(cycle_time - 1)); (cycle_time - 1));
if(wait < wait_before + additional_wait) { if(wait < guard_time) {
wait += cycle_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) { if(ctimewait > PHASE_DEFER_THRESHOLD) {
struct phase_queueitem *p; 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)) { if(!RTIMER_CLOCK_LT(expected, now)) {
/* Wait until the receiver is expected to be awake */ /* 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; return PHASE_SEND_NOW;
} }