Improved phase lock behaviour when neighbor is not duty cycling: senders notify receivers via the 802.15.4 pending bit that they are not duty cycling. Neighbors then will start sending packets immediately and not wait for neighbors' phase. Tweaking of ContikiMAC timers to make it more reliable.

This commit is contained in:
adamdunkels 2010-04-03 13:28:30 +00:00
parent 3a286c4f93
commit 121ca946e1
4 changed files with 170 additions and 126 deletions

View file

@ -28,7 +28,7 @@
*
* This file is part of the Contiki operating system.
*
* $Id: contikimac.c,v 1.23 2010/04/01 17:17:36 joxe Exp $
* $Id: contikimac.c,v 1.24 2010/04/03 13:28:30 adamdunkels Exp $
*/
/**
@ -102,24 +102,25 @@ struct announcement_msg {
#define MAX_PHASE_STROBE_TIME RTIMER_ARCH_SECOND / 20
#define CCA_COUNT_MAX 2
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192
#define CCA_SLEEP_TIME RTIMER_ARCH_SECOND / 2000 //+ CCA_CHECK_TIME
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 //- RTIMER_ARCH_SECOND / 5000
#define CCA_SLEEP_TIME RTIMER_ARCH_SECOND / 2000 //- RTIMER_ARCH_SECOND / 5000 //+ CCA_CHECK_TIME
#define CHECK_TIME (CCA_COUNT_MAX * (CCA_CHECK_TIME + CCA_SLEEP_TIME))
#define STROBE_TIME (CYCLE_TIME + 2 * CHECK_TIME)
#define STREAM_CCA_COUNT (CYCLE_TIME / (CCA_SLEEP_TIME + CCA_CHECK_TIME) - CCA_COUNT_MAX)
#define GUARD_TIME 7 * CHECK_TIME
#define GUARD_TIME 9 * CHECK_TIME
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1500
#define LISTEN_TIME_AFTER_PACKET_DETECTED RTIMER_ARCH_SECOND / 100
#define SHORTEST_PACKET_SIZE 23
#define SHORTEST_PACKET_SIZE 43
#define MAX_SILENCE_PERIODS 5
#define MAX_NONACTIVITY_PERIODIC 30
/* The cycle time for announcements. */
#ifdef ANNOUNCEMENT_CONF_PERIOD
@ -185,7 +186,7 @@ static volatile uint8_t is_streaming;
static rimeaddr_t is_streaming_to, is_streaming_to_too;
static volatile rtimer_clock_t stream_until;
#define DEFAULT_STREAM_TIME (4 * CYCLE_TIME)
#define DEFAULT_STREAM_TIME (1 * CYCLE_TIME)
#ifndef MIN
#define MIN(a, b) ((a) < (b)? (a) : (b))
@ -205,7 +206,7 @@ on(void)
static void
off(void)
{
if(contikimac_is_on && radio_is_on != 0 && is_streaming == 0) {
if(contikimac_is_on && radio_is_on != 0 && is_streaming == 0 && is_snooping == 0) {
radio_is_on = 0;
NETSTACK_RADIO.off();
}
@ -225,8 +226,11 @@ schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
}
while(RTIMER_TIME(t) + time == RTIMER_NOW() ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 1) {
++time;
RTIMER_TIME(t) + time == RTIMER_NOW() + 1 ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 2 ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 3 ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 4) {
time++;
}
#if NURTIMER
@ -347,8 +351,9 @@ powercycle(struct rtimer *t, void *ptr)
leds_off(LEDS_RED);
break;
}
if(periods > 10 && !(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) {
#if 1
if(periods > MAX_NONACTIVITY_PERIODIC && !(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) {
leds_on(LEDS_GREEN);
powercycle_turn_radio_off();
#if CONTIKIMAC_CONF_COMPOWER
@ -358,6 +363,7 @@ powercycle(struct rtimer *t, void *ptr)
leds_off(LEDS_GREEN);
break;
}
#endif /* 0 */
if(NETSTACK_RADIO.pending_packet()) {
break;
}
@ -381,15 +387,19 @@ powercycle(struct rtimer *t, void *ptr)
compower_accumulate(&compower_idle_activity);
#endif /* CONTIKIMAC_CONF_COMPOWER */
}
} while((is_snooping) &&
RTIMER_NOW() - cycle_start < CYCLE_TIME - CCA_CHECK_TIME * CCA_COUNT_MAX);
if(RTIMER_NOW() - cycle_start < CYCLE_TIME) {
} while(0 && (is_snooping) &&
RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - 8 * CHECK_TIME * CCA_COUNT_MAX));
if(is_snooping) {
leds_on(LEDS_RED);
}
if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - 4)) {
schedule_powercycle(t, CYCLE_TIME - (RTIMER_NOW() - cycle_start) + 1);
/* printf("cycle_start 0x%02x now 0x%02x wait 0x%02x\n",
cycle_start, RTIMER_NOW(), CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/
PT_YIELD(&pt);
}
leds_off(LEDS_RED);
}
PT_END(&pt);
@ -446,11 +456,13 @@ format_announcement(char *hdr)
adata.announcement_magic[1] = ANNOUNCEMENT_MAGIC2;
adata.num = 0;
for(a = announcement_list();
a != NULL && a->has_value && adata.num < ANNOUNCEMENT_MAX;
a != NULL && adata.num < ANNOUNCEMENT_MAX;
a = a->next) {
adata.data[adata.num].id = a->id;
adata.data[adata.num].value = a->value;
adata.num++;
if(a->has_value) {
adata.data[adata.num].id = a->id;
adata.data[adata.num].value = a->value;
adata.num++;
}
}
memcpy(hdr, &adata, sizeof(struct announcement_msg));
@ -528,6 +540,9 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
}
}
if(is_streaming || !contikimac_is_on) {
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
}
/* Create the MAC header for the data packet. */
hdrlen = NETSTACK_FRAMER.create();
if(hdrlen == 0) {
@ -664,9 +679,9 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
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)) {
break;
}
}*/
len = 0;
@ -677,9 +692,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
rtimer_clock_t wt;
rtimer_clock_t now = RTIMER_NOW();
leds_on(LEDS_RED);
NETSTACK_RADIO.transmit(transmit_len);
leds_off(LEDS_RED);
wt = RTIMER_NOW();
#if NURTIMER
@ -825,7 +838,15 @@ input_packet(void)
}
}
#endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */
#if WITH_PHASE_OPTIMIZATION
/* If the sender has set its pending flag, it has its radio
turned on and we should drop the phase estimation that we
have from before. */
if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) {
phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER));
}
#endif /* WITH_PHASE_OPTIMIZATION */
#if CONTIKIMAC_CONF_COMPOWER
/* Accumulate the power consumption for the packet reception. */
@ -903,6 +924,7 @@ send_announcement(void *ptr)
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + CCA_SLEEP_TIME + CCA_CHECK_TIME)) { }
#endif
}
if(collisions == 0) {
NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());

