Significant improvements to the Collect protocol:

* Loop detection and untangling. Now uses in-band loop detection that
  works.

* Link quality estimation. Now starts with a conservative /
  pessimistic estimate for new links.

* Retransmissions. MAC layer and network layer retransmissions are now
  decoupled.

* Loss handling. Deals better with losses now.

* Concurrent applications. Each connection now maintains its own
  neighbor table with separated cost to sink estimates for each
  connection.
This commit is contained in:
adamdunkels 2010-09-13 13:28:14 +00:00
parent e64dca7b77
commit 591766e663
6 changed files with 491 additions and 270 deletions

View file

@ -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 <adam@sics.se>
*/
@ -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;
}
/*---------------------------------------------------------------------------*/

View file

@ -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

View file

@ -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);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -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__ */
/** @} */

View file

@ -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 <stdio.h>
@ -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);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -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__ */