Contiki 2.5
collect-neighbor.c
Go to the documentation of this file.
1 /**
2  * \addtogroup rimecollect_neighbor
3  * @{
4  */
5 
6 /*
7  * Copyright (c) 2006, Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the Institute nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * This file is part of the Contiki operating system.
35  *
36  * $Id: collect-neighbor.c,v 1.10 2011/01/10 15:08:52 adamdunkels Exp $
37  */
38 
39 /**
40  * \file
41  * Radio neighborhood management
42  * \author
43  * Adam Dunkels <adam@sics.se>
44  */
45 
46 #include <limits.h>
47 #include <stdio.h>
48 
49 #include "contiki.h"
50 #include "lib/memb.h"
51 #include "lib/list.h"
52 
54 #include "net/rime/collect.h"
55 
56 #ifdef COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
57 #define MAX_COLLECT_NEIGHBORS COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
58 #else /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
59 #define MAX_COLLECT_NEIGHBORS 8
60 #endif /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
61 
62 #define RTMETRIC_MAX COLLECT_MAX_DEPTH
63 
64 MEMB(collect_neighbors_mem, struct collect_neighbor, MAX_COLLECT_NEIGHBORS);
65 
66 #define MAX_AGE 180
67 #define MAX_LE_AGE 10
68 #define PERIODIC_INTERVAL CLOCK_SECOND * 60
69 
70 #define EXPECTED_CONGESTION_DURATION CLOCK_SECOND * 240
71 #define CONGESTION_PENALTY 8 * COLLECT_LINK_ESTIMATE_UNIT
72 
73 #define DEBUG 0
74 #if DEBUG
75 #include <stdio.h>
76 #define PRINTF(...) printf(__VA_ARGS__)
77 #else
78 #define PRINTF(...)
79 #endif
80 
81 /*---------------------------------------------------------------------------*/
82 static void
83 periodic(void *ptr)
84 {
85  struct collect_neighbor_list *neighbor_list;
86  struct collect_neighbor *n;
87 
88  neighbor_list = ptr;
89 
90  /* Go through all collect_neighbors and increase their age. */
91  for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
92  n->age++;
93  n->le_age++;
94  }
95  for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
96  if(n->le_age == MAX_LE_AGE) {
98  n->le_age = 0;
99  }
100  if(n->age == MAX_AGE) {
101  memb_free(&collect_neighbors_mem, n);
102  list_remove(neighbor_list->list, n);
103  n = list_head(neighbor_list->list);
104  }
105  }
106  ctimer_set(&neighbor_list->periodic, PERIODIC_INTERVAL,
107  periodic, neighbor_list);
108 }
109 /*---------------------------------------------------------------------------*/
110 void
111 collect_neighbor_init(void)
112 {
113  static uint8_t initialized = 0;
114  if(initialized == 0) {
115  initialized = 1;
116  memb_init(&collect_neighbors_mem);
117  }
118 }
119 /*---------------------------------------------------------------------------*/
120 void
121 collect_neighbor_list_new(struct collect_neighbor_list *neighbors_list)
122 {
123  LIST_STRUCT_INIT(neighbors_list, list);
124  list_init(neighbors_list->list);
125  ctimer_set(&neighbors_list->periodic, CLOCK_SECOND, periodic, neighbors_list);
126 }
127 /*---------------------------------------------------------------------------*/
128 struct collect_neighbor *
129 collect_neighbor_list_find(struct collect_neighbor_list *neighbors_list,
130  const rimeaddr_t *addr)
131 {
132  struct collect_neighbor *n;
133  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
134  if(rimeaddr_cmp(&n->addr, addr)) {
135  return n;
136  }
137  }
138  return NULL;
139 }
140 /*---------------------------------------------------------------------------*/
141 int
142 collect_neighbor_list_add(struct collect_neighbor_list *neighbors_list,
143  const rimeaddr_t *addr, uint16_t nrtmetric)
144 {
145  struct collect_neighbor *n;
146 
147  if(addr == NULL) {
148  PRINTF("collect_neighbor_list_add: attempt to add NULL addr\n");
149  return 0;
150  }
151 
152  PRINTF("collect_neighbor_add: adding %d.%d\n", addr->u8[0], addr->u8[1]);
153 
154  /* Check if the collect_neighbor is already on the list. */
155  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
156  if(rimeaddr_cmp(&n->addr, addr)) {
157  PRINTF("collect_neighbor_add: already on list %d.%d\n",
158  addr->u8[0], addr->u8[1]);
159  break;
160  }
161  }
162 
163  /* If the collect_neighbor was not on the list, we try to allocate memory
164  for it. */
165  if(n == NULL) {
166  PRINTF("collect_neighbor_add: not on list, allocating %d.%d\n",
167  addr->u8[0], addr->u8[1]);
168  n = memb_alloc(&collect_neighbors_mem);
169  if(n != NULL) {
170  list_add(neighbors_list->list, n);
171  }
172  }
173 
174  /* If we could not allocate memory, we try to recycle an old
175  neighbor. XXX Should also look for the one with the worst
176  rtmetric (not link esimate). XXX Also make sure that we don't
177  replace a neighbor with a neighbor that has a worse metric. */
178  if(n == NULL) {
179  uint16_t worst_rtmetric;
180  struct collect_neighbor *worst_neighbor;
181 
182  /* Find the neighbor that has the highest rtmetric. This is the
183  neighbor that we are least likely to be using in the
184  future. But we also need to make sure that the neighbor we are
185  currently adding is not worst than the one we would be
186  replacing. If so, we don't put the new neighbor on the list. */
187  worst_rtmetric = 0;
188  worst_neighbor = NULL;
189 
190  for(n = list_head(neighbors_list->list);
191  n != NULL; n = list_item_next(n)) {
192  if(n->rtmetric > worst_rtmetric) {
193  worst_neighbor = n;
194  worst_rtmetric = n->rtmetric;
195  }
196  }
197 
198  /* Only add this new neighbor if its rtmetric is lower than the
199  one it would replace. */
200  if(nrtmetric < worst_rtmetric) {
201  n = worst_neighbor;
202  }
203  if(n != NULL) {
204  PRINTF("collect_neighbor_add: not on list, not allocated, recycling %d.%d\n",
205  n->addr.u8[0], n->addr.u8[1]);
206  }
207  }
208 
209  if(n != NULL) {
210  n->age = 0;
211  rimeaddr_copy(&n->addr, addr);
212  n->rtmetric = nrtmetric;
214  n->le_age = 0;
215  return 1;
216  }
217  return 0;
218 }
219 /*---------------------------------------------------------------------------*/
220 list_t
221 collect_neighbor_list(struct collect_neighbor_list *neighbors_list)
222 {
223  return neighbors_list->list;
224 }
225 /*---------------------------------------------------------------------------*/
226 void
227 collect_neighbor_list_remove(struct collect_neighbor_list *neighbors_list,
228  const rimeaddr_t *addr)
229 {
230  struct collect_neighbor *n = collect_neighbor_list_find(neighbors_list, addr);
231 
232  if(n != NULL) {
233  list_remove(neighbors_list->list, n);
234  memb_free(&collect_neighbors_mem, n);
235  }
236 }
237 /*---------------------------------------------------------------------------*/
238 struct collect_neighbor *
239 collect_neighbor_list_best(struct collect_neighbor_list *neighbors_list)
240 {
241  int found;
242  struct collect_neighbor *n, *best;
243  uint16_t rtmetric;
244 
245  rtmetric = RTMETRIC_MAX;
246  best = NULL;
247  found = 0;
248 
249  /* PRINTF("%d: ", node_id);*/
250  PRINTF("collect_neighbor_best: ");
251 
252  /* Find the neighbor with the lowest rtmetric + linkt estimate. */
253  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
254  PRINTF("%d.%d %d+%d=%d, ",
255  n->addr.u8[0], n->addr.u8[1],
256  n->rtmetric, collect_neighbor_link_estimate(n),
257  collect_neighbor_rtmetric(n));
258  if(collect_neighbor_rtmetric_link_estimate(n) < rtmetric) {
259  rtmetric = collect_neighbor_rtmetric_link_estimate(n);
260  best = n;
261  }
262  }
263  PRINTF("\n");
264 
265  return best;
266 }
267 /*---------------------------------------------------------------------------*/
268 int
269 collect_neighbor_list_num(struct collect_neighbor_list *neighbors_list)
270 {
271  PRINTF("collect_neighbor_num %d\n", list_length(neighbors_list->list));
272  return list_length(neighbors_list->list);
273 }
274 /*---------------------------------------------------------------------------*/
275 struct collect_neighbor *
276 collect_neighbor_list_get(struct collect_neighbor_list *neighbors_list, int num)
277 {
278  int i;
279  struct collect_neighbor *n;
280 
281  PRINTF("collect_neighbor_get %d\n", num);
282 
283  i = 0;
284  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
285  if(i == num) {
286  PRINTF("collect_neighbor_get found %d.%d\n",
287  n->addr.u8[0], n->addr.u8[1]);
288  return n;
289  }
290  i++;
291  }
292  return NULL;
293 }
294 /*---------------------------------------------------------------------------*/
295 void
296 collect_neighbor_list_purge(struct collect_neighbor_list *neighbors_list)
297 {
298  while(list_head(neighbors_list->list) != NULL) {
299  memb_free(&collect_neighbors_mem, list_pop(neighbors_list->list));
300  }
301 }
302 /*---------------------------------------------------------------------------*/
303 void
304 collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint16_t rtmetric)
305 {
306  if(n != NULL) {
307  PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n",
309  n->addr.u8[0], n->addr.u8[1], rtmetric);
310  n->rtmetric = rtmetric;
311  n->age = 0;
312  }
313 }
314 /*---------------------------------------------------------------------------*/
315 void
316 collect_neighbor_tx_fail(struct collect_neighbor *n, uint16_t num_tx)
317 {
318  collect_link_estimate_update_tx_fail(&n->le, num_tx);
319  n->le_age = 0;
320  n->age = 0;
321 }
322 /*---------------------------------------------------------------------------*/
323 void
324 collect_neighbor_tx(struct collect_neighbor *n, uint16_t num_tx)
325 {
326  collect_link_estimate_update_tx(&n->le, num_tx);
327  n->le_age = 0;
328  n->age = 0;
329 }
330 /*---------------------------------------------------------------------------*/
331 void
332 collect_neighbor_rx(struct collect_neighbor *n)
333 {
335  n->age = 0;
336 }
337 /*---------------------------------------------------------------------------*/
338 uint16_t
339 collect_neighbor_link_estimate(struct collect_neighbor *n)
340 {
341  if(collect_neighbor_is_congested(n)) {
342  /* printf("Congested %d.%d, sould return %d, returning %d\n",
343  n->addr.u8[0], n->addr.u8[1],
344  collect_link_estimate(&n->le),
345  collect_link_estimate(&n->le) + CONGESTION_PENALTY);*/
346  return collect_link_estimate(&n->le) + CONGESTION_PENALTY;
347  } else {
348  return collect_link_estimate(&n->le);
349  }
350 }
351 /*---------------------------------------------------------------------------*/
352 uint16_t
353 collect_neighbor_rtmetric_link_estimate(struct collect_neighbor *n)
354 {
355  return n->rtmetric + collect_link_estimate(&n->le);
356 }
357 /*---------------------------------------------------------------------------*/
358 uint16_t
359 collect_neighbor_rtmetric(struct collect_neighbor *n)
360 {
361  return n->rtmetric;
362 }
363 /*---------------------------------------------------------------------------*/
364 void
365 collect_neighbor_set_congested(struct collect_neighbor *n)
366 {
367  timer_set(&n->congested_timer, EXPECTED_CONGESTION_DURATION);
368 }
369 /*---------------------------------------------------------------------------*/
370 int
371 collect_neighbor_is_congested(struct collect_neighbor *n)
372 {
373  if(timer_expired(&n->congested_timer)) {
374  return 0;
375  } else {
376  return 1;
377  }
378 }
379 /*---------------------------------------------------------------------------*/
380 /** @} */