From ed52586e18fbc7286a9caddae245a9569c8b2e5f Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Tue, 23 Feb 2010 18:49:05 +0000 Subject: [PATCH] Rework of parts of the ContikiMAC code based on input from experimental results. When channel check is triggered because of a false positive, the new version checks the radio several times to make sure that there really is an incoming packet. Otherwise, the radio is switched off. Cleaned up and removed old unused code. Added a few temporary debugging mechanisms and functions. --- core/net/mac/contikimac.c | 247 +++++++++++++++++++++++++------------- 1 file changed, 165 insertions(+), 82 deletions(-) diff --git a/core/net/mac/contikimac.c b/core/net/mac/contikimac.c index bb27af6d3..0c359556c 100644 --- a/core/net/mac/contikimac.c +++ b/core/net/mac/contikimac.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * $Id: contikimac.c,v 1.3 2010/02/18 23:52:34 adamdunkels Exp $ + * $Id: contikimac.c,v 1.4 2010/02/23 18:49:05 adamdunkels Exp $ */ /** @@ -92,11 +92,6 @@ struct announcement_msg { #define DISPATCH 0 #define TYPE_ANNOUNCEMENT 0x12 -struct contikimac_hdr { - uint8_t dispatch; - uint8_t type; -}; - #ifdef CONTIKIMAC_CONF_CYCLE_TIME #define CYCLE_TIME (CONTIKIMAC_CONF_CYCLE_TIME) #else @@ -135,25 +130,12 @@ static volatile uint8_t contikimac_is_on = 0; static volatile unsigned char we_are_sending = 0; static volatile unsigned char radio_is_on = 0; -#undef LEDS_ON -#undef LEDS_OFF -#undef LEDS_TOGGLE - -#define LEDS_ON(x) leds_on(x) -#define LEDS_OFF(x) leds_off(x) -#define LEDS_TOGGLE(x) leds_toggle(x) #define DEBUG 0 #if DEBUG #include #define PRINTF(...) printf(__VA_ARGS__) #define PRINTDEBUG(...) printf(__VA_ARGS__) #else -#undef LEDS_ON -#undef LEDS_OFF -#undef LEDS_TOGGLE -#define LEDS_ON(x) -#define LEDS_OFF(x) -#define LEDS_TOGGLE(x) #define PRINTF(...) #define PRINTDEBUG(...) #endif @@ -193,6 +175,13 @@ static rtimer_clock_t stream_until; #define MIN(a, b) ((a) < (b)? (a) : (b)) #endif /* MIN */ +static volatile uint8_t packet_indication_flag; +static volatile uint16_t packet_indicated_but_not_received, + packet_indicated_but_not_received_clear_third_time; + +volatile uint16_t +packet_indicated_but_not_received_clear_second_time; + /*---------------------------------------------------------------------------*/ static void on(void) @@ -200,7 +189,6 @@ on(void) if(contikimac_is_on && radio_is_on == 0) { radio_is_on = 1; NETSTACK_RADIO.on(); - LEDS_ON(LEDS_RED); } } /*---------------------------------------------------------------------------*/ @@ -210,7 +198,6 @@ off(void) if(contikimac_is_on && radio_is_on != 0 && is_listening == 0 && is_streaming == 0) { radio_is_on = 0; NETSTACK_RADIO.off(); - LEDS_OFF(LEDS_RED); } } /*---------------------------------------------------------------------------*/ @@ -221,6 +208,12 @@ schedule_powercycle(struct rtimer *t, rtimer_clock_t time) int r; if(contikimac_is_on) { + + while(RTIMER_TIME(t) + time == RTIMER_NOW() || + RTIMER_TIME(t) + time == RTIMER_NOW() + 1) { + ++time; + } + #if NURTIMER r = rtimer_reschedule(t, time, 1); #else @@ -238,9 +231,6 @@ powercycle_turn_radio_off(void) if(we_are_sending == 0) { off(); } -#if CONTIKIMAC_CONF_COMPOWER - compower_accumulate(&compower_idle_activity); -#endif /* CONTIKIMAC_CONF_COMPOWER */ } static void powercycle_turn_radio_on(void) @@ -274,10 +264,12 @@ powercycle(struct rtimer *t, void *ptr) static uint8_t packet_seen; static rtimer_clock_t t0, cycle_start; static uint8_t count; + static uint8_t clear_second_time, clear_third_time; cycle_start = RTIMER_NOW(); packet_seen = 0; + clear_second_time = clear_third_time = 0; if(we_are_sending == 0) { for(count = 0; count < CCA_COUNT_MAX; ++count) { t0 = RTIMER_NOW(); @@ -288,6 +280,7 @@ powercycle(struct rtimer *t, void *ptr) while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)); #endif if(NETSTACK_RADIO.channel_clear() == 0) { + packet_indication_flag = 1; packet_seen = 1; break; } @@ -298,9 +291,80 @@ powercycle(struct rtimer *t, void *ptr) /* If there were a packet in the air, turn radio on */ if(packet_seen) { - schedule_powercycle(t, LISTEN_TIME); - PT_YIELD(&pt); - powercycle_turn_radio_off(); + static rtimer_clock_t start; + static uint8_t silence_periods, periods; + + start = RTIMER_NOW(); + + periods = silence_periods = 0; + while(we_are_sending == 0 && radio_is_on && + RTIMER_CLOCK_LT(RTIMER_NOW(), (start + LISTEN_TIME))) { + + /* Check for two consecutive periods of non-activity. If we + see two such periods, we turn the radio off. Also, if a + packet has been successfully received (as indicated by + the NETSTACK_RADIO.pending_packet() function), we stop + listening. */ + if(NETSTACK_RADIO.channel_clear()) { + ++silence_periods; + } else { + silence_periods = 0; + } + + ++periods; + + if(NETSTACK_RADIO.receiving_packet()) { + silence_periods = 0; + } + if(silence_periods > 2) { + leds_on(LEDS_RED); + powercycle_turn_radio_off(); +#if CONTIKIMAC_CONF_COMPOWER + compower_accumulate(&compower_idle_activity); +#endif /* CONTIKIMAC_CONF_COMPOWER */ + leds_off(LEDS_RED); + break; + } + if(periods > 4 && !NETSTACK_RADIO.receiving_packet()) { + leds_on(LEDS_GREEN); + powercycle_turn_radio_off(); +#if CONTIKIMAC_CONF_COMPOWER + compower_accumulate(&compower_idle_activity); +#endif /* CONTIKIMAC_CONF_COMPOWER */ + + leds_off(LEDS_GREEN); + break; + } + if(NETSTACK_RADIO.pending_packet()) { + break; + } + + schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME); + leds_on(LEDS_BLUE); + PT_YIELD(&pt); + leds_off(LEDS_BLUE); + } + if(radio_is_on && !NETSTACK_RADIO.pending_packet) { + leds_on(LEDS_RED + LEDS_GREEN); + powercycle_turn_radio_off(); +#if CONTIKIMAC_CONF_COMPOWER + compower_accumulate(&compower_idle_activity); +#endif /* CONTIKIMAC_CONF_COMPOWER */ + leds_off(LEDS_RED + LEDS_GREEN); + } + + } else { +#if CONTIKIMAC_CONF_COMPOWER + compower_accumulate(&compower_idle_activity); +#endif /* CONTIKIMAC_CONF_COMPOWER */ + } + break_the_loop: + /* If the packet indication flag is still set, it means that + there was never a packet received by the radio. We increase + the packet_indicated_but_not_received counter. */ + if(packet_indication_flag) { + packet_indicated_but_not_received += packet_indication_flag; + packet_indication_flag = 0; } } if(RTIMER_NOW() - cycle_start < CYCLE_TIME) { @@ -455,7 +519,6 @@ send_packet(void) #endif /* WITH_ACK_OPTIMIZATION */ #endif /* WITH_PHASE_OPTIMIZATION */ - leds_on(LEDS_GREEN); /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; @@ -466,7 +529,6 @@ send_packet(void) packet will be retransmitted later by the MAC protocol instread. */ if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet()) { - leds_off(LEDS_GREEN); we_are_sending = 0; return MAC_TX_COLLISION; } @@ -478,15 +540,11 @@ send_packet(void) strobes = 0; - LEDS_ON(LEDS_BLUE); - /* Send a train of strobes until the receiver answers with an ACK. */ collisions = 0; got_strobe_ack = 0; - leds_off(LEDS_GREEN); - if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { /* Check if there are any transmissions by others. */ @@ -514,6 +572,7 @@ send_packet(void) if(collisions > 0) { we_are_sending = 0; + off(); return MAC_TX_COLLISION; } @@ -559,10 +618,8 @@ send_packet(void) while(RTIMER_CLOCK_LT (RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK_CCA)) { } #endif - leds_on(LEDS_RED); if(!is_broadcast && !NETSTACK_RADIO.channel_clear()) { uint8_t ackbuf[ACK_LEN]; - leds_on(LEDS_BLUE); wt = RTIMER_NOW(); #if NURTIMER while(RTIMER_CLOCK_LT @@ -571,19 +628,19 @@ send_packet(void) while(RTIMER_CLOCK_LT (RTIMER_NOW(), wt + WAIT_TIME_AFTER_STROBE_ACK_CCA)) { } #endif - leds_off(LEDS_BLUE); if(!is_broadcast) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN) { got_strobe_ack = 1; encounter_time = now; - } else { + packet_indication_flag = 0; + } else if(len > 0) { + packet_indication_flag = 0; collisions++; } } else { } } - leds_off(LEDS_RED); } } @@ -627,17 +684,15 @@ send_packet(void) we_are_sending = 0; - LEDS_OFF(LEDS_BLUE); - if(collisions == 0) { - if(!is_broadcast && !got_strobe_ack) { - return MAC_TX_NOACK; - } else { - return MAC_TX_OK; - } - } else { + if(collisions > 0) { return MAC_TX_COLLISION; } - + + if(!is_broadcast && !got_strobe_ack) { + return MAC_TX_NOACK; + } else { + return MAC_TX_OK; + } } /*---------------------------------------------------------------------------*/ static void @@ -650,53 +705,43 @@ qsend_packet(mac_callback_t sent, void *ptr) static void input_packet(void) { - struct contikimac_hdr *hdr; - /* We have received the packet, so we can go back to being asleep. */ off(); - if(framer_get()->parse()) { - hdr = packetbuf_dataptr(); - - if(hdr->dispatch != DISPATCH) { - if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - &rimeaddr_node_addr) || - rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - &rimeaddr_null)) { - /* This is a regular packet that is destined to us or to the - broadcast address. */ + packet_indication_flag = 0; + if(packetbuf_totlen() > 0 && framer_get()->parse()) { + + if(packetbuf_datalen() > 0 && + packetbuf_totlen() > 0 && + (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), + &rimeaddr_node_addr) || + rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), + &rimeaddr_null))) { + /* This is a regular packet that is destined to us or to the + broadcast address. */ #if CONTIKIMAC_CONF_COMPOWER - /* Accumulate the power consumption for the packet reception. */ - compower_accumulate(¤t_packet); - /* Convert the accumulated power consumption for the received - packet to packet attributes so that the higher levels can - keep track of the amount of energy spent on receiving the - packet. */ - compower_attrconv(¤t_packet); + /* Accumulate the power consumption for the packet reception. */ + compower_accumulate(¤t_packet); + /* Convert the accumulated power consumption for the received + packet to packet attributes so that the higher levels can + keep track of the amount of energy spent on receiving the + packet. */ + compower_attrconv(¤t_packet); - /* Clear the accumulated power consumption so that it is ready - for the next packet. */ - compower_clear(¤t_packet); + /* Clear the accumulated power consumption so that it is ready + for the next packet. */ + compower_clear(¤t_packet); #endif /* CONTIKIMAC_CONF_COMPOWER */ - PRINTDEBUG("contikimac: data(%u)\n", packetbuf_datalen()); + PRINTDEBUG("contikimac: data(%u)\n", packetbuf_datalen()); - NETSTACK_MAC.input(); - return; - } else { - PRINTDEBUG("contikimac: data not for us\n"); - } -#if CONTIKIMAC_CONF_ANNOUNCEMENTS - } else if(hdr->type == TYPE_ANNOUNCEMENT) { - packetbuf_hdrreduce(sizeof(struct contikimac_hdr)); - parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER)); -#endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */ + NETSTACK_MAC.input(); + return; } else { - PRINTF("contikimac: unknown type %u (%u/%u)\n", hdr->type, - packetbuf_datalen(), len); + PRINTDEBUG("contikimac: data not for us\n"); } } else { PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen()); @@ -830,3 +875,41 @@ const struct mac_driver contikimac_driver = { turn_off, duty_cycle, }; +/*---------------------------------------------------------------------------*/ +uint16_t +contikimac_debug_print(void) +{ + uint16_t c1, c2; + uint16_t indicated, clear_second, clear_third; + static uint16_t indicated_last, clear_second_last, clear_third_last; + + do { + c1 = packet_indicated_but_not_received; + c2 = packet_indicated_but_not_received; + } while(c1 != c2); + + indicated = c1; + + do { + c1 = packet_indicated_but_not_received_clear_second_time; + c2 = packet_indicated_but_not_received_clear_second_time; + } while(c1 != c2); + + clear_second = c1; + + do { + c1 = packet_indicated_but_not_received_clear_third_time; + c2 = packet_indicated_but_not_received_clear_third_time; + } while(c1 != c2); + + clear_third = c1; + + printf("indicated %d clear second %d clear_third %d\n", + indicated - indicated_last, + clear_second - clear_second_last, + clear_third - clear_third_last); + indicated_last = indicated; + clear_second_last = clear_second; + clear_third_last = clear_third; +} +/*---------------------------------------------------------------------------*/