View file

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: framer-802154.c,v 1.7 2010/03/16 18:11:58 adamdunkels Exp $
* $Id: framer-802154.c,v 1.8 2010/04/03 13:28:30 adamdunkels Exp $
*/
/**
@ -89,7 +89,7 @@ create(void)
/* Build the FCF. */
params.fcf.frame_type = FRAME802154_DATAFRAME;
params.fcf.security_enabled = 0;
params.fcf.frame_pending = 0;
params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING);
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
params.fcf.ack_required = 0;
} else {
@ -184,8 +184,9 @@ parse(void)
}
}
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (rimeaddr_t *)&frame.src_addr);
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
/* packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, frame.fcf.ack_required);*/
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
/* packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);*/
PRINTF("15.4-IN: %2X", frame.fcf.frame_type);
PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));

View file

@ -28,7 +28,7 @@
*
* This file is part of the Contiki operating system.
*
* $Id: phase.c,v 1.7 2010/03/31 20:27:15 adamdunkels Exp $
* $Id: phase.c,v 1.8 2010/04/03 13:28:30 adamdunkels Exp $
*/
/**
@ -54,10 +54,10 @@ struct phase_queueitem {
struct queuebuf *q;
};
#define PHASE_DEFER_THRESHOLD 2
#define PHASE_DEFER_THRESHOLD 1
#define PHASE_QUEUESIZE 8
#define MAX_NOACKS 3
#define MAX_NOACKS 2
MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE);
@ -71,6 +71,30 @@ MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE);
#define PRINTDEBUG(...)
#endif
/*---------------------------------------------------------------------------*/
struct phase *
find_neighbor(const struct phase_list *list, const rimeaddr_t *addr)
{
struct phase *e;
for(e = list_head(*list->list); e != NULL; e = e->next) {
if(rimeaddr_cmp(addr, &e->neighbor)) {
return e;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void
phase_remove(const struct phase_list *list, const rimeaddr_t *neighbor)
{
struct phase *e;
e = find_neighbor(list, neighbor);
if(e != NULL) {
list_remove(*list->list, e);
memb_free(&phase_memb, e);
}
}
/*---------------------------------------------------------------------------*/
void
phase_update(const struct phase_list *list,
const rimeaddr_t *neighbor, rtimer_clock_t time,
@ -79,46 +103,45 @@ phase_update(const struct phase_list *list,
struct phase *e;
/* If we have an entry for this neighbor already, we renew it. */
for(e = list_head(*list->list); e != NULL; e = e->next) {
if(rimeaddr_cmp(neighbor, &e->neighbor)) {
if(mac_status == MAC_TX_OK) {
e->time = time;
e = find_neighbor(list, neighbor);
if(e != NULL) {
if(mac_status == MAC_TX_OK) {
e->time = time;
}
/* If the neighbor didn't reply to us, it may have switched
phase (rebooted). We try a number of transmissions to it
before we drop it from the phase list. */
if(mac_status == MAC_TX_NOACK) {
PRINTF("phase noacks %d to %d.%d\n", e->noacks, neighbor->u8[0], neighbor->u8[1]);
e->noacks++;
if(e->noacks >= MAX_NOACKS) {
list_remove(*list->list, e);
memb_free(&phase_memb, e);
return;
}
/* If the neighbor didn't reply to us, it may have switched
phase (rebooted). We try a number of transmissions to it
before we drop it from the phase list. */
if(mac_status == MAC_TX_NOACK) {
PRINTF("phase noacks %d to %d.%d\n", e->noacks, neighbor->u8[0], neighbor->u8[1]);
e->noacks++;
if(e->noacks >= MAX_NOACKS) {
list_remove(*list->list, e);
memb_free(&phase_memb, e);
return;
}
} else if(mac_status == MAC_TX_OK) {
e->noacks = 0;
}
/* Make sure this entry is first on the list so subsequent
} else if(mac_status == MAC_TX_OK) {
e->noacks = 0;
}
/* Make sure this entry is first on the list so subsequent
searches are faster. */
list_remove(*list->list, e);
list_push(*list->list, e);
break;
}
}
/* No matching phase was found, so we allocate a new one. */
if(mac_status == MAC_TX_OK && e == NULL) {
e = memb_alloc(list->memb);
if(e == NULL) {
/* We could not allocate memory for this phase, so we drop
the last item on the list and reuse it for our phase. */
e = list_chop(*list->list);
}
rimeaddr_copy(&e->neighbor, neighbor);
e->time = time;
e->noacks = 0;
list_remove(*list->list, e);
list_push(*list->list, e);
} else {
/* No matching phase was found, so we allocate a new one. */
if(mac_status == MAC_TX_OK && e == NULL) {
e = memb_alloc(list->memb);
if(e == NULL) {
/* We could not allocate memory for this phase, so we drop
the last item on the list and reuse it for our phase. */
e = list_chop(*list->list);
}
rimeaddr_copy(&e->neighbor, neighbor);
e->time = time;
e->noacks = 0;
list_push(*list->list, e);
}
}
}
/*---------------------------------------------------------------------------*/
@ -140,68 +163,65 @@ phase_wait(struct phase_list *list,
mac_callback_t mac_callback, void *mac_callback_ptr)
{
struct phase *e;
// const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
/* We go through the list of phases to find if we have recorded a
phase for this particular neighbor. If so, we can compute the
time for the next expected phase and setup a ctimer to switch on
the radio just before the phase. */
for(e = list_head(*list->list); e != NULL; e = e->next) {
const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(rimeaddr_cmp(neighbor, &e->neighbor)) {
rtimer_clock_t wait, now, expected, additional_wait;
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. */
/* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1),
cycle_time);*/
additional_wait = 2 * e->noacks * wait_before;
/* if(e->noacks > 0) {
printf("additional wait %d\n", additional_wait);
}*/
now = RTIMER_NOW();
wait = (rtimer_clock_t)((e->time - now) &
(cycle_time - 1));
if(wait < wait_before + additional_wait) {
wait += cycle_time;
}
ctimewait = (CLOCK_SECOND * (wait - wait_before - additional_wait)) / 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 - additional_wait;
if(!RTIMER_CLOCK_LT(expected, now)) {
/* Wait until the receiver is expected to be awake */
while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)) {
}
}
return PHASE_SEND_NOW;
e = find_neighbor(list, neighbor);
if(e != NULL) {
rtimer_clock_t wait, now, expected, additional_wait;
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. */
/* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1),
cycle_time);*/
additional_wait = 2 * e->noacks * wait_before;
/* if(e->noacks > 0) {
printf("additional wait %d\n", additional_wait);
}*/
now = RTIMER_NOW();
wait = (rtimer_clock_t)((e->time - now) &
(cycle_time - 1));
if(wait < wait_before + additional_wait) {
wait += cycle_time;
}
ctimewait = (CLOCK_SECOND * (wait - wait_before - additional_wait)) / 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 - additional_wait;
if(!RTIMER_CLOCK_LT(expected, now)) {
/* Wait until the receiver is expected to be awake */
while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)) {
}
}
return PHASE_SEND_NOW;
}
return PHASE_UNKNOWN;
}

View file

@ -28,7 +28,7 @@
*
* This file is part of the Contiki operating system.
*
* $Id: phase.h,v 1.3 2010/03/14 22:59:23 adamdunkels Exp $
* $Id: phase.h,v 1.4 2010/04/03 13:28:30 adamdunkels Exp $
*/
/**
@ -74,8 +74,9 @@ void phase_init(struct phase_list *list);
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_update(const struct phase_list *list, const rimeaddr_t * neighbor,
void phase_update(const struct phase_list *list, const rimeaddr_t *neighbor,
rtimer_clock_t time, int mac_status);
void phase_remove(const struct phase_list *list, const rimeaddr_t *neighbor);
#endif /* PHASE_H */