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:
parent
e64dca7b77
commit
591766e663
6 changed files with 491 additions and 270 deletions
|
@ -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;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
||||
|
|
|
@ -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__ */
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in a new issue