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:
parent
3a286c4f93
commit
121ca946e1
4 changed files with 170 additions and 126 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue