From 410d860a930d9c4d726c7243fa0072c2cf7d2b87 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Sun, 28 Feb 2010 20:19:47 +0000 Subject: [PATCH] Improved handling of neighbor phase estimation: instead of busy-waiting while waiting for neighbor's phase, the new code schedules a timer just before neighbor wakes up --- core/net/mac/contikimac.c | 44 +++++++++++++++----------- core/net/mac/phase.c | 66 ++++++++++++++++++++++++++++++++++++--- core/net/mac/phase.h | 14 +++++++-- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/core/net/mac/contikimac.c b/core/net/mac/contikimac.c index 8581b8996..53b34b06b 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.6 2010/02/28 08:33:21 adamdunkels Exp $ + * $Id: contikimac.c,v 1.7 2010/02/28 20:19:47 adamdunkels Exp $ */ /** @@ -439,7 +439,7 @@ format_announcement(char *hdr) #endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */ /*---------------------------------------------------------------------------*/ static int -send_packet(void) +send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) { rtimer_clock_t t0; rtimer_clock_t t; @@ -453,7 +453,28 @@ send_packet(void) int transmit_len; int i; - /* Create the X-MAC header for the data packet. */ +#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 && is_streaming == 0) { + + if(phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), + CYCLE_TIME, 5 * CHECK_TIME, + mac_callback, mac_callback_ptr) == PHASE_DEFERRED) { + return MAC_TX_DEFERRED; + } + } +#else /* WITH_ACK_OPTIMIZATION */ + if(phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), + CYCLE_TIME, 5 * CHECK_TIME) == PHASE_DEFERRED) { + return MAC_TX_DEFERRED; + } +#endif /* WITH_ACK_OPTIMIZATION */ +#endif /* WITH_PHASE_OPTIMIZATION */ + + + /* Create the MAC header for the data packet. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { is_broadcast = 1; @@ -508,21 +529,6 @@ send_packet(void) #endif /* WITH_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 && is_streaming == 0) { - - phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - CYCLE_TIME, 5 * CHECK_TIME); - } -#else /* WITH_ACK_OPTIMIZATION */ - phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - CYCLE_TIME, 5 * CHECK_TIME); -#endif /* WITH_ACK_OPTIMIZATION */ -#endif /* WITH_PHASE_OPTIMIZATION */ - /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; @@ -704,7 +710,7 @@ send_packet(void) static void qsend_packet(mac_callback_t sent, void *ptr) { - int ret = send_packet(); + int ret = send_packet(sent, ptr); mac_call_sent_callback(sent, ptr, ret, 1); } /*---------------------------------------------------------------------------*/ diff --git a/core/net/mac/phase.c b/core/net/mac/phase.c index 8e8519379..d7489e79a 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.2 2010/02/28 14:15:16 adamdunkels Exp $ + * $Id: phase.c,v 1.3 2010/02/28 20:19:47 adamdunkels Exp $ */ /** @@ -40,6 +40,24 @@ #include "net/mac/phase.h" #include "net/rime/packetbuf.h" +#include "sys/clock.h" +#include "lib/memb.h" +#include "net/rime/ctimer.h" +#include "net/rime/queuebuf.h" +#include "dev/watchdog.h" +#include "dev/leds.h" + +struct phase_queueitem { + struct ctimer timer; + mac_callback_t mac_callback; + void *mac_callback_ptr; + struct queuebuf *q; +}; + +#define PHASE_DEFER_THRESHOLD 4 +#define PHASE_QUEUESIZE 2 + +MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE); /*---------------------------------------------------------------------------*/ void @@ -69,10 +87,25 @@ phase_register(const struct phase_list *list, } } /*---------------------------------------------------------------------------*/ -void +static void +send_packet(void *ptr) +{ + struct phase_queueitem *p = ptr; + + leds_on(LEDS_ALL); + + queuebuf_to_packetbuf(p->q); + queuebuf_free(p->q); + memb_free(&phase_memb, p); + NETSTACK_RDC.send(p->mac_callback, p->mac_callback_ptr); + leds_off(LEDS_ALL); +} +/*---------------------------------------------------------------------------*/ +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 wait_before, + mac_callback_t mac_callback, void *mac_callback_ptr) { struct phase *e; @@ -85,19 +118,40 @@ phase_wait(struct phase_list *list, if(rimeaddr_cmp(neighbor, &e->neighbor)) { rtimer_clock_t wait, now, expected; - + clock_time_t ctimewait; + /* We expect phases to happen every CYCLE_TIME time units. The next expected phase is at time e->time + CYCLE_TIME. To compute a relative offset, we subtract with clock_time(). Because we are only interested in turning on the radio within the CYCLE_TIME period, we compute the waiting time with modulo CYCLE_TIME. */ - + now = RTIMER_NOW(); wait = (rtimer_clock_t)((e->time - now) & (cycle_time - 1)); if(wait < wait_before) { wait += cycle_time; } + + ctimewait = (CLOCK_SECOND * (wait - wait_before)) / RTIMER_ARCH_SECOND; + + if(ctimewait > PHASE_DEFER_THRESHOLD) { + struct phase_queueitem *p; + + p = memb_alloc(&phase_memb); + if(p != NULL) { + p->q = queuebuf_new_from_packetbuf(); + if(p->q != NULL) { + p->mac_callback = mac_callback; + p->mac_callback_ptr = mac_callback_ptr; + ctimer_set(&p->timer, ctimewait, send_packet, p); + return PHASE_DEFERRED; + } else { + memb_free(&phase_memb, p); + } + } + } + expected = now + wait - wait_before; if(!RTIMER_CLOCK_LT(expected, now)) { /* Wait until the receiver is expected to be awake */ @@ -107,6 +161,7 @@ phase_wait(struct phase_list *list, } } } + return PHASE_SEND_NOW; } /*---------------------------------------------------------------------------*/ void @@ -114,5 +169,6 @@ phase_init(struct phase_list *list) { list_init(*list->list); memb_init(list->memb); + memb_init(&phase_memb); } /*---------------------------------------------------------------------------*/ diff --git a/core/net/mac/phase.h b/core/net/mac/phase.h index eb24b2c26..05f730f79 100644 --- a/core/net/mac/phase.h +++ b/core/net/mac/phase.h @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * $Id: phase.h,v 1.1 2010/02/18 20:58:59 adamdunkels Exp $ + * $Id: phase.h,v 1.2 2010/02/28 20:19:47 adamdunkels Exp $ */ /** @@ -45,6 +45,7 @@ #include "sys/rtimer.h" #include "lib/list.h" #include "lib/memb.h" +#include "net/netstack.h" struct phase { struct phase *next; @@ -57,13 +58,20 @@ struct phase_list { struct memb *memb; }; +typedef enum { + PHASE_SEND_NOW, + PHASE_DEFERRED, +} phase_status_t; + + #define PHASE_LIST(name, num) LIST(phase_list_list); \ MEMB(phase_list_memb, struct phase, num); \ struct phase_list name = { &phase_list_list, &phase_list_memb } void phase_init(struct phase_list *list); -void phase_wait(struct phase_list *list, const rimeaddr_t *neighbor, - rtimer_clock_t cycle_time, rtimer_clock_t wait_before); +phase_status_t phase_wait(struct phase_list *list, const rimeaddr_t *neighbor, + rtimer_clock_t cycle_time, rtimer_clock_t wait_before, + mac_callback_t mac_callback, void *mac_callback_ptr); void phase_register(const struct phase_list *list, const rimeaddr_t * neighbor, rtimer_clock_t time);