Contiki 2.6
|
00001 /** 00002 * \addtogroup uip6 00003 * @{ 00004 */ 00005 /* 00006 * Copyright (c) 2010, Swedish Institute of Computer Science. 00007 * All rights reserved. 00008 * 00009 * Redistribution and use in source and binary forms, with or without 00010 * modification, are permitted provided that the following conditions 00011 * are met: 00012 * 1. Redistributions of source code must retain the above copyright 00013 * notice, this list of conditions and the following disclaimer. 00014 * 2. Redistributions in binary form must reproduce the above copyright 00015 * notice, this list of conditions and the following disclaimer in the 00016 * documentation and/or other materials provided with the distribution. 00017 * 3. Neither the name of the Institute nor the names of its contributors 00018 * may be used to endorse or promote products derived from this software 00019 * without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00022 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00023 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00024 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00025 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00026 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00027 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00028 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00029 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00030 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00031 * SUCH DAMAGE. 00032 * 00033 * This file is part of the Contiki operating system. 00034 */ 00035 /** 00036 * \file 00037 * RPL timer management. 00038 * 00039 * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se> 00040 */ 00041 00042 #include "contiki-conf.h" 00043 #include "net/rpl/rpl-private.h" 00044 #include "lib/random.h" 00045 #include "sys/ctimer.h" 00046 00047 #define DEBUG DEBUG_NONE 00048 #include "net/uip-debug.h" 00049 00050 /************************************************************************/ 00051 static struct ctimer periodic_timer; 00052 00053 static void handle_periodic_timer(void *ptr); 00054 static void new_dio_interval(rpl_instance_t *instance); 00055 static void handle_dio_timer(void *ptr); 00056 00057 static uint16_t next_dis; 00058 00059 /* dio_send_ok is true if the node is ready to send DIOs */ 00060 static uint8_t dio_send_ok; 00061 00062 /************************************************************************/ 00063 static void 00064 handle_periodic_timer(void *ptr) 00065 { 00066 rpl_purge_routes(); 00067 rpl_recalculate_ranks(); 00068 00069 /* handle DIS */ 00070 #ifdef RPL_DIS_SEND 00071 next_dis++; 00072 if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) { 00073 next_dis = 0; 00074 dis_output(NULL); 00075 } 00076 #endif 00077 ctimer_reset(&periodic_timer); 00078 } 00079 /************************************************************************/ 00080 static void 00081 new_dio_interval(rpl_instance_t *instance) 00082 { 00083 uint32_t time; 00084 00085 /* TODO: too small timer intervals for many cases */ 00086 time = 1UL << instance->dio_intcurrent; 00087 00088 /* Convert from milliseconds to CLOCK_TICKS. */ 00089 time = (time * CLOCK_SECOND) / 1000; 00090 00091 instance->dio_next_delay = time; 00092 00093 /* random number between I/2 and I */ 00094 time = time >> 1; 00095 time += (time * random_rand()) / RANDOM_RAND_MAX; 00096 00097 /* 00098 * The intervals must be equally long among the nodes for Trickle to 00099 * operate efficiently. Therefore we need to calculate the delay between 00100 * the randomized time and the start time of the next interval. 00101 */ 00102 instance->dio_next_delay -= time; 00103 instance->dio_send = 1; 00104 00105 #if RPL_CONF_STATS 00106 /* keep some stats */ 00107 instance->dio_totint++; 00108 instance->dio_totrecv += instance->dio_counter; 00109 ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n", 00110 DAG_RANK(instance->current_dag->rank, instance), 00111 (10 * (instance->current_dag->rank % instance->min_hoprankinc)) / instance->min_hoprankinc, 00112 instance->current_dag->version, 00113 instance->dio_totint, instance->dio_totsend, 00114 instance->dio_totrecv,instance->dio_intcurrent, 00115 instance->current_dag->rank == ROOT_RANK(instance) ? "BLUE" : "ORANGE"); 00116 #endif /* RPL_CONF_STATS */ 00117 00118 /* reset the redundancy counter */ 00119 instance->dio_counter = 0; 00120 00121 /* schedule the timer */ 00122 PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", time); 00123 ctimer_set(&instance->dio_timer, time, &handle_dio_timer, instance); 00124 } 00125 /************************************************************************/ 00126 static void 00127 handle_dio_timer(void *ptr) 00128 { 00129 rpl_instance_t *instance; 00130 00131 instance = (rpl_instance_t *)ptr; 00132 00133 PRINTF("RPL: DIO Timer triggered\n"); 00134 if(!dio_send_ok) { 00135 if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) { 00136 dio_send_ok = 1; 00137 } else { 00138 PRINTF("RPL: Postponing DIO transmission since link local address is not ok\n"); 00139 ctimer_set(&instance->dio_timer, CLOCK_SECOND, &handle_dio_timer, instance); 00140 return; 00141 } 00142 } 00143 00144 if(instance->dio_send) { 00145 /* send DIO if counter is less than desired redundancy */ 00146 if(instance->dio_counter < instance->dio_redundancy) { 00147 #if RPL_CONF_STATS 00148 instance->dio_totsend++; 00149 #endif /* RPL_CONF_STATS */ 00150 dio_output(instance, NULL); 00151 } else { 00152 PRINTF("RPL: Supressing DIO transmission (%d >= %d)\n", 00153 instance->dio_counter, instance->dio_redundancy); 00154 } 00155 instance->dio_send = 0; 00156 PRINTF("RPL: Scheduling DIO timer %lu ticks in future (sent)\n", 00157 instance->dio_next_delay); 00158 ctimer_set(&instance->dio_timer, instance->dio_next_delay, handle_dio_timer, instance); 00159 } else { 00160 /* check if we need to double interval */ 00161 if(instance->dio_intcurrent < instance->dio_intmin + instance->dio_intdoubl) { 00162 instance->dio_intcurrent++; 00163 PRINTF("RPL: DIO Timer interval doubled %d\n", instance->dio_intcurrent); 00164 } 00165 new_dio_interval(instance); 00166 } 00167 } 00168 /************************************************************************/ 00169 void 00170 rpl_reset_periodic_timer(void) 00171 { 00172 next_dis = RPL_DIS_INTERVAL - RPL_DIS_START_DELAY; 00173 ctimer_set(&periodic_timer, CLOCK_SECOND, handle_periodic_timer, NULL); 00174 } 00175 /************************************************************************/ 00176 /* Resets the DIO timer in the instance to its minimal interval. */ 00177 void 00178 rpl_reset_dio_timer(rpl_instance_t *instance) 00179 { 00180 #if !RPL_LEAF_ONLY 00181 /* Do not reset if we are already on the minimum interval, 00182 unless forced to do so. */ 00183 if(instance->dio_intcurrent > instance->dio_intmin) { 00184 instance->dio_counter = 0; 00185 instance->dio_intcurrent = instance->dio_intmin; 00186 new_dio_interval(instance); 00187 } 00188 #if RPL_CONF_STATS 00189 rpl_stats.resets++; 00190 #endif /* RPL_CONF_STATS */ 00191 #endif /* RPL_LEAF_ONLY */ 00192 } 00193 /************************************************************************/ 00194 static void 00195 handle_dao_timer(void *ptr) 00196 { 00197 rpl_instance_t *instance; 00198 00199 instance = (rpl_instance_t *)ptr; 00200 00201 if(!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) { 00202 PRINTF("RPL: Postpone DAO transmission\n"); 00203 ctimer_set(&instance->dao_timer, CLOCK_SECOND, handle_dao_timer, instance); 00204 return; 00205 } 00206 00207 /* Send the DAO to the DAO parent set -- the preferred parent in our case. */ 00208 if(instance->current_dag->preferred_parent != NULL) { 00209 PRINTF("RPL: handle_dao_timer - sending DAO\n"); 00210 /* Set the route lifetime to the default value. */ 00211 dao_output(instance->current_dag->preferred_parent, instance->default_lifetime); 00212 } else { 00213 PRINTF("RPL: No suitable DAO parent\n"); 00214 } 00215 ctimer_stop(&instance->dao_timer); 00216 } 00217 /************************************************************************/ 00218 void 00219 rpl_schedule_dao(rpl_instance_t *instance) 00220 { 00221 clock_time_t expiration_time; 00222 00223 expiration_time = etimer_expiration_time(&instance->dao_timer.etimer); 00224 00225 if(!etimer_expired(&instance->dao_timer.etimer)) { 00226 PRINTF("RPL: DAO timer already scheduled\n"); 00227 } else { 00228 expiration_time = RPL_DAO_LATENCY / 2 + 00229 (random_rand() % (RPL_DAO_LATENCY)); 00230 PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", 00231 (unsigned)expiration_time); 00232 ctimer_set(&instance->dao_timer, expiration_time, 00233 handle_dao_timer, instance); 00234 } 00235 } 00236 /************************************************************************/