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