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. * 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 MAX_PHASE_STROBE_TIME RTIMER_ARCH_SECOND / 20
#define CCA_COUNT_MAX 2 #define CCA_COUNT_MAX 2
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 #define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 //- RTIMER_ARCH_SECOND / 5000
#define CCA_SLEEP_TIME RTIMER_ARCH_SECOND / 2000 //+ CCA_CHECK_TIME #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 CHECK_TIME (CCA_COUNT_MAX * (CCA_CHECK_TIME + CCA_SLEEP_TIME))
#define STROBE_TIME (CYCLE_TIME + 2 * CHECK_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 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 INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1500 #define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1500
#define LISTEN_TIME_AFTER_PACKET_DETECTED RTIMER_ARCH_SECOND / 100 #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_SILENCE_PERIODS 5
#define MAX_NONACTIVITY_PERIODIC 30
/* The cycle time for announcements. */ /* The cycle time for announcements. */
#ifdef ANNOUNCEMENT_CONF_PERIOD #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 rimeaddr_t is_streaming_to, is_streaming_to_too;
static volatile rtimer_clock_t stream_until; static volatile rtimer_clock_t stream_until;
#define DEFAULT_STREAM_TIME (4 * CYCLE_TIME) #define DEFAULT_STREAM_TIME (1 * CYCLE_TIME)
#ifndef MIN #ifndef MIN
#define MIN(a, b) ((a) < (b)? (a) : (b)) #define MIN(a, b) ((a) < (b)? (a) : (b))
@ -205,7 +206,7 @@ on(void)
static void static void
off(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; radio_is_on = 0;
NETSTACK_RADIO.off(); NETSTACK_RADIO.off();
} }
@ -225,8 +226,11 @@ schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
} }
while(RTIMER_TIME(t) + time == RTIMER_NOW() || while(RTIMER_TIME(t) + time == RTIMER_NOW() ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 1) { RTIMER_TIME(t) + time == RTIMER_NOW() + 1 ||
++time; RTIMER_TIME(t) + time == RTIMER_NOW() + 2 ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 3 ||
RTIMER_TIME(t) + time == RTIMER_NOW() + 4) {
time++;
} }
#if NURTIMER #if NURTIMER
@ -347,8 +351,9 @@ powercycle(struct rtimer *t, void *ptr)
leds_off(LEDS_RED); leds_off(LEDS_RED);
break; break;
} }
if(periods > 10 && !(NETSTACK_RADIO.receiving_packet() || #if 1
NETSTACK_RADIO.pending_packet())) { if(periods > MAX_NONACTIVITY_PERIODIC && !(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) {
leds_on(LEDS_GREEN); leds_on(LEDS_GREEN);
powercycle_turn_radio_off(); powercycle_turn_radio_off();
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
@ -358,6 +363,7 @@ powercycle(struct rtimer *t, void *ptr)
leds_off(LEDS_GREEN); leds_off(LEDS_GREEN);
break; break;
} }
#endif /* 0 */
if(NETSTACK_RADIO.pending_packet()) { if(NETSTACK_RADIO.pending_packet()) {
break; break;
} }
@ -381,15 +387,19 @@ powercycle(struct rtimer *t, void *ptr)
compower_accumulate(&compower_idle_activity); compower_accumulate(&compower_idle_activity);
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
} }
} while((is_snooping) && } while(0 && (is_snooping) &&
RTIMER_NOW() - cycle_start < CYCLE_TIME - CCA_CHECK_TIME * CCA_COUNT_MAX); RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - 8 * CHECK_TIME * CCA_COUNT_MAX));
if(RTIMER_NOW() - cycle_start < CYCLE_TIME) { 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); schedule_powercycle(t, CYCLE_TIME - (RTIMER_NOW() - cycle_start) + 1);
/* printf("cycle_start 0x%02x now 0x%02x wait 0x%02x\n", /* printf("cycle_start 0x%02x now 0x%02x wait 0x%02x\n",
cycle_start, RTIMER_NOW(), CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/ cycle_start, RTIMER_NOW(), CYCLE_TIME - (RTIMER_NOW() - cycle_start));*/
PT_YIELD(&pt); PT_YIELD(&pt);
} }
leds_off(LEDS_RED);
} }
PT_END(&pt); PT_END(&pt);
@ -446,11 +456,13 @@ format_announcement(char *hdr)
adata.announcement_magic[1] = ANNOUNCEMENT_MAGIC2; adata.announcement_magic[1] = ANNOUNCEMENT_MAGIC2;
adata.num = 0; adata.num = 0;
for(a = announcement_list(); for(a = announcement_list();
a != NULL && a->has_value && adata.num < ANNOUNCEMENT_MAX; a != NULL && adata.num < ANNOUNCEMENT_MAX;
a = a->next) { a = a->next) {
adata.data[adata.num].id = a->id; if(a->has_value) {
adata.data[adata.num].value = a->value; adata.data[adata.num].id = a->id;
adata.num++; adata.data[adata.num].value = a->value;
adata.num++;
}
} }
memcpy(hdr, &adata, sizeof(struct announcement_msg)); 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. */ /* Create the MAC header for the data packet. */
hdrlen = NETSTACK_FRAMER.create(); hdrlen = NETSTACK_FRAMER.create();
if(hdrlen == 0) { if(hdrlen == 0) {
@ -664,9 +679,9 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
watchdog_periodic(); 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; break;
} }*/
len = 0; len = 0;
@ -677,9 +692,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
rtimer_clock_t wt; rtimer_clock_t wt;
rtimer_clock_t now = RTIMER_NOW(); rtimer_clock_t now = RTIMER_NOW();
leds_on(LEDS_RED);
NETSTACK_RADIO.transmit(transmit_len); NETSTACK_RADIO.transmit(transmit_len);
leds_off(LEDS_RED);
wt = RTIMER_NOW(); wt = RTIMER_NOW();
#if NURTIMER #if NURTIMER
@ -825,7 +838,15 @@ input_packet(void)
} }
} }
#endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */ #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 #if CONTIKIMAC_CONF_COMPOWER
/* Accumulate the power consumption for the packet reception. */ /* 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)) { } while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + CCA_SLEEP_TIME + CCA_CHECK_TIME)) { }
#endif #endif
} }
if(collisions == 0) { if(collisions == 0) {
NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); 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 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * 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. */ /* Build the FCF. */
params.fcf.frame_type = FRAME802154_DATAFRAME; params.fcf.frame_type = FRAME802154_DATAFRAME;
params.fcf.security_enabled = 0; 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)) { if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
params.fcf.ack_required = 0; params.fcf.ack_required = 0;
} else { } else {
@ -184,8 +184,9 @@ parse(void)
} }
} }
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (rimeaddr_t *)&frame.src_addr); 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_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); PRINTF("15.4-IN: %2X", frame.fcf.frame_type);
PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));

View file

@ -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.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; struct queuebuf *q;
}; };
#define PHASE_DEFER_THRESHOLD 2 #define PHASE_DEFER_THRESHOLD 1
#define PHASE_QUEUESIZE 8 #define PHASE_QUEUESIZE 8
#define MAX_NOACKS 3 #define MAX_NOACKS 2
MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE); MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE);
@ -71,6 +71,30 @@ MEMB(phase_memb, struct phase_queueitem, PHASE_QUEUESIZE);
#define PRINTDEBUG(...) #define PRINTDEBUG(...)
#endif #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 void
phase_update(const struct phase_list *list, phase_update(const struct phase_list *list,
const rimeaddr_t *neighbor, rtimer_clock_t time, const rimeaddr_t *neighbor, rtimer_clock_t time,
@ -79,46 +103,45 @@ phase_update(const struct phase_list *list,
struct phase *e; struct phase *e;
/* If we have an entry for this neighbor already, we renew it. */ /* If we have an entry for this neighbor already, we renew it. */
for(e = list_head(*list->list); e != NULL; e = e->next) { e = find_neighbor(list, neighbor);
if(rimeaddr_cmp(neighbor, &e->neighbor)) { if(e != NULL) {
if(mac_status == MAC_TX_OK) { if(mac_status == MAC_TX_OK) {
e->time = time; 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;
} }
} else if(mac_status == MAC_TX_OK) {
/* If the neighbor didn't reply to us, it may have switched e->noacks = 0;
phase (rebooted). We try a number of transmissions to it }
before we drop it from the phase list. */
if(mac_status == MAC_TX_NOACK) { /* Make sure this entry is first on the list so subsequent
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
searches are faster. */ searches are faster. */
list_remove(*list->list, e); 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_push(*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) mac_callback_t mac_callback, void *mac_callback_ptr)
{ {
struct phase *e; 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 /* 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 phase for this particular neighbor. If so, we can compute the
time for the next expected phase and setup a ctimer to switch on time for the next expected phase and setup a ctimer to switch on
the radio just before the phase. */ the radio just before the phase. */
for(e = list_head(*list->list); e != NULL; e = e->next) { e = find_neighbor(list, neighbor);
const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(e != NULL) {
rtimer_clock_t wait, now, expected, additional_wait;
if(rimeaddr_cmp(neighbor, &e->neighbor)) { clock_time_t ctimewait;
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 +
/* We expect phases to happen every CYCLE_TIME time CYCLE_TIME. To compute a relative offset, we subtract
units. The next expected phase is at time e->time + with clock_time(). Because we are only interested in turning
CYCLE_TIME. To compute a relative offset, we subtract on the radio within the CYCLE_TIME period, we compute the
with clock_time(). Because we are only interested in turning waiting time with modulo CYCLE_TIME. */
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);*/
/* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1),
cycle_time);*/ additional_wait = 2 * e->noacks * wait_before;
additional_wait = 2 * e->noacks * wait_before; /* if(e->noacks > 0) {
printf("additional wait %d\n", additional_wait);
/* if(e->noacks > 0) { }*/
printf("additional wait %d\n", additional_wait);
}*/ now = RTIMER_NOW();
wait = (rtimer_clock_t)((e->time - now) &
now = RTIMER_NOW(); (cycle_time - 1));
wait = (rtimer_clock_t)((e->time - now) & if(wait < wait_before + additional_wait) {
(cycle_time - 1)); wait += cycle_time;
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;
} }
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; return PHASE_UNKNOWN;
} }

View file

@ -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.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, 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); 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); rtimer_clock_t time, int mac_status);
void phase_remove(const struct phase_list *list, const rimeaddr_t *neighbor);
#endif /* PHASE_H */ #endif /* PHASE_H */