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

This commit is contained in:
adamdunkels 2010-02-28 20:19:47 +00:00
parent e6fceb7200
commit 410d860a93
3 changed files with 97 additions and 27 deletions

View file

@ -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);
}
/*---------------------------------------------------------------------------*/

View file

@ -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);
}
/*---------------------------------------------------------------------------*/

View file

@ -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);