2013-02-13 15:00:43 +01:00
|
|
|
#include <string.h>
|
2013-03-15 17:48:13 +01:00
|
|
|
#include <stdio.h>
|
2013-02-13 15:00:43 +01:00
|
|
|
#include "of_mrhof.h"
|
|
|
|
|
2013-03-28 15:27:30 +01:00
|
|
|
#include "etx_beaconing.h"
|
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
// Function Prototypes
|
|
|
|
static uint16_t calc_rank(rpl_parent_t *, uint16_t);
|
|
|
|
static rpl_parent_t *which_parent(rpl_parent_t *, rpl_parent_t *);
|
|
|
|
static rpl_dodag_t *which_dodag(rpl_dodag_t *, rpl_dodag_t *);
|
|
|
|
static void reset(rpl_dodag_t *);
|
2013-08-08 13:39:00 +02:00
|
|
|
static uint16_t calc_path_cost(rpl_parent_t *parent);
|
2013-02-21 18:25:35 +01:00
|
|
|
|
|
|
|
uint16_t cur_min_path_cost = MAX_PATH_COST;
|
2013-08-08 13:39:00 +02:00
|
|
|
rpl_parent_t *cur_preferred_parent = NULL;
|
2013-02-21 18:25:35 +01:00
|
|
|
|
2013-02-13 15:00:43 +01:00
|
|
|
rpl_of_t rpl_of_mrhof = {
|
2013-08-08 13:39:00 +02:00
|
|
|
0x1,
|
|
|
|
calc_rank,
|
|
|
|
which_parent,
|
|
|
|
which_dodag,
|
|
|
|
reset,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
rpl_of_t *rpl_get_of_mrhof(void)
|
|
|
|
{
|
2013-02-13 15:00:43 +01:00
|
|
|
return &rpl_of_mrhof;
|
|
|
|
}
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
void reset(rpl_dodag_t *dodag)
|
|
|
|
{
|
2013-02-13 15:00:43 +01:00
|
|
|
}
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
static uint16_t calc_path_cost(rpl_parent_t *parent)
|
|
|
|
{
|
2013-03-29 13:41:48 +01:00
|
|
|
puts("calc_pathcost");
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-02-21 18:25:35 +01:00
|
|
|
/*
|
2013-03-15 17:48:13 +01:00
|
|
|
* Calculates the path cost through the parent, for now, only for ETX
|
2013-02-21 18:25:35 +01:00
|
|
|
*/
|
2013-08-08 13:39:00 +02:00
|
|
|
if (parent == NULL) {
|
2013-03-15 17:48:13 +01:00
|
|
|
// Shouldn't ever happen since this function is supposed to be always
|
|
|
|
// run with a parent. If it does happen, we can assume a root called it.
|
2013-03-29 13:41:48 +01:00
|
|
|
puts("[WARNING] calc_path_cost called without parent!");
|
2013-03-15 17:48:13 +01:00
|
|
|
return DEFAULT_MIN_HOP_RANK_INCREASE;
|
2013-02-21 18:25:35 +01:00
|
|
|
}
|
|
|
|
|
2013-03-28 15:27:30 +01:00
|
|
|
double etx_value = etx_get_metric(&(parent->addr));
|
2013-03-29 13:41:48 +01:00
|
|
|
printf("Metric for parent returned: %f", etx_value);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
if (etx_value != 0) {
|
|
|
|
/*
|
|
|
|
* (ETX_for_link_to_neighbor * 128) + Rank_of_that_neighbor
|
|
|
|
*
|
|
|
|
* This means I get the rank of that neighbor (which is the etx
|
|
|
|
* of the whole path from him to the root node) plus my ETX to
|
|
|
|
* that neighbor*128, which would be the 'rank' of the single link
|
|
|
|
* from me to that neighbor
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
if (etx_value * ETX_RANK_MULTIPLIER > MAX_LINK_METRIC) {
|
|
|
|
// Disallow links with an estimated ETX of 4 or higher
|
|
|
|
return MAX_PATH_COST;
|
2013-02-13 15:00:43 +01:00
|
|
|
}
|
2013-02-21 18:25:35 +01:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
if (etx_value * ETX_RANK_MULTIPLIER + parent->rank
|
2013-08-08 13:39:00 +02:00
|
|
|
< parent->rank) {
|
2013-03-15 17:48:13 +01:00
|
|
|
//Overflow
|
|
|
|
return MAX_PATH_COST;
|
|
|
|
}
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
//TODO runden
|
|
|
|
return etx_value * ETX_RANK_MULTIPLIER
|
2013-08-08 13:39:00 +02:00
|
|
|
+ parent->rank;
|
|
|
|
}
|
|
|
|
else {
|
2013-03-15 17:48:13 +01:00
|
|
|
// IMPLEMENT HANDLING OF OTHER METRICS HERE
|
|
|
|
// if it is 0, it hasn't been computed, thus we cannot compute a path
|
|
|
|
// cost
|
|
|
|
return MAX_PATH_COST;
|
|
|
|
}
|
2013-02-21 18:25:35 +01:00
|
|
|
}
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
static uint16_t calc_rank(rpl_parent_t *parent, uint16_t base_rank)
|
|
|
|
{
|
2013-03-29 13:41:48 +01:00
|
|
|
puts("calc_rank");
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-02-21 18:25:35 +01:00
|
|
|
/*
|
2013-03-15 17:48:13 +01:00
|
|
|
* Return the rank for this node.
|
2013-02-21 18:25:35 +01:00
|
|
|
*
|
|
|
|
* For now, there is no metric-selection or specification, so the rank com-
|
|
|
|
* putation will always be assumed to be done for the ETX metric.
|
2013-03-15 17:48:13 +01:00
|
|
|
* Baserank is pretty much only used to find out if a node is a root or not.
|
2013-02-21 18:25:35 +01:00
|
|
|
*/
|
2013-08-08 13:39:00 +02:00
|
|
|
if (parent == NULL) {
|
2013-03-15 17:48:13 +01:00
|
|
|
if (base_rank == 0) {
|
|
|
|
//No parent, no rank, a root node would have a rank != 0
|
|
|
|
return INFINITE_RANK;
|
|
|
|
}
|
2013-02-21 18:25:35 +01:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
/*
|
|
|
|
* No parent, base_rank != 0 means this is a root node or a node which
|
|
|
|
* is recalculating.
|
|
|
|
* Since a recalculating node must have a parent in this implementation
|
|
|
|
* (see rpl.c, function global_repair), we can assume this node is root.
|
|
|
|
*/
|
|
|
|
return DEFAULT_MIN_HOP_RANK_INCREASE;
|
2013-08-08 13:39:00 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-03-15 17:48:13 +01:00
|
|
|
/*
|
|
|
|
* We have a parent and are a non-root node, calculate the path cost for
|
|
|
|
* the parent and choose the maximum of that value and the advertised
|
|
|
|
* rank of the parent + minhoprankincrease for our rank.
|
|
|
|
*/
|
|
|
|
uint16_t calculated_pcost = calc_path_cost(parent);
|
|
|
|
|
|
|
|
if (calculated_pcost < MAX_PATH_COST) {
|
|
|
|
if ((parent->rank + parent->dodag->minhoprankincrease)
|
2013-08-08 13:39:00 +02:00
|
|
|
> calculated_pcost) {
|
2013-03-15 17:48:13 +01:00
|
|
|
return parent->rank + parent->dodag->minhoprankincrease;
|
2013-08-08 13:39:00 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-03-15 17:48:13 +01:00
|
|
|
return calculated_pcost;
|
2013-02-21 18:25:35 +01:00
|
|
|
}
|
2013-08-08 13:39:00 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-03-15 17:48:13 +01:00
|
|
|
//Path costs are greater than allowed
|
|
|
|
return INFINITE_RANK;
|
2013-02-21 18:25:35 +01:00
|
|
|
}
|
2013-02-13 15:00:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
static rpl_parent_t *which_parent(rpl_parent_t *p1, rpl_parent_t *p2)
|
|
|
|
{
|
2013-03-29 13:41:48 +01:00
|
|
|
puts("which_parent");
|
2013-02-21 18:25:35 +01:00
|
|
|
/*
|
2013-03-15 17:48:13 +01:00
|
|
|
* Return the parent with the lowest path cost.
|
|
|
|
* Before returning any of the two given parents, make sure that a switch is
|
|
|
|
* desirable.
|
2013-02-21 18:25:35 +01:00
|
|
|
*
|
|
|
|
*/
|
2013-03-15 17:48:13 +01:00
|
|
|
uint16_t path_p1 = calc_path_cost(p1);
|
|
|
|
uint16_t path_p2 = calc_path_cost(p2);
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
if (cur_preferred_parent != NULL) {
|
2013-03-15 17:48:13 +01:00
|
|
|
//test if the parent from which we got this path is still active
|
2013-08-08 13:39:00 +02:00
|
|
|
if (cur_preferred_parent->used != 0) {
|
2013-03-15 17:48:13 +01:00
|
|
|
// Test, if the current best path is better than both parents given
|
2013-08-08 13:39:00 +02:00
|
|
|
if (cur_min_path_cost < path_p1 + PARENT_SWITCH_THRESHOLD
|
|
|
|
&& cur_min_path_cost < path_p2 + PARENT_SWITCH_THRESHOLD) {
|
2013-03-15 17:48:13 +01:00
|
|
|
return cur_preferred_parent;
|
2013-02-21 18:25:35 +01:00
|
|
|
}
|
|
|
|
}
|
2013-02-13 15:00:43 +01:00
|
|
|
}
|
2013-02-21 18:25:35 +01:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
if (path_p1 < path_p2) {
|
|
|
|
/*
|
|
|
|
* Return the current best parent, and set it as current best parent
|
|
|
|
*/
|
|
|
|
cur_min_path_cost = path_p1;
|
|
|
|
cur_preferred_parent = p1;
|
|
|
|
return p1;
|
|
|
|
}
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
cur_min_path_cost = path_p2;
|
|
|
|
cur_preferred_parent = p2;
|
|
|
|
return p2;
|
2013-02-13 15:00:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//Not used yet, as the implementation only makes use of one dodag for now.
|
2013-08-08 13:39:00 +02:00
|
|
|
static rpl_dodag_t *which_dodag(rpl_dodag_t *d1, rpl_dodag_t *d2)
|
|
|
|
{
|
2013-02-13 15:00:43 +01:00
|
|
|
return d1;
|
|
|
|
}
|