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_dag_t *dag);
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_dag(RPL_ANY_INSTANCE) == 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_dag_t *dag)
00082 {
00083   uint32_t time;
00084 
00085   /* TODO: too small timer intervals for many cases */
00086   time = 1UL << dag->dio_intcurrent;
00087 
00088   /* Convert from milliseconds to CLOCK_TICKS. */
00089   time = (time * CLOCK_SECOND) / 1000;
00090 
00091   dag->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   dag->dio_next_delay -= time;
00103   dag->dio_send = 1;
00104 
00105 #if RPL_CONF_STATS
00106   /* keep some stats */
00107   dag->dio_totint++;
00108   dag->dio_totrecv += dag->dio_counter;
00109   ANNOTATE("#A rank=%u.%u(%u),stats=%d %d %d %d,color=%s\n",
00110            DAG_RANK(dag->rank, dag),
00111            (10 * (dag->rank % dag->min_hoprankinc)) / dag->min_hoprankinc,
00112            dag->version,
00113            dag->dio_totint, dag->dio_totsend,
00114            dag->dio_totrecv,dag->dio_intcurrent,
00115            dag->rank == ROOT_RANK(dag) ? "BLUE" : "ORANGE");
00116 #endif /* RPL_CONF_STATS */
00117 
00118   /* reset the redundancy counter */
00119   dag->dio_counter = 0;
00120 
00121   /* schedule the timer */
00122   PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", time);
00123   ctimer_set(&dag->dio_timer, time, &handle_dio_timer, dag);
00124 }
00125 /************************************************************************/
00126 static void
00127 handle_dio_timer(void *ptr)
00128 {
00129   rpl_dag_t *dag;
00130 
00131   dag = (rpl_dag_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(&dag->dio_timer, CLOCK_SECOND, &handle_dio_timer, dag);
00140       return;
00141     }
00142   }
00143 
00144   if(dag->dio_send) {
00145     /* send DIO if counter is less than desired redundancy */
00146     if(dag->dio_counter < dag->dio_redundancy) {
00147 #if RPL_CONF_STATS
00148       dag->dio_totsend++;
00149 #endif /* RPL_CONF_STATS */
00150       dio_output(dag, NULL);
00151     } else {
00152       PRINTF("RPL: Supressing DIO transmission (%d >= %d)\n",
00153              dag->dio_counter, dag->dio_redundancy);
00154     }
00155     dag->dio_send = 0;
00156     PRINTF("RPL: Scheduling DIO timer %u ticks in future (sent)\n",
00157            dag->dio_next_delay);
00158     ctimer_set(&dag->dio_timer, dag->dio_next_delay, handle_dio_timer, dag);
00159   } else {
00160     /* check if we need to double interval */
00161     if(dag->dio_intcurrent < dag->dio_intmin + dag->dio_intdoubl) {
00162       dag->dio_intcurrent++;
00163       PRINTF("RPL: DIO Timer interval doubled %d\n", dag->dio_intcurrent);
00164     }
00165     new_dio_interval(dag);
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 DAG to its minimal interval. */
00177 void
00178 rpl_reset_dio_timer(rpl_dag_t *dag, uint8_t force)
00179 {
00180   /* only reset if not just reset or started */
00181   if(force || dag->dio_intcurrent > dag->dio_intmin) {
00182     dag->dio_counter = 0;
00183     dag->dio_intcurrent = dag->dio_intmin;
00184     new_dio_interval(dag);
00185   }
00186 #if RPL_CONF_STATS
00187   rpl_stats.resets++;
00188 #endif
00189 }
00190 /************************************************************************/
00191 static void
00192 handle_dao_timer(void *ptr)
00193 {
00194   rpl_dag_t *dag;
00195 
00196   dag = (rpl_dag_t *)ptr;
00197 
00198   if (!dio_send_ok && uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) {
00199     PRINTF("RPL: Postpone DAO transmission... \n");
00200     ctimer_set(&dag->dao_timer, CLOCK_SECOND, handle_dao_timer, dag);
00201     return;
00202   }
00203 
00204   /* Send the DAO to the best parent. rpl-07 section C.2 lists the
00205      fan-out as being under investigation. */
00206   if(dag->preferred_parent != NULL) {
00207     PRINTF("RPL: handle_dao_timer - sending DAO\n");
00208     /* set time to maxtime */
00209     dao_output(dag->preferred_parent, dag->lifetime_unit * 0xffUL);
00210   } else {
00211     PRINTF("RPL: Could not find a parent to send a DAO to \n");
00212   }
00213   ctimer_stop(&dag->dao_timer);
00214 }
00215 /************************************************************************/
00216 void
00217 rpl_schedule_dao(rpl_dag_t *dag)
00218 {
00219   clock_time_t expiration_time;
00220 
00221   expiration_time = etimer_expiration_time(&dag->dao_timer.etimer);
00222 
00223   if(!etimer_expired(&dag->dao_timer.etimer)) {
00224     PRINTF("RPL: DAO timer already scheduled\n");
00225   } else {
00226     expiration_time = DEFAULT_DAO_LATENCY / 2 +
00227       (random_rand() % (DEFAULT_DAO_LATENCY));
00228     PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n",
00229            (unsigned)expiration_time);
00230     ctimer_set(&dag->dao_timer, expiration_time,
00231                handle_dao_timer, dag);
00232   }
00233 }
00234 /************************************************************************/

Generated on Mon Apr 11 14:23:31 2011 for Contiki 2.5 by  doxygen 1.6.1