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.
|
* 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 */
|
#endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
send_packet(void)
|
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 t;
|
||||||
|
@ -453,7 +453,28 @@ send_packet(void)
|
||||||
int transmit_len;
|
int transmit_len;
|
||||||
int i;
|
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);
|
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
|
||||||
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
|
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
|
||||||
is_broadcast = 1;
|
is_broadcast = 1;
|
||||||
|
@ -508,21 +529,6 @@ send_packet(void)
|
||||||
#endif /* WITH_STREAMING */
|
#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
|
/* By setting we_are_sending to one, we ensure that the rtimer
|
||||||
powercycle interrupt do not interfere with us sending the packet. */
|
powercycle interrupt do not interfere with us sending the packet. */
|
||||||
we_are_sending = 1;
|
we_are_sending = 1;
|
||||||
|
@ -704,7 +710,7 @@ send_packet(void)
|
||||||
static void
|
static void
|
||||||
qsend_packet(mac_callback_t sent, void *ptr)
|
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);
|
mac_call_sent_callback(sent, ptr, ret, 1);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -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.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/mac/phase.h"
|
||||||
#include "net/rime/packetbuf.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
|
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,
|
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 wait_before,
|
||||||
|
mac_callback_t mac_callback, void *mac_callback_ptr)
|
||||||
{
|
{
|
||||||
struct phase *e;
|
struct phase *e;
|
||||||
|
|
||||||
|
@ -85,6 +118,7 @@ phase_wait(struct phase_list *list,
|
||||||
|
|
||||||
if(rimeaddr_cmp(neighbor, &e->neighbor)) {
|
if(rimeaddr_cmp(neighbor, &e->neighbor)) {
|
||||||
rtimer_clock_t wait, now, expected;
|
rtimer_clock_t wait, now, expected;
|
||||||
|
clock_time_t ctimewait;
|
||||||
|
|
||||||
/* We expect phases to happen every CYCLE_TIME time
|
/* We expect phases to happen every CYCLE_TIME time
|
||||||
units. The next expected phase is at time e->time +
|
units. The next expected phase is at time e->time +
|
||||||
|
@ -98,6 +132,26 @@ phase_wait(struct phase_list *list,
|
||||||
if(wait < wait_before) {
|
if(wait < wait_before) {
|
||||||
wait += cycle_time;
|
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;
|
expected = now + wait - wait_before;
|
||||||
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 */
|
||||||
|
@ -107,6 +161,7 @@ phase_wait(struct phase_list *list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return PHASE_SEND_NOW;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
@ -114,5 +169,6 @@ phase_init(struct phase_list *list)
|
||||||
{
|
{
|
||||||
list_init(*list->list);
|
list_init(*list->list);
|
||||||
memb_init(list->memb);
|
memb_init(list->memb);
|
||||||
|
memb_init(&phase_memb);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*
|
*
|
||||||
* This file is part of the Contiki operating system.
|
* 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 "sys/rtimer.h"
|
||||||
#include "lib/list.h"
|
#include "lib/list.h"
|
||||||
#include "lib/memb.h"
|
#include "lib/memb.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
|
||||||
struct phase {
|
struct phase {
|
||||||
struct phase *next;
|
struct phase *next;
|
||||||
|
@ -57,13 +58,20 @@ struct phase_list {
|
||||||
struct memb *memb;
|
struct memb *memb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PHASE_SEND_NOW,
|
||||||
|
PHASE_DEFERRED,
|
||||||
|
} phase_status_t;
|
||||||
|
|
||||||
|
|
||||||
#define PHASE_LIST(name, num) LIST(phase_list_list); \
|
#define PHASE_LIST(name, num) LIST(phase_list_list); \
|
||||||
MEMB(phase_list_memb, struct phase, num); \
|
MEMB(phase_list_memb, struct phase, num); \
|
||||||
struct phase_list name = { &phase_list_list, &phase_list_memb }
|
struct phase_list name = { &phase_list_list, &phase_list_memb }
|
||||||
|
|
||||||
void phase_init(struct phase_list *list);
|
void phase_init(struct phase_list *list);
|
||||||
void phase_wait(struct phase_list *list, const rimeaddr_t *neighbor,
|
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 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,
|
void phase_register(const struct phase_list *list, const rimeaddr_t * neighbor,
|
||||||
rtimer_clock_t time);
|
rtimer_clock_t time);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue