Contiki 2.5
rpl-of-etx.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 /*
6  * Copyright (c) 2010, Swedish Institute of Computer Science.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the Institute nor the names of its contributors
18  * may be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * This file is part of the Contiki operating system.
34  *
35  */
36 /**
37  * \file
38  * The minrank-hysteresis objective function (OCP 1).
39  *
40  * This implementation uses the estimated number of
41  * transmissions (ETX) as the additive routing metric.
42  *
43  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
44  */
45 
46 #include "net/rpl/rpl-private.h"
47 #include "net/neighbor-info.h"
48 
49 #define DEBUG DEBUG_NONE
50 #include "net/uip-debug.h"
51 
52 static void reset(rpl_dag_t *);
53 static void parent_state_callback(rpl_parent_t *, int, int);
54 static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
55 static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
56 static void update_metric_container(rpl_dag_t *);
57 
58 rpl_of_t rpl_of_etx = {
59  reset,
60  parent_state_callback,
61  best_parent,
62  calculate_rank,
63  update_metric_container,
64  1
65 };
66 
67 #define NI_ETX_TO_RPL_ETX(etx) \
68  ((etx) * (RPL_DAG_MC_ETX_DIVISOR / NEIGHBOR_INFO_ETX_DIVISOR))
69 #define RPL_ETX_TO_NI_ETX(etx) \
70  ((etx) / (RPL_DAG_MC_ETX_DIVISOR / NEIGHBOR_INFO_ETX_DIVISOR))
71 
72 /* Reject parents that have a higher link metric than the following. */
73 #define MAX_LINK_METRIC 10
74 
75 /* Reject parents that have a higher path cost than the following. */
76 #define MAX_PATH_COST 100
77 
78 /*
79  * The rank must differ more than 1/PARENT_SWITCH_THRESHOLD_DIV in order
80  * to switch preferred parent.
81  */
82 #define PARENT_SWITCH_THRESHOLD_DIV 2
83 
84 typedef uint16_t rpl_path_metric_t;
85 
86 static rpl_path_metric_t
87 calculate_path_metric(rpl_parent_t *p)
88 {
89  if(p == NULL || (p->mc.obj.etx == 0 && p->rank > ROOT_RANK(p->dag))) {
90  return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
91  }
92  return p->mc.obj.etx + NI_ETX_TO_RPL_ETX(p->link_metric);
93 }
94 
95 static void
96 reset(rpl_dag_t *dag)
97 {
98 }
99 
100 static void
101 parent_state_callback(rpl_parent_t *parent, int known, int etx)
102 {
103 }
104 
105 static rpl_rank_t
106 calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
107 {
108  rpl_rank_t new_rank;
109  rpl_rank_t rank_increase;
110 
111  if(p == NULL) {
112  if(base_rank == 0) {
113  return INFINITE_RANK;
114  }
115  rank_increase = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * DEFAULT_MIN_HOPRANKINC;
116  } else {
117  rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag->min_hoprankinc;
118  if(base_rank == 0) {
119  base_rank = p->rank;
120  }
121  }
122 
123  if(INFINITE_RANK - base_rank < rank_increase) {
124  /* Reached the maximum rank. */
125  new_rank = INFINITE_RANK;
126  } else {
127  /* Calculate the rank based on the new rank information from DIO or
128  stored otherwise. */
129  new_rank = base_rank + rank_increase;
130  }
131 
132  return new_rank;
133 }
134 
135 static rpl_parent_t *
136 best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
137 {
138  rpl_dag_t *dag;
139  rpl_path_metric_t min_diff;
140  rpl_path_metric_t p1_metric;
141  rpl_path_metric_t p2_metric;
142 
143  dag = p1->dag; /* Both parents must be in the same DAG. */
144 
145  min_diff = RPL_DAG_MC_ETX_DIVISOR /
146  PARENT_SWITCH_THRESHOLD_DIV;
147 
148  p1_metric = calculate_path_metric(p1);
149  p2_metric = calculate_path_metric(p2);
150 
151  /* Maintain stability of the preferred parent in case of similar ranks. */
152  if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
153  if(p1_metric < p2_metric + min_diff &&
154  p1_metric > p2_metric - min_diff) {
155  PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n",
156  p2_metric - min_diff,
157  p1_metric,
158  p2_metric + min_diff);
159  return dag->preferred_parent;
160  }
161  }
162 
163  return p1_metric < p2_metric ? p1 : p2;
164 }
165 
166 static void
167 update_metric_container(rpl_dag_t *dag)
168 {
169  rpl_path_metric_t path_metric;
170 #if RPL_DAG_MC == RPL_DAG_MC_ENERGY
171  uint8_t type;
172 #endif
173 
174  dag->mc.flags = RPL_DAG_MC_FLAG_P;
175  dag->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE;
176  dag->mc.prec = 0;
177 
178  if(dag->rank == ROOT_RANK(dag)) {
179  path_metric = 0;
180  } else {
181  path_metric = calculate_path_metric(dag->preferred_parent);
182  }
183 
184 #if RPL_DAG_MC == RPL_DAG_MC_ETX
185 
186  dag->mc.type = RPL_DAG_MC_ETX;
187  dag->mc.length = sizeof(dag->mc.obj.etx);
188  dag->mc.obj.etx = path_metric;
189 
190  PRINTF("RPL: My path ETX to the root is %u.%u\n",
191  dag->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR,
192  (dag->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / RPL_DAG_MC_ETX_DIVISOR);
193 
194 #elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
195 
196  dag->mc.type = RPL_DAG_MC_ENERGY;
197  dag->mc.length = sizeof(dag->mc.obj.energy);
198 
199  if(dag->rank == ROOT_RANK(dag)) {
200  type = RPL_DAG_MC_ENERGY_TYPE_MAINS;
201  } else {
202  type = RPL_DAG_MC_ENERGY_TYPE_BATTERY;
203  }
204 
205  dag->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE;
206  dag->mc.obj.energy.energy_est = path_metric;
207 
208 #else
209 
210 #error "Unsupported RPL_DAG_MC configured. See rpl.h."
211 
212 #endif /* RPL_DAG_MC */
213 }