Contiki 2.6

rpl-timers.c

Go to the documentation of this file.
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 /************************************************************************/