Contiki 2.6

collect-neighbor.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup rimecollect_neighbor
00003  * @{
00004  */
00005 
00006 /*
00007  * Copyright (c) 2006, Swedish Institute of Computer Science.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted provided that the following conditions
00012  * are met:
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of the Institute nor the names of its contributors
00019  *    may be used to endorse or promote products derived from this software
00020  *    without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * This file is part of the Contiki operating system.
00035  *
00036  * $Id: collect-neighbor.c,v 1.10 2011/01/10 15:08:52 adamdunkels Exp $
00037  */
00038 
00039 /**
00040  * \file
00041  *         Radio neighborhood management
00042  * \author
00043  *         Adam Dunkels <adam@sics.se>
00044  */
00045 
00046 #include <limits.h>
00047 #include <stdio.h>
00048 
00049 #include "contiki.h"
00050 #include "lib/memb.h"
00051 #include "lib/list.h"
00052 
00053 #include "net/rime/collect-neighbor.h"
00054 #include "net/rime/collect.h"
00055 
00056 #ifdef COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
00057 #define MAX_COLLECT_NEIGHBORS COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
00058 #else /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
00059 #define MAX_COLLECT_NEIGHBORS 8
00060 #endif /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
00061 
00062 #define RTMETRIC_MAX COLLECT_MAX_DEPTH
00063 
00064 MEMB(collect_neighbors_mem, struct collect_neighbor, MAX_COLLECT_NEIGHBORS);
00065 
00066 #define MAX_AGE                      180
00067 #define MAX_LE_AGE                   10
00068 #define PERIODIC_INTERVAL            CLOCK_SECOND * 60
00069 
00070 #define EXPECTED_CONGESTION_DURATION CLOCK_SECOND * 240
00071 #define CONGESTION_PENALTY           8 * COLLECT_LINK_ESTIMATE_UNIT
00072 
00073 #define DEBUG 0
00074 #if DEBUG
00075 #include <stdio.h>
00076 #define PRINTF(...) printf(__VA_ARGS__)
00077 #else
00078 #define PRINTF(...)
00079 #endif
00080 
00081 /*---------------------------------------------------------------------------*/
00082 static void
00083 periodic(void *ptr)
00084 {
00085   struct collect_neighbor_list *neighbor_list;
00086   struct collect_neighbor *n;
00087 
00088   neighbor_list = ptr;
00089 
00090   /* Go through all collect_neighbors and increase their age. */
00091   for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
00092     n->age++;
00093     n->le_age++;
00094   }
00095   for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
00096     if(n->le_age == MAX_LE_AGE) {
00097       collect_link_estimate_new(&n->le);
00098       n->le_age = 0;
00099     }
00100     if(n->age == MAX_AGE) {
00101       memb_free(&collect_neighbors_mem, n);
00102       list_remove(neighbor_list->list, n);
00103       n = list_head(neighbor_list->list);
00104     }
00105   }
00106   ctimer_set(&neighbor_list->periodic, PERIODIC_INTERVAL,
00107              periodic, neighbor_list);
00108 }
00109 /*---------------------------------------------------------------------------*/
00110 void
00111 collect_neighbor_init(void)
00112 {
00113   static uint8_t initialized = 0;
00114   if(initialized == 0) {
00115     initialized = 1;
00116     memb_init(&collect_neighbors_mem);
00117   }
00118 }
00119 /*---------------------------------------------------------------------------*/
00120 void
00121 collect_neighbor_list_new(struct collect_neighbor_list *neighbors_list)
00122 {
00123   LIST_STRUCT_INIT(neighbors_list, list);
00124   list_init(neighbors_list->list);
00125   ctimer_set(&neighbors_list->periodic, CLOCK_SECOND, periodic, neighbors_list);
00126 }
00127 /*---------------------------------------------------------------------------*/
00128 struct collect_neighbor *
00129 collect_neighbor_list_find(struct collect_neighbor_list *neighbors_list,
00130                            const rimeaddr_t *addr)
00131 {
00132   struct collect_neighbor *n;
00133   for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
00134     if(rimeaddr_cmp(&n->addr, addr)) {
00135       return n;
00136     }
00137   }
00138   return NULL;
00139 }
00140 /*---------------------------------------------------------------------------*/
00141 int
00142 collect_neighbor_list_add(struct collect_neighbor_list *neighbors_list,
00143                           const rimeaddr_t *addr, uint16_t nrtmetric)
00144 {
00145   struct collect_neighbor *n;
00146 
00147   if(addr == NULL) {
00148     PRINTF("collect_neighbor_list_add: attempt to add NULL addr\n");
00149     return 0;
00150   }
00151 
00152   PRINTF("collect_neighbor_add: adding %d.%d\n", addr->u8[0], addr->u8[1]);
00153 
00154   /* Check if the collect_neighbor is already on the list. */
00155   for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
00156     if(rimeaddr_cmp(&n->addr, addr)) {
00157       PRINTF("collect_neighbor_add: already on list %d.%d\n",
00158              addr->u8[0], addr->u8[1]);
00159       break;
00160     }
00161   }
00162 
00163   /* If the collect_neighbor was not on the list, we try to allocate memory
00164      for it. */
00165   if(n == NULL) {
00166     PRINTF("collect_neighbor_add: not on list, allocating %d.%d\n",
00167            addr->u8[0], addr->u8[1]);
00168     n = memb_alloc(&collect_neighbors_mem);
00169     if(n != NULL) {
00170       list_add(neighbors_list->list, n);
00171     }
00172   }
00173 
00174   /* If we could not allocate memory, we try to recycle an old
00175      neighbor. XXX Should also look for the one with the worst
00176      rtmetric (not link esimate). XXX Also make sure that we don't
00177      replace a neighbor with a neighbor that has a worse metric. */
00178   if(n == NULL) {
00179     uint16_t worst_rtmetric;
00180     struct collect_neighbor *worst_neighbor;
00181 
00182     /* Find the neighbor that has the highest rtmetric. This is the
00183        neighbor that we are least likely to be using in the
00184        future. But we also need to make sure that the neighbor we are
00185        currently adding is not worst than the one we would be
00186        replacing. If so, we don't put the new neighbor on the list. */
00187     worst_rtmetric = 0;
00188     worst_neighbor = NULL;
00189 
00190     for(n = list_head(neighbors_list->list);
00191         n != NULL; n = list_item_next(n)) {
00192       if(n->rtmetric > worst_rtmetric) {
00193         worst_neighbor = n;
00194         worst_rtmetric = n->rtmetric;
00195       }
00196     }
00197 
00198     /* Only add this new neighbor if its rtmetric is lower than the
00199        one it would replace. */
00200     if(nrtmetric < worst_rtmetric) {
00201       n = worst_neighbor;
00202     }
00203     if(n != NULL) {
00204       PRINTF("collect_neighbor_add: not on list, not allocated, recycling %d.%d\n",
00205              n->addr.u8[0], n->addr.u8[1]);
00206     }
00207   }
00208 
00209   if(n != NULL) {
00210     n->age = 0;
00211     rimeaddr_copy(&n->addr, addr);
00212     n->rtmetric = nrtmetric;
00213     collect_link_estimate_new(&n->le);
00214     n->le_age = 0;
00215     return 1;
00216   }
00217   return 0;
00218 }
00219 /*---------------------------------------------------------------------------*/
00220 list_t
00221 collect_neighbor_list(struct collect_neighbor_list *neighbors_list)
00222 {
00223   return neighbors_list->list;
00224 }
00225 /*---------------------------------------------------------------------------*/
00226 void
00227 collect_neighbor_list_remove(struct collect_neighbor_list *neighbors_list,
00228                              const rimeaddr_t *addr)
00229 {
00230   struct collect_neighbor *n = collect_neighbor_list_find(neighbors_list, addr);
00231 
00232   if(n != NULL) {
00233     list_remove(neighbors_list->list, n);
00234     memb_free(&collect_neighbors_mem, n);
00235   }
00236 }
00237 /*---------------------------------------------------------------------------*/
00238 struct collect_neighbor *
00239 collect_neighbor_list_best(struct collect_neighbor_list *neighbors_list)
00240 {
00241   int found;
00242   struct collect_neighbor *n, *best;
00243   uint16_t rtmetric;
00244 
00245   rtmetric = RTMETRIC_MAX;
00246   best = NULL;
00247   found = 0;
00248 
00249   /*  PRINTF("%d: ", node_id);*/
00250   PRINTF("collect_neighbor_best: ");
00251 
00252   /* Find the neighbor with the lowest rtmetric + linkt estimate. */
00253   for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
00254     PRINTF("%d.%d %d+%d=%d, ",
00255            n->addr.u8[0], n->addr.u8[1],
00256            n->rtmetric, collect_neighbor_link_estimate(n),
00257            collect_neighbor_rtmetric(n));
00258     if(collect_neighbor_rtmetric_link_estimate(n) < rtmetric) {
00259       rtmetric = collect_neighbor_rtmetric_link_estimate(n);
00260       best = n;
00261     }
00262   }
00263   PRINTF("\n");
00264 
00265   return best;
00266 }
00267 /*---------------------------------------------------------------------------*/
00268 int
00269 collect_neighbor_list_num(struct collect_neighbor_list *neighbors_list)
00270 {
00271   PRINTF("collect_neighbor_num %d\n", list_length(neighbors_list->list));
00272   return list_length(neighbors_list->list);
00273 }
00274 /*---------------------------------------------------------------------------*/
00275 struct collect_neighbor *
00276 collect_neighbor_list_get(struct collect_neighbor_list *neighbors_list, int num)
00277 {
00278   int i;
00279   struct collect_neighbor *n;
00280 
00281   PRINTF("collect_neighbor_get %d\n", num);
00282 
00283   i = 0;
00284   for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
00285     if(i == num) {
00286       PRINTF("collect_neighbor_get found %d.%d\n",
00287              n->addr.u8[0], n->addr.u8[1]);
00288       return n;
00289     }
00290     i++;
00291   }
00292   return NULL;
00293 }
00294 /*---------------------------------------------------------------------------*/
00295 void
00296 collect_neighbor_list_purge(struct collect_neighbor_list *neighbors_list)
00297 {
00298   while(list_head(neighbors_list->list) != NULL) {
00299     memb_free(&collect_neighbors_mem, list_pop(neighbors_list->list));
00300   }
00301 }
00302 /*---------------------------------------------------------------------------*/
00303 void
00304 collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint16_t rtmetric)
00305 {
00306   if(n != NULL) {
00307     PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n",
00308            rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00309            n->addr.u8[0], n->addr.u8[1], rtmetric);
00310     n->rtmetric = rtmetric;
00311     n->age = 0;
00312   }
00313 }
00314 /*---------------------------------------------------------------------------*/
00315 void
00316 collect_neighbor_tx_fail(struct collect_neighbor *n, uint16_t num_tx)
00317 {
00318   collect_link_estimate_update_tx_fail(&n->le, num_tx);
00319   n->le_age = 0;
00320   n->age = 0;
00321 }
00322 /*---------------------------------------------------------------------------*/
00323 void
00324 collect_neighbor_tx(struct collect_neighbor *n, uint16_t num_tx)
00325 {
00326   collect_link_estimate_update_tx(&n->le, num_tx);
00327   n->le_age = 0;
00328   n->age = 0;
00329 }
00330 /*---------------------------------------------------------------------------*/
00331 void
00332 collect_neighbor_rx(struct collect_neighbor *n)
00333 {
00334   collect_link_estimate_update_rx(&n->le);
00335   n->age = 0;
00336 }
00337 /*---------------------------------------------------------------------------*/
00338 uint16_t
00339 collect_neighbor_link_estimate(struct collect_neighbor *n)
00340 {
00341   if(collect_neighbor_is_congested(n)) {
00342     /*    printf("Congested %d.%d, sould return %d, returning %d\n",
00343            n->addr.u8[0], n->addr.u8[1],
00344            collect_link_estimate(&n->le),
00345            collect_link_estimate(&n->le) + CONGESTION_PENALTY);*/
00346     return collect_link_estimate(&n->le) + CONGESTION_PENALTY;
00347   } else {
00348     return collect_link_estimate(&n->le);
00349   }
00350 }
00351 /*---------------------------------------------------------------------------*/
00352 uint16_t
00353 collect_neighbor_rtmetric_link_estimate(struct collect_neighbor *n)
00354 {
00355   return n->rtmetric + collect_link_estimate(&n->le);
00356 }
00357 /*---------------------------------------------------------------------------*/
00358 uint16_t
00359 collect_neighbor_rtmetric(struct collect_neighbor *n)
00360 {
00361   return n->rtmetric;
00362 }
00363 /*---------------------------------------------------------------------------*/
00364 void
00365 collect_neighbor_set_congested(struct collect_neighbor *n)
00366 {
00367   timer_set(&n->congested_timer, EXPECTED_CONGESTION_DURATION);
00368 }
00369 /*---------------------------------------------------------------------------*/
00370 int
00371 collect_neighbor_is_congested(struct collect_neighbor *n)
00372 {
00373   if(timer_expired(&n->congested_timer)) {
00374     return 0;
00375   } else {
00376     return 1;
00377   }
00378 }
00379 /*---------------------------------------------------------------------------*/
00380 /** @} */