diff --git a/core/net/rime/collect-link-estimate.c b/core/net/rime/collect-link-estimate.c index f9128047a..3c364b53c 100644 --- a/core/net/rime/collect-link-estimate.c +++ b/core/net/rime/collect-link-estimate.c @@ -32,12 +32,12 @@ * * This file is part of the Contiki operating system. * - * $Id: collect-link-estimate.c,v 1.1 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect-link-estimate.c,v 1.2 2010/09/13 13:28:14 adamdunkels Exp $ */ /** * \file - * Implementation of Contiki link estimate based on ETX + * Implementation of Collect link estimate based on ETX * \author * Adam Dunkels */ @@ -56,8 +56,11 @@ void collect_link_estimate_new(struct collect_link_estimate *le) { int i; + + /* Start with a conservative / pessimistic estimate of link quality + for new links. */ for(i = 0; i < ETX_HISTORY_WINDOW; i++) { - le->history[i] = 1; + le->history[i] = 4; } le->historyptr = 0; } @@ -66,7 +69,7 @@ void collect_link_estimate_update_tx_fail(struct collect_link_estimate *le, int tx) { if(le != NULL) { - le->history[le->historyptr] += tx * 2; + le->history[le->historyptr] = tx * 2; le->historyptr = (le->historyptr + 1) % ETX_HISTORY_WINDOW; } } @@ -91,10 +94,13 @@ collect_link_estimate(struct collect_link_estimate *le) { int i, etx; + /* printf("collect_link_estimate: ");*/ etx = 0; for(i = 0; i < ETX_HISTORY_WINDOW; ++i) { + /* printf("%d ", le->history[i]);*/ etx += le->history[i]; } + /* printf(", %d\n", (COLLECT_LINK_ESTIMATE_UNIT * etx) / ETX_HISTORY_WINDOW);*/ return (COLLECT_LINK_ESTIMATE_UNIT * etx) / ETX_HISTORY_WINDOW; } /*---------------------------------------------------------------------------*/ diff --git a/core/net/rime/collect-link-estimate.h b/core/net/rime/collect-link-estimate.h index a8ad2108a..af8f0c993 100644 --- a/core/net/rime/collect-link-estimate.h +++ b/core/net/rime/collect-link-estimate.h @@ -42,7 +42,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect-link-estimate.h,v 1.1 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect-link-estimate.h,v 1.2 2010/09/13 13:28:14 adamdunkels Exp $ */ /** @@ -55,7 +55,7 @@ #ifndef COLLECT_LINK_ESTIMATE_H #define COLLECT_LINK_ESTIMATE_H -#define COLLECT_LINK_ESTIMATE_UNIT 16 +#define COLLECT_LINK_ESTIMATE_UNIT 8 diff --git a/core/net/rime/collect-neighbor.c b/core/net/rime/collect-neighbor.c index 37a6fd508..03fca74cf 100644 --- a/core/net/rime/collect-neighbor.c +++ b/core/net/rime/collect-neighbor.c @@ -33,7 +33,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect-neighbor.c,v 1.4 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect-neighbor.c,v 1.5 2010/09/13 13:28:14 adamdunkels Exp $ */ /** @@ -62,11 +62,6 @@ #define RTMETRIC_MAX COLLECT_MAX_DEPTH MEMB(collect_neighbors_mem, struct collect_neighbor, MAX_COLLECT_NEIGHBORS); -LIST(collect_neighbors_list); - -/*static struct collect_neighbor collect_neighbors[MAX_COLLECT_NEIGHBORS];*/ - -static struct ctimer t; static int max_time = 2400; @@ -78,17 +73,18 @@ static int max_time = 2400; #define PRINTF(...) #endif - /*---------------------------------------------------------------------------*/ static void periodic(void *ptr) -{ +{ + struct collect_neighbor_list *neighbor_list; struct collect_neighbor *n, *next; + neighbor_list = ptr; + /* Go through all collect_neighbors and remove old ones. */ - for(n = list_head(collect_neighbors_list); n != NULL; n = next) { + for(n = list_head(neighbor_list->list); n != NULL; n = next) { next = NULL; - /* for(i = 0; i < MAX_COLLECT_NEIGHBORS; ++i) {*/ if(!rimeaddr_cmp(&n->addr, &rimeaddr_null) && n->time < max_time) { n->time++; @@ -99,7 +95,7 @@ periodic(void *ptr) n->addr.u8[0], n->addr.u8[1]); rimeaddr_copy(&n->addr, &rimeaddr_null); next = list_item_next(n); - list_remove(collect_neighbors_list, n); + list_remove(neighbor_list->list, n); memb_free(&collect_neighbors_mem, n); } } @@ -107,8 +103,7 @@ periodic(void *ptr) next = list_item_next(n); } } - /* PRINTF("collect_neighbor periodic\n");*/ - ctimer_set(&t, CLOCK_SECOND, periodic, NULL); + ctimer_set(&neighbor_list->periodic, CLOCK_SECOND, periodic, neighbor_list); } /*---------------------------------------------------------------------------*/ void @@ -118,16 +113,23 @@ collect_neighbor_init(void) if(initialized == 0) { initialized = 1; memb_init(&collect_neighbors_mem); - list_init(collect_neighbors_list); - ctimer_set(&t, CLOCK_SECOND, periodic, NULL); } } /*---------------------------------------------------------------------------*/ +void +collect_neighbor_list_new(struct collect_neighbor_list *neighbors_list) +{ + LIST_STRUCT_INIT(neighbors_list, list); + list_init(neighbors_list->list); + ctimer_set(&neighbors_list->periodic, CLOCK_SECOND, periodic, neighbors_list); +} +/*---------------------------------------------------------------------------*/ struct collect_neighbor * -collect_neighbor_find(const rimeaddr_t *addr) +collect_neighbor_list_find(struct collect_neighbor_list *neighbors_list, + const rimeaddr_t *addr) { struct collect_neighbor *n; - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { if(rimeaddr_cmp(&n->addr, addr)) { return n; } @@ -136,45 +138,8 @@ collect_neighbor_find(const rimeaddr_t *addr) } /*---------------------------------------------------------------------------*/ void -collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint8_t rtmetric) -{ - if(n != NULL) { - PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - n->addr.u8[0], n->addr.u8[1], rtmetric); - n->rtmetric = rtmetric; - n->time = 0; - } -} -/*---------------------------------------------------------------------------*/ -void -collect_neighbor_timedout(struct collect_neighbor *n, uint8_t num_tx) -{ - collect_link_estimate_update_tx_fail(&n->le, num_tx); -} -/*---------------------------------------------------------------------------*/ -void -collect_neighbor_tx(struct collect_neighbor *n, uint8_t num_tx) -{ - collect_link_estimate_update_tx(&n->le, num_tx); - n->time = 0; -} -/*---------------------------------------------------------------------------*/ -void -collect_neighbor_rx(struct collect_neighbor *n) -{ - collect_link_estimate_update_rx(&n->le); - n->time = 0; -} -/*---------------------------------------------------------------------------*/ -int -collect_neighbor_link_estimate(struct collect_neighbor *n) -{ - return collect_link_estimate(&n->le); -} -/*---------------------------------------------------------------------------*/ -void -collect_neighbor_add(const rimeaddr_t *addr, uint8_t nrtmetric) +collect_neighbor_list_add(struct collect_neighbor_list *neighbors_list, + const rimeaddr_t *addr, uint8_t nrtmetric) { uint16_t rtmetric; uint16_t le; @@ -183,10 +148,11 @@ collect_neighbor_add(const rimeaddr_t *addr, uint8_t nrtmetric) PRINTF("collect_neighbor_add: adding %d.%d\n", addr->u8[0], addr->u8[1]); /* Check if the collect_neighbor is already on the list. */ - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { if(rimeaddr_cmp(&n->addr, &rimeaddr_null) || rimeaddr_cmp(&n->addr, addr)) { - PRINTF("collect_neighbor_add: already on list %d.%d\n", addr->u8[0], addr->u8[1]); + PRINTF("collect_neighbor_add: already on list %d.%d\n", + addr->u8[0], addr->u8[1]); break; } } @@ -194,24 +160,26 @@ collect_neighbor_add(const rimeaddr_t *addr, uint8_t nrtmetric) /* If the collect_neighbor was not on the list, we try to allocate memory for it. */ if(n == NULL) { - PRINTF("collect_neighbor_add: not on list, allocating %d.%d\n", addr->u8[0], addr->u8[1]); + PRINTF("collect_neighbor_add: not on list, allocating %d.%d\n", + addr->u8[0], addr->u8[1]); n = memb_alloc(&collect_neighbors_mem); if(n != NULL) { - list_add(collect_neighbors_list, n); + list_add(neighbors_list->list, n); } } - + /* If we could not allocate memory, we try to recycle an old collect_neighbor */ if(n == NULL) { - PRINTF("collect_neighbor_add: not on list, not allocated, recycling %d.%d\n", addr->u8[0], addr->u8[1]); + PRINTF("collect_neighbor_add: not on list, not allocated, recycling %d.%d\n", + addr->u8[0], addr->u8[1]); /* Find the first unused entry or the used entry with the highest rtmetric and highest link estimate. */ rtmetric = 0; le = 0; max = NULL; - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { if(!rimeaddr_cmp(&n->addr, &rimeaddr_null)) { if(n->rtmetric > rtmetric) { rtmetric = n->rtmetric; @@ -243,39 +211,29 @@ collect_neighbor_add(const rimeaddr_t *addr, uint8_t nrtmetric) } /*---------------------------------------------------------------------------*/ void -collect_neighbor_remove(const rimeaddr_t *addr) +collect_neighbor_list_remove(struct collect_neighbor_list *neighbors_list, + const rimeaddr_t *addr) { struct collect_neighbor *n; - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { if(rimeaddr_cmp(&n->addr, addr)) { PRINTF("%d.%d: removing %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], addr->u8[0], addr->u8[1]); rimeaddr_copy(&n->addr, &rimeaddr_null); n->rtmetric = RTMETRIC_MAX; - list_remove(collect_neighbors_list, n); + list_remove(neighbors_list->list, n); memb_free(&collect_neighbors_mem, n); return; } } - /* int i; - - for(i = 0; i < MAX_COLLECT_NEIGHBORS; ++i) { - if(rimeaddr_cmp(&collect_neighbors[i].addr, addr)) { - PRINTF("%d: removing %d @ %d\n", rimeaddr_node_addr.u16[0], addr->u16[0], i); - rimeaddr_copy(&collect_neighbors[i].addr, &rimeaddr_null); - collect_neighbors[i].rtmetric = RTMETRIC_MAX; - return; - } - }*/ } /*---------------------------------------------------------------------------*/ struct collect_neighbor * -collect_neighbor_best(void) +collect_neighbor_list_best(struct collect_neighbor_list *neighbors_list) { int found; - /* int lowest, best;*/ struct collect_neighbor *n, *best; uint16_t rtmetric; @@ -284,10 +242,11 @@ collect_neighbor_best(void) found = 0; /* PRINTF("%d: ", node_id);*/ + PRINTF("collect_neighbor_best: "); /* Find the lowest rtmetric. */ - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { - PRINTF("collect_neighbor_best: checking %d.%d with rtmetric %d + %d (%d)\n", + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { + PRINTF("%d.%d %d+%d=%d, ", n->addr.u8[0], n->addr.u8[1], n->rtmetric, collect_neighbor_link_estimate(n), collect_neighbor_rtmetric(n)); @@ -297,11 +256,85 @@ collect_neighbor_best(void) best = n; } } + PRINTF("\n"); return best; } /*---------------------------------------------------------------------------*/ int +collect_neighbor_list_num(struct collect_neighbor_list *neighbors_list) +{ + PRINTF("collect_neighbor_num %d\n", list_length(neighbors_list->list)); + return list_length(neighbors_list->list); +} +/*---------------------------------------------------------------------------*/ +struct collect_neighbor * +collect_neighbor_list_get(struct collect_neighbor_list *neighbors_list, int num) +{ + int i; + struct collect_neighbor *n; + + PRINTF("collect_neighbor_get %d\n", num); + + i = 0; + for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) { + if(i == num) { + PRINTF("collect_neighbor_get found %d.%d\n", + n->addr.u8[0], n->addr.u8[1]); + return n; + } + i++; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +collect_neighbor_list_purge(struct collect_neighbor_list *neighbors_list) +{ + while(list_head(neighbors_list->list) != NULL) { + memb_free(&collect_neighbors_mem, list_pop(neighbors_list->list)); + } +} +/*---------------------------------------------------------------------------*/ +void +collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint8_t rtmetric) +{ + if(n != NULL) { + PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + n->addr.u8[0], n->addr.u8[1], rtmetric); + n->rtmetric = rtmetric; + n->time = 0; + } +} +/*---------------------------------------------------------------------------*/ +void +collect_neighbor_tx_fail(struct collect_neighbor *n, uint8_t num_tx) +{ + collect_link_estimate_update_tx_fail(&n->le, num_tx); +} +/*---------------------------------------------------------------------------*/ +void +collect_neighbor_tx(struct collect_neighbor *n, uint8_t num_tx) +{ + collect_link_estimate_update_tx(&n->le, num_tx); + n->time = 0; +} +/*---------------------------------------------------------------------------*/ +void +collect_neighbor_rx(struct collect_neighbor *n) +{ + collect_link_estimate_update_rx(&n->le); + n->time = 0; +} +/*---------------------------------------------------------------------------*/ +int +collect_neighbor_link_estimate(struct collect_neighbor *n) +{ + return collect_link_estimate(&n->le); +} +/*---------------------------------------------------------------------------*/ +int collect_neighbor_rtmetric(struct collect_neighbor *n) { return n->rtmetric + collect_link_estimate(&n->le); @@ -313,37 +346,4 @@ collect_neighbor_set_lifetime(int seconds) max_time = seconds; } /*---------------------------------------------------------------------------*/ -int -collect_neighbor_num(void) -{ - PRINTF("collect_neighbor_num %d\n", list_length(collect_neighbors_list)); - return list_length(collect_neighbors_list); -} -/*---------------------------------------------------------------------------*/ -struct collect_neighbor * -collect_neighbor_get(int num) -{ - int i; - struct collect_neighbor *n; - - PRINTF("collect_neighbor_get %d\n", num); - - i = 0; - for(n = list_head(collect_neighbors_list); n != NULL; n = list_item_next(n)) { - if(i == num) { - PRINTF("collect_neighbor_get found %d.%d\n", n->addr.u8[0], n->addr.u8[1]); - return n; - } - i++; - } - return NULL; -} -/*---------------------------------------------------------------------------*/ -void -collect_neighbor_purge(void) -{ - memb_init(&collect_neighbors_mem); - list_init(collect_neighbors_list); -} -/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/core/net/rime/collect-neighbor.h b/core/net/rime/collect-neighbor.h index 953a57654..19f3ce3ab 100644 --- a/core/net/rime/collect-neighbor.h +++ b/core/net/rime/collect-neighbor.h @@ -39,7 +39,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect-neighbor.h,v 1.2 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect-neighbor.h,v 1.3 2010/09/13 13:28:14 adamdunkels Exp $ */ /** @@ -54,6 +54,12 @@ #include "net/rime/rimeaddr.h" #include "net/rime/collect-link-estimate.h" +#include "lib/list.h" + +struct collect_neighbor_list { + LIST_STRUCT(list); + struct ctimer periodic; +}; struct collect_neighbor { struct collect_neighbor *next; @@ -64,27 +70,29 @@ struct collect_neighbor { }; void collect_neighbor_init(void); -/*void collect_neighbor_periodic(int max_time);*/ -void collect_neighbor_add(const rimeaddr_t *addr, uint8_t rtmetric); -void collect_neighbor_remove(const rimeaddr_t *addr); + +void collect_neighbor_list_new(struct collect_neighbor_list *neighbor_list); + +void collect_neighbor_list_add(struct collect_neighbor_list *neighbor_list, + const rimeaddr_t *addr, uint8_t rtmetric); +void collect_neighbor_list_remove(struct collect_neighbor_list *neighbor_list, + const rimeaddr_t *addr); +struct collect_neighbor *collect_neighbor_list_find(struct collect_neighbor_list *neighbor_list, + const rimeaddr_t *addr); +struct collect_neighbor *collect_neighbor_list_best(struct collect_neighbor_list *neighbor_list); +int collect_neighbor_list_num(struct collect_neighbor_list *neighbor_list); +struct collect_neighbor *collect_neighbor_list_get(struct collect_neighbor_list *neighbor_list, int num); +void collect_neighbor_list_purge(struct collect_neighbor_list *neighbor_list); void collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint8_t rtmetric); - -struct collect_neighbor *collect_neighbor_find(const rimeaddr_t *addr); -struct collect_neighbor *collect_neighbor_best(void); void collect_neighbor_set_lifetime(int seconds); - void collect_neighbor_tx(struct collect_neighbor *n, uint8_t num_tx); void collect_neighbor_rx(struct collect_neighbor *n); -void collect_neighbor_timedout(struct collect_neighbor *n, uint8_t num_tx); +void collect_neighbor_tx_fail(struct collect_neighbor *n, uint8_t num_tx); int collect_neighbor_link_estimate(struct collect_neighbor *n); int collect_neighbor_rtmetric(struct collect_neighbor *n); -int collect_neighbor_num(void); -struct collect_neighbor *collect_neighbor_get(int num); - -void collect_neighbor_purge(void); #endif /* __COLLECT_NEIGHBOR_H__ */ /** @} */ diff --git a/core/net/rime/collect.c b/core/net/rime/collect.c index 338fc2f8d..a5c26e089 100644 --- a/core/net/rime/collect.c +++ b/core/net/rime/collect.c @@ -33,7 +33,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect.c,v 1.50 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect.c,v 1.51 2010/09/13 13:28:14 adamdunkels Exp $ */ /** @@ -71,12 +71,12 @@ static const struct packetbuf_attrlist attributes[] = and the connection for packets that have been recently forwarded. This list is maintained to avoid forwarding duplicate packets. */ -#define NUM_RECENT_PACKETS 8 +#define NUM_RECENT_PACKETS 16 struct recent_packet { struct collect_conn *conn; rimeaddr_t originator; - uint8_t seqno; + uint8_t eseqno; }; static struct recent_packet recent_packets[NUM_RECENT_PACKETS]; @@ -95,19 +95,22 @@ struct data_msg_hdr { /* This is the header of ACK packets. It contains a flags field that indicates if the node is congested (ACK_FLAGS_CONGESTED), if the - packet was dropped (ACK_FLAGS_DROPPED), and if a packet was dropped - due to its lifetime was exceeded (ACK_FLAGS_LIFETIME_EXCEEDED). The - flags can contain any combination of the flags. The ACK header also - contains the routing metric of the node that sends tha ACK. This is - used to keep an up-to-date routing state in the network. */ + packet was dropped (ACK_FLAGS_DROPPED), if a packet was dropped due + to its lifetime was exceeded (ACK_FLAGS_LIFETIME_EXCEEDED), and if + an outdated rtmetric was detected + (ACK_FLAGS_RTMETRIC_NEEDS_UPDATE). The flags can contain any + combination of the flags. The ACK header also contains the routing + metric of the node that sends tha ACK. This is used to keep an + up-to-date routing state in the network. */ struct ack_msg { uint8_t flags, dummy; uint16_t rtmetric; }; -#define ACK_FLAGS_CONGESTED 0x80 -#define ACK_FLAGS_DROPPED 0x40 -#define ACK_FLAGS_LIFETIME_EXCEEDED 0x20 +#define ACK_FLAGS_CONGESTED 0x80 +#define ACK_FLAGS_DROPPED 0x40 +#define ACK_FLAGS_LIFETIME_EXCEEDED 0x20 +#define ACK_FLAGS_RTMETRIC_NEEDS_UPDATE 0x10 /* These are configuration knobs that normally should not be @@ -121,13 +124,12 @@ struct ack_msg { forwarding queue before it is removed. The MAX_SENDING_QUEUE specifies the maximum length of the output queue. If the queue is full, incoming packets are dropped instead of being forwarded. */ -#define MAX_MAC_REXMITS 3 -#define MAX_ACK_MAC_REXMITS 3 -#define REXMIT_TIME CLOCK_SECOND * 2 +#define MAX_MAC_REXMITS 4 +#define MAX_ACK_MAC_REXMITS 5 +#define REXMIT_TIME CLOCK_SECOND * 1 #define FORWARD_PACKET_LIFETIME (6 * (REXMIT_TIME) << 3) -#define MAX_SENDING_QUEUE 6 -PACKETQUEUE(sending_queue, MAX_SENDING_QUEUE); - +#define MAX_SENDING_QUEUE 16 +MEMB(send_queue_memb, struct packetqueue_item, MAX_SENDING_QUEUE); /* These specifiy the sink's routing metric (0) and the maximum routing metric. If a node has routing metric zero, it is the @@ -140,8 +142,8 @@ PACKETQUEUE(sending_queue, MAX_SENDING_QUEUE); rtmetric. This is used to determine when a new parent should be chosen over an old parent and when to begin more rapidly advertise a new rtmetric. */ -#define SIGNIFICANT_RTMETRIC_IMPROVEMENT (COLLECT_LINK_ESTIMATE_UNIT + \ - COLLECT_LINK_ESTIMATE_UNIT / 1) +#define SIGNIFICANT_RTMETRIC_CHANGE (COLLECT_LINK_ESTIMATE_UNIT + \ + COLLECT_LINK_ESTIMATE_UNIT / 2) /* This defines the maximum hops that a packet can take before it is dropped. */ @@ -166,6 +168,31 @@ PACKETQUEUE(sending_queue, MAX_SENDING_QUEUE); #define ANNOUNCEMENT_SCAN_TIME CLOCK_SECOND #endif /* ANNOUNCEMENT_CONF_PERIOD */ + +/* Statistics structure */ +struct { + uint32_t foundroute; + uint32_t newparent; + uint32_t routelost; + + uint32_t acksent; + uint32_t datasent; + + uint32_t datarecv; + uint32_t ackrecv; + uint32_t badack; + uint32_t duprecv; + + uint32_t qdrop; + uint32_t rtdrop; + uint32_t ttldrop; + uint32_t ackdrop; + uint32_t timedout; +} stats; + +/* Debug definition: draw routing tree in Cooja. */ +#define DRAW_TREE 1 + #define DEBUG 0 #if DEBUG #include @@ -174,7 +201,8 @@ PACKETQUEUE(sending_queue, MAX_SENDING_QUEUE); #define PRINTF(...) #endif -static void send_queued_packet(void); +/* Forward declarations. */ +static void send_queued_packet(struct collect_conn *c); static void retransmit_callback(void *ptr); /*---------------------------------------------------------------------------*/ /** @@ -196,7 +224,7 @@ rtmetric_compute(struct collect_conn *tc) /* The collect connection structure stores the address of its current parent. We look up the neighbor identification struct in the collect-neighbor list. */ - n = collect_neighbor_find(&tc->parent); + n = collect_neighbor_list_find(&tc->neighbor_list, &tc->parent); /* If n is NULL, we have no best neighbor. Thus our rtmetric is then COLLECT_RTMETRIC_MAX. */ @@ -225,11 +253,11 @@ update_parent(struct collect_conn *tc) struct collect_neighbor *best; /* We grab the collect_neighbor struct of our current parent. */ - current = collect_neighbor_find(&tc->parent); + current = collect_neighbor_list_find(&tc->neighbor_list, &tc->parent); /* We call the collect_neighbor module to find the current best parent. */ - best = collect_neighbor_best(); + best = collect_neighbor_list_best(&tc->neighbor_list); /* We check if we need to switch parent. Switching parent is done in the following situations: @@ -251,27 +279,54 @@ update_parent(struct collect_conn *tc) if(best != NULL) { if(current == NULL) { /* New parent. */ - PRINTF("update_parent: new parent %d.%d\n", best->addr.u8[0], best->addr.u8[1]); + PRINTF("update_parent: new parent %d.%d\n", + best->addr.u8[0], best->addr.u8[1]); rimeaddr_copy(&tc->parent, &best->addr); + stats.foundroute++; } else { - PRINTF("#L %d 0\n", tc->parent.u8[0]); - if(collect_neighbor_rtmetric(best) + SIGNIFICANT_RTMETRIC_IMPROVEMENT < +#if DRAW_TREE + printf("#L %d 0\n", tc->parent.u8[0]); +#endif /* DRAW_TREE */ + if(collect_neighbor_rtmetric(best) + SIGNIFICANT_RTMETRIC_CHANGE < collect_neighbor_rtmetric(current)) { /* We switch parent. */ - PRINTF("update_parent: new parent %d.%d old parent %d.%d\n", + PRINTF("update_parent: new parent %d.%d (%d) old parent %d.%d (%d)\n", best->addr.u8[0], best->addr.u8[1], - tc->parent.u8[0], tc->parent.u8[1]); + collect_neighbor_rtmetric(best), + tc->parent.u8[0], tc->parent.u8[1], + collect_neighbor_rtmetric(current)); rimeaddr_copy(&tc->parent, &best->addr); + stats.newparent++; } } - PRINTF("#L %d 1\n", tc->parent.u8[0]); +#if DRAW_TREE + printf("#L %d 1\n", tc->parent.u8[0]); +#endif /* DRAW_TREE */ } else { /* No parent. */ - PRINTF("#L %d 0\n", tc->parent.u8[0]); +#if DRAW_TREE + printf("#L %d 0\n", tc->parent.u8[0]); +#endif /* DRAW_TREE */ + stats.routelost++; rimeaddr_copy(&tc->parent, &rimeaddr_null); } } /*---------------------------------------------------------------------------*/ +/** + * This function is called when the route advertisements need to be + * transmitted more rapidly. + * + */ +static void +bump_advertisement(struct collect_conn *c) +{ +#if !COLLECT_ANNOUNCEMENTS + neighbor_discovery_start(&c->neighbor_discovery_conn, c->rtmetric); +#else + announcement_bump(&c->announcement); +#endif /* !COLLECT_ANNOUNCEMENTS */ +} +/*---------------------------------------------------------------------------*/ /** * This function is called whenever there is a chance that the routing * metric has changed. The function goes through the list of neighbors @@ -314,25 +369,24 @@ update_rtmetric(struct collect_conn *tc) if(tc->is_router) { /* If we are a router, we update our advertised rtmetric. */ - + #if COLLECT_ANNOUNCEMENTS announcement_set_value(&tc->announcement, tc->rtmetric); #else /* COLLECT_ANNOUNCEMENTS */ neighbor_discovery_set_val(&tc->neighbor_discovery_conn, tc->rtmetric); #endif /* COLLECT_ANNOUNCEMENTS */ - /* If we now have a significantly better rtmetric than we had - before, what we need to make sure that our neighbors find out - about this quickly. */ - if(new_rtmetric + SIGNIFICANT_RTMETRIC_IMPROVEMENT < old_rtmetric) { -#if ! COLLECT_ANNOUNCEMENTS - neighbor_discovery_start(&tc->neighbor_discovery_conn, tc->rtmetric); -#else /* ! COLLECT_ANNOUNCEMENTS */ - announcement_bump(&tc->announcement); -#endif /* ! COLLECT_ANNOUNCEMENTS */ + /* If we now have a significantly better or worse rtmetric than + we had before, what we need to make sure that our neighbors + find out about this quickly. */ + if(new_rtmetric + SIGNIFICANT_RTMETRIC_CHANGE < old_rtmetric && + new_rtmetric > old_rtmetric + SIGNIFICANT_RTMETRIC_CHANGE) { + PRINTF("update_rtmetric: new_rtmetric %d + %d < old_rtmetric %d\n", + new_rtmetric, SIGNIFICANT_RTMETRIC_CHANGE, old_rtmetric); + bump_advertisement(tc); } } - + PRINTF("%d.%d: new rtmetric %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], tc->rtmetric); @@ -340,10 +394,13 @@ update_rtmetric(struct collect_conn *tc) /* We got a new, working, route we send any queued packets we may have. */ if(old_rtmetric == RTMETRIC_MAX && new_rtmetric != RTMETRIC_MAX) { PRINTF("Sending queued packet because rtmetric was max\n"); - send_queued_packet(); + send_queued_packet(tc); } } +#if DRAW_TREE + printf("#A rt=%d,p=%d\n", tc->rtmetric, tc->parent.u8[0]); +#endif /* DRAW_TREE */ } /*---------------------------------------------------------------------------*/ /** @@ -354,15 +411,16 @@ update_rtmetric(struct collect_conn *tc) * */ static void -send_queued_packet(void) +send_queued_packet(struct collect_conn *c) { struct queuebuf *q; struct collect_neighbor *n; struct packetqueue_item *i; - struct collect_conn *c; + struct data_msg_hdr hdr; + int max_mac_rexmits; /* Grab the first packet on the send queue. */ - i = packetqueue_first(&sending_queue); + i = packetqueue_first(&c->send_queue); if(i == NULL) { PRINTF("%d.%d: nothing on queue\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); @@ -370,16 +428,6 @@ send_queued_packet(void) return; } - /* Obtain the Collect connection on which this packet should be - sent. */ - c = packetqueue_ptr(i); - if(c == NULL) { - /* c should not be NULL, but we check it just to be sure. */ - PRINTF("%d.%d: queue, c == NULL!\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); - return; - } - if(c->sending) { /* If we are currently sending a packet, we wait until the packet is forwarded and try again then. */ @@ -396,16 +444,14 @@ send_queued_packet(void) /* Pick the neighbor to which to send the packet. We use the parent in the n->parent. */ - n = collect_neighbor_find(&c->parent); + n = collect_neighbor_list_find(&c->neighbor_list, &c->parent); if(n != NULL) { - clock_time_t time; - uint8_t rexmit_time_scaling; /* If the connection had a neighbor, we construct the packet buffer attributes and set the appropriate flags in the Collect connection structure and send the packet. */ - + PRINTF("%d.%d: sending packet to %d.%d with eseqno %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], n->addr.u8[0], n->addr.u8[1], @@ -414,6 +460,9 @@ send_queued_packet(void) /* Mark that we are currently sending a packet. */ c->sending = 1; + /* Remember the parent that we sent this packet to. */ + rimeaddr_copy(&c->current_parent, &c->parent); + /* This is the first time we transmit this packet, so set transmissions to zero. */ c->transmissions = 0; @@ -428,30 +477,30 @@ send_queued_packet(void) MAX_MAC_REXMITS times; and the PACKETBUF_ATTR_PACKET_ID is set to the current sequence number on the connection. */ packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1); - packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, MAX_MAC_REXMITS); + + max_mac_rexmits = c->max_rexmits > MAX_MAC_REXMITS? + MAX_MAC_REXMITS : c->max_rexmits; + packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, max_mac_rexmits); packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->seqno); + stats.datasent++; + + /* Copy our rtmetric into the packet header of the outgoing + packet. */ + memset(&hdr, 0, sizeof(hdr)); + hdr.rtmetric = c->rtmetric; + memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr)); + /* Send the packet. */ unicast_send(&c->unicast_conn, &n->addr); - /* Compute the retransmission timeout and set up the - retransmission timer. */ - rexmit_time_scaling = c->transmissions; - if(rexmit_time_scaling > 3) { - rexmit_time_scaling = 3; - } - time = REXMIT_TIME << rexmit_time_scaling; - time = time / 2 + random_rand() % (time / 2); - PRINTF("retransmission time %lu scaling %d\n", time, rexmit_time_scaling); - ctimer_set(&c->retransmission_timer, time, - retransmit_callback, c); } else { #if COLLECT_ANNOUNCEMENTS #if COLLECT_CONF_WITH_LISTEN PRINTF("listen\n"); announcement_listen(1); ctimer_set(&c->transmit_after_scan_timer, ANNOUNCEMENT_SCAN_TIME, - send_queued_packet, NULL); + send_queued_packet, tc); #else /* COLLECT_CONF_WITH_LISTEN */ announcement_set_value(&c->announcement, RTMETRIC_MAX); announcement_bump(&c->announcement); @@ -462,26 +511,89 @@ send_queued_packet(void) } /*---------------------------------------------------------------------------*/ /** - * This function is called + * This function is called to retransmit the first packet on the send + * queue. * */ static void +retransmit_current_packet(struct collect_conn *c) +{ + struct queuebuf *q; + struct collect_neighbor *n; + struct packetqueue_item *i; + struct data_msg_hdr hdr; + int max_mac_rexmits; + + /* Grab the first packet on the send queue, which is the one we are + about to retransmit. */ + i = packetqueue_first(&c->send_queue); + if(i == NULL) { + PRINTF("%d.%d: nothing on queue\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); + /* No packet on the queue, so there is nothing for us to send. */ + return; + } + + /* Get hold of the queuebuf. */ + q = packetqueue_queuebuf(i); + if(q != NULL) { + /* Place the queued packet into the packetbuf. */ + queuebuf_to_packetbuf(q); + + /* Pick the neighbor to which to send the packet. We use the + parent in the n->parent. */ + n = collect_neighbor_list_find(&c->neighbor_list, &c->current_parent); + + if(n != NULL) { + + /* If the connection had a neighbor, we construct the packet + buffer attributes and set the appropriate flags in the + Collect connection structure and send the packet. */ + + PRINTF("%d.%d: sending packet to %d.%d with eseqno %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + n->addr.u8[0], n->addr.u8[1], + packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID)); + + /* Mark that we are currently sending a packet. */ + c->sending = 1; + packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1); + max_mac_rexmits = c->max_rexmits - c->transmissions > MAX_MAC_REXMITS? + MAX_MAC_REXMITS : c->max_rexmits - c->transmissions; + packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, max_mac_rexmits); + packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->seqno); + + /* Copy our rtmetric into the packet header of the outgoing + packet. */ + memset(&hdr, 0, sizeof(hdr)); + hdr.rtmetric = c->rtmetric; + memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr)); + + /* Send the packet. */ + unicast_send(&c->unicast_conn, &n->addr); + + } + } + +} +/*---------------------------------------------------------------------------*/ +static void send_next_packet(struct collect_conn *tc) { /* Cancel retransmission timer. */ ctimer_stop(&tc->retransmission_timer); /* Remove the first packet on the queue, the packet that was just sent. */ - packetqueue_dequeue(&sending_queue); + packetqueue_dequeue(&tc->send_queue); tc->seqno = (tc->seqno + 1) % (1 << COLLECT_PACKET_ID_BITS); tc->sending = 0; tc->transmissions = 0; PRINTF("sending next packet, seqno %d, queue len %d\n", - tc->seqno, packetqueue_len(&sending_queue)); + tc->seqno, packetqueue_len(&tc->send_queue)); /* Send the next packet in the queue, if any. */ - send_queued_packet(); + send_queued_packet(tc); } /*---------------------------------------------------------------------------*/ static void @@ -491,38 +603,61 @@ handle_ack(struct collect_conn *tc) uint16_t rtmetric; struct collect_neighbor *n; - PRINTF("handle_ack: sender %d.%d parent %d.%d, id %d seqno %d\n", + PRINTF("handle_ack: sender %d.%d current_parent %d.%d, id %d seqno %d\n", packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[1], - tc->parent.u8[0], tc->parent.u8[1], + tc->current_parent.u8[0], tc->current_parent.u8[1], packetbuf_attr(PACKETBUF_ATTR_PACKET_ID), tc->seqno); if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), - &tc->parent) && + &tc->current_parent) && packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == tc->seqno) { + stats.ackrecv++; msg = packetbuf_dataptr(); memcpy(&rtmetric, &msg->rtmetric, sizeof(uint16_t)); - n = collect_neighbor_find(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + + /* It is possible that we receive an ACK for a packet that we + think we have not yet sent: if our transmission was received by + the other node, but the link-layer ACK was lost, our + transmission counter may still be zero. If this is the case, we + play it safe by believing that we have sent MAX_MAC_REXMITS + transmissions. */ + if(tc->transmissions == 0) { + tc->transmissions = MAX_MAC_REXMITS; + } + PRINTF("Updating link estimate with %d transmissions\n", + tc->transmissions); + n = collect_neighbor_list_find(&tc->neighbor_list, + packetbuf_addr(PACKETBUF_ADDR_SENDER)); + collect_neighbor_tx(n, tc->transmissions); + if(n != NULL) { collect_neighbor_update_rtmetric(n, rtmetric); update_rtmetric(tc); } - - PRINTF("%d.%d: ACK from %d.%d after %d transmissions, flags %02x\n", + + PRINTF("%d.%d: ACK from %d.%d after %d transmissions, flags %02x, rtmetric %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - tc->parent.u8[0], tc->parent.u8[1], + tc->current_parent.u8[0], tc->current_parent.u8[1], tc->transmissions, - msg->flags); + msg->flags, + rtmetric); if(!(msg->flags & ACK_FLAGS_DROPPED)) { send_next_packet(tc); } - } + if(msg->flags & ACK_FLAGS_RTMETRIC_NEEDS_UPDATE) { + bump_advertisement(tc); + } + } else { + stats.badack++; + } } /*---------------------------------------------------------------------------*/ static void send_ack(struct collect_conn *tc, const rimeaddr_t *to, int flags) -{ struct ack_msg *ack; +{ + struct ack_msg *ack; struct queuebuf *q; uint16_t packet_seqno, packet_eseqno; @@ -557,11 +692,13 @@ send_ack(struct collect_conn *tc, const rimeaddr_t *to, int flags) queuebuf_to_packetbuf(q); queuebuf_free(q); + stats.acksent++; } else { PRINTF("%d.%d: collect: could not send ACK to %d.%d for %d: no queued buffers\n", rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1], to->u8[0], to->u8[1], packet_seqno); + stats.ackdrop++; } } /*---------------------------------------------------------------------------*/ @@ -571,6 +708,22 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) struct collect_conn *tc = (struct collect_conn *) ((char *)c - offsetof(struct collect_conn, unicast_conn)); int i; + struct data_msg_hdr hdr; + uint8_t ackflags = 0; + struct collect_neighbor *n; + + memcpy(&hdr, packetbuf_dataptr(), sizeof(struct data_msg_hdr)); + + /* First update the neighbors rtmetric with the information in the + packet header. */ + PRINTF("node_packet_received: from %d.%d rtmetric %d\n", + from->u8[0], from->u8[1], hdr.rtmetric); + n = collect_neighbor_list_find(&tc->neighbor_list, + packetbuf_addr(PACKETBUF_ADDR_SENDER)); + if(n != NULL) { + collect_neighbor_update_rtmetric(n, hdr.rtmetric); + update_rtmetric(tc); + } /* To protect against sending duplicate packets, we keep a list of recently forwarded packet seqnos. If the seqno of the current @@ -581,6 +734,8 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) rimeaddr_t ack_to; uint8_t packet_seqno; + stats.datarecv++; + /* Remember to whom we should send the ACK, since we reuse the packet buffer and its attributes when sending the ACK. */ rimeaddr_copy(&ack_to, packetbuf_addr(PACKETBUF_ADDR_SENDER)); @@ -588,7 +743,7 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) for(i = 0; i < NUM_RECENT_PACKETS; i++) { if(recent_packets[i].conn == tc && - recent_packets[i].seqno == packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID) && + recent_packets[i].eseqno == packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID) && rimeaddr_cmp(&recent_packets[i].originator, packetbuf_addr(PACKETBUF_ADDR_ESENDER))) { /* This is a duplicate of a packet we recently received, so we @@ -600,12 +755,14 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[1]); send_ack(tc, &ack_to, 0); + stats.duprecv++; return; } } /* Remember that we have seen this packet for later. */ - recent_packets[recent_packet_ptr].seqno = packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID); + recent_packets[recent_packet_ptr].eseqno = + packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID); rimeaddr_copy(&recent_packets[recent_packet_ptr].originator, packetbuf_addr(PACKETBUF_ADDR_ESENDER)); recent_packets[recent_packet_ptr].conn = tc; @@ -626,6 +783,7 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[1], from->u8[0], from->u8[1]); + packetbuf_hdrreduce(sizeof(struct data_msg_hdr)); /* Call receive function. */ if(tc->cb->recv != NULL) { tc->cb->recv(packetbuf_addr(PACKETBUF_ADDR_ESENDER), @@ -635,14 +793,25 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) return; } else if(packetbuf_attr(PACKETBUF_ATTR_TTL) > 1 && tc->rtmetric != RTMETRIC_MAX) { - /* If we are not the sink, we forward the packet to our best - neighbor. First, we update the hop count and ttl. */ + neighbor. First, we make sure that the packet comes from a + neighbor that has a higher rtmetric than we have. If not, we + have a loop and we inform the sender that its rtmetric needs + to be updated. Second, we set our rtmetric in the outgoing + packet to let the next hop know what our rtmetric is. Third, + we update the hop count and ttl. */ + + if(hdr.rtmetric <= tc->rtmetric) { + ackflags |= ACK_FLAGS_RTMETRIC_NEEDS_UPDATE; + bump_advertisement(tc); + } + packetbuf_set_attr(PACKETBUF_ATTR_HOPS, packetbuf_attr(PACKETBUF_ATTR_HOPS) + 1); packetbuf_set_attr(PACKETBUF_ATTR_TTL, packetbuf_attr(PACKETBUF_ATTR_TTL) - 1); + PRINTF("%d.%d: packet received from %d.%d via %d.%d, sending %d, max_rexmits %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[0], @@ -655,20 +824,23 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) we are unable to enqueue the packet, we send a negative ACK to inform the sender that the packet was dropped due to memory problems. */ - if(packetqueue_enqueue_packetbuf(&sending_queue, + if(packetqueue_enqueue_packetbuf(&tc->send_queue, FORWARD_PACKET_LIFETIME, tc)) { - send_ack(tc, &ack_to, 0); - send_queued_packet(); + send_ack(tc, &ack_to, ackflags); + send_queued_packet(tc); } else { - send_ack(tc, &ack_to, ACK_FLAGS_DROPPED | ACK_FLAGS_CONGESTED); + send_ack(tc, &ack_to, ackflags | ACK_FLAGS_DROPPED | ACK_FLAGS_CONGESTED); PRINTF("%d.%d: packet dropped: no queue buffer available\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); + stats.qdrop++; } } else if(packetbuf_attr(PACKETBUF_ATTR_TTL) <= 1) { PRINTF("%d.%d: packet dropped: ttl %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], packetbuf_attr(PACKETBUF_ATTR_TTL)); - send_ack(tc, &ack_to, ACK_FLAGS_DROPPED | ACK_FLAGS_LIFETIME_EXCEEDED); + send_ack(tc, &ack_to, ackflags | + ACK_FLAGS_DROPPED | ACK_FLAGS_LIFETIME_EXCEEDED); + stats.ttldrop++; } } else if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) { @@ -676,11 +848,12 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE), packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_SENDER)->u8[1], - tc->parent.u8[0], - tc->parent.u8[1], + tc->current_parent.u8[0], + tc->current_parent.u8[1], packetbuf_attr(PACKETBUF_ATTR_PACKET_ID), tc->seqno); handle_ack(tc); + stats.ackrecv++; } return; } @@ -688,40 +861,48 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) static void node_packet_sent(struct unicast_conn *c, int status, int transmissions) { - uint16_t tx; struct collect_conn *tc = (struct collect_conn *) ((char *)c - offsetof(struct collect_conn, unicast_conn)); + clock_time_t time; + uint8_t rexmit_time_scaling; /* For data packets, we record the number of transmissions */ if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA && transmissions > 0) { - PRINTF("%d.%d: sent to %d.%d after %d transmissions\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - tc->parent.u8[0], tc->parent.u8[1], - transmissions); tc->transmissions += transmissions; + + PRINTF("%d.%d: MAC sent %d transmissions to %d.%d, status %d, total transmissions %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + transmissions, + tc->current_parent.u8[0], tc->current_parent.u8[1], + status, tc->transmissions); - tx = tc->transmissions; - - /* Update neighgor with the number of transmissions. */ - PRINTF("Updating link estimate with %d (%d) transmissions\n", - tc->transmissions, tx); - collect_neighbor_tx(collect_neighbor_find(&tc->parent), tx); - - update_rtmetric(tc); + /* Compute the retransmission timeout and set up the + retransmission timer. */ + rexmit_time_scaling = tc->transmissions / MAX_MAC_REXMITS; + if(rexmit_time_scaling > 3) { + rexmit_time_scaling = 3; + } + time = REXMIT_TIME << rexmit_time_scaling; + time = time / 2 + random_rand() % (time / 2); + PRINTF("retransmission time %lu scaling %d\n", time, rexmit_time_scaling); + ctimer_set(&tc->retransmission_timer, time, + retransmit_callback, tc); } } /*---------------------------------------------------------------------------*/ static void timedout(struct collect_conn *tc) { - PRINTF("%d.%d: timedout after %d retransmissions (max retransmissions %d): packet dropped\n", + printf("%d.%d: timedout after %d retransmissions (max retransmissions %d): packet dropped\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], tc->transmissions, tc->max_rexmits); tc->sending = 0; - collect_neighbor_timedout(collect_neighbor_find(&tc->parent), tc->transmissions); + collect_neighbor_tx_fail(collect_neighbor_list_find(&tc->neighbor_list, + &tc->current_parent), + tc->max_rexmits); update_rtmetric(tc); send_next_packet(tc); @@ -732,12 +913,13 @@ retransmit_callback(void *ptr) { struct collect_conn *c = ptr; - PRINTF("retransmit\n"); + PRINTF("retransmit, %d transmissions\n", c->transmissions); if(c->transmissions >= c->max_rexmits) { timedout(c); + stats.timedout++; } else { c->sending = 0; - send_queued_packet(); + retransmit_current_packet(c); } } /*---------------------------------------------------------------------------*/ @@ -750,10 +932,10 @@ adv_received(struct neighbor_discovery_conn *c, const rimeaddr_t *from, ((char *)c - offsetof(struct collect_conn, neighbor_discovery_conn)); struct collect_neighbor *n; - n = collect_neighbor_find(from); + n = collect_neighbor_list_find(&tc->neighbor_list, from); if(n == NULL) { - collect_neighbor_add(from, rtmetric); + collect_neighbor_list_add(&tc->neighbor_list, from, rtmetric); } else { collect_neighbor_update_rtmetric(n, rtmetric); PRINTF("%d.%d: updating neighbor %d.%d, etx %d\n", @@ -772,10 +954,10 @@ received_announcement(struct announcement *a, const rimeaddr_t *from, ((char *)a - offsetof(struct collect_conn, announcement)); struct collect_neighbor *n; - n = collect_neighbor_find(from); + n = collect_neighbor_list_find(&tc->neighbor_list, from); if(n == NULL) { - collect_neighbor_add(from, value); + collect_neighbor_list_add(&tc->neighbor_list, from, value); PRINTF("%d.%d: new neighbor %d.%d, etx %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], from->u8[0], from->u8[1], value); @@ -815,8 +997,11 @@ collect_open(struct collect_conn *tc, uint16_t channels, tc->cb = cb; tc->is_router = is_router; tc->seqno = 10; + LIST_STRUCT_INIT(tc, send_queue_list); + collect_neighbor_list_new(&tc->neighbor_list); + tc->send_queue.list = &(tc->send_queue_list); + tc->send_queue.memb = &send_queue_memb; collect_neighbor_init(); - packetqueue_init(&sending_queue); #if !COLLECT_ANNOUNCEMENTS neighbor_discovery_open(&tc->neighbor_discovery_conn, channels, @@ -843,6 +1028,9 @@ collect_close(struct collect_conn *tc) neighbor_discovery_close(&tc->neighbor_discovery_conn); #endif /* COLLECT_ANNOUNCEMENTS */ unicast_close(&tc->unicast_conn); + while(packetqueue_first(&tc->send_queue) != NULL) { + packetqueue_dequeue(&tc->send_queue); + } } /*---------------------------------------------------------------------------*/ void @@ -852,11 +1040,7 @@ collect_set_sink(struct collect_conn *tc, int should_be_sink) tc->is_router = 1; tc->rtmetric = RTMETRIC_SINK; PRINTF("collect_set_sink: tc->rtmetric %d\n", tc->rtmetric); -#if !COLLECT_ANNOUNCEMENTS - neighbor_discovery_start(&tc->neighbor_discovery_conn, tc->rtmetric); -#else - announcement_bump(&tc->announcement); -#endif /* !COLLECT_ANNOUNCEMENTS */ + bump_advertisement(tc); } else { tc->rtmetric = RTMETRIC_MAX; } @@ -882,8 +1066,6 @@ collect_send(struct collect_conn *tc, int rexmits) packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID), packetbuf_attr(PACKETBUF_ATTR_MAX_REXMIT)); - // PRINTF("rexmit %d\n", rexmits); - if(tc->rtmetric == RTMETRIC_SINK) { packetbuf_set_attr(PACKETBUF_ATTR_HOPS, 0); if(tc->cb->recv != NULL) { @@ -893,16 +1075,20 @@ collect_send(struct collect_conn *tc, int rexmits) } return 1; } else { - // update_rtmetric(tc); - n = collect_neighbor_best(); + + /* Allocate space for the header. */ + packetbuf_hdralloc(sizeof(struct data_msg_hdr)); + + n = collect_neighbor_list_find(&tc->neighbor_list, &tc->parent); if(n != NULL) { PRINTF("%d.%d: sending to %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], n->addr.u8[0], n->addr.u8[1]); - if(packetqueue_enqueue_packetbuf(&sending_queue, FORWARD_PACKET_LIFETIME, + if(packetqueue_enqueue_packetbuf(&tc->send_queue, + FORWARD_PACKET_LIFETIME, tc)) { - send_queued_packet(); + send_queued_packet(tc); return 1; } else { PRINTF("%d.%d: drop originated packet: no queuebuf\n", @@ -917,14 +1103,15 @@ collect_send(struct collect_conn *tc, int rexmits) PRINTF("listen\n"); announcement_listen(1); ctimer_set(&tc->transmit_after_scan_timer, ANNOUNCEMENT_SCAN_TIME, - send_queued_packet, NULL); + send_queued_packet, tc); #else /* COLLECT_CONF_WITH_LISTEN */ announcement_set_value(&tc->announcement, RTMETRIC_MAX); announcement_bump(&tc->announcement); #endif /* COLLECT_CONF_WITH_LISTEN */ #endif /* COLLECT_ANNOUNCEMENTS */ - if(packetqueue_enqueue_packetbuf(&sending_queue, FORWARD_PACKET_LIFETIME, + if(packetqueue_enqueue_packetbuf(&tc->send_queue, + FORWARD_PACKET_LIFETIME, tc)) { return 1; } else { @@ -945,10 +1132,23 @@ collect_depth(struct collect_conn *tc) void collect_purge(struct collect_conn *tc) { - collect_neighbor_purge(); + collect_neighbor_list_purge(&tc->neighbor_list); update_rtmetric(tc); - PRINTF("#L %d 0\n", tc->parent.u8[0]); +#if DRAW_TREE + printf("#L %d 0\n", tc->parent.u8[0]); +#endif /* DRAW_TREE */ rimeaddr_copy(&tc->parent, &rimeaddr_null); } /*---------------------------------------------------------------------------*/ +void +collect_print_stats(void) +{ + printf("collect stats foundroute %lu newparent %lu routelost %lu acksent %lu datasent %lu datarecv %lu ackrecv %lu badack %lu duprecv %lu qdrop %lu rtdrop %lu ttldrop %lu ackdrop %lu timedout %lu\n", + stats.foundroute, stats.newparent, stats.routelost, + stats.acksent, stats.datasent, stats.datarecv, + stats.ackrecv, stats.badack, stats.duprecv, + stats.qdrop, stats.rtdrop, stats.ttldrop, stats.ackdrop, + stats.timedout); +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/core/net/rime/collect.h b/core/net/rime/collect.h index cd2c6e0d0..88a8815a1 100644 --- a/core/net/rime/collect.h +++ b/core/net/rime/collect.h @@ -47,7 +47,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect.h,v 1.19 2010/09/08 19:21:45 adamdunkels Exp $ + * $Id: collect.h,v 1.20 2010/09/13 13:28:14 adamdunkels Exp $ */ /** @@ -63,7 +63,10 @@ #include "net/rime/announcement.h" #include "net/rime/runicast.h" #include "net/rime/neighbor-discovery.h" +#include "net/rime/collect-neighbor.h" +#include "net/packetqueue.h" #include "sys/ctimer.h" +#include "lib/list.h" #define COLLECT_PACKET_ID_BITS 8 @@ -92,10 +95,12 @@ struct collect_conn { const struct collect_callbacks *cb; struct ctimer t; struct ctimer retransmission_timer; - rimeaddr_t parent; - /* rimeaddr_t last_received_addr;*/ + LIST_STRUCT(send_queue_list); + struct packetqueue send_queue; + struct collect_neighbor_list neighbor_list; + rimeaddr_t parent, current_parent; uint16_t rtmetric; - uint8_t seqno; /*, last_received_seqno;*/ + uint8_t seqno; uint8_t sending, transmissions, max_rexmits; uint8_t eseqno; uint8_t is_router; @@ -117,6 +122,8 @@ void collect_set_sink(struct collect_conn *c, int should_be_sink); int collect_depth(struct collect_conn *c); +void collect_print_stats(void); + #define COLLECT_MAX_DEPTH 255 #endif /* __COLLECT_H__ */