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:
parent
e6fceb7200
commit
410d860a93
3 changed files with 97 additions and 27 deletions
|
@ -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);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue