Updated Contiki X-MAC to use hardware acks, which allows for tighter timing and results in a lower duty cycle. Hardware acks also make X-MAC more robust against packet losses, as there is a direct way for the CSMA layer to detect loss of data packets. Before, Contiki X-MAC only detected loss of strobes.
This commit is contained in:
parent
d51e99a3dd
commit
09c223f549
@ -28,7 +28,7 @@
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: xmac.c,v 1.59 2010/10/03 22:46:53 joxe Exp $
|
||||
* $Id: xmac.c,v 1.60 2011/01/25 14:31:09 adamdunkels Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -137,7 +137,7 @@ struct xmac_hdr {
|
||||
cycle. */
|
||||
#define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD))
|
||||
|
||||
#define DEFAULT_STROBE_WAIT_TIME (7 * DEFAULT_ON_TIME / 8)
|
||||
#define DEFAULT_STROBE_WAIT_TIME (5 * DEFAULT_ON_TIME / 8)
|
||||
|
||||
struct xmac_config xmac_config = {
|
||||
DEFAULT_ON_TIME,
|
||||
@ -415,6 +415,40 @@ register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time)
|
||||
#endif /* WITH_ENCOUNTER_OPTIMIZATION */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
detect_ack(void)
|
||||
{
|
||||
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
|
||||
#define ACK_LEN 3
|
||||
#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1000
|
||||
rtimer_clock_t wt;
|
||||
uint8_t ack_received = 0;
|
||||
|
||||
wt = RTIMER_NOW();
|
||||
leds_on(LEDS_GREEN);
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { }
|
||||
leds_off(LEDS_GREEN);
|
||||
/* Check for incoming ACK. */
|
||||
if((NETSTACK_RADIO.receiving_packet() ||
|
||||
NETSTACK_RADIO.pending_packet() ||
|
||||
NETSTACK_RADIO.channel_clear() == 0)) {
|
||||
int len;
|
||||
uint8_t ackbuf[ACK_LEN + 2];
|
||||
|
||||
wt = RTIMER_NOW();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
|
||||
|
||||
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
||||
if(len == ACK_LEN) {
|
||||
ack_received = 1;
|
||||
}
|
||||
}
|
||||
if(ack_received) {
|
||||
leds_toggle(LEDS_RED);
|
||||
}
|
||||
return ack_received;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
send_packet(void)
|
||||
{
|
||||
rtimer_clock_t t0;
|
||||
@ -422,7 +456,8 @@ send_packet(void)
|
||||
rtimer_clock_t encounter_time = 0;
|
||||
int strobes;
|
||||
struct xmac_hdr *hdr;
|
||||
int got_strobe_ack = 0;
|
||||
uint8_t got_strobe_ack = 0;
|
||||
uint8_t got_ack = 0;
|
||||
uint8_t strobe[MAX_STROBE_SIZE];
|
||||
int strobe_len, len;
|
||||
int is_broadcast = 0;
|
||||
@ -456,6 +491,8 @@ send_packet(void)
|
||||
}
|
||||
is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);
|
||||
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
|
||||
len = NETSTACK_FRAMER.create();
|
||||
strobe_len = len + sizeof(struct xmac_hdr);
|
||||
if(len == 0 || strobe_len > sizeof(strobe)) {
|
||||
@ -518,6 +555,9 @@ send_packet(void)
|
||||
|
||||
now = RTIMER_NOW();
|
||||
wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
|
||||
if(wait < 2 * DEFAULT_ON_TIME) {
|
||||
wait = DEFAULT_PERIOD;
|
||||
}
|
||||
expected = now + wait - 2 * DEFAULT_ON_TIME;
|
||||
|
||||
#if WITH_ACK_OPTIMIZATION
|
||||
@ -549,7 +589,7 @@ send_packet(void)
|
||||
/* Send a train of strobes until the receiver answers with an ACK. */
|
||||
|
||||
/* Turn on the radio to listen for the strobe ACK. */
|
||||
on();
|
||||
// on();
|
||||
collisions = 0;
|
||||
if(!is_already_streaming) {
|
||||
watchdog_stop();
|
||||
@ -563,6 +603,8 @@ send_packet(void)
|
||||
while(got_strobe_ack == 0 &&
|
||||
RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) {
|
||||
rtimer_clock_t now = RTIMER_NOW();
|
||||
|
||||
#if 0
|
||||
/* See if we got an ACK */
|
||||
packetbuf_clear();
|
||||
len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
|
||||
@ -588,8 +630,9 @@ send_packet(void)
|
||||
PRINTF("xmac: send failed to parse %u\n", len);
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
}
|
||||
|
||||
|
||||
t = RTIMER_NOW();
|
||||
/* Send the strobe packet. */
|
||||
if(got_strobe_ack == 0 && collisions == 0) {
|
||||
@ -602,11 +645,12 @@ send_packet(void)
|
||||
queuebuf_to_packetbuf(packet);
|
||||
NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
|
||||
#endif
|
||||
off();
|
||||
off();
|
||||
} else {
|
||||
rtimer_clock_t wt;
|
||||
on();
|
||||
NETSTACK_RADIO.send(strobe, strobe_len);
|
||||
#if 1
|
||||
#if 0
|
||||
/* Turn off the radio for a while to let the other side
|
||||
respond. We don't need to keep our radio on when we know
|
||||
that the other side needs some time to produce a reply. */
|
||||
@ -614,8 +658,13 @@ send_packet(void)
|
||||
wt = RTIMER_NOW();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
|
||||
#endif /* 0 */
|
||||
on();
|
||||
}
|
||||
|
||||
if(detect_ack()) {
|
||||
got_strobe_ack = 1;
|
||||
} else {
|
||||
off();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -633,8 +682,6 @@ send_packet(void)
|
||||
} else {
|
||||
off();
|
||||
}
|
||||
#else /* WITH_ACK_OPTIMIZATION */
|
||||
off();
|
||||
#endif /* WITH_ACK_OPTIMIZATION */
|
||||
|
||||
/* restore the packet to send */
|
||||
@ -644,7 +691,14 @@ send_packet(void)
|
||||
/* Send the data packet. */
|
||||
if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
|
||||
NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
|
||||
|
||||
if(!is_broadcast) {
|
||||
if(detect_ack()) {
|
||||
got_ack = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
off();
|
||||
|
||||
#if WITH_ENCOUNTER_OPTIMIZATION
|
||||
if(got_strobe_ack && !is_streaming) {
|
||||
@ -675,7 +729,7 @@ send_packet(void)
|
||||
|
||||
LEDS_OFF(LEDS_BLUE);
|
||||
if(collisions == 0) {
|
||||
if(!is_broadcast && !got_strobe_ack) {
|
||||
if(is_broadcast == 0 && got_ack == 0) {
|
||||
return MAC_TX_NOACK;
|
||||
} else {
|
||||
return MAC_TX_OK;
|
||||
@ -781,6 +835,8 @@ input_packet(void)
|
||||
acknowledge the strobe and wait for the packet. By using
|
||||
the same address as both sender and receiver, we flag the
|
||||
message is a strobe ack. */
|
||||
waiting_for_packet = 1;
|
||||
#if 0
|
||||
hdr->type = TYPE_STROBE_ACK;
|
||||
packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
|
||||
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
@ -797,6 +853,7 @@ input_packet(void)
|
||||
} else {
|
||||
PRINTF("xmac: failed to send strobe ack\n");
|
||||
}
|
||||
#endif /* 0 */
|
||||
} else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||
&rimeaddr_null)) {
|
||||
/* If the receiver address is null, the strobe is sent to
|
||||
@ -808,7 +865,7 @@ input_packet(void)
|
||||
} else {
|
||||
PRINTDEBUG("xmac: strobe not for us\n");
|
||||
}
|
||||
|
||||
|
||||
/* We are done processing the strobe and we therefore return
|
||||
to the caller. */
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user