diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 6430e3df982..39837d48d01 100755 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -62,6 +62,46 @@ #define DEBUG DEBUG_PRINT #include "net/ip/uip-debug.h" +#include "net/nbr-table.h" + + + static void reset(rpl_dag_t *); + static void neighbor_link_callback(rpl_parent_t *, int, int); + static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); + static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); + static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); + static void update_metric_container(rpl_instance_t *); + + rpl_of_t rpl_mrhof = { + reset, + neighbor_link_callback, + best_parent, + best_dag, + calculate_rank, + update_metric_container, + 1 + }; + + /* Constants for the ETX moving average */ + #define ETX_SCALE 100 + #define ETX_ALPHA 90 + + + + /* Reject parents that have a higher link metric than the following. */ + #define MAX_LINK_METRIC 10 + + + /* Reject parents that have a higher path cost than the following. */ + #define MAX_PATH_COST 100 + + /* + * The rank must differ more than 1/PARENT_SWITCH_THRESHOLD_DIV in order + * to switch preferred parent. + */ + #define PARENT_SWITCH_THRESHOLD_DIV 2 + + /*---------------------------------------------------------------------------*/ #define RPL_DIO_GROUNDED 0x80 @@ -79,8 +119,191 @@ static void dao_input(void); static void dao_ack_input(void); static void dco_input(void); static void dco_ack_input(void); +/*----------------------------------------------------------------------------*/ +typedef uint16_t rpl_path_metric_t; + + static rpl_path_metric_t + calculate_path_metric(rpl_parent_t *p) + { + if(p == NULL) { + return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; + } + +#if RPL_DAG_MC == RPL_DAG_MC_NONE + return p->rank + (uint16_t)p->link_metric; +#elif RPL_DAG_MC == RPL_DAG_MC_ETX + return p->mc.obj.etx + (uint16_t)p->link_metric; +#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY + return p->mc.obj.energy.energy_est + (uint16_t)p->link_metric; +#else +#error "Unsupported RPL_DAG_MC configured. See rpl.h." +#endif /* RPL_DAG_MC */ +} +static void +reset(rpl_dag_t *sag) +{ + PRINTF("RPL: Reset MRHOF\n"); +} +static void +neighbor_link_callback(rpl_parent_t *p, int status, int numtx) +{ + uint16_t recorded_etx = p->link_metric; + uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR; + uint16_t new_etx; + + /* Do not penalize the ETX when collisions or transmission errors occur. */ + if(status == MAC_TX_OK || status == MAC_TX_NOACK) { + if(status == MAC_TX_NOACK) { + packet_etx = MAX_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; + } + + new_etx = ((uint32_t)recorded_etx * ETX_ALPHA + + (uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE; + + PRINTF("RPL: ETX changed from %u to %u (packet ETX = %u)\n", + (unsigned)(recorded_etx / RPL_DAG_MC_ETX_DIVISOR), + (unsigned)(new_etx / RPL_DAG_MC_ETX_DIVISOR), + (unsigned)(packet_etx / RPL_DAG_MC_ETX_DIVISOR)); + p->link_metric = new_etx; + } +} + +static rpl_rank_t +calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) +{ + rpl_rank_t new_rank; + rpl_rank_t rank_increase; + + if(p == NULL) { + if(base_rank == 0) { + return INFINITE_RANK; + } + rank_increase = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; + } else { + rank_increase = p->link_metric; + if(base_rank == 0) { + base_rank = p->rank; + } + } + + if(INFINITE_RANK - base_rank < rank_increase) { + /* Reached the maximum rank. */ + new_rank = INFINITE_RANK; + } else { + /* Calculate the rank based on the new rank information from DIO or + stored otherwise. */ + new_rank = base_rank + rank_increase; + } + + return new_rank; +} + +static rpl_dag_t * +best_dag(rpl_dag_t *d1, rpl_dag_t *d2) +{ + if(d1->grounded != d2->grounded) { + return d1->grounded ? d1 : d2; + } + + if(d1->preference != d2->preference) { + return d1->preference > d2->preference ? d1 : d2; + } + + return d1->rank < d2->rank ? d1 : d2; +} + +static rpl_parent_t * +best_parent(rpl_parent_t *p1, rpl_parent_t *p2) +{ + rpl_dag_t *dag; + rpl_path_metric_t min_diff; + rpl_path_metric_t p1_metric; + rpl_path_metric_t p2_metric; + + dag = p1->dag; /* Both parents are in the same DAG. */ + + min_diff = RPL_DAG_MC_ETX_DIVISOR / + PARENT_SWITCH_THRESHOLD_DIV; + + p1_metric = calculate_path_metric(p1); + p2_metric = calculate_path_metric(p2); + + /* Maintain stability of the preferred parent in case of similar ranks. */ + if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) { + if(p1_metric < p2_metric + min_diff && + p1_metric > p2_metric - min_diff) { + PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n", + p2_metric - min_diff, + p1_metric, + p2_metric + min_diff); + return dag->preferred_parent; + } + } + + return p1_metric < p2_metric ? p1 : p2; +} + +#if RPL_DAG_MC == RPL_DAG_MC_NONE +static void +update_metric_container(rpl_instance_t *instance) +{ + instance->mc.type = RPL_DAG_MC; +} +#else +static void +update_metric_container(rpl_instance_t *instance) +{ + rpl_path_metric_t path_metric; + rpl_dag_t *dag; +#if RPL_DAG_MC == RPL_DAG_MC_ENERGY + uint8_t type; +#endif + + instance->mc.type = RPL_DAG_MC; + instance->mc.flags = RPL_DAG_MC_FLAG_P; + instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; + instance->mc.prec = 0; + + dag = instance->current_dag; + + if (!dag->joined) { + PRINTF("RPL: Cannot update the metric container when not joined\n"); + return; + } + + if(dag->rank == ROOT_RANK(instance)) { + path_metric = 0; + } else { + path_metric = calculate_path_metric(dag->preferred_parent); + } + +#if RPL_DAG_MC == RPL_DAG_MC_ETX + instance->mc.length = sizeof(instance->mc.obj.etx); + instance->mc.obj.etx = path_metric; + + PRINTF("RPL: My path ETX to the root is %u.%u\n", + instance->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR, + (instance->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / + RPL_DAG_MC_ETX_DIVISOR); +#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY + instance->mc.length = sizeof(instance->mc.obj.energy); + + if(dag->rank == ROOT_RANK(instance)) { + type = RPL_DAG_MC_ENERGY_TYPE_MAINS; + } else { + type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; + } + + instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; + instance->mc.obj.energy.energy_est = path_metric; +#endif /* RPL_DAG_MC == RPL_DAG_MC_ETX */ +} +#endif /* RPL_DAG_MC == RPL_DAG_MC_NONE */ + +/*------------------------------------------------------------------*/ + static void dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime, uint8_t seq_no); void dco_output @@ -109,6 +332,11 @@ void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); static uint8_t dao_sequence = RPL_LOLLIPOP_INIT; +uint8_t rpl_leaf = RPL_LEAF_ONLY; +uint8_t leaf_dio = 0; + +extern rpl_of_t RPL_OF; + #if RPL_WITH_DCO uint8_t path_sequence = RPL_LOLLIPOP_INIT; static uint8_t dco_sequence = RPL_LOLLIPOP_INIT; diff --git a/core/net/rpl/rpl-mrhof.c b/core/net/rpl/rpl-mrhof.c index c51ac869422..9d75f319ba7 100755 --- a/core/net/rpl/rpl-mrhof.c +++ b/core/net/rpl/rpl-mrhof.c @@ -1,3 +1,7 @@ +/** + * \addtogroup uip6 + * @{ + */ /* * Copyright (c) 2010, Swedish Institute of Computer Science. * All rights reserved. @@ -29,288 +33,234 @@ * This file is part of the Contiki operating system. * */ - /** * \file - * The Minimum Rank with Hysteresis Objective Function (MRHOF), RFC6719 + * The Minimum Rank with Hysteresis Objective Function (MRHOF) * - * This implementation uses the estimated number of + * This implementation uses the estimated number of * transmissions (ETX) as the additive routing metric, * and also provides stubs for the energy metric. * * \author Joakim Eriksson , Nicolas Tsiftes */ -/** - * \addtogroup uip6 - * @{ - */ - -#include "net/rpl/rpl.h" #include "net/rpl/rpl-private.h" #include "net/nbr-table.h" -#include "net/link-stats.h" #define DEBUG DEBUG_NONE #include "net/ip/uip-debug.h" -/* RFC6551 and RFC6719 do not mandate the use of a specific formula to - * compute the ETX value. This MRHOF implementation relies on the value - * computed by the link-stats module. It has an optional feature, - * RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value. - * This basically penalizes bad links while preserving the semantics of ETX - * (1 = perfect link, more = worse link). As a result, MRHOF will favor - * good links over short paths. Recommended when reliability is a priority. - * Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two - * perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former - * path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */ -#ifdef RPL_MRHOF_CONF_SQUARED_ETX -#define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX -#else /* RPL_MRHOF_CONF_SQUARED_ETX */ -#define RPL_MRHOF_SQUARED_ETX 0 -#endif /* RPL_MRHOF_CONF_SQUARED_ETX */ - -#if !RPL_MRHOF_SQUARED_ETX -/* Configuration parameters of RFC6719. Reject parents that have a higher - * link metric than the following. The default value is 512 but we use 1024. */ -#define MAX_LINK_METRIC 1024 /* Eq ETX of 8 */ -/* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV - * in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5. - * We use a more aggressive setting: 96, eq ETX of 0.75. - */ -#define PARENT_SWITCH_THRESHOLD 96 /* Eq ETX of 0.75 */ -#else /* !RPL_MRHOF_SQUARED_ETX */ -#define MAX_LINK_METRIC 2048 /* Eq ETX of 4 */ -#define PARENT_SWITCH_THRESHOLD 160 /* Eq ETX of 1.25 (results in a churn comparable -to the threshold of 96 in the non-squared case) */ -#endif /* !RPL_MRHOF_SQUARED_ETX */ +static void reset(rpl_dag_t *); +static void neighbor_link_callback(rpl_parent_t *, int, int); +static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); +static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); +static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); +static void update_metric_container(rpl_instance_t *); + +rpl_of_t rpl_mrhof = { + reset, + neighbor_link_callback, + best_parent, + best_dag, + calculate_rank, + update_metric_container, + 1 +}; + +/* Constants for the ETX moving average */ +#define ETX_SCALE 100 +#define ETX_ALPHA 90 + +/* Reject parents that have a higher link metric than the following. */ +#define MAX_LINK_METRIC 10 /* Reject parents that have a higher path cost than the following. */ -#define MAX_PATH_COST 32768 /* Eq path ETX of 256 */ +#define MAX_PATH_COST 100 -/*---------------------------------------------------------------------------*/ -static void -reset(rpl_dag_t *dag) +/* + * The rank must differ more than 1/PARENT_SWITCH_THRESHOLD_DIV in order + * to switch preferred parent. + */ +#define PARENT_SWITCH_THRESHOLD_DIV 2 + +typedef uint16_t rpl_path_metric_t; + +static rpl_path_metric_t +calculate_path_metric(rpl_parent_t *p) { - PRINTF("RPL: Reset MRHOF\n"); + if(p == NULL) { + return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; + } + +#if RPL_DAG_MC == RPL_DAG_MC_NONE + return p->rank + (uint16_t)p->link_metric; +#elif RPL_DAG_MC == RPL_DAG_MC_ETX + return p->mc.obj.etx + (uint16_t)p->link_metric; +#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY + return p->mc.obj.energy.energy_est + (uint16_t)p->link_metric; +#else +#error "Unsupported RPL_DAG_MC configured. See rpl.h." +#endif /* RPL_DAG_MC */ } -/*---------------------------------------------------------------------------*/ -#if RPL_WITH_DAO_ACK + static void -dao_ack_callback(rpl_parent_t *p, int status) +reset(rpl_dag_t *sag) { - if(status == RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT) { - return; - } - /* here we need to handle failed DAO's and other stuff */ - PRINTF("RPL: MRHOF - DAO ACK received with status: %d\n", status); - if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) { - /* punish the ETX as if this was 10 packets lost */ - link_stats_packet_sent(rpl_get_parent_lladdr(p), MAC_TX_OK, 10); - } else if(status == RPL_DAO_ACK_TIMEOUT) { /* timeout = no ack */ - /* punish the total lack of ACK with a similar punishment */ - link_stats_packet_sent(rpl_get_parent_lladdr(p), MAC_TX_OK, 10); - } + PRINTF("RPL: Reset MRHOF\n"); } -#endif /* RPL_WITH_DAO_ACK */ -/*---------------------------------------------------------------------------*/ -static uint16_t -parent_link_metric(rpl_parent_t *p) + +static void +neighbor_link_callback(rpl_parent_t *p, int status, int numtx) { - const struct link_stats *stats = rpl_get_parent_link_stats(p); - if(stats != NULL) { -#if RPL_MRHOF_SQUARED_ETX - uint32_t squared_etx = ((uint32_t)stats->etx * stats->etx) / LINK_STATS_ETX_DIVISOR; - return (uint16_t)MIN(squared_etx, 0xffff); -#else /* RPL_MRHOF_SQUARED_ETX */ - return stats->etx; -#endif /* RPL_MRHOF_SQUARED_ETX */ + uint16_t recorded_etx = p->link_metric; + uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR; + uint16_t new_etx; + + /* Do not penalize the ETX when collisions or transmission errors occur. */ + if(status == MAC_TX_OK || status == MAC_TX_NOACK) { + if(status == MAC_TX_NOACK) { + packet_etx = MAX_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; + } + + new_etx = ((uint32_t)recorded_etx * ETX_ALPHA + + (uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE; + + PRINTF("RPL: ETX changed from %u to %u (packet ETX = %u)\n", + (unsigned)(recorded_etx / RPL_DAG_MC_ETX_DIVISOR), + (unsigned)(new_etx / RPL_DAG_MC_ETX_DIVISOR), + (unsigned)(packet_etx / RPL_DAG_MC_ETX_DIVISOR)); + p->link_metric = new_etx; } - return 0xffff; } -/*---------------------------------------------------------------------------*/ -static uint16_t -parent_path_cost(rpl_parent_t *p) + +static rpl_rank_t +calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) { - uint16_t base; + rpl_rank_t new_rank; + rpl_rank_t rank_increase; - if(p == NULL || p->dag == NULL || p->dag->instance == NULL) { - return 0xffff; + if(p == NULL) { + if(base_rank == 0) { + return INFINITE_RANK; + } + rank_increase = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; + } else { + rank_increase = p->link_metric; + if(base_rank == 0) { + base_rank = p->rank; + } } -#if RPL_WITH_MC - /* Handle the different MC types */ - switch(p->dag->instance->mc.type) { - case RPL_DAG_MC_ETX: - base = p->mc.obj.etx; - break; - case RPL_DAG_MC_ENERGY: - base = p->mc.obj.energy.energy_est << 8; - break; - default: - base = p->rank; - break; + if(INFINITE_RANK - base_rank < rank_increase) { + /* Reached the maximum rank. */ + new_rank = INFINITE_RANK; + } else { + /* Calculate the rank based on the new rank information from DIO or + stored otherwise. */ + new_rank = base_rank + rank_increase; } -#else /* RPL_WITH_MC */ - base = p->rank; -#endif /* RPL_WITH_MC */ - /* path cost upper bound: 0xffff */ - return MIN((uint32_t)base + parent_link_metric(p), 0xffff); + return new_rank; } -/*---------------------------------------------------------------------------*/ -static rpl_rank_t -rank_via_parent(rpl_parent_t *p) -{ - uint16_t min_hoprankinc; - uint16_t path_cost; - if(p == NULL || p->dag == NULL || p->dag->instance == NULL) { - return INFINITE_RANK; +static rpl_dag_t * +best_dag(rpl_dag_t *d1, rpl_dag_t *d2) +{ + if(d1->grounded != d2->grounded) { + return d1->grounded ? d1 : d2; } - min_hoprankinc = p->dag->instance->min_hoprankinc; - path_cost = parent_path_cost(p); + if(d1->preference != d2->preference) { + return d1->preference > d2->preference ? d1 : d2; + } - /* Rank lower-bound: parent rank + min_hoprankinc */ - return MAX(MIN((uint32_t)p->rank + min_hoprankinc, 0xffff), path_cost); -} -/*---------------------------------------------------------------------------*/ -static int -parent_is_acceptable(rpl_parent_t *p) -{ - uint16_t link_metric = parent_link_metric(p); - uint16_t path_cost = parent_path_cost(p); - /* Exclude links with too high link metrics or path cost (RFC6719, 3.2.2) */ - return link_metric <= MAX_LINK_METRIC && path_cost <= MAX_PATH_COST; -} -/*---------------------------------------------------------------------------*/ -static int -parent_has_usable_link(rpl_parent_t *p) -{ - uint16_t link_metric = parent_link_metric(p); - /* Exclude links with too high link metrics */ - return link_metric <= MAX_LINK_METRIC; + return d1->rank < d2->rank ? d1 : d2; } -/*---------------------------------------------------------------------------*/ + static rpl_parent_t * best_parent(rpl_parent_t *p1, rpl_parent_t *p2) { rpl_dag_t *dag; - uint16_t p1_cost; - uint16_t p2_cost; - int p1_is_acceptable; - int p2_is_acceptable; + rpl_path_metric_t min_diff; + rpl_path_metric_t p1_metric; + rpl_path_metric_t p2_metric; - p1_is_acceptable = p1 != NULL && parent_is_acceptable(p1); - p2_is_acceptable = p2 != NULL && parent_is_acceptable(p2); + dag = p1->dag; /* Both parents are in the same DAG. */ - if(!p1_is_acceptable) { - return p2_is_acceptable ? p2 : NULL; - } - if(!p2_is_acceptable) { - return p1_is_acceptable ? p1 : NULL; - } + min_diff = RPL_DAG_MC_ETX_DIVISOR / + PARENT_SWITCH_THRESHOLD_DIV; - dag = p1->dag; /* Both parents are in the same DAG. */ - p1_cost = parent_path_cost(p1); - p2_cost = parent_path_cost(p2); + p1_metric = calculate_path_metric(p1); + p2_metric = calculate_path_metric(p2); /* Maintain stability of the preferred parent in case of similar ranks. */ if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) { - if(p1_cost < p2_cost + PARENT_SWITCH_THRESHOLD && - p1_cost > p2_cost - PARENT_SWITCH_THRESHOLD) { + if(p1_metric < p2_metric + min_diff && + p1_metric > p2_metric - min_diff) { + PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n", + p2_metric - min_diff, + p1_metric, + p2_metric + min_diff); return dag->preferred_parent; } } - return p1_cost < p2_cost ? p1 : p2; + return p1_metric < p2_metric ? p1 : p2; } -/*---------------------------------------------------------------------------*/ -static rpl_dag_t * -best_dag(rpl_dag_t *d1, rpl_dag_t *d2) -{ - if(d1->grounded != d2->grounded) { - return d1->grounded ? d1 : d2; - } - - if(d1->preference != d2->preference) { - return d1->preference > d2->preference ? d1 : d2; - } - return d1->rank < d2->rank ? d1 : d2; -} -/*---------------------------------------------------------------------------*/ -#if !RPL_WITH_MC +#if RPL_DAG_MC == RPL_DAG_MC_NONE static void update_metric_container(rpl_instance_t *instance) { - instance->mc.type = RPL_DAG_MC_NONE; + instance->mc.type = RPL_DAG_MC; } -#else /* RPL_WITH_MC */ +#else static void update_metric_container(rpl_instance_t *instance) { + rpl_path_metric_t path_metric; rpl_dag_t *dag; - uint16_t path_cost; +#if RPL_DAG_MC == RPL_DAG_MC_ENERGY uint8_t type; +#endif + + instance->mc.type = RPL_DAG_MC; + instance->mc.flags = RPL_DAG_MC_FLAG_P; + instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; + instance->mc.prec = 0; dag = instance->current_dag; - if(dag == NULL || !dag->joined) { + + if (!dag->joined) { PRINTF("RPL: Cannot update the metric container when not joined\n"); return; } if(dag->rank == ROOT_RANK(instance)) { - /* Configure MC at root only, other nodes are auto-configured when joining */ - instance->mc.type = RPL_DAG_MC; - instance->mc.flags = 0; - instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE; - instance->mc.prec = 0; - path_cost = dag->rank; + path_metric = 0; } else { - path_cost = parent_path_cost(dag->preferred_parent); + path_metric = calculate_path_metric(dag->preferred_parent); } - /* Handle the different MC types */ - switch(instance->mc.type) { - case RPL_DAG_MC_NONE: - break; - case RPL_DAG_MC_ETX: - instance->mc.length = sizeof(instance->mc.obj.etx); - instance->mc.obj.etx = path_cost; - break; - case RPL_DAG_MC_ENERGY: - instance->mc.length = sizeof(instance->mc.obj.energy); - if(dag->rank == ROOT_RANK(instance)) { - type = RPL_DAG_MC_ENERGY_TYPE_MAINS; - } else { - type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; - } - instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; - /* Energy_est is only one byte, use the least significant byte of the path metric. */ - instance->mc.obj.energy.energy_est = path_cost >> 8; - break; - default: - PRINTF("RPL: MRHOF, non-supported MC %u\n", instance->mc.type); - break; +#if RPL_DAG_MC == RPL_DAG_MC_ETX + instance->mc.length = sizeof(instance->mc.obj.etx); + instance->mc.obj.etx = path_metric; + + PRINTF("RPL: My path ETX to the root is %u.%u\n", + instance->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR, + (instance->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) / + RPL_DAG_MC_ETX_DIVISOR); +#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY + instance->mc.length = sizeof(instance->mc.obj.energy); + + if(dag->rank == ROOT_RANK(instance)) { + type = RPL_DAG_MC_ENERGY_TYPE_MAINS; + } else { + type = RPL_DAG_MC_ENERGY_TYPE_BATTERY; } -} -#endif /* RPL_WITH_MC */ -/*---------------------------------------------------------------------------*/ -rpl_of_t rpl_mrhof = { - reset, -#if RPL_WITH_DAO_ACK - dao_ack_callback, -#endif - parent_link_metric, - parent_has_usable_link, - parent_path_cost, - rank_via_parent, - best_parent, - best_dag, - update_metric_container, - RPL_OCP_MRHOF -}; -/** @}*/ + instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE; + instance->mc.obj.energy.energy_est = path_metric; +#endif /* RPL_DAG_MC == RPL_DAG_MC_ETX */ +} +#endif /* RPL_DAG_MC == RPL_DAG_MC_NONE */ diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index d0bfd1296fa..a35d12fc9d3 100755 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -50,6 +50,29 @@ #define DEBUG DEBUG_NONE #include "net/ip/uip-debug.h" +static void reset(rpl_dag_t *); + static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); + static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); + static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); + static void update_metric_container(rpl_instance_t *); + + + rpl_of_t rpl_of0 = { + reset, + NULL, + best_parent, + best_dag, + calculate_rank, + update_metric_container, + 0 + }; + + #define DEFAULT_RANK_INCREMENT RPL_MIN_HOPRANKINC + + + + #define MIN_DIFFERENCE (RPL_MIN_HOPRANKINC + RPL_MIN_HOPRANKINC / 2) + /* Constants from RFC6552. We use the default values. */ #define RANK_STRETCH 0 /* Must be in the range [0;5] */ #define RANK_FACTOR 1 /* Must be in the range [1;4] */ @@ -161,78 +184,82 @@ parent_has_usable_link(rpl_parent_t *p) return parent_is_acceptable(p); } /*---------------------------------------------------------------------------*/ -static rpl_parent_t * -best_parent(rpl_parent_t *p1, rpl_parent_t *p2) -{ - rpl_dag_t *dag; - uint16_t p1_cost; - uint16_t p2_cost; - int p1_is_acceptable; - int p2_is_acceptable; - - p1_is_acceptable = p1 != NULL && parent_is_acceptable(p1); - p2_is_acceptable = p2 != NULL && parent_is_acceptable(p2); - - if(!p1_is_acceptable) { - return p2_is_acceptable ? p2 : NULL; - } - if(!p2_is_acceptable) { - return p1_is_acceptable ? p1 : NULL; - } - - dag = p1->dag; /* Both parents are in the same DAG. */ - p1_cost = parent_path_cost(p1); - p2_cost = parent_path_cost(p2); - - /* Paths costs coarse-grained (multiple of min_hoprankinc), we operate without hysteresis */ - if(p1_cost != p2_cost) { - /* Pick parent with lowest path cost */ - return p1_cost < p2_cost ? p1 : p2; - } else { - /* We have a tie! */ - /* Stik to current preferred parent if possible */ - if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) { - return dag->preferred_parent; - } - /* None of the nodes is the current preferred parent, - * choose parent with best link metric */ - return parent_link_metric(p1) < parent_link_metric(p2) ? p1 : p2; - } -} + static rpl_parent_t * + best_parent(rpl_parent_t *p1, rpl_parent_t *p2) + { + rpl_rank_t r1, r2; + rpl_dag_t *dag; + + PRINTF("RPL: Comparing parent "); + PRINT6ADDR(rpl_get_parent_ipaddr(p1)); + PRINTF(" (confidence %d, rank %d) with parent ", + p1->link_metric, p1->rank); + PRINT6ADDR(rpl_get_parent_ipaddr(p2)); + PRINTF(" (confidence %d, rank %d)\n", + p2->link_metric, p2->rank); + + + + + r1 = DAG_RANK(p1->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC + + p1->link_metric; + r2 = DAG_RANK(p2->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC + + p2->link_metric; + /* Compare two parents by looking both and their rank and at the ETX + for that parent. We choose the parent that has the most + favourable combination. */ + + + + + dag = (rpl_dag_t *)p1->dag; /* Both parents must be in the same DAG. */ + if(r1 < r2 + MIN_DIFFERENCE && + r1 > r2 - MIN_DIFFERENCE) { + return dag->preferred_parent; + } else if(r1 < r2) { + return p1; + } else { + return p2; + + + + + + + + } + } /*---------------------------------------------------------------------------*/ -static rpl_dag_t * -best_dag(rpl_dag_t *d1, rpl_dag_t *d2) -{ - if(d1->grounded != d2->grounded) { - return d1->grounded ? d1 : d2; - } + static rpl_dag_t * + best_dag(rpl_dag_t *d1, rpl_dag_t *d2) + + { + if(d1->grounded) { + if (!d2->grounded) { + return d1; + } + } else if(d2->grounded) { + return d2; - if(d1->preference != d2->preference) { - return d1->preference > d2->preference ? d1 : d2; - } + } + + if(d1->preference < d2->preference) { + return d2; + } else { + if(d1->preference > d2->preference) { + return d1; + } + + + } + + if(d2->rank < d1->rank) { + return d2; + + } else { + return d1; + } + } - return d1->rank < d2->rank ? d1 : d2; -} -/*---------------------------------------------------------------------------*/ -static void -update_metric_container(rpl_instance_t *instance) -{ - instance->mc.type = RPL_DAG_MC_NONE; -} -/*---------------------------------------------------------------------------*/ -rpl_of_t rpl_of0 = { - reset, -#if RPL_WITH_DAO_ACK - dao_ack_callback, -#endif - parent_link_metric, - parent_has_usable_link, - parent_path_cost, - rank_via_parent, - best_parent, - best_dag, - update_metric_container, - RPL_OCP_OF0 -}; /** @}*/ diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 88c98353def..b9420f94836 100755 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -77,6 +77,8 @@ static uint16_t next_dis; /* dio_send_ok is true if the node is ready to send DIOs */ static uint8_t dio_send_ok; +extern uint8_t rpl_leaf; + /*---------------------------------------------------------------------------*/ static void handle_periodic_timer(void *ptr) diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index b601a71da6c..b66ebb8eceb 100755 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -266,7 +266,7 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx) if(parent != NULL) { /* Trigger DAG rank recalculation. */ PRINTF("RPL: rpl_link_neighbor_callback triggering update\n"); - parent->flags |= RPL_PARENT_FLAG_UPDATED; + parent->updated = 1; } } } @@ -293,7 +293,7 @@ rpl_ipv6_neighbor_callback(uip_ds6_nbr_t *nbr) p->rank = INFINITE_RANK; /* Trigger DAG rank recalculation. */ PRINTF("RPL: rpl_ipv6_neighbor_callback infinite rank\n"); - p->flags |= RPL_PARENT_FLAG_UPDATED; + p->updated = 1; } } } diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index 26ee71edc49..903d07b2df2 100755 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -38,12 +38,24 @@ #ifndef RPL_H #define RPL_H -#include "rpl-conf.h" + + #include "net/rpl/rpl-conf.h" + + #include "lib/list.h" + #include "net/ip/uip.h" + #include "net/ipv6/uip-ds6.h" + #include "sys/ctimer.h" -#include "lib/list.h" -#include "net/ip/uip.h" -#include "net/ipv6/uip-ds6.h" -#include "sys/ctimer.h" +struct rpl_metric_object_energy { + uint8_t flags; + uint8_t energy_est; +}; + +typedef struct rpl_metric_object_energy rpl_metric_object_energy_t; + + #ifdef USE_METRIC_CONTAINERS + #include "rpl-metrics-data.h" + #endif /* USE_METRIC_CONTAINERS */ /*---------------------------------------------------------------------------*/ typedef uint16_t rpl_rank_t; @@ -72,6 +84,26 @@ typedef uint16_t rpl_ocp_t; #define RPL_DAG_MC_AGGR_MINIMUM 2 #define RPL_DAG_MC_AGGR_MULTIPLICATIVE 3 + /* position of the fields in metric container * + * object header flags */ + #define RPL_DAG_MC_POS_P_BIT 10 + #define RPL_DAG_MC_POS_C_BIT 9 + #define RPL_DAG_MC_POS_O_BIT 8 + #define RPL_DAG_MC_POS_R_BIT 7 + #define RPL_DAG_MC_POS_A_FIELD 4 + #define RPL_DAG_MC_POS_PREC_FIELD 0 + + /* The bit index within the flags field of + the rpl_metric_object_energy structure. */ + #define RPL_DAG_MC_ENERGY_INCLUDED 3 + #define RPL_DAG_MC_ENERGY_TYPE 1 + #define RPL_DAG_MC_ENERGY_ESTIMATION 0 + + #define RPL_DAG_MC_ENERGY_TYPE_MAINS 0 + #define RPL_DAG_MC_ENERGY_TYPE_BATTERY 1 + #define RPL_DAG_MC_ENERGY_TYPE_SCAVENGING 2 + + /* The bit index within the flags field of the rpl_metric_object_energy structure. */ #define RPL_DAG_MC_ENERGY_INCLUDED 3 #define RPL_DAG_MC_ENERGY_TYPE 1 @@ -86,11 +118,12 @@ typedef uint16_t rpl_ocp_t; #define RPL_OCP_OF0 0 #define RPL_OCP_MRHOF 1 -struct rpl_metric_object_energy { +/*struct rpl_metric_object_energy { uint8_t flags; uint8_t energy_est; -}; +};*/ +#ifndef USE_METRIC_CONTAINERS /* Logical representation of a DAG Metric Container. */ struct rpl_metric_container { uint8_t type; @@ -104,6 +137,7 @@ struct rpl_metric_container { } obj; }; typedef struct rpl_metric_container rpl_metric_container_t; +#endif /* USE_METRIC_CONTAINERS */ /*---------------------------------------------------------------------------*/ struct rpl_instance; struct rpl_dag; @@ -111,16 +145,29 @@ struct rpl_dag; #define RPL_PARENT_FLAG_UPDATED 0x1 #define RPL_PARENT_FLAG_LINK_METRIC_VALID 0x2 -struct rpl_parent { - struct rpl_dag *dag; -#if RPL_WITH_MC - rpl_metric_container_t mc; -#endif /* RPL_WITH_MC */ - rpl_rank_t rank; - uint8_t dtsn; - uint8_t flags; -}; -typedef struct rpl_parent rpl_parent_t; + struct rpl_parent { + struct rpl_parent *next; + struct rpl_dag *dag; + #if RPL_DAG_MC != RPL_DAG_MC_NONE + rpl_metric_container_t mc; + #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ + rpl_rank_t rank; + + //#ifdef RPL_DAG_MC_USE_ETX + uint16_t etx; + //#endif /* RPL_DAG_MC_USE_ETX */ + #ifdef RPL_DAG_MC_USE_LQL + uint8_t lql; + #endif /* RPL_DAG_MC_USE_LQL */ + #ifdef RPL_DAG_MC_USE_LC + uint16_t lc; + #endif /* RPL_DAG_MC_USE_LC */ + uint8_t link_metric; + uint8_t dtsn; + uint8_t updated; + uint8_t flags; + }; + typedef struct rpl_parent rpl_parent_t; /*---------------------------------------------------------------------------*/ /* RPL DIO prefix suboption */ struct rpl_prefix { @@ -144,6 +191,7 @@ struct rpl_dag { rpl_parent_t *preferred_parent; rpl_rank_t rank; struct rpl_instance *instance; + LIST_STRUCT(parents); rpl_prefix_t prefix_info; uint32_t lifetime; }; @@ -200,6 +248,11 @@ typedef struct rpl_instance rpl_instance_t; */ struct rpl_of { void (*reset)(struct rpl_dag *); + + #if defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) + void (*neighbor_link_callback)(rpl_parent_t *, int, int); + #endif /* defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) */ + #if RPL_WITH_DAO_ACK void (*dao_ack_callback)(rpl_parent_t *, int status); #endif @@ -209,6 +262,7 @@ struct rpl_of { rpl_rank_t (*rank_via_parent)(rpl_parent_t *); rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *); rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *); + rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t); void (*update_metric_container)( rpl_instance_t *); rpl_ocp_t ocp; }; @@ -277,8 +331,12 @@ rpl_instance_t *rpl_get_instance(uint8_t instance_id); int rpl_update_header(void); int rpl_finalize_header(uip_ipaddr_t *addr); int rpl_verify_hbh_header(int); +void rpl_update_header_empty(void); +int rpl_update_header_final(uip_ipaddr_t *addr); +int rpl_verify_header(int); void rpl_insert_header(void); void rpl_remove_header(void); +uint8_t rpl_invert_header(void); const struct link_stats *rpl_get_parent_link_stats(rpl_parent_t *p); int rpl_parent_is_fresh(rpl_parent_t *p); int rpl_parent_is_reachable(rpl_parent_t *p); @@ -288,6 +346,7 @@ const linkaddr_t *rpl_get_parent_lladdr(rpl_parent_t *p); uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr); rpl_parent_t *rpl_get_parent(uip_lladdr_t *addr); rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr); + void rpl_dag_init(void); uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent); void rpl_print_neighbor_list(void); diff --git a/examples/containers/#Makefile# b/examples/containers/#Makefile# new file mode 100644 index 00000000000..5ece27b4927 --- /dev/null +++ b/examples/containers/#Makefile# @@ -0,0 +1,49 @@ +CONTIKI = ../.. + + +ifndef TARGET +TARGET=z1 +endif + +#OPTI=0 for debugging +ifndef OPTI +OPTI=0 +endif + + +APPS = powertrace collect-view +CONTIKI_PROJECT = server client +PROJECT_SOURCEFILES += collect-common.c rpl-metrics.c rpl-metrics-get.c rpl-metrics-containers-OF.c + + +WITH_UIP6=1 +UIP_CONF_IPV6=1 +UIP_CONF_TCP=0 +#RPL_CONF_DAG_MC=2 !!!!!!!!!!!!!! +SMALL=1 + +#to debug a file add to CFLAGS -Dtag with tag= +#DEBUG_RPL_ICMP6 +#DEBUG_RPL_DAG +#DEBUG_RPL_METRICS +#DEBUG_RPL_METRICS_GET +#DEBUG_RPL_OF + +#use LEDS to show when there is a default parent +#USE_LEDS_DEF_PARENT + +#use button to simulate loss of communication from/to a node +#BUTTON_INTERFERENCE + +#-gdwarf-4 for debugging +CFLAGS+= -DDEBUG_RPL_METRICS -DDEBUG_RPL_OF -DDEBUG_RPL_DAG +CFLAGS+= -DUIP_CONF_IPV6_RPL -DUSE_LEDS_DEF_PARENT -DBUTTON_INTERFERENCE -DPROJECT_CONF_H=\"project-conf.h\" + +#ifdef PERIOD +#CFLAGS=-DPERIOD=$(PERIOD) +#endif + +all: $(CONTIKI_PROJECT) + +include $(CONTIKI)/Makefile.include + diff --git a/examples/containers/3 nodos.csc b/examples/containers/3 nodos.csc new file mode 100644 index 00000000000..b593147bc0a --- /dev/null +++ b/examples/containers/3 nodos.csc @@ -0,0 +1,168 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + My simulation + 123456 + 100000 + + se.sics.cooja.radiomediums.UDGM + 20.0 + 25.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.Z1MoteType + z11 + server + [CONFIG_DIR]/server.z1 + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.MspButton + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + se.sics.cooja.mspmote.interfaces.MspLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + + + se.sics.cooja.mspmote.Z1MoteType + z12 + client + [CONFIG_DIR]/client.z1 + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.MspButton + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + se.sics.cooja.mspmote.interfaces.MspLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + + + + + se.sics.cooja.interfaces.Position + 54.335467383479994 + 4.747565694681829 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + z11 + + + + + se.sics.cooja.interfaces.Position + 63.06567445836441 + 17.713731231936247 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + net~; + + z12 + + + + + se.sics.cooja.interfaces.Position + 58.933032056052255 + 31.919689489884306 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 6 + + z12 + + + + se.sics.cooja.plugins.SimControl + 280 + 1 + 160 + 191 + 3 + + + se.sics.cooja.plugins.Visualizer + + true + se.sics.cooja.plugins.skins.IDVisualizerSkin + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + se.sics.cooja.plugins.skins.TrafficVisualizerSkin + se.sics.cooja.plugins.skins.LEDVisualizerSkin + 3.87161492391604 0.0 0.0 3.87161492391604 -131.16600641983428 -3.580746195802032 + + 154 + 2 + 236 + 6 + -1 + + + se.sics.cooja.plugins.RadioLogger + + 150 + + false + false + + + + + + + + + + + + 803 + 3 + 424 + 371 + 166 + + + se.sics.cooja.plugins.LogListener + + PRUEBA + + + + 888 + 0 + 991 + -4 + 332 + + + diff --git a/examples/containers/Makefile b/examples/containers/Makefile new file mode 100644 index 00000000000..86e13d0b51f --- /dev/null +++ b/examples/containers/Makefile @@ -0,0 +1,51 @@ +CONTIKI = ../.. + + +ifndef TARGET +TARGET=z1 +endif + +#OPTI=0 for debugging +ifndef OPTI +OPTI=0 +endif + + +APPS = powertrace collect-view +CONTIKI_PROJECT = server client +PROJECT_SOURCEFILES += collect-common.c rpl-metrics.c rpl-metrics-get.c rpl-metrics-containers-OF.c + + +WITH_UIP6=1 +UIP_CONF_IPV6=1 +UIP_CONF_TCP=0 +PERIOD=30 +#RPL_CONF_DAG_MC=2 +SMALL=1 + +#to debug a file add to CFLAGS -Dtag with tag= +#DEBUG_RPL_ICMP6 +#DEBUG_RPL_DAG +#DEBUG_RPL_TIMERS +#DEBUG_RPL_METRICS +#DEBUG_RPL_METRICS_GET +#DEBUG_RPL_OF + +#use LEDS to show when there is a default parent +#USE_LEDS_DEF_PARENT + +#use button to simulate loss of communication from/to a node +#BUTTON_INTERFERENCE + +#-gdwarf-4 for debugging +CFLAGS+= #-DDEBUG_RPL_METRICS -DDEBUG_RPL_OF +CFLAGS+= -DSTATISTICS -DUIP_CONF_IPV6_RPL -DUSE_LEDS_DEF_PARENT -DBUTTON_INTERFERENCE -DPROJECT_CONF_H=\"project-conf.h\" + +#ifdef PERIOD +#CFLAGS=-DPERIOD=$(PERIOD) +#endif + +all: $(CONTIKI_PROJECT) + +include $(CONTIKI)/Makefile.include + diff --git a/examples/containers/client.c b/examples/containers/client.c new file mode 100644 index 00000000000..a33fe908abe --- /dev/null +++ b/examples/containers/client.c @@ -0,0 +1,502 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "contiki.h" +#include +#include +#include +#include "lib/random.h" +#include "sys/ctimer.h" +#include "net/ip/uip.h" +#include "net/ipv6/uip-ds6.h" +#include "net/ip/uip-udp-packet.h" +#include "net/rpl/rpl.h" +#include "sys/ctimer.h" +#ifdef WITH_COMPOWER +#include "powertrace.h" +#endif +#include +#include +#include "common-hdr.h" +#include "dev/serial-line.h" +#include "net/rime/rimeaddr.h" +#include "common-hdr.h" +#include "udp-app.h" + +#ifdef BUTTON_INTERFERENCE +#include "dev/button-sensor.h" +#endif +//#ifdef USE_LEDS_DEF_PARENT +#include "dev/leds.h" +//#endif + + +#if CONTIKI_TARGET_Z1 +#include "dev/uart0.h" +#else +#include "dev/uart1.h" +#endif +#include "collect-common.h" +#include "collect-view.h" + +#include +#include + +#define UDP_CLIENT_PORT 8765 +#define UDP_SERVER_PORT 5678 + +#define DEBUG DEBUG_PRINT +#include "net/ip/uip-debug.h" + +#include "net/ipv6/uip-ds6-route.h" + +#define UDP_EXAMPLE_ID 190 + +#ifndef PERIOD +#define PERIOD 300 +#endif + +#define START_INTERVAL (15 * CLOCK_SECOND) +#define SEND_INTERVAL (PERIOD * CLOCK_SECOND) +#define SEND_TIME (random_rand() % (SEND_INTERVAL)) +#define MAX_PAYLOAD_LEN 1024 +#if 0 +typedef struct _app_stat_ +{ + uint32_t lastseq; + uint32_t dropcnt; + uint32_t unordered; + uint32_t rcvcnt; + uint32_t dupcnt; + long leastLatency; +}app_stat_t; + +app_stat_t g_stats; +#endif + +dpkt_stat_t g_pktstat; + +static struct uip_udp_conn *client_conn; +static uip_ipaddr_t server_ipaddr; + +/*---------------------------------------------------------------------------*/ +PROCESS(udp_client_process, "UDP client process"); +AUTOSTART_PROCESSES(&udp_client_process, &collect_common_process); + +static int seq_id; + static int reply; + + long dpkt_latency_time(struct timeval *tv) + { + long duration=0; + long sentTime=0; + long recvTime=0; + struct timeval curTime; + gettimeofday(&curTime, NULL); + + sentTime = tv->tv_sec * 1000000; + sentTime += tv->tv_usec; + + recvTime = curTime.tv_sec * 1000000; + recvTime += curTime.tv_usec; + + if (recvTime > sentTime){ + duration = recvTime-sentTime; + } + + #if 0 + if (curTime.tv_sec > tv->tv_sec){ + duration = (curTime.tv_sec - tv->tv_sec) * 1000000; + + + + } + + if (curTime.tv_usec > tv->tv_usec){ + duration += (curTime.tv_usec - tv->tv_usec); + + + } + #endif + + return duration; + } +/*---------------------------------------------------------------------------*/ +void +collect_common_set_sink(void) +{ + /* A udp client can never become sink */ +} +/*---------------------------------------------------------------------------*/ + +/* Information printed with "net" in serial port interface */ +void +collect_common_net_print(void) +{ + rpl_dag_t *dag; + uip_ds6_route_t *r; + + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); + if(dag->preferred_parent != NULL) { + PRINTF("Preferred parent: "); + PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent)); + PRINTF("\n"); + } + for(r = uip_ds6_route_head(); + r != NULL; + r = uip_ds6_route_next(r)) { + PRINT6ADDR(&r->ipaddr); + PRINTF("\n"); + } + PRINTF("---\n"); + +} +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + dpkt_t *pkt; + long curpktlatency; + + if(uip_newdata()) { + pkt = (dpkt_t *)uip_appdata; + + if (!g_pktstat.lastseq){ + g_pktstat.lastseq = pkt->seq; + g_pktstat.rcvcnt++; + g_pktstat.leastLatency = g_pktstat.maxLatency = curpktlatency = dpkt_latency_time(&(pkt->sendTime)); + return; + } + + PRINTF("Recvd Response with seq[%u] last rsp seq[%u]\n",pkt->seq, g_pktstat.lastseq); + + if (pkt->seq == g_pktstat.lastseq){ + g_pktstat.dupcnt++; + } + else if(pkt->seq < g_pktstat.lastseq) { + g_pktstat.unordered++; + g_pktstat.rcvcnt++; + } + else{ + g_pktstat.lastseq = pkt->seq; + g_pktstat.rcvcnt++; + } + + curpktlatency = dpkt_latency_time(&(pkt->sendTime)); + if (curpktlatency < g_pktstat.leastLatency){ + g_pktstat.leastLatency = curpktlatency; + + } + if (curpktlatency > g_pktstat.maxLatency){ + g_pktstat.maxLatency = curpktlatency; +} + +reply++; + printf("DATA recv (s:%d, r:%d) end2nd latency[%lu] minlatency[%lu]\n", seq_id, reply, curpktlatency, g_pktstat.leastLatency); + } + } + + uint32_t g_seq = 0; + uint32_t g_payload_len=32; + +static void +send_packet(void *ptr) +{ + char buf[MAX_PAYLOAD_LEN]; + dpkt_t *pkt=(dpkt_t*)buf; + + if(sizeof(buf) < sizeof(pkt)+g_payload_len) { + printf("buffer size mismatch .. expect no UDP pkt\n"); + return; + } + + seq_id++; + pkt->seq = seq_id; + gettimeofday(&(pkt->sendTime), NULL); + + PRINTF("DATA send to %d 'Hello %d' size-%lu\n", + server_ipaddr.u8[sizeof(server_ipaddr.u8) - 1], seq_id, sizeof(pkt)+g_payload_len); + + uip_udp_packet_sendto(client_conn, buf, sizeof(pkt)+g_payload_len, + &server_ipaddr, UIP_HTONS(UDP_SERVER_PORT)); +} +/*---------------------------------------------------------------------------*/ +void +collect_common_send(void) +{ + static uint8_t seqno; + struct { + uint8_t seqno; + uint8_t for_alignment; + struct collect_view_data_msg msg; + } msg; + /* struct collect_neighbor *n; */ + uint16_t parent_etx; + uint16_t rtmetric; + uint16_t num_neighbors; + uint16_t beacon_interval; + rpl_parent_t *preferred_parent; + rimeaddr_t parent; + rpl_dag_t *dag; + + if(client_conn == NULL) { + /* Not setup yet */ + return; + } + memset(&msg, 0, sizeof(msg)); + seqno++; + if(seqno == 0) { + /* Wrap to 128 to identify restarts */ + seqno = 128; + } + msg.seqno = seqno; + + //rimeaddr_copy(&parent, &rimeaddr_null); + parent_etx = 0; + + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); + if(dag != NULL) { + preferred_parent = dag->preferred_parent; + if(preferred_parent != NULL) { + uip_ds6_nbr_t *nbr; + nbr = uip_ds6_nbr_lookup(rpl_get_parent_ipaddr(preferred_parent)); + if(nbr != NULL) { + /* Use parts of the IPv6 address as the parent address, in reversed byte order. */ + parent.u8[RIMEADDR_SIZE - 1] = nbr->ipaddr.u8[sizeof(uip_ipaddr_t) - 2]; + parent.u8[RIMEADDR_SIZE - 2] = nbr->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]; + + parent_etx= preferred_parent->etx; + /*parent_etx is divided by 8 in the java graphics*/ + parent_etx *= 8; + + } + } + rtmetric = dag->rank; + beacon_interval = (uint16_t) ((2L << dag->instance->dio_intcurrent) / 1000); + + num_neighbors= 0; + + + } else { + rtmetric = 0; + beacon_interval = 0; + num_neighbors = 0; + } + + /* num_neighbors = collect_neighbor_list_num(&tc.neighbor_list); */ + collect_view_construct_message(&msg.msg, &parent, + parent_etx, rtmetric, + num_neighbors, beacon_interval); + + uip_udp_packet_sendto(client_conn, &msg, sizeof(msg), + &server_ipaddr, UIP_HTONS(UDP_SERVER_PORT)); + +#ifdef STATISTICS + { + static uint16_t pack_sent=0; + printf("30 Packet sent: %u\n",++pack_sent); + } +#endif /*STATISTICS*/ + +} +/*---------------------------------------------------------------------------*/ +void +collect_common_net_init(void) +{ +/*#if CONTIKI_TARGET_Z1 + uart0_set_input(serial_line_input_byte); +#else + uart1_set_input(serial_line_input_byte); +#endif*/ + serial_line_init(); +} +/*---------------------------------------------------------------------------*/ +static void +print_local_addresses(void) +{ + int i; + uint8_t state; + + PRINTF("Client IPv6 addresses: "); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + PRINTF("\n"); + /* hack to make address "final" */ + if (state == ADDR_TENTATIVE) { + uip_ds6_if.addr_list[i].state = ADDR_PREFERRED; + } + } + } +} +/*---------------------------------------------------------------------------*/ +static void +set_global_address(void) +{ + uip_ipaddr_t ipaddr; + + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); + +/* Mode 2 - 16 bits inline */ + uip_ip6addr(&server_ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0x00ff, 0xfe00, 1); + + +} + + int g_send_interval=0; + int g_auto_start = 1; + void set_udp_param(void) + { + char *ptr = getenv("UDPCLI_SEND_INT"); + if(!ptr){ + PRINTF("UDP_SEND_INT env var not found\n"); + return; + } + + g_send_interval = (int)(atof(ptr)*CLOCK_SECOND); + + char *ptr1 = getenv("AUTO_START"); + if(!ptr1){ + PRINTF("AUTO_START env var not found\n"); + return; + } + + g_auto_start = (int)(atof(ptr1)); + + ptr = getenv("UDP_PAYLOAD_LEN"); + if(ptr) g_payload_len = (int)atoi(ptr); + PRINTF("UDP g_send_interval:%d g_payload_len:%d\n", + g_send_interval, g_payload_len); + + memset(&g_pktstat, 0, sizeof(g_pktstat)); + } + + static struct etimer periodic; + int udp_started = 0; +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_client_process, ev, data) +{ + +//static struct etimer periodic; + static struct ctimer backoff_timer; + unsigned long backoff; + PROCESS_BEGIN(); + + PROCESS_PAUSE(); + + +#ifdef USE_LEDS_DEF_PARENT + SENSORS_ACTIVATE(button_sensor); +#endif + + + set_global_address(); + + PRINTF("UDP client process started\n"); + + print_local_addresses(); + + /* new connection with remote host */ + client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL); + if(client_conn == NULL) { + PRINTF("No UDP connection available, exiting the process!\n"); + PROCESS_EXIT(); + } + udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT)); + + PRINTF("Created a connection with the server "); + PRINT6ADDR(&client_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", + UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); + +backoff = g_send_interval/4 + (g_send_interval / 4 * (uint32_t)random_rand()) / RANDOM_RAND_MAX; + PRINTF("Gnerated backoff[%lu]\n",backoff); + + if(g_send_interval > 0){ + etimer_set(&periodic, g_send_interval); + udp_started = 1; + } + + PRINTF("Will enter to while\n"); + + + + while(1) { + PRINTF("Will call PROCESS Yield\n"); + PROCESS_YIELD(); + PRINTF("PROCESS Yield exited\n"); + if(ev == tcpip_event) { + tcpip_handler(); + } + +PRINTF("udp_started[%d]\n", udp_started); + if(etimer_expired(&periodic)) { + etimer_reset(&periodic); + PRINTF("Timer Expired [%d]\n",g_auto_start); + //send_packet(NULL); + if (g_auto_start){ + //ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL); + backoff = g_send_interval/4 + (g_send_interval / 4 * (uint32_t)random_rand()) / RANDOM_RAND_MAX; + ctimer_set(&backoff_timer, backoff, send_packet, NULL); + } + + } + } + PRINTF("Process Stopped\n"); + PROCESS_END(); + } + + void start_udp_process() + { + PRINTF("Need to start the UDP process\n "); + if(!g_auto_start && g_send_interval > 0){ + udp_started = 1; + g_auto_start = 1; + PRINTF("Started the UDP process[%d]\n", g_send_interval); + } + } + +void udp_get_app_stat(udpapp_stat_t *appstat) +{ + PRINTF("Stats Called on Node\n"); + + appstat->totalpktsent = seq_id; + appstat->totalpktrecvd = g_pktstat.rcvcnt; + appstat->totalduppkt = g_pktstat.dupcnt; + appstat->minroudtriptime = g_pktstat.leastLatency; + appstat->maxroundtriptime = g_pktstat.maxLatency; +} + +/*---------------------------------------------------------------------------*/ diff --git a/examples/containers/collect-common.c b/examples/containers/collect-common.c new file mode 100644 index 00000000000..e61ca84e343 --- /dev/null +++ b/examples/containers/collect-common.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/** + * \file + * Example of how the collect primitive works. + * \author + * Adam Dunkels + */ + +#include "contiki.h" +#include "lib/random.h" +#include "net/netstack.h" +#include "dev/serial-line.h" +#include "dev/leds.h" +#include "collect-common.h" + +#include +#include +#include + +static unsigned long time_offset; +static int send_active = 1; + +#ifndef PERIOD +#define PERIOD 30 +#endif +#define RANDWAIT (PERIOD) + +/*---------------------------------------------------------------------------*/ +PROCESS(collect_common_process, "collect common process"); +AUTOSTART_PROCESSES(&collect_common_process); +/*---------------------------------------------------------------------------*/ +static unsigned long +get_time(void) +{ + return clock_seconds() + time_offset; +} +/*---------------------------------------------------------------------------*/ +static unsigned long +strtolong(const char *data) { + unsigned long value = 0; + int i; + for(i = 0; i < 10 && isdigit(data[i]); i++) { + value = value * 10 + data[i] - '0'; + } + return value; +} +/*---------------------------------------------------------------------------*/ +void +collect_common_set_send_active(int active) +{ + send_active = active; +} +/*---------------------------------------------------------------------------*/ +void +collect_common_recv(const rimeaddr_t *originator, uint8_t seqno, uint8_t hops, + uint8_t *payload, uint16_t payload_len) +{ + unsigned long time; + uint16_t data; + int i; + + + printf("%u", 8 + payload_len / 2); + /* Timestamp. Ignore time synch for now. */ + time = get_time(); + printf(" %lu %lu 0", ((time >> 16) & 0xffff), time & 0xffff); + /* Ignore latency for now */ + printf(" %u %u %u %u", + originator->u8[0] + (originator->u8[1] << 8), seqno, hops, 0); + for(i = 0; i < payload_len / 2; i++) { + memcpy(&data, payload, sizeof(data)); + payload += sizeof(data); + printf(" %u", data); + } + printf("\n"); + leds_blink(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(collect_common_process, ev, data) +{ + static struct etimer period_timer, wait_timer; + PROCESS_BEGIN(); + + collect_common_net_init(); + + /* Send a packet every 60-62 seconds. */ + etimer_set(&period_timer, CLOCK_SECOND * PERIOD); + while(1) { + PROCESS_WAIT_EVENT(); + if(ev == serial_line_event_message) { + char *line; + line = (char *)data; + if(strncmp(line, "collect", 7) == 0 || + strncmp(line, "gw", 2) == 0) { + collect_common_set_sink(); + } else if(strncmp(line, "net", 3) == 0) { + collect_common_net_print(); + } else if(strncmp(line, "time ", 5) == 0) { + unsigned long tmp; + line += 6; + while(*line == ' ') { + line++; + } + tmp = strtolong(line); + time_offset = clock_seconds() - tmp; + printf("Time offset set to %lu\n", time_offset); + } else if(strncmp(line, "mac ", 4) == 0) { + line +=4; + while(*line == ' ') { + line++; + } + if(*line == '0') { + NETSTACK_RDC.off(1); + printf("mac: turned MAC off (keeping radio on): %s\n", + NETSTACK_RDC.name); + } else { + NETSTACK_RDC.on(); + printf("mac: turned MAC on: %s\n", NETSTACK_RDC.name); + } + + } else if(strncmp(line, "~K", 2) == 0 || + strncmp(line, "killall", 7) == 0) { + /* Ignore stop commands */ + } else { + printf("unhandled command: %s\n", line); + } + } + if(ev == PROCESS_EVENT_TIMER) { + if(data == &period_timer) { + etimer_reset(&period_timer); + etimer_set(&wait_timer, random_rand() % (CLOCK_SECOND * RANDWAIT)); + } else if(data == &wait_timer) { + if(send_active) { + /* Time to send the data */ + collect_common_send(); + } + } + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/containers/collect-common.h b/examples/containers/collect-common.h new file mode 100644 index 00000000000..32019d4cd1a --- /dev/null +++ b/examples/containers/collect-common.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/** + * \file + * Common code between collect client and server + * \author + * Niclas Finne + */ + +#ifndef __COLLECT_COMMON_H__ +#define __COLLECT_COMMON_H__ + +#include "contiki.h" +#include "net/rime/rimeaddr.h" + +void collect_common_net_init(void); +void collect_common_net_print(void); +void collect_common_set_sink(void); +void collect_common_send(void); +void collect_common_recv(const rimeaddr_t *originator, uint8_t seqno, + uint8_t hops, + uint8_t *payload, + uint16_t payload_len); +void collect_common_set_send_active(int active); + +PROCESS_NAME(collect_common_process); + +#endif /* __COLLECT_COMMON_H__ */ diff --git a/examples/containers/collect-data.conf b/examples/containers/collect-data.conf new file mode 100644 index 00000000000..5f26d1530b6 --- /dev/null +++ b/examples/containers/collect-data.conf @@ -0,0 +1,4 @@ +#Configuration for Collect +#Wed Jul 30 16:33:07 CEST 2014 +collect.bounds=2,52,636,596 +collect.nodeinfo.table=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 diff --git a/examples/containers/collect-data.conf.bak b/examples/containers/collect-data.conf.bak new file mode 100644 index 00000000000..347be7e3e2e --- /dev/null +++ b/examples/containers/collect-data.conf.bak @@ -0,0 +1,4 @@ +#Configuration for Collect +#Wed Jul 30 13:29:39 CEST 2014 +collect.bounds=2,52,636,596 +collect.nodeinfo.table=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 diff --git a/examples/containers/collect-tree-dense-noloss.csc b/examples/containers/collect-tree-dense-noloss.csc new file mode 100644 index 00000000000..c3d13cf7202 --- /dev/null +++ b/examples/containers/collect-tree-dense-noloss.csc @@ -0,0 +1,503 @@ + + + [CONTIKI_DIR]/tools/cooja/apps/mrm + [CONTIKI_DIR]/tools/cooja/apps/mspsim + [CONTIKI_DIR]/tools/cooja/apps/avrora + [CONTIKI_DIR]/tools/cooja/apps/serial_socket + [CONTIKI_DIR]/tools/cooja/apps/collect-view + + My simulation + 0 + 123456 + 1000000 + + se.sics.cooja.radiomediums.UDGM + 100.0 + 120.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.SkyMoteType + sky1 + Sky Mote Type #sky1 + [CONFIG_DIR]/udp-sink.c + make udp-sink.sky TARGET=sky + [CONFIG_DIR]/udp-sink.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + se.sics.cooja.mspmote.SkyMoteType + sky2 + Sky Mote Type #sky2 + [CONFIG_DIR]/udp-sender.c + make udp-sender.sky TARGET=sky + [CONFIG_DIR]/udp-sender.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + + + se.sics.cooja.interfaces.Position + 242.83184008074136 + -88.93434685786869 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 223.5175954004352 + -69.05842098947238 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 250.51864863077387 + -59.2420165357677 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 3 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 294.4736028715864 + -63.23792146675066 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 4 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 188.6638305152632 + -41.28432709660093 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 5 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 222.54731411389315 + -32.869043991280165 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 6 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 273.694897230475 + -29.672320046493798 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 7 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 321.64575640227054 + -33.66822497747676 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 8 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 159.4120162043624 + -2.500166515809672 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 9 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 196.97352255560222 + -0.10262355721989598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 10 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 252.91619158936365 + 1.495738415173288 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 11 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 301.66623174735577 + -0.10262355721989598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 12 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 346.4203669743649 + 1.495738415173288 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 13 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 124.24805281171236 + 22.27444405628468 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 14 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 180.1907218454738 + 35.86052082162674 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 15 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 224.14567608628633 + 30.266253918250598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 16 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 276.0924401890648 + 35.86052082162674 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 17 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 351.2154528915445 + 37.45888279401993 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 18 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 89.08408941906231 + 47.04905462837903 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 19 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 180.1907218454738 + 75.02038914525976 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 20 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 245.7235627135943 + 66.22939829709723 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 21 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 290.4776979406035 + 67.82776026949043 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 22 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 370.3957965602627 + 64.63103632470406 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 23 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 93.07999435004527 + 82.21301802102909 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 24 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 204.16615143137156 + 106.18844760692684 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 25 + + sky2 + + + + se.sics.cooja.plugins.SimControl + 259 + 2 + 184 + 0 + 0 + + + se.sics.cooja.plugins.Visualizer + + se.sics.cooja.plugins.skins.IDVisualizerSkin + se.sics.cooja.plugins.skins.AttributeVisualizerSkin + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + 1.836243522352668 0.0 0.0 1.836243522352668 -93.43273668589363 192.8080782058222 + + 666 + 0 + 510 + 369 + -8 + + + se.sics.cooja.plugins.LogListener + + + + 1347 + 4 + 150 + 0 + 438 + + + se.sics.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + + + + 109 + 500.0 + + 1347 + 3 + 150 + 0 + 588 + + + se.sics.cooja.plugins.collectview.CollectView + 0 + 203 + 1 + 75 + 33 + 188 + + + diff --git a/examples/containers/collect-tree-sparse-lossy.csc b/examples/containers/collect-tree-sparse-lossy.csc new file mode 100644 index 00000000000..f3f1bbeb9a5 --- /dev/null +++ b/examples/containers/collect-tree-sparse-lossy.csc @@ -0,0 +1,501 @@ + + + [CONTIKI_DIR]/tools/cooja/apps/mrm + [CONTIKI_DIR]/tools/cooja/apps/mspsim + [CONTIKI_DIR]/tools/cooja/apps/avrora + [CONTIKI_DIR]/tools/cooja/apps/serial_socket + [CONTIKI_DIR]/tools/cooja/apps/collect-view + + My simulation + 0 + 123456 + 1000000 + + se.sics.cooja.radiomediums.UDGM + 70.0 + 90.0 + 1.0 + 0.0 + + + 40000 + + + se.sics.cooja.mspmote.SkyMoteType + sky1 + Sky Mote Type #sky1 + [CONFIG_DIR]/server.c + make server.z1 TARGET=z1 + [CONFIG_DIR]/server.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + se.sics.cooja.mspmote.SkyMoteType + sky2 + Sky Mote Type #sky2 + [CONFIG_DIR]/client.c + make client.sky TARGET=sky + [CONFIG_DIR]/client.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + + + se.sics.cooja.interfaces.Position + 242.83184008074136 + -88.93434685786869 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 205.7645134037647 + -62.438740480554074 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 250.51864863077387 + -59.2420165357677 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 3 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 294.4736028715864 + -63.23792146675066 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 4 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 176.19481691449084 + -35.26658694986995 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 5 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 222.54731411389315 + -32.869043991280165 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 6 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 273.694897230475 + -29.672320046493798 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 7 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 321.64575640227054 + -33.66822497747676 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 8 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 159.4120162043624 + -2.500166515809672 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 9 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 196.97352255560222 + -0.10262355721989598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 10 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 252.91619158936365 + 1.495738415173288 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 11 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 301.66623174735577 + -0.10262355721989598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 12 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 346.4203669743649 + 1.495738415173288 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 13 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 124.24805281171236 + 22.27444405628468 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 14 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 180.1907218454738 + 35.86052082162674 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 15 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 224.14567608628633 + 30.266253918250598 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 16 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 276.0924401890648 + 35.86052082162674 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 17 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 351.2154528915445 + 37.45888279401993 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 18 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 89.08408941906231 + 47.04905462837903 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 19 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 180.1907218454738 + 75.02038914525976 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 20 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 245.7235627135943 + 66.22939829709723 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 21 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 290.4776979406035 + 67.82776026949043 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 22 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 370.3957965602627 + 64.63103632470406 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 23 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 93.07999435004527 + 82.21301802102909 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 24 + + sky2 + + + + + se.sics.cooja.interfaces.Position + 204.16615143137156 + 106.18844760692684 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 25 + + sky2 + + + + se.sics.cooja.plugins.SimControl + 259 + 3 + 184 + 0 + 0 + + + se.sics.cooja.plugins.Visualizer + + se.sics.cooja.plugins.skins.IDVisualizerSkin + se.sics.cooja.plugins.skins.AttributeVisualizerSkin + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + 1.836243522352668 0.0 0.0 1.836243522352668 -124.43273668589376 177.8080782058222 + + 610 + 2 + 482 + 420 + -2 + + + se.sics.cooja.plugins.LogListener + + + + 1347 + 4 + 150 + 0 + 438 + + + se.sics.cooja.plugins.TimeLine + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + + 109 + 500.0 + + 1347 + 0 + 150 + 0 + 588 + + + se.sics.cooja.plugins.collectview.CollectView + 0 + 203 + 1 + 75 + 120 + 120 + + + diff --git a/examples/containers/common-hdr.h b/examples/containers/common-hdr.h new file mode 100644 index 00000000000..990bc566984 --- /dev/null +++ b/examples/containers/common-hdr.h @@ -0,0 +1,27 @@ +#ifndef _COMMON_HDR_H_ +#define _COMMON_HDR_H_ + +#include +#include +#include +typedef struct _dpkt_ +{ + uint32_t seq; + struct timeval sendTime; + uint8_t buflen; + uint8_t buf[1]; +}dpkt_t; + +typedef struct _dpkt_stat_ +{ + uip_ipaddr_t ip; + uint32_t lastseq; + uint32_t dropcnt; + uint32_t unordered; + uint32_t rcvcnt; + uint32_t dupcnt; + long leastLatency; + long maxLatency; +}dpkt_stat_t; + +#endif // _COMMON_HDR_H_ diff --git a/examples/containers/project-conf.h b/examples/containers/project-conf.h new file mode 100644 index 00000000000..dcc3703013c --- /dev/null +++ b/examples/containers/project-conf.h @@ -0,0 +1,343 @@ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +/********************************************************************/ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +#ifndef WITH_NON_STORING +#define WITH_NON_STORING 0 /* Set this to run with non-storing mode */ +#endif /* WITH_NON_STORING */ + +#undef NBR_TABLE_CONF_MAX_NEIGHBORS +#undef UIP_CONF_MAX_ROUTES + +#ifdef TEST_MORE_ROUTES +/* configure number of neighbors and routes */ +#define NBR_TABLE_CONF_MAX_NEIGHBORS 10 +#define UIP_CONF_MAX_ROUTES 30 +#else +/* configure number of neighbors and routes */ +#define NBR_TABLE_CONF_MAX_NEIGHBORS 100 +#define UIP_CONF_MAX_ROUTES 100 +#endif /* TEST_MORE_ROUTES */ + +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nullrdc_driver +#undef NULLRDC_CONF_802154_AUTOACK +#define NULLRDC_CONF_802154_AUTOACK 1 + +/* Define as minutes */ +#define RPL_CONF_DEFAULT_LIFETIME_UNIT 60 + +/* 10 minutes lifetime of routes */ +#define RPL_CONF_DEFAULT_LIFETIME 10 + +#define RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME 1 +#define SCSLOWPAN_CONF_FRAG_FORWARDING 0 +#define SICSLOWPAN_CONF_REASS_CONTEXTS 10 + +#define SERVER_REPLY 1 + +#if WITH_NON_STORING +#undef RPL_NS_CONF_LINK_NUM +#define RPL_NS_CONF_LINK_NUM 40 /* Number of links maintained at the root. Can be set to 0 at non-root nodes. */ +#undef UIP_CONF_MAX_ROUTES +#define UIP_CONF_MAX_ROUTES 0 /* No need for routes */ +#undef RPL_CONF_MOP +#define RPL_CONF_MOP RPL_MOP_NON_STORING /* Mode of operation*/ +#endif /* WITH_NON_STORING */ + +#define RPL_CONF_WITH_DCO 1 + +#endif + + +/********************************************************************/ + + + + + + + + + + + + + + + + +#define USE_METRIC_CONTAINERS + +#ifdef USE_METRIC_CONTAINERS +#define RPL_CONF_DAG_MC RPL_DAG_MC_ENERGY +#endif /* USE_METRIC_CONTAINERS*/ + +/* objective function */ +#define RPL_CONF_OF rpl_metrics_containers_OF + +/* DIOs with rank lower than this will be ignored.* + * It must be selected in function of the metrics * + */ +#define RPL_CONF_MIN_HOPRANKINC 128 +/*by default, RPL_CONF_MAX_RANKINC = 7*RPL_CONF_MIN_HOPRANKINC*/ +//#define RPL_CONF_MAX_HOPRANKINC 1000 + +/* By default used weighted composition */ +#define LEXIC_COMPOSITION + +/********************weighted composition****************************/ +/* + * The maximum difference between metrics to not change the parent * + */ + +#define WEIGHTED_DIFF_THRESHOLD 64 + +/* (optional) + * The weight of each metric, with the precedence order * + * The number of elements must be the same as * + * NUMBER_OF_METRICS_AND_CONST_USED * + */ + +//#define METRICS_WEIGHTS {1,0} + +/*******************************************************************/ + +/*******************lexicographic composition***********************/ +/* +* Which metrics to maximize (the bigger, the better); the others * +* are minimized. The last element must be 0 * +*/ + +#define MAXIMIZED_METRICS {RPL_DAG_MC_THROUGHPUT,\ + 0} + +/* + * The maximum difference between each metric pair to consider * + * them equal and compare the next pair. It follows the * + * precedence order. * + * The number of elements must be the same as * + * NUMBER_OF_METRICS_AND_CONST_USED * + */ + +#define LEXIC_DIFF_THRESHOLD {64, 0} + + +/********************************************************************/ +/********************************************************************/ + + +/* number of path metrics and constraint objects used. */ +#define NUMBER_OF_METRICS_AND_CONST_USED 2 + +/* difference between metrics to check optional constraints */ +#define OPTIONAL_CONSTRAINTS_THRESHOLD 0 + + +/* select containers used and add the routing metric object * + * header as described in RFC6551 (in hexadecimal) * + * + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Routing-MC-Type|Res Flags|P|C|O|R| A | Prec | Length (bytes)| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | + */ + +/* +* Headers ONLY for path metrics. * +* Uncomment only the used ones. * +* Length and type cannot be changed. * +*/ + +//#define RPL_DAG_MC_USE_NSA 0x01000102 +#define RPL_DAG_MC_USE_ENERGY 0x02001102 +//#define RPL_DAG_MC_USE_HOPCOUNT 0x03000002 +//#define RPL_DAG_MC_USE_THROUGHPUT 0x04002204 +//#define RPL_DAG_MC_USE_LATENCY 0x05001304 +//#define RPL_DAG_MC_USE_LQL 0x06000402 +#define RPL_DAG_MC_USE_ETX 0x07000002 +//#define RPL_DAG_MC_USE_LC 0x08000303 + +/* +* Headers ONLY for path constraints * +* Uncomment only the used ones. * +* Length and type cannot be changed. * +* For each constraint it is mandatory a metric of the same type! * +*/ + +//#define RPL_DAG_MC_CONST_USE_NSA 0x01030102 +//#define RPL_DAG_MC_CONST_USE_ENERGY 0x02031102 +//#define RPL_DAG_MC_CONST_USE_HOPCOUNT 0x03030202 +//#define RPL_DAG_MC_CONST_USE_THROUGHPUT +//#define RPL_DAG_MC_CONST_USE_LATENCY +//#define RPL_DAG_MC_CONST_USE_LQL 0x06030202 +//#define RPL_DAG_MC_CONST_USE_ETX +//#define RPL_DAG_MC_CONST_USE_LC 0x08020303 + + +/******************************NSA ******************************************/ + +/* metric */ +#define RPL_DAG_MC_NSA_A_AGGREGATION 0 +#define RPL_DAG_MC_NSA_O_OVERLOAD 0 + +/* constraint */ +#define RPL_DAG_MC_CONST_NSA_A_AGGREGATION 0 +#define RPL_DAG_MC_CONST_NSA_O_OVERLOAD 0 + +#define RPL_DAG_MC_NSA_AGGREGATION_BIT 2 +#define RPL_DAG_MC_NSA_OVERLOAD_BIT 1 +/***************************************************************************/ + + +/*****************************energy ***************************************/ +/*between 20L (minimum resolution) and 7200L (overflow of ticks)*/ +#define BATT_CHARGE 250L /*uAh*/ + +/*simplify a division by shifting ( 32768 = 2^15 )*/ +#define TICKS_PER_SECOND 15 + +#define CURRENT_CPU 4000 /*uA*/ +#define CURRENT_LPM 20 /*uA*/ +#define CURRENT_TRANSMIT 17400 /*uA*/ +#define CURRENT_LISTEN 18800 /*uA*/ + +/***************************************************/ +#define RPL_DAG_MC_ENERGY_TYPE_MAINS 0 +#define RPL_DAG_MC_ENERGY_TYPE_BATTERY 1 +#define RPL_DAG_MC_ENERGY_TYPE_SCAVENGING 2 + +#define RPL_DAG_MC_ENERGY_TYPE_MYSELF RPL_DAG_MC_ENERGY_TYPE_BATTERY + +/* metric */ +/*in additive mode, avoids overflow of the 8-bit variable*/ +//#define RPL_DAG_MC_ENERGY_DIVISOR 3 /*>> bits*/ + +#define RPL_DAG_MC_ENERGY_I_INCLUDED 1 +#define RPL_DAG_MC_ENERGY_T_TYPE RPL_DAG_MC_ENERGY_TYPE_BATTERY +#define RPL_DAG_MC_ENERGY_E_ESTIMATION 1 +#define RPL_DAG_MC_ENERGY_INITIALIZATION 1 + +/* constraint */ +#define RPL_DAG_MC_CONST_ENERGY_I_INCLUDED 1 +#define RPL_DAG_MC_CONST_ENERGY_T_TYPE RPL_DAG_MC_ENERGY_TYPE_BATTERY +#define RPL_DAG_MC_CONST_ENERGY_E_ESTIMATION 1 +#define RPL_DAG_MC_CONST_ENERGY_THRESHOLD 175 +/**************************************************************************/ + + +/****************************hop count ************************************/ + +#define RPL_DAG_MC_HOPCOUNT_MULTIPLIER 256 + +/* metric */ +#define RPL_DAG_MC_HOPCOUNT_INITIALIZATION 1 +/* constraint */ +#define RPL_DAG_MC_CONST_HOPCOUNT_THRESHOLD 4 +/*************************************************************************/ + +/***************************throughput ***********************************/ + +/*throughput is 4 Bytes, but Rank is only 2 Bytes long */ +/*value is then divided by 2^RPL_DAG_MC_THROUGHPUT_DIVISOR */ + +#define RPL_DAG_MC_THROUGHPUT_DIVISOR 16 + +/* metric */ +#define RPL_DAG_MC_THROUGHPUT_INITIALIZATION 6553600 +/* constraint */ +#define RPL_DAG_MC_CONST_THROUGHPUT_THRESHOLD 3276800 +/*************************************************************************/ + +/***************************latency **************************************/ + +/*latency is 4 Bytes, but Rank is only 2 Bytes long */ +/*value is then divided by 2^ RPL_DAG_MC_LATENCY_DIVISOR */ + +#define RPL_DAG_MC_LATENCY_DIVISOR 16 + +/* metric */ +#define RPL_DAG_MC_LATENCY_INITIALIZATION 6533600 +/* constraint */ +#define RPL_DAG_MC_CONST_LATENCY_THRESHOLD 655360 +/*************************************************************************/ + +/***************************LQL ******************************************/ + +/* metric */ +#define RPL_DAG_MC_LQL_INITIALIZATION 3 +/* constraint */ +#define RPL_DAG_MC_CONST_LQL_THRESHOLD 5 +/*************************************************************************/ + +/***************************etx ******************************************/ + +/* metric */ +#define RPL_DAG_MC_ETX_INITIALIZATION 5 +/* constraint */ +#define RPL_DAG_MC_CONST_ETX_THRESHOLD 7 +/*****/ + +//#define RPL_CONF_INIT_LINK_METRIC RPL_DAG_MC_ETX_INITIALIZATION +/*ETX when no Ack from the node is received*/ +#define RPL_DAG_MC_ETX_MAX 10 +#define RPL_DAG_MC_ETX_DIVISOR 128 +/*weight of the old ETX when the new is calculated*/ +#define ETX_ALPHA 90 +#define ETX_SCALE 100 + + +/*************************************************************************/ + +/***************************LC *******************************************/ + +#define RPL_DAG_MC_LC_I_INCLUDED 0 + +/* don't change this */ +#define RPL_DAG_MC_LC_MASK_BIT_1 0x001 +#define RPL_DAG_MC_LC_MASK_BIT_2 0x002 +#define RPL_DAG_MC_LC_MASK_BIT_3 0x004 +#define RPL_DAG_MC_LC_MASK_BIT_4 0x008 +#define RPL_DAG_MC_LC_MASK_BIT_5 0x010 +#define RPL_DAG_MC_LC_MASK_BIT_6 0x020 +#define RPL_DAG_MC_LC_MASK_BIT_7 0x040 +#define RPL_DAG_MC_LC_MASK_BIT_8 0x080 +#define RPL_DAG_MC_LC_MASK_BIT_9 0x100 +#define RPL_DAG_MC_LC_MASK_BIT_10 0x200 + +/* metric */ +#define RPL_DAG_MC_LC_INITIALIZATION 0 //10 bits +/* constraint */ +#define RPL_DAG_MC_CONST_LC_THRESHOLD 1 //10 bits +/*************************************************************************/ + + + +/* DAG Metric Container Object Types by IANA. */ +#define RPL_DAG_MC_NONE 0 /* Local identifier for empty MC */ +#define RPL_DAG_MC_NSA 1 /* Node State and Attributes */ +#define RPL_DAG_MC_ENERGY 2 /* Node Energy */ +#define RPL_DAG_MC_HOPCOUNT 3 /* Hop Count */ +#define RPL_DAG_MC_THROUGHPUT 4 /* Throughput */ +#define RPL_DAG_MC_LATENCY 5 /* Latency */ +#define RPL_DAG_MC_LQL 6 /* Link Quality Level */ +#define RPL_DAG_MC_ETX 7 /* Expected Transmission Count */ +#define RPL_DAG_MC_LC 8 /* Link Color */ + +/* DAG Metric Container aggregation mode. */ +#define RPL_DAG_MC_AGGR_ADDITIVE 0 +#define RPL_DAG_MC_AGGR_MAXIMUM 1 +#define RPL_DAG_MC_AGGR_MINIMUM 2 +#define RPL_DAG_MC_AGGR_MULTIPLICATIVE 3 + + +extern uint8_t depleted_battery; +extern unsigned char node_mac[8]; +#define AM_I_NODE(node) (node_mac[7]==node) + +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/containers/rpl-metrics-containers-OF.c b/examples/containers/rpl-metrics-containers-OF.c new file mode 100644 index 00000000000..92178af7970 --- /dev/null +++ b/examples/containers/rpl-metrics-containers-OF.c @@ -0,0 +1,321 @@ + +#include "net/rpl/rpl-private.h" +#include "net/nbr-table.h" +#include "rpl-metrics.h" +#include "rpl-metrics-get.h" + +#ifdef DEBUG_RPL_OF +#include +#define DEBUG DEBUG_PRINT + +#else /*DEBUG_RPL_OF*/ +#define DEBUG DEBUG_NONE +#endif /*DEBUG_RPL_OF*/ + +#include "net/ip/uip-debug.h" + + +static void reset(rpl_dag_t *); +#if defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) +static void neighbor_link_callback(rpl_parent_t *, int, int); +#endif /* defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) */ +static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); +static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); +static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); +static rpl_parent_t *check_optional_constraints (rpl_parent_t *, rpl_parent_t *); +static void update_metric_container(rpl_instance_t *); + + +rpl_of_t rpl_metrics_containers_OF = { + reset, +#if defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) + neighbor_link_callback, +#endif /* defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) */ + best_parent, + best_dag, + calculate_rank, + update_metric_container, + 1 +}; + +typedef uint16_t rpl_path_metric_t; +extern uint8_t rpl_leaf; +static uint8_t etx_weight=1; + + +static void +reset(rpl_dag_t *sag) +{ + PRINTF("RPL: Reset OF\n"); +} + +/**********************************************************************/ + +/* + * Function called when a packet is sent, in order to refresh + * etx of the link + */ + +#if defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) + +static void +neighbor_link_callback(rpl_parent_t *p, int status, int numtx) +{ + rpl_metrics_etx_refresh(p,status, numtx); +} + +#endif /* defined (RPL_DAG_MC_USE_ETX) || defined (RPL_DAG_MC_CONST_USE_ETX) */ + + +/**********************************************************************/ + +static rpl_rank_t +calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) +{ + rpl_rank_t new_rank= 0; + rpl_metric_element_t array_of_metrics[NUMBER_OF_METRICS_AND_CONST_USED]; + uint8_t number_of_elems; + uint8_t i,j; + + if(p == NULL) { + if(base_rank == 0) { + return INFINITE_RANK; + } + new_rank = RPL_INIT_LINK_METRIC + base_rank; + } + else { + + number_of_elems= rpl_metrics_array_of_metrics (&(p->dag->instance->mc), array_of_metrics); + + +#ifndef LEXIC_COMPOSITION /*then WEIGHTED_COMPOSITION */ +{ +#if defined(METRICS_WEIGHTS) + uint8_t weights_array[]= METRICS_WEIGHTS; +#else /* defined(METRICS_WEIGHTS) */ + uint8_t weights_array[NUMBER_OF_METRICS_AND_CONST_USED]; + for (i=0, j=number_of_elems; j>0; j--) + weights_array[i++]= j; +#endif /* defined(METRICS_WEIGHTS) */ + +#ifdef DEBUG_RPL_OF + PRINTF("RPL: METRICS: OF: weighted composition of weights[ "); + for (i=0; iINFINITE_RANK) + new_rank= INFINITE_RANK; + + PRINTF("RPL: METRICS: OF: new rank: %u\n",new_rank); + + return new_rank; +} + + +/**********************************************************************/ + + +static rpl_dag_t * +best_dag(rpl_dag_t *d1, rpl_dag_t *d2) +{ + if(d1->grounded != d2->grounded) { + return d1->grounded ? d1 : d2; + } + + if(d1->preference != d2->preference) { + return d1->preference > d2->preference ? d1 : d2; + } + + return d1->rank < d2->rank ? d1 : d2; +} + + + +/**********************************************************************/ + + + +static rpl_parent_t * +best_parent(rpl_parent_t *p1, rpl_parent_t *p2) +{ + rpl_parent_t *p_parent; + +#ifndef LEXIC_COMPOSITION /*then WEIGHTED_COMPOSITION */ + + rpl_dag_t *dag; + rpl_path_metric_t p1_metric; + rpl_path_metric_t p2_metric; + + uint16_t etx1, etx2; + + dag = p1->dag; /* Both parents are in the same DAG. */ + + p1_metric= p1->rank; + p2_metric= p2->rank; + +#if defined( RPL_DAG_MC_USE_ETX) + /* + * ETX is the only metric of the node that doesn't remain the * + * same for both parents. LQL and LC not implemented yet. * + */ + + etx1= p1->etx; + etx2= p2->etx; + + p1_metric+= etx1 * etx_weight; + p2_metric+= etx2 * etx_weight; +#endif /* defined( RPL_DAG_MC_USE_ETX) */ + + /* check optional constraints if difference between metrics smaller than OPTIONAL_CONSTRAINTS_THRESHOLD*/ + + if(p1_metric < p2_metric + OPTIONAL_CONSTRAINTS_THRESHOLD && + p1_metric >(p2_metric>OPTIONAL_CONSTRAINTS_THRESHOLD?(p2_metric-OPTIONAL_CONSTRAINTS_THRESHOLD):0)) { + p_parent= check_optional_constraints (p1, p2); + if(p_parent!= NULL){ + return p_parent; + } + } + + /* Maintain stability of the preferred parent in case of similar ranks. */ + if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) { + if(p1_metric < p2_metric + WEIGHTED_DIFF_THRESHOLD && + p1_metric >(p2_metric>WEIGHTED_DIFF_THRESHOLD?(p2_metric-WEIGHTED_DIFF_THRESHOLD):0)) { + PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n", + p2_metric>WEIGHTED_DIFF_THRESHOLD?(p2_metric-WEIGHTED_DIFF_THRESHOLD):0, + p1_metric, + p2_metric + WEIGHTED_DIFF_THRESHOLD); + + return dag->preferred_parent; + } + } + return p1_metric < p2_metric ? p1 : p2; + +#else /* LEXIC_COMPOSITION */ + + rpl_metric_element_t array_of_metrics_1[NUMBER_OF_METRICS_AND_CONST_USED]; + rpl_metric_element_t array_of_metrics_2[NUMBER_OF_METRICS_AND_CONST_USED]; + uint32_t lexic_diff_thres[]= LEXIC_DIFF_THRESHOLD; + uint8_t number_of_elems_1, number_of_elems_2; + uint8_t maximization_types[]=MAXIMIZED_METRICS; + int16_t diff; + uint8_t i,j; + + number_of_elems_1= rpl_metrics_array_of_metrics (&(p1->mc), array_of_metrics_1); + number_of_elems_2= rpl_metrics_array_of_metrics (&(p2->mc), array_of_metrics_2); + + if(number_of_elems_1 != number_of_elems_2){ + PRINTF("RPL: METRICS: OF: Parents have different metric containers to compare\n"); + return NULL; + } + else { + for (i= 0; i< number_of_elems_1; i++){ + if(array_of_metrics_1[i].type != array_of_metrics_2[i].type){ + PRINTF("RPL: METRICS: OF: Different metric objects to compare\n"); + return NULL; + } + diff= array_of_metrics_1[i].data- array_of_metrics_2[i].data; + + /* + * ETX is the only metric of the node that doesn't remain the * + * same for both parents. LQL and LC not implemented yet. * + */ + if(array_of_metrics_1[i].type == RPL_DAG_MC_ETX) + diff+= p1->etx - p2->etx; + + if( (diff > lexic_diff_thres[i]) || (diff < -lexic_diff_thres[i]) ){ + /*check if type is in maximization metrics array*/ + for(j=0; j<(sizeof(maximization_types)/ sizeof(maximization_types[0])); j++){ + if(array_of_metrics_1[i].type == maximization_types[j]) + return(diff>0 ? p1 : p2); + } + return(diff<0 ? p1 : p2); + } + } + return p1->dag->preferred_parent; /* Both parents are in the same DAG. */ + } + +#endif /* LEXIC_COMPOSITION */ + +} + + + +/**********************************************************************/ + + +static rpl_parent_t * +check_optional_constraints (rpl_parent_t *p1, rpl_parent_t *p2){ + + rpl_metric_object_t *p_obj, *opt_const[NUMBER_OF_METRICS_AND_CONST_USED>>1]; + uint8_t i, j, imin, num_objects, num_opt_const; + uint16_t flags; + uint8_t p1_const, p2_const; + + /*identify optional constraints*/ + num_opt_const= 0; + num_objects= p1->mc.metric_and_const_obj; + for(i=0; imc.metric_and_const_objects[i]; + flags= p_obj->flags; + if( READ_BIT(flags, RPL_DAG_MC_POS_C_BIT) ) + if( READ_BIT(flags, RPL_DAG_MC_POS_O_BIT)) + opt_const[num_opt_const++]= p_obj; + } + + if(num_opt_const){ + + /* sort by precedence */ + for (i=0; i< num_opt_const-1; i++){ + imin= i; + for(j=i+1; j< num_opt_const; j++){ + if( (RPL_METRIC_READ_PREC_FIELD((opt_const[j]->flags))) < (RPL_METRIC_READ_PREC_FIELD((opt_const[imin]->flags))) ) + imin= j; + } + p_obj= opt_const[i]; + opt_const[i]= opt_const[imin]; + opt_const[imin]= p_obj; + } + + /*compare candidates*/ + p1_const= p2_const= 0; + for(i=0; imc)); + p2_const= rpl_metrics_satisfies_constraint (opt_const[i], &(p2->mc)); + if(p1_const!=p2_const) + return (p1_const ? p1 : p2); + } + } + return NULL; +} + + +/**********************************************************************/ + + +static void +update_metric_container(rpl_instance_t *instance) +{ + rpl_metrics_update_metric_container(instance); +} + diff --git a/examples/containers/rpl-metrics-data.h b/examples/containers/rpl-metrics-data.h new file mode 100644 index 00000000000..81c194adfe9 --- /dev/null +++ b/examples/containers/rpl-metrics-data.h @@ -0,0 +1,85 @@ +#ifndef RPL_METRICS_DATA_H +#define RPL_METRICS_DATA_H + + +struct rpl_metric_object_NSA { + uint8_t flags; +}; +typedef struct rpl_metric_object_NSA rpl_metric_object_NSA_t; + +struct rpl_metric_object_energy { + uint8_t flags; + uint8_t energy_est; +}; +typedef struct rpl_metric_object_energy rpl_metric_object_energy_t; + +struct rpl_metric_object_hop_count { + uint8_t hop_count; +}; +typedef struct rpl_metric_object_hop_count rpl_metric_object_hop_count_t; + +struct rpl_metric_object_throughput { + uint32_t throughput; +}; +typedef struct rpl_metric_object_throughput rpl_metric_object_throughput_t; + +struct rpl_metric_object_latency { + uint32_t latency; +}; +typedef struct rpl_metric_object_latency rpl_metric_object_latency_t; + +struct rpl_metric_object_LQL { + uint8_t value_and_counter; +}; +typedef struct rpl_metric_object_LQL rpl_metric_object_LQL_t; + +struct rpl_metric_object_ETX { + uint16_t etx; +}; +typedef struct rpl_metric_object_ETX rpl_metric_object_ETX_t; + +struct rpl_metric_object_LC { + uint16_t color_and_counter; +}; +typedef struct rpl_metric_object_LC rpl_metric_object_LC_t; + + + +struct rpl_metric_object { + uint8_t type; + uint16_t flags; + uint8_t length; + union { + struct rpl_metric_object_NSA *nsa; + struct rpl_metric_object_LQL *lql; + struct rpl_metric_object_energy *energy; + struct rpl_metric_object_hop_count *hop_count; + struct rpl_metric_object_ETX *etx; + struct rpl_metric_object_LC *lc; + struct rpl_metric_object_throughput *throughput; + struct rpl_metric_object_latency *latency; + void *rpl_metric_object_data_pointer; + } ; +}; +typedef struct rpl_metric_object rpl_metric_object_t; + + + +struct rpl_metric_container { + + uint8_t metric_and_const_obj; + + rpl_metric_object_t* metric_and_const_objects[NUMBER_OF_METRICS_AND_CONST_USED]; +}; +typedef struct rpl_metric_container rpl_metric_container_t; + + + +struct rpl_metric_element { + uint8_t type; + uint8_t aggregation_mode; + uint16_t data; +}; +typedef struct rpl_metric_element rpl_metric_element_t; + +#endif /* RPL_METRICS_DATA_H */ diff --git a/examples/containers/rpl-metrics-get.c b/examples/containers/rpl-metrics-get.c new file mode 100644 index 00000000000..9f5099f8c20 --- /dev/null +++ b/examples/containers/rpl-metrics-get.c @@ -0,0 +1,262 @@ +#include "net/rpl/rpl-private.h" +#include "sys/energest.h" +#include "dev/leds.h" + + +#ifdef DEBUG_RPL_METRICS_GET +#define DEBUG DEBUG_PRINT +#else +#define DEBUG DEBUG_NONE +#endif +#include "net/ip/uip-debug.h" +#include + +static uint16_t max_charge; +uint8_t rpl_metrics_power_refresh(); + + +/********************************************************************/ + +uint8_t rpl_metrics_get_NSA() +{ + // if((AM_I_NODE(2))||(AM_I_NODE(3))) + // return ((1<<1)+1); + return ((RPL_DAG_MC_NSA_A_AGGREGATION<<1)+RPL_DAG_MC_NSA_O_OVERLOAD); +} + + +/********************************************************************/ + +#if defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) +uint8_t rpl_metrics_get_energy() +{ + uint8_t power; + static uint8_t initialized= 0; + + if(!initialized){ + initialized++; + // if(AM_I_NODE(6)) + // max_charge= (100L*3600)>>16; + // else + max_charge= (BATT_CHARGE*3600)>>16; + } +power= rpl_metrics_power_refresh(); + +#ifdef RPL_DAG_MC_ENERGY_DIVISOR + power>>= RPL_DAG_MC_ENERGY_DIVISOR; +#endif + + return( power==0 ? 1 : power ); + +} +#endif /*defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY)*/ + + +/********************************************************************/ + +uint8_t rpl_metrics_get_hop_count() +{ + rpl_dag_t *dag; + rpl_metric_container_t *p_container; + uint8_t i; + + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); + + if(dag->preferred_parent != NULL) { + p_container=&(dag->preferred_parent->mc); + for(i=0; i< p_container->metric_and_const_obj; i++){ + if(p_container->metric_and_const_objects[i]->type == RPL_DAG_MC_HOPCOUNT) + return(p_container->metric_and_const_objects[i]->hop_count->hop_count + 1); + } + } + + return 0; + +} + + +/********************************************************************/ + +uint32_t rpl_metrics_get_throughput() +{ + + /* if(AM_I_NODE(3)) + return (150*65536);*/ + return (100*65536); +} + +/********************************************************************/ + +uint32_t rpl_metrics_get_latency() +{ + + /*if(AM_I_NODE(3)) + return (100*65536); + return (150*65536);*/ +} + +/********************************************************************/ + +uint8_t rpl_metrics_get_LQL() +{ + + // if((AM_I_NODE(2))||(AM_I_NODE(3))) + // return (6 <<5); + return ((RPL_DAG_MC_LQL_INITIALIZATION & 0x7)<<5); +} + + +/********************************************************************/ + +#if defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) + +uint16_t rpl_metrics_get_ETX() +{ + rpl_dag_t *dag; + + /* Let's suppose we have only one instance */ + dag = rpl_get_any_dag(); + + if(dag->preferred_parent != NULL) + return (dag->preferred_parent->etx); + else + return 0 ; +} +#endif /* defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX)*/ + +/********************************************************************/ + +uint16_t rpl_metrics_get_LC() +{ + // if((AM_I_NODE(2))||(AM_I_NODE(3))) + // return (2 <<6); + return (RPL_DAG_MC_LC_INITIALIZATION<<6); +} + + +/********************************************************************/ + +#if defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) + +void rpl_metrics_etx_refresh(rpl_parent_t *p, int status, int numtx) +{ + uint16_t recorded_etx = p->etx; + uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR; + uint16_t new_etx; + +/* When the radio was explicitly turned off, mac returns MAC_TX_ERR_FATAL. + * To simulate loss of communication with the parent, it is changed for + * no Ack received + */ +#ifdef BUTTON_INTERFERENCE + if(status== MAC_TX_ERR_FATAL) + status= MAC_TX_NOACK; +#endif /*BUTTON_INTERFERENCE*/ + + /* Do not penalize the ETX when collisions or transmission errors occur. */ + if(status == MAC_TX_OK || status == MAC_TX_NOACK) { + if(status == MAC_TX_NOACK) { + packet_etx = RPL_DAG_MC_ETX_MAX * RPL_DAG_MC_ETX_DIVISOR; + } + + new_etx = ((uint32_t)recorded_etx * ETX_ALPHA + + (uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE; + + PRINTF("RPL: METRICS: ETX old: %u,new: %u (packet ETX = %u)\n", + recorded_etx, new_etx, packet_etx); + p->etx = new_etx; + } + +#ifdef DEBUG_RPL_METRICS_GET + if(status == MAC_TX_OK) //The MAC layer transmission was OK. + printf("- OK\n"); + else if (status == MAC_TX_NOACK) //The MAC layer did not get an acknowledgement for the packet. + printf("- NO ACK\n"); + else + printf("- PROBLEM\n"); +#endif /* DEBUG_RPL_METRICS_GET */ + +} +#endif /* defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) */ + + + +/********************************************************************/ + +#if defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) + +uint8_t rpl_metrics_power_refresh() +{ + uint32_t ticks_cpu, ticks_lpm, ticks_transmit, ticks_listen; + uint8_t batt_used; + uint32_t power32; + + energest_flush(); + + ticks_lpm = energest_type_time(ENERGEST_TYPE_LPM)>>8; + ticks_cpu = energest_type_time(ENERGEST_TYPE_CPU)>>8; + ticks_transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT)>>8; + ticks_listen = energest_type_time(ENERGEST_TYPE_LISTEN)>>8; + + power32= (ticks_lpm * (uint16_t)CURRENT_LPM) + (ticks_cpu * (uint16_t)CURRENT_CPU) + (ticks_transmit * (uint16_t)CURRENT_TRANSMIT) + (ticks_listen * (uint16_t)CURRENT_LISTEN); + + power32>>=(TICKS_PER_SECOND-8); + + if(power32 >= ((uint32_t)max_charge<<16)){ + batt_used= 0xFF; +#ifdef STATISTICS + // if(!depleted_battery) + printf("30 Battery used: 100%%\n"); +#endif /*STATISTICS*/ + + // depleted_battery= 1; + leds_on(1);//BLUE + + + } + else + batt_used= (uint8_t) ((power32/max_charge)>>8); + +#ifdef STATISTICS + { + uint8_t perc; + static uint8_t perc_25=0; + static uint8_t perc_50=0; + static uint8_t perc_75=0; + + perc= (batt_used*100)/0xFF; + if( (perc>= 75)){ // && (!depleted_battery) + if(!perc_75){ + perc_75++; + printf("30 Battery used: 75%%\n"); + } + } + else if(perc>= 50){ + if(!perc_50){ + perc_50++; + printf("30 Battery used: 50%%\n"); + } + } + else if(perc>= 25){ + if(!perc_25){ + perc_25++; + printf("30 Battery used: 25%%\n"); + } + } + } +#endif /*STATISTICS*/ + + + PRINTF("RPL:METRICS:ticks_lpm %lu-0x%08lx\n",ticks_lpm<<8,ticks_lpm<<8); + PRINTF("RPL:METRICS:ticks_cpu %lu-0x%08lx\n",ticks_cpu<<8,ticks_cpu<<8); + PRINTF("RPL:METRICS:ticks_trans %lu-0x%08lx\n",ticks_transmit<<8,ticks_transmit<<8); + PRINTF("RPL:METRICS:ticks_rx %lu-0x%08lx\n",ticks_listen<<8,ticks_listen<<8); + + PRINTF("RPL:METRICS:consumed= %lu-0x%08lx (uAs) total= %lu\n", power32,power32, (uint32_t)max_charge<<16); + PRINTF("RPL:METRICS:% bat= %u\n",batt_used); + + + return batt_used; +} +#endif /*defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY)*/ diff --git a/examples/containers/rpl-metrics-get.h b/examples/containers/rpl-metrics-get.h new file mode 100644 index 00000000000..bd21b79ea36 --- /dev/null +++ b/examples/containers/rpl-metrics-get.h @@ -0,0 +1,13 @@ +#ifndef RPL_METRICS_GET_H +#define RPL_METRICS_GET_H + +uint8_t rpl_metrics_get_NSA(); +uint8_t rpl_metrics_get_energy(); +uint32_t rpl_metrics_get_throughput(); +uint32_t rpl_metrics_get_latency(); +uint8_t rpl_metrics_get_LQL(); +uint16_t rpl_metrics_get_ETX(); +uint16_t rpl_metrics_get_LC(); + +void rpl_metrics_etx_refresh(rpl_parent_t *p, int status, int numtx); +#endif /* RPL_METRICS_GET_H */ diff --git a/examples/containers/rpl-metrics.c b/examples/containers/rpl-metrics.c new file mode 100644 index 00000000000..4b940ea5f56 --- /dev/null +++ b/examples/containers/rpl-metrics.c @@ -0,0 +1,890 @@ + +#include "rpl-metrics.h" +#include "net/rpl/rpl-private.h" +#include "rpl-metrics-get.h" +#include +#include + +#ifdef DEBUG_RPL_METRICS +#define DEBUG DEBUG_PRINT +#else +#define DEBUG DEBUG_NONE +#endif +#include "net/uip-debug.h" + +extern uint8_t rpl_leaf; +extern uint8_t leaf_dio; + +uint8_t +rpl_metrics_create_object (rpl_metric_container_t *p_mc, uint8_t type, uint8_t pos_obj) +{ + rpl_metric_object_t *p_obj; + uint8_t error; + + if( NULL == (p_mc->metric_and_const_objects[pos_obj]= malloc (sizeof(rpl_metric_object_t)))) + return 1; + + error= 0; + p_obj= p_mc->metric_and_const_objects[pos_obj]; + + switch (type){ +#if defined( RPL_DAG_MC_USE_NSA) || defined (RPL_DAG_MC_CONST_USE_NSA) + case RPL_DAG_MC_NSA: + if( NULL == (p_obj->nsa= malloc (sizeof(rpl_metric_object_NSA_t)))) + error= 1; + break; +#endif /* defined( RPL_DAG_MC_USE_NSA) || defined (RPL_DAG_MC_CONST_USE_NSA) */ +#if defined( RPL_DAG_MC_USE_ENERGY) || defined( RPL_DAG_MC_CONST_USE_ENERGY) + case RPL_DAG_MC_ENERGY: + if( NULL == (p_obj->energy= malloc (sizeof(rpl_metric_object_energy_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_ENERGY) || defined( RPL_DAG_MC_CONST_USE_ENERGY)*/ +#if defined( RPL_DAG_MC_USE_HOPCOUNT) || defined( RPL_DAG_MC_CONST_USE_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + if( NULL == (p_obj->hop_count= malloc (sizeof(rpl_metric_object_hop_count_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_HOPCOUNT) || defined( RPL_DAG_MC_CONST_USE_HOPCOUNT)*/ +#if defined( RPL_DAG_MC_USE_THROUGHPUT) || defined( RPL_DAG_MC_CONST_USE_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + if( NULL == (p_obj->throughput= malloc (sizeof(rpl_metric_object_throughput_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_THROUGHPUT) || defined( RPL_DAG_MC_CONST_USE_THROUGHPUT)*/ +#if defined( RPL_DAG_MC_USE_LATENCY) || defined( RPL_DAG_MC_CONST_USE_LATENCY) + case RPL_DAG_MC_LATENCY: + if( NULL == (p_obj->latency= malloc (sizeof(rpl_metric_object_latency_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_LATENCY) || defined( RPL_DAG_MC_CONST_USE_LATENCY)*/ +#if defined( RPL_DAG_MC_USE_LQL) || defined( RPL_DAG_MC_CONST_USE_LQL) + case RPL_DAG_MC_LQL: + if( NULL == (p_obj->lql= malloc (sizeof(rpl_metric_object_LQL_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_LQL) || defined( RPL_DAG_MC_CONST_USE_LQL)*/ +#if defined( RPL_DAG_MC_USE_ETX) || defined( RPL_DAG_MC_CONST_USE_ETX) + case RPL_DAG_MC_ETX: + if( NULL == (p_obj->etx= malloc (sizeof(rpl_metric_object_ETX_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_ETX) || defined( RPL_DAG_MC_CONST_USE_ETX)*/ +#if defined( RPL_DAG_MC_USE_LC) || defined( RPL_DAG_MC_CONST_USE_LC) + case RPL_DAG_MC_LC: + if( NULL == (p_obj->lc= malloc (sizeof(rpl_metric_object_LC_t)))) + error= 1; + break; +#endif /*defined( RPL_DAG_MC_USE_LC) || defined( RPL_DAG_MC_CONST_USE_LC)*/ + default: + /* unknown metric object */ + error= 2; + } + if(error){ + free(p_obj); + PRINTF("RPL: METRICS: ERROR creating an object\n"); + } + + return error; +} + + + +/*****************************************************************************************************/ + + +uint8_t +rpl_metrics_create_root_container(rpl_metric_container_t *p_mc) +{ + uint8_t objects_created; + uint32_t header; + rpl_metric_object_t **p_p_obj; + uint32_t object_headers[NUMBER_OF_METRICS_AND_CONST_USED]; + uint8_t i; + + if (NUMBER_OF_METRICS_AND_CONST_USED){ + objects_created= 0; + p_p_obj= p_mc->metric_and_const_objects; +#ifdef RPL_DAG_MC_USE_NSA + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_NSA, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_NSA; + (*p_p_obj++)->nsa->flags= RPL_DAG_MC_NSA_O_OVERLOAD|(RPL_DAG_MC_NSA_A_AGGREGATION<<1); +#endif /* RPL_DAG_MC_USE_NSA */ + +#ifdef RPL_DAG_MC_USE_ENERGY + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_ENERGY, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_ENERGY; + (*p_p_obj)->energy->flags= (RPL_DAG_MC_ENERGY_I_INCLUDED<<3)|(RPL_DAG_MC_ENERGY_T_TYPE<<1)|RPL_DAG_MC_ENERGY_E_ESTIMATION; + (*p_p_obj++)->energy->energy_est= RPL_DAG_MC_ENERGY_INITIALIZATION; +#endif /* RPL_DAG_MC_USE_ENERGY */ + +#ifdef RPL_DAG_MC_USE_HOPCOUNT + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_HOPCOUNT, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_HOPCOUNT; + (*p_p_obj++)->hop_count->hop_count= RPL_DAG_MC_HOPCOUNT_INITIALIZATION; +#endif /* RPL_DAG_MC_USE_HOPCOUNT */ + +#ifdef RPL_DAG_MC_USE_THROUGHPUT + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_THROUGHPUT, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_THROUGHPUT; + (*p_p_obj++)->throughput->throughput= RPL_DAG_MC_THROUGHPUT_INITIALIZATION; +#endif /* RPL_DAG_MC_USE_THROUGHPUT */ + +#ifdef RPL_DAG_MC_USE_LATENCY + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LATENCY, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_LATENCY; + (*p_p_obj++)->latency->latency= RPL_DAG_MC_LATENCY_INITIALIZATION; +#endif /* RPL_DAG_MC_USE_LATENCY */ + +#ifdef RPL_DAG_MC_USE_LQL + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LQL, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_LQL; + (*p_p_obj++)->lql->value_and_counter= RPL_DAG_MC_LQL_INITIALIZATION<<5; +#endif /* RPL_DAG_MC_USE_LQL */ + +#ifdef RPL_DAG_MC_USE_ETX + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_ETX, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_ETX; + (*p_p_obj++)->etx->etx= RPL_DAG_MC_ETX_INITIALIZATION * RPL_DAG_MC_ETX_DIVISOR; +#endif /* RPL_DAG_MC_USE_ETX */ + +#ifdef RPL_DAG_MC_USE_LC + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LC, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_USE_LC; + (*p_p_obj++)->lc->color_and_counter= RPL_DAG_MC_LC_INITIALIZATION<<6; +#endif /* RPL_DAG_MC_USE_LC */ + +#ifdef RPL_DAG_MC_CONST_USE_NSA + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_NSA, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_NSA; + (*p_p_obj++)->nsa->flags= RPL_DAG_MC_CONST_NSA_O_OVERLOAD|(RPL_DAG_MC_CONST_NSA_A_AGGREGATION<<1); +#endif /* RPL_DAG_MC_CONST_USE_NSA */ + +#ifdef RPL_DAG_MC_CONST_USE_ENERGY + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_ENERGY, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_ENERGY; + (*p_p_obj)->energy->flags= (RPL_DAG_MC_CONST_ENERGY_I_INCLUDED<<3)|(RPL_DAG_MC_CONST_ENERGY_T_TYPE<<1)|RPL_DAG_MC_CONST_ENERGY_E_ESTIMATION; + (*p_p_obj++)->energy->energy_est= RPL_DAG_MC_CONST_ENERGY_THRESHOLD; +#endif /* RPL_DAG_MC_CONST_USE_ENERGY */ + +#ifdef RPL_DAG_MC_CONST_USE_HOPCOUNT + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_HOPCOUNT, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_HOPCOUNT; + (*p_p_obj++)->hop_count->hop_count= RPL_DAG_MC_CONST_HOPCOUNT_THRESHOLD; +#endif /* RPL_DAG_MC_CONST_USE_HOPCOUNT */ + +#ifdef RPL_DAG_MC_CONST_USE_THROUGHPUT + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_THROUGHPUT, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_THROUGHPUT; + (*p_p_obj++)->throughput->throughput= RPL_DAG_MC_CONST_THROUGHPUT_THRESHOLD; +#endif /* RPL_DAG_MC_CONST_USE_THROUGHPUT */ + +#ifdef RPL_DAG_MC_CONST_USE_LATENCY + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LATENCY, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_LATENCY; + (*p_p_obj++)->latency->latency= RPL_DAG_MC_CONST_LATENCY_THRESHOLD; +#endif /* RPL_DAG_MC_CONST_USE_LATENCY */ + +#ifdef RPL_DAG_MC_CONST_USE_LQL + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LQL, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_LQL; + (*p_p_obj++)->lql->value_and_counter= RPL_DAG_MC_CONST_LQL_THRESHOLD<<5; +#endif /* RPL_DAG_MC_CONST_USE_LQL */ + +#ifdef RPL_DAG_MC_CONST_USE_ETX + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_ETX, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_ETX; + (*p_p_obj++)->etx->etx= RPL_DAG_MC_CONST_ETX_THRESHOLD; +#endif /* RPL_DAG_MC_CONST_USE_ETX */ + +#ifdef RPL_DAG_MC_CONST_USE_LC + if( rpl_metrics_create_object (p_mc, RPL_DAG_MC_LC, objects_created) ) + return 0; + object_headers[objects_created++]= RPL_DAG_MC_CONST_USE_LC; + (*p_p_obj++)->lc->color_and_counter= (RPL_DAG_MC_CONST_LC_THRESHOLD<<6) | RPL_DAG_MC_LC_I_INCLUDED; +#endif /* RPL_DAG_MC_CONST_USE_LC */ + + p_mc->metric_and_const_obj= objects_created; + +#ifdef DEBUG_RPL_METRICS + if(NUMBER_OF_METRICS_AND_CONST_USED != objects_created) + printf("RPL: METRICS: NUMBER_OF_CONSTRAINTS_USED is not the same as objects created\n"); +#endif /* DEBUG_RPL_METRICS */ + + p_p_obj= p_mc->metric_and_const_objects; + for (i= 0; i< objects_created; i++){ + header= object_headers[i]; + (*p_p_obj)->type= RPL_METRIC_OBJECT_HEADER_TYPE(header); + (*p_p_obj)->flags= RPL_METRIC_OBJECT_HEADER_FLAGS(header); + (*p_p_obj++)->length= RPL_METRIC_OBJECT_HEADER_LENGTH(header); + } + } +return 1; + +} + + +/**************************************************************************************************/ + + +uint8_t +rpl_metrics_copy_mc (rpl_metric_container_t *p_mc_dest, rpl_metric_container_t *p_mc_orig) +{ + uint8_t i; + uint8_t ok_ret_value; + uint8_t num_dest_objects, num_orig_objects; + rpl_metric_object_t *p_obj_dest, *p_obj_orig; + + num_dest_objects= p_mc_dest->metric_and_const_obj; + num_orig_objects= p_mc_orig->metric_and_const_obj; + ok_ret_value = 1; + if(num_dest_objects < num_orig_objects){ + for (i= num_dest_objects; i< num_orig_objects; i++){ + if( rpl_metrics_create_object(p_mc_dest,p_mc_orig->metric_and_const_objects[i]->type, i)){ + PRINTF("RPL: METRICS: Error creating an object\n"); + num_orig_objects= i; + ok_ret_value= 0; + } + else{ + p_mc_dest->metric_and_const_obj++; + p_mc_dest->metric_and_const_objects[i]->length = p_mc_orig->metric_and_const_objects[i]->length; + } + } + } + else if(num_dest_objects > num_orig_objects){ + for(i= num_orig_objects; i< num_dest_objects; i++){ + free( p_mc_dest->metric_and_const_objects[i]->rpl_metric_object_data_pointer); + free( p_mc_dest->metric_and_const_objects[i]); + p_mc_dest->metric_and_const_obj--; + } + } + + for (i=0; i< num_orig_objects; i++){ + p_obj_dest= p_mc_dest->metric_and_const_objects[i]; + p_obj_orig= p_mc_orig->metric_and_const_objects[i]; + if(p_obj_dest->length != p_obj_orig->length ){ + free(p_obj_dest->rpl_metric_object_data_pointer); + if( NULL == (p_obj_dest->rpl_metric_object_data_pointer= malloc (sizeof(p_obj_orig->length * sizeof(uint8_t))))){ + PRINTF("RPL: METRICS: Error allocating memory for a metric object\n"); + return 0; + } + } + p_obj_dest->type = p_obj_orig->type; + p_obj_dest->flags = p_obj_orig->flags; + p_obj_dest->length = p_obj_orig->length; + memcpy(p_obj_dest->rpl_metric_object_data_pointer,p_obj_orig->rpl_metric_object_data_pointer, p_obj_dest->length * sizeof(uint8_t)); + } + p_mc_dest->metric_and_const_obj= num_orig_objects; + + return ok_ret_value; +} + + +/*************************************************************************************************/ + + +uint8_t +rpl_metrics_write_object_to_metric_container (rpl_metric_container_t *mc, uint8_t *buffer, uint8_t obj_cont){ + + rpl_metric_object_t* p_obj= NULL; + uint8_t error_code; + uint8_t type; + uint8_t number_objects; + uint8_t i; + uint16_t temp16; + uint32_t temp32; + + number_objects= mc->metric_and_const_obj; + if ( (obj_cont >= NUMBER_OF_METRICS_AND_CONST_USED) || (obj_cont > number_objects)){ + PRINTF("RPL: METRICS: DIO has too many metric objects or not memory enough\n"); + return 0; + } + + i=0; + type= buffer[i++]; + + if ( ((obj_cont < number_objects)&&(mc->metric_and_const_objects[obj_cont]->type != type)) || (obj_cont == number_objects) ){ + if(obj_cont != number_objects) + free(mc->metric_and_const_objects[obj_cont]); + error_code= rpl_metrics_create_object (mc, type, obj_cont); + if (error_code==1){ + PRINTF("RPL: METRICS: Unable to allocate mem for an object\n"); + return 0; + } + if (error_code==2){ + PRINTF("RPL: METRICS: Unknown metric object\n"); + return 0; + } + if (obj_cont == number_objects) + (mc->metric_and_const_obj)++; + } + + p_obj= mc->metric_and_const_objects[obj_cont]; + p_obj->type= type; + temp16= buffer[i++]; + temp16= (temp16<<8)+buffer[i++]; + p_obj->flags= temp16; + p_obj->length= buffer[i++]; + + switch (type){ +#if defined (RPL_DAG_MC_USE_NSA) || defined (RPL_DAG_MC_CONST_USE_NSA) + case RPL_DAG_MC_NSA: + i++; //reserved flags + p_obj->nsa->flags= buffer[i++]; + PRINTF("RPL: METRICS: DIO had an NSA object\n"); + break; +#endif /* defined (RPL_DAG_MC_USE_NSA) || defined (RPL_DAG_MC_CONST_USE_NSA) */ +#if defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) + case RPL_DAG_MC_ENERGY: + p_obj->energy->flags= buffer[i++]; + p_obj->energy->energy_est= buffer[i++]; + PRINTF("RPL: METRICS: DIO had an energy object with flags:0x%02x, value:%u\n",p_obj->energy->flags, p_obj->energy->energy_est); + break; +#endif /* defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) */ +#if defined(RPL_DAG_MC_USE_HOPCOUNT) || defined(RPL_DAG_MC_CONST_USE_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + i++; //reserved flags + p_obj->hop_count->hop_count= buffer[i++]; + PRINTF("RPL: METRICS: DIO had a hop-count object with value:%u\n",buffer[i-1]); + break; +#endif /* defined(RPL_DAG_MC_USE_HOPCOUNT) || defined(RPL_DAG_MC_CONST_USE_HOPCOUNT) */ +#if defined(RPL_DAG_MC_USE_THROUGHPUT) || defined(RPL_DAG_MC_CONST_USE_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + temp32= buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + p_obj->throughput->throughput= temp32; + PRINTF("RPL: METRICS: DIO had a throughput object with value:%lu\n",p_obj->throughput->throughput); + break; +#endif /* defined(RPL_DAG_MC_USE_THROUGHPUT) || defined(RPL_DAG_MC_CONST_USE_THROUGHPUT) */ +#if defined(RPL_DAG_MC_USE_LATENCY) || defined(RPL_DAG_MC_CONST_USE_LATENCY) + case RPL_DAG_MC_LATENCY: + temp32= buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + temp32= (temp32<<8)+buffer[i++]; + p_obj->latency->latency= temp32; + PRINTF("RPL: METRICS: DIO had a latency object with value:%lu\n",p_obj->latency->latency); + break; +#endif /* defined(RPL_DAG_MC_USE_LATENCY) || defined(RPL_DAG_MC_CONST_USE_LATENCY) */ +#if defined(RPL_DAG_MC_USE_LQL) || defined(RPL_DAG_MC_CONST_USE_LQL) + case RPL_DAG_MC_LQL: + i++; //reserved flags + p_obj->lql->value_and_counter= buffer[i++]; + PRINTF("RPL: METRICS: DIO had an LQL object\n"); + break; +#endif /* defined(RPL_DAG_MC_USE_LQL) || defined(RPL_DAG_MC_CONST_USE_LQL) */ +#if defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) + case RPL_DAG_MC_ETX: + temp16= buffer[i++]; + temp16= (temp16<<8)+buffer[i++]; + p_obj->etx->etx= temp16; + PRINTF("RPL: METRICS: DIO had an ETX object with value:%u\n",p_obj->etx->etx); + break; +#endif /* defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) */ +#if defined(RPL_DAG_MC_USE_LC) || defined(RPL_DAG_MC_CONST_USE_LC) + case RPL_DAG_MC_LC: + i++; //reserved flags + temp16= buffer[i++]; + temp16= (temp16<<8)+buffer[i++]; + p_obj->lc->color_and_counter= temp16; + PRINTF("RPL: METRICS: DIO had an LC object\n"); + break; +#endif /* defined(RPL_DAG_MC_USE_LC) || defined(RPL_DAG_MC_CONST_USE_LC) */ + } + return i; + +} + + +/********************************************************************************************/ + + +uint8_t +rpl_metrics_read_from_metric_container (rpl_metric_object_t *obj, uint8_t *buffer) +{ + + uint8_t type, length; + uint16_t temp16; + uint32_t temp32; + + /* metric container object header */ + type= obj->type; + length= obj->length; + + *buffer++ = type; + *buffer++ = obj->flags >> 8; + *buffer++ = obj->flags & 0xFF; + *buffer++ = length; + + switch (type){ +#if defined(RPL_DAG_MC_USE_NSA) || defined(RPL_DAG_MC_CONST_USE_NSA) + case RPL_DAG_MC_NSA: + *buffer++= 0; //reserved flags + *buffer= obj->nsa->flags; + PRINTF("RPL: METRICS: add in the DIO an NSA object with flags:0x%04x\n",obj->nsa->flags); + break; +#endif /*defined(RPL_DAG_MC_USE_NSA) || defined(RPL_DAG_MC_CONST_USE_NSA) */ +#if defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) + case RPL_DAG_MC_ENERGY: + *buffer++= obj->energy->flags; + *buffer= obj->energy->energy_est; + PRINTF("RPL: METRICS: add in the DIO an energy object with value:%u\n",obj->energy->energy_est); + break; +#endif /*defined(RPL_DAG_MC_USE_ENERGY) || defined(RPL_DAG_MC_CONST_USE_ENERGY) */ +#if defined(RPL_DAG_MC_USE_HOPCOUNT) || defined(RPL_DAG_MC_CONST_USE_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + *buffer++= 0; //reserved flags + *buffer= obj->hop_count->hop_count; + PRINTF("RPL: METRICS: add in the DIO a hop-count object with value:%u\n",obj->hop_count->hop_count); + break; +#endif /*defined(RPL_DAG_MC_USE_HOPCOUNT) || defined(RPL_DAG_MC_CONST_USE_HOPCOUNT) */ +#if defined(RPL_DAG_MC_USE_THROUGHPUT) || defined(RPL_DAG_MC_CONST_USE_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + temp32= obj->throughput->throughput; + *buffer++= READ_FIELD(temp32, 24, 0xFF000000); + *buffer++= READ_FIELD(temp32, 16, 0x00FF0000); + *buffer++= READ_FIELD(temp32, 8, 0x0000FF00); + *buffer= READ_FIELD(temp32, 0, 0x000000FF); + PRINTF("RPL: METRICS: add in the DIO a throughput object with value:%lu\n",temp32); + break; +#endif /*defined(RPL_DAG_MC_USE_THROUGHPUT) || defined(RPL_DAG_MC_CONST_USE_THROUGHPUT) */ +#if defined(RPL_DAG_MC_USE_LATENCY) || defined(RPL_DAG_MC_CONST_USE_LATENCY) + case RPL_DAG_MC_LATENCY: + temp32= obj->latency->latency; + *buffer++= READ_FIELD(temp32, 24, 0xFF000000); + *buffer++= READ_FIELD(temp32, 16, 0x00FF0000); + *buffer++= READ_FIELD(temp32, 8, 0x0000FF00); + *buffer= READ_FIELD(temp32, 0, 0x000000FF); + PRINTF("RPL: METRICS: add in the DIO a latency object with value:%lu\n",temp32); + break; +#endif /*defined(RPL_DAG_MC_USE_LATENCY) || defined(RPL_DAG_MC_CONST_USE_LATENCY) */ +#if defined(RPL_DAG_MC_USE_LQL) || defined(RPL_DAG_MC_CONST_USE_LQL) + case RPL_DAG_MC_LQL: + *buffer++= 0; //reserved flags + *buffer= obj->lql->value_and_counter; + PRINTF("RPL: METRICS: add in the DIO an LQL object\n"); + break; +#endif /*defined(RPL_DAG_MC_USE_LQL) || defined(RPL_DAG_MC_CONST_USE_LQL) */ +#if defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) + case RPL_DAG_MC_ETX: + temp16= obj->etx->etx; + *buffer++= READ_FIELD(temp16, 8, 0xFF00); + *buffer= READ_FIELD(temp16, 0, 0x00FF); + PRINTF("RPL: METRICS: add in the DIO an ETX object with value:%u\n",temp16); + break; +#endif /*defined(RPL_DAG_MC_USE_ETX) || defined(RPL_DAG_MC_CONST_USE_ETX) */ +#if defined(RPL_DAG_MC_USE_LC) || defined(RPL_DAG_MC_CONST_USE_LC) + case RPL_DAG_MC_LC: + *buffer++= 0; //reserved flags + temp16= obj->lc->color_and_counter; + *buffer++= READ_FIELD(temp16, 8, 0xFF00); + *buffer= READ_FIELD(temp16, 0, 0x00FF); + PRINTF("RPL: METRICS: add in the DIO an LC object\n"); + break; +#endif /*defined(RPL_DAG_MC_USE_LC) || defined(RPL_DAG_MC_CONST_USE_LC) */ + } + +return (length+4); // length object body + header (bytes) +} + + +/********************************************************************************/ + + +uint8_t +rpl_metrics_array_of_metrics (rpl_metric_container_t *p_mc, rpl_metric_element_t *array_of_metrics) +{ + + uint8_t type; + uint16_t flags; + uint8_t agg_mode; + uint8_t number_of_elem= 0; + rpl_metric_object_t *p_obj; + rpl_metric_element_t temp_elem; + uint8_t precedence[NUMBER_OF_METRICS_AND_CONST_USED]; + uint8_t i, j, imin; + + for(i=0; i< NUMBER_OF_METRICS_AND_CONST_USED; i++){ + p_obj= p_mc->metric_and_const_objects[i]; + flags= p_obj->flags; + + /* if not a constraint */ + if( !READ_BIT(flags, RPL_DAG_MC_POS_C_BIT)){ + type= p_obj->type; + agg_mode= RPL_METRIC_READ_A_FIELD(flags); + precedence[number_of_elem]= RPL_METRIC_READ_PREC_FIELD(flags); + + array_of_metrics[number_of_elem].type= type; + array_of_metrics[number_of_elem].aggregation_mode= agg_mode; + + switch (type){ +#ifdef RPL_DAG_MC_USE_NSA + case RPL_DAG_MC_NSA: + //array_of_metrics[number_of_elem++].data= p_obj->nsa->flags; + break; +#endif /* RPL_DAG_MC_USE_NSA */ +#ifdef RPL_DAG_MC_USE_ENERGY + case RPL_DAG_MC_ENERGY: + array_of_metrics[number_of_elem++].data= p_obj->energy->energy_est; + break; +#endif /* RPL_DAG_MC_USE_ENERGY */ +#ifdef RPL_DAG_MC_USE_HOPCOUNT + case RPL_DAG_MC_HOPCOUNT: + array_of_metrics[number_of_elem++].data= (p_obj->hop_count->hop_count) * RPL_DAG_MC_HOPCOUNT_MULTIPLIER; + break; +#endif /* RPL_DAG_MC_USE_HOPCOUNT */ +#ifdef RPL_DAG_MC_USE_THROUGHPUT + case RPL_DAG_MC_THROUGHPUT: + array_of_metrics[number_of_elem++].data= (p_obj->throughput->throughput)>>RPL_DAG_MC_THROUGHPUT_DIVISOR; + break; +#endif /* RPL_DAG_MC_USE_THROUGHPUT */ +#ifdef RPL_DAG_MC_USE_LATENCY + case RPL_DAG_MC_LATENCY: + array_of_metrics[number_of_elem++].data= (p_obj->latency->latency)>>RPL_DAG_MC_LATENCY_DIVISOR; + break; +#endif /* RPL_DAG_MC_USE_LATENCY */ +#ifdef RPL_DAG_MC_USE_LQL + case RPL_DAG_MC_LQL: + //array_of_metrics[number_of_elem++].data= p_obj->lql->value_and_counter; + break; +#endif /* RPL_DAG_MC_USE_LQL */ +#ifdef RPL_DAG_MC_USE_ETX + case RPL_DAG_MC_ETX: + array_of_metrics[number_of_elem++].data= p_obj->etx->etx; + break; +#endif /* RPL_DAG_MC_USE_ETX */ +#ifdef RPL_DAG_MC_USE_LC + case RPL_DAG_MC_LC: + //array_of_metrics[number_of_elem++].data= p_obj->lc->color_and_counter; + break; +#endif /* RPL_DAG_MC_USE_LC */ + } + } + } + + /* sort by precedence */ + for (i=0; i< number_of_elem-1; i++){ + imin= i; + for(j=i+1; j< number_of_elem; j++){ + if(precedence[j] < precedence[imin]) + imin= j; + } + temp_elem= array_of_metrics[i]; + array_of_metrics[i]= array_of_metrics[imin]; + array_of_metrics[imin]= temp_elem; + } + + return number_of_elem; +} + + +/**********************************************************************************************/ + + +uint32_t rpl_metrics_aggregated(uint8_t metric_comb_type, uint32_t parent_metric, uint32_t new_metric) +{ + + switch (metric_comb_type){ + case RPL_DAG_MC_AGGR_ADDITIVE: + return (parent_metric + new_metric); + break; + + case RPL_DAG_MC_AGGR_MAXIMUM: + return (parent_metric > new_metric ? parent_metric : new_metric); + break; + + case RPL_DAG_MC_AGGR_MINIMUM: + return (parent_metric < new_metric ? parent_metric : new_metric); + break; + + case RPL_DAG_MC_AGGR_MULTIPLICATIVE: + return (parent_metric * new_metric); + break; + + default: + PRINTF("RPL: METRICS: Error aggregation type: %u\n", metric_comb_type); + return 0; + break; + } +} + + +/**********************************************************************************************/ + + +void +rpl_metrics_update_metric_container(rpl_instance_t *instance) +{ + + rpl_metric_container_t *p_parent_container, *p_instance_container; + rpl_metric_object_t *p_obj_parent, *p_obj_instance; + uint8_t i, num_constraints,constraints[5]; + uint8_t type, metric_comb_type; + uint16_t flags; + uint32_t new_metric, parent_metric; + uint8_t copy_const= 0; + + + if( instance->current_dag->rank == ROOT_RANK(instance) ) + rpl_metrics_create_root_container(&(instance->mc)); + else{ + p_instance_container= &(instance->mc); + p_parent_container= &(instance->current_dag->preferred_parent->mc); + num_constraints=0; + + for(i=0; i< p_parent_container->metric_and_const_obj; i++){ + p_obj_instance= p_instance_container->metric_and_const_objects[i]; + p_obj_parent= p_parent_container->metric_and_const_objects[i]; + + flags= p_obj_parent->flags; + + copy_const= 0; + /* constraint */ + + if( READ_BIT(flags, RPL_DAG_MC_POS_C_BIT) ) { + if( !READ_BIT(flags, RPL_DAG_MC_POS_O_BIT)){ + constraints[num_constraints]= i; + num_constraints++; + } + copy_const=1; + } + + metric_comb_type= RPL_METRIC_READ_A_FIELD(flags); + type= p_obj_parent->type; + + switch (type){ +#if defined( RPL_DAG_MC_USE_NSA) || defined( RPL_DAG_MC_CONST_USE_NSA) + case RPL_DAG_MC_NSA: + if(copy_const) + p_obj_instance->nsa->flags= p_obj_parent->nsa->flags; + else + p_obj_instance->nsa->flags= rpl_metrics_get_NSA(); + break; +#endif /*defined( RPL_DAG_MC_USE_NSA) || defined( RPL_DAG_MC_CONST_USE_NSA)*/ + +#if defined( RPL_DAG_MC_USE_ENERGY) || defined( RPL_DAG_MC_CONST_USE_ENERGY) + case RPL_DAG_MC_ENERGY: + p_obj_instance->energy->flags= p_obj_parent->energy->flags; + if(copy_const) + p_obj_instance->energy->energy_est= p_obj_parent->energy->energy_est; + else{ + new_metric= rpl_metrics_get_energy(); + parent_metric= (uint32_t)p_obj_parent->energy->energy_est; + new_metric= rpl_metrics_aggregated(metric_comb_type, parent_metric, new_metric); + p_obj_instance->energy->energy_est= (new_metric>255?255:new_metric); + } + break; +#endif /*defined( RPL_DAG_MC_USE_ENERGY) || defined( RPL_DAG_MC_CONST_USE_ENERGY)*/ + +#if defined( RPL_DAG_MC_USE_HOPCOUNT) || defined( RPL_DAG_MC_CONST_USE_HOPCOUNT) + case RPL_DAG_MC_HOPCOUNT: + p_obj_instance->hop_count->hop_count= p_obj_parent->hop_count->hop_count; + if(!copy_const) + (p_obj_instance->hop_count->hop_count)++; + break; +#endif /*defined( RPL_DAG_MC_USE_HOPCOUNT) || defined( RPL_DAG_MC_CONST_USE_HOPCOUNT)*/ + +#if defined( RPL_DAG_MC_USE_THROUGHPUT) || defined( RPL_DAG_MC_CONST_USE_THROUGHPUT) + case RPL_DAG_MC_THROUGHPUT: + if(copy_const) + new_metric= p_obj_parent->throughput->throughput; + else{ + new_metric= rpl_metrics_get_throughput(); + parent_metric= p_obj_parent->throughput->throughput; + new_metric= rpl_metrics_aggregated(metric_comb_type, parent_metric, new_metric); + } + p_obj_instance->throughput->throughput= new_metric; + break; +#endif /*defined( RPL_DAG_MC_USE_THROUGHPUT) || defined( RPL_DAG_MC_CONST_USE_THROUGHPUT)*/2 +#if defined( RPL_DAG_MC_USE_LATENCY) || defined( RPL_DAG_MC_CONST_USE_LATENCY) + case RPL_DAG_MC_LATENCY: + if(copy_const) + new_metric= p_obj_parent->latency->latency; + else{ + new_metric= rpl_metrics_get_latency(); + parent_metric= p_obj_parent->latency->latency; + new_metric= rpl_metrics_aggregated(metric_comb_type, parent_metric, new_metric); + } + p_obj_instance->latency->latency= new_metric; + break; +#endif /*defined( RPL_DAG_MC_USE_LATENCY) || defined( RPL_DAG_MC_CONST_USE_LATENCY)*/ + +#if defined( RPL_DAG_MC_USE_LQL) || defined( RPL_DAG_MC_CONST_USE_LQL) + case RPL_DAG_MC_LQL: + if(copy_const) + p_obj_instance->lql->value_and_counter=p_obj_parent->lql->value_and_counter; + else + p_obj_instance->lql->value_and_counter= rpl_metrics_get_LQL(); + break; +#endif /*defined( RPL_DAG_MC_USE_LQL) || defined( RPL_DAG_MC_CONST_USE_LQL)*/ + +#if defined( RPL_DAG_MC_USE_ETX) || defined( RPL_DAG_MC_CONST_USE_ETX) + case RPL_DAG_MC_ETX: + if(copy_const) + new_metric= p_obj_parent->etx->etx; + else{ + new_metric= rpl_metrics_get_ETX(); + parent_metric= p_obj_parent->etx->etx; + new_metric= rpl_metrics_aggregated(metric_comb_type, parent_metric, new_metric); + } + p_obj_instance->etx->etx= new_metric; + break; +#endif /*defined( RPL_DAG_MC_USE_ETX) || defined( RPL_DAG_MC_CONST_USE_ETX)*/ + +#if defined( RPL_DAG_MC_USE_LC) || defined( RPL_DAG_MC_CONST_USE_LC) + case RPL_DAG_MC_LC: + if(copy_const) + p_obj_instance->lc->color_and_counter=p_obj_parent->lc->color_and_counter; + else + p_obj_instance->lc->color_and_counter= rpl_metrics_get_LC(); + break; +#endif /*defined( RPL_DAG_MC_USE_LC) || defined( RPL_DAG_MC_CONST_USE_LC)*/ + } + } + + /*check mandatory constraints*/ + for(i=0; imetric_and_const_objects[constraints[i]]; + flags= p_obj_instance->flags; + + if(!rpl_metrics_satisfies_constraint(p_obj_instance, p_instance_container)){ + PRINTF("RPL: METRICS: does not satisfy a mandatory constraint and become a leaf node\n"); + if(!rpl_leaf){ + rpl_leaf= 1; + leaf_dio= 1; + } + return; + } + } + } +} + + +/************************************************************************************************/ + + +uint8_t +rpl_metrics_satisfies_constraint(rpl_metric_object_t *p_obj_const, rpl_metric_container_t *p_instance_container) +{ + uint8_t return_value; + uint8_t i, type, metric_found, num_objects; + uint8_t temp_8; + uint16_t temp_16_const,temp_16_inst, flags; + uint8_t energy_type,bit_I; + rpl_metric_object_t *p_obj_inst; + + metric_found= 0; + type= p_obj_const->type; + num_objects= p_instance_container->metric_and_const_obj; + + for(i=0; (imetric_and_const_objects[i]; + if(p_obj_inst->type == type){ + flags= p_obj_inst->flags; + if( !READ_BIT(flags, RPL_DAG_MC_POS_C_BIT) ) + metric_found++; + } + } + + return_value= 1; + if(metric_found){ + switch (type){ + +#ifdef RPL_DAG_MC_CONST_USE_NSA + case RPL_DAG_MC_NSA: + if( ! ((p_obj_const->nsa->flags) & RPL_DAG_MC_NSA_OVERLOAD_BIT)) + if( (p_obj_inst->nsa->flags) & RPL_DAG_MC_NSA_OVERLOAD_BIT) + return_value= 0; + + if((p_obj_const->nsa->flags) & RPL_DAG_MC_NSA_AGGREGATION_BIT) + if( ! ((p_obj_inst->nsa->flags) & RPL_DAG_MC_NSA_AGGREGATION_BIT)) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_NSA */ +#ifdef RPL_DAG_MC_CONST_USE_ENERGY + case RPL_DAG_MC_ENERGY: + + bit_I= ((p_obj_const->energy->flags) >> 3) & 0x1; + energy_type= ((p_obj_const->energy->flags) >> 1) & 0x3; + + if(bit_I){ + if(energy_type< RPL_DAG_MC_ENERGY_TYPE_MYSELF) + return_value = 0; + } + else{ + if(energy_type<= RPL_DAG_MC_ENERGY_TYPE_MYSELF) + return_value = 0; + } + if(p_obj_inst->energy->energy_est > p_obj_const->energy->energy_est) + return_value = 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_ENERGY */ +#ifdef RPL_DAG_MC_CONST_USE_HOPCOUNT + case RPL_DAG_MC_HOPCOUNT: + if(p_obj_const->hop_count->hop_count < p_obj_inst->hop_count->hop_count) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_HOPCOUNT */ +#ifdef RPL_DAG_MC_CONST_USE_THROUGHPUT + case RPL_DAG_MC_THROUGHPUT: + if(p_obj_const->throughput->throughput > p_obj_inst->throughput->throughput) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_THROUGHPUT */ +#ifdef RPL_DAG_MC_CONST_USE_LATENCY + case RPL_DAG_MC_LATENCY: + if(p_obj_const->latency->latency < p_obj_inst->latency->latency) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_LATENCY */ +#ifdef RPL_DAG_MC_CONST_USE_LQL + case RPL_DAG_MC_LQL: + temp_8= (p_obj_const->lql->value_and_counter >> 5) & 0x07; + if(temp_8 < ((p_obj_inst->lql->value_and_counter >> 5) & 0x07)) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_LQL */ +#ifdef RPL_DAG_MC_CONST_USE_ETX + case RPL_DAG_MC_ETX: + if(p_obj_const->etx->etx < p_obj_inst->etx->etx); + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_ETX */ +#ifdef RPL_DAG_MC_CONST_USE_LC + case RPL_DAG_MC_LC: + /* If 'I'=1, 1's of constraint and instance must be equal */ + /* If 'I'=0, 0's of constraint and instance must be equal */ + temp_16_const= (p_obj_const->lc->color_and_counter >> 6) & 0x3FF;; + temp_16_inst= (p_obj_inst->lc->color_and_counter >> 6) & 0x3FF;; + if( ! (p_obj_const->lc->color_and_counter & 0x1)){ + temp_16_const= (~temp_16_const) & 0x3FF;; + temp_16_inst= (~temp_16_inst) & 0x3FF;; + } + if(temp_16_const != (temp_16_const & temp_16_inst)) + return_value= 0; + break; +#endif /* RPL_DAG_MC_CONST_USE_LC */ + } + } + else + PRINTF("RPL: METRICS: not found a metric for a constraint of type %u\n",type); + + return return_value; +} diff --git a/examples/containers/rpl-metrics.h b/examples/containers/rpl-metrics.h new file mode 100644 index 00000000000..d7744481a08 --- /dev/null +++ b/examples/containers/rpl-metrics.h @@ -0,0 +1,32 @@ +#ifndef RPL_METRICS_H +#define RPL_METRICS_H + +#include "net/rpl/rpl.h" +#include "rpl-metrics-data.h" + + +#define READ_BIT(flags, pos) ((((flags) & (1<> pos) + +#define RPL_METRIC_READ_A_FIELD(flags) READ_FIELD((flags), RPL_DAG_MC_POS_A_FIELD, 0x70) +#define RPL_METRIC_READ_PREC_FIELD(flags) ((flags) & 0xF) +#define RPL_METRIC_WRITE_A_FIELD(flags,val) ((flags)= (((flags) & 0xFF8F) | (val<<4))) +#define RPL_METRIC_WRITE_PREC_FIELD(flags,val) ((flags)= (((flags) & 0xFFF0) | val)) + +#define RPL_METRIC_OBJECT_HEADER_TYPE(header) READ_FIELD(header,24,0xFF000000) +#define RPL_METRIC_OBJECT_HEADER_FLAGS(header) READ_FIELD(header,8,0x00FFFF00) +#define RPL_METRIC_OBJECT_HEADER_LENGTH(header) READ_FIELD(header,0,0x000000FF) + +uint8_t rpl_metrics_create_object (rpl_metric_container_t *p_mc, uint8_t type, uint8_t pos_obj); +uint8_t rpl_metrics_create_root_container(rpl_metric_container_t *mc); +uint8_t rpl_metrics_copy_mc (rpl_metric_container_t *p_mc_dest, rpl_metric_container_t *p_mc_orig); +uint8_t rpl_metrics_write_object_to_metric_container (rpl_metric_container_t *mc, uint8_t *buffer, uint8_t obj_cont); +uint8_t rpl_metrics_read_from_metric_container (rpl_metric_object_t *obj, uint8_t *buffer); +uint8_t rpl_metrics_array_of_metrics (rpl_metric_container_t *p_mc, rpl_metric_element_t *array_of_metrics); +uint32_t rpl_metrics_aggregated(uint8_t metric_comb_type, uint32_t parent_metric, uint32_t new_metric); +void rpl_metrics_update_metric_container(rpl_instance_t *instance); +uint8_t rpl_metrics_satisfies_constraint(rpl_metric_object_t *p_obj, rpl_metric_container_t *p_instance_container); + +#endif /* RPL_METRICS_H */ + diff --git a/examples/containers/server.c b/examples/containers/server.c new file mode 100644 index 00000000000..3f703f290e7 --- /dev/null +++ b/examples/containers/server.c @@ -0,0 +1,370 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/ip/uip.h" +#include "net/rpl/rpl.h" +#include "net/rime/rimeaddr.h" + +#include "net/netstack.h" +#include "dev/button-sensor.h" +#include "dev/serial-line.h" +//#if CONTIKI_TARGET_Z1 +//#include "dev/uart0.h" +//#else +//#include "dev/uart1.h" +//#endif +#include +#include +#include +#include +#include "collect-common.h" +#include "collect-view.h" +#include "common-hdr.h" +#include "udp-app.h" + + +#define DEBUG DEBUG_PRINT +#include "net/ip/uip-debug.h" + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +#define UDP_CLIENT_PORT 8765 +#define UDP_SERVER_PORT 5678 + +#define UDP_EXAMPLE_ID 190 + +static struct uip_udp_conn *server_conn; + +PROCESS(udp_server_process, "UDP server process"); +AUTOSTART_PROCESSES(&udp_server_process,&collect_common_process); + +#define MAX_NODES 1000 + + #if 0 + typedef struct _dpkt_stat_ + { + uip_ipaddr_t ip; + uint32_t lastseq; + uint32_t dropcnt; + uint32_t unordered; + uint32_t rcvcnt; + uint32_t dupcnt; + long leastLatency; + }dpkt_stat_t; + #endif + + dpkt_stat_t g_dstats[MAX_NODES]; + uint32_t g_ds_cnt; + + + dpkt_stat_t *get_dpkt_stat(uip_ipaddr_t *srcip) + { + int i; + dpkt_stat_t *ds; + + for(i=0;iip)) { + return ds; + } + } + return NULL; + } + + long dpkt_latency_time(struct timeval *tv) + + { + long duration=0; + long sentTime=0; + long recvTime=0; + struct timeval curTime; + gettimeofday(&curTime, NULL); + + + sentTime = tv->tv_sec * 1000000; + sentTime += tv->tv_usec; + + recvTime = curTime.tv_sec * 1000000; + recvTime += curTime.tv_usec; + + if (recvTime > sentTime){ + duration = recvTime-sentTime; + } + + #if 0 + if (curTime.tv_sec > tv->tv_sec){ + duration = (curTime.tv_sec - tv->tv_sec) * 1000000; + } + + if (curTime.tv_usec > tv->tv_usec){ + duration += (curTime.tv_usec - tv->tv_usec); + } + #endif + + return duration; + } +/*---------------------------------------------------------------------------*/ +void +collect_common_set_sink(void) +{ +} +/*---------------------------------------------------------------------------*/ +void +collect_common_net_print(void) +{ + printf("I am sink!\n"); +} +/*---------------------------------------------------------------------------*/ +void +collect_common_send(void) +{ + /* Server never sends */ +} +/*---------------------------------------------------------------------------*/ +void +collect_common_net_init(void) +{ +/*#if CONTIKI_TARGET_Z1 + uart0_set_input(serial_line_input_byte); +#else + uart1_set_input(serial_line_input_byte); +#endif */ + serial_line_init(); + + PRINTF("I am sink!\n"); +} +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + dpkt_t *pkt; + dpkt_stat_t *ds; + long curpktlatency; + + if(!uip_newdata()) { + return; + } + + pkt = (dpkt_t *)uip_appdata; + ds = get_dpkt_stat(&(UIP_IP_BUF->srcipaddr)); + if(!ds) { + if(g_ds_cnt>=MAX_NODES) { + printf("dstats exceeded!\n"); + return; + } + + ds = &g_dstats[g_ds_cnt++]; + memset(ds, 0, sizeof(dpkt_stat_t)); + ds->ip = UIP_IP_BUF->srcipaddr; + } + + if (!ds->lastseq){ + ds->lastseq = pkt->seq; + ds->rcvcnt++; + ds->leastLatency = ds->maxLatency = curpktlatency = dpkt_latency_time(&(pkt->sendTime)); + goto SEND_REPLY; + } + + if (pkt->seq == ds->lastseq){ + ds->dupcnt++; + } + else if(pkt->seq < ds->lastseq) { + ds->unordered++; + ds->rcvcnt++; + } + else{ + ds->lastseq = pkt->seq; + ds->rcvcnt++; + } + + curpktlatency = dpkt_latency_time(&(pkt->sendTime)); + if (curpktlatency < ds->leastLatency){ + ds->leastLatency = curpktlatency; + } + + if (curpktlatency > ds->maxLatency){ + ds->maxLatency = curpktlatency; + } + + SEND_REPLY: + PRINTF("DATA Received from [%d] with seq[%d] in duration[%ld mus] min duration[%ld mus] pkt drop[%u]\n", + ds->ip.u8[sizeof(ds->ip.u8) - 1], pkt->seq, curpktlatency, ds->leastLatency, (ds->lastseq - ds->rcvcnt)); + +#if SERVER_REPLY + PRINTF("DATA sending reply\n"); + uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr); + //uip_udp_packet_send(server_conn, "Reply", sizeof("Reply")); + uip_udp_packet_send(server_conn, (unsigned char *)pkt, sizeof(dpkt_t)); + uip_create_unspecified(&server_conn->ripaddr); +#endif +} +/*---------------------------------------------------------------------------*/ +static void +print_local_addresses(void) +{ + int i; + uint8_t state; + + PRINTF("Server IPv6 addresses: "); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) { + PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + PRINTF("\n"); + /* hack to make address "final" */ + if (state == ADDR_TENTATIVE) { + uip_ds6_if.addr_list[i].state = ADDR_PREFERRED; + } + } + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_server_process, ev, data) +{ + uip_ipaddr_t ipaddr; + struct uip_ds6_addr *root_if; + + PROCESS_BEGIN(); + + PROCESS_PAUSE(); + + SENSORS_ACTIVATE(button_sensor); + + PRINTF("UDP server started\n"); + +#if UIP_CONF_ROUTER +/* The choice of server address determines its 6LoWPAN header compression. + * Obviously the choice made here must also be selected in udp-client.c. + * + * For correct Wireshark decoding using a sniffer, add the /64 prefix to the + * 6LowPAN protocol preferences, + * e.g. set Context 0 to fd00::. At present Wireshark copies Context/128 and + * then overwrites it. + * (Setting Context 0 to fd00::1111:2222:3333:4444 will report a 16 bit + * compressed address of fd00::1111:22ff:fe33:xxxx) + * Note Wireshark's IPCMV6 checksum verification depends on the correct + * uncompressed addresses. + */ + +#if 0 +/* Mode 1 - 64 bits inline */ + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 1); +#elif 1 +/* Mode 2 - 16 bits inline */ + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0x00ff, 0xfe00, 1); +#else +/* Mode 3 - derived from link local (MAC) address */ + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); +#endif + + uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL); + root_if = uip_ds6_addr_lookup(&ipaddr); + if(root_if != NULL) { + rpl_dag_t *dag; + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr); + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + rpl_set_prefix(dag, &ipaddr, 64); + PRINTF("created a new RPL dag\n"); + } else { + PRINTF("failed to create a new RPL DAG\n"); + } +#endif /* UIP_CONF_ROUTER */ + + print_local_addresses(); + + /* The data sink runs with a 100% duty cycle in order to ensure high + packet reception rates. */ + NETSTACK_RDC.off(1); + + server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL); +if(server_conn == NULL) { + PRINTF("No UDP connection available, exiting the process!\n"); + PROCESS_EXIT(); + } + udp_bind(server_conn, UIP_HTONS(UDP_SERVER_PORT)); + + PRINTF("Created a server connection with remote address "); + PRINT6ADDR(&server_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", UIP_HTONS(server_conn->lport), + UIP_HTONS(server_conn->rport)); + + while(1) { + PROCESS_YIELD(); + + if(ev == tcpip_event) { + tcpip_handler(); + } else if (ev == sensors_event && data == &button_sensor) { + PRINTF("Initiating global repair\n"); + rpl_repair_root(RPL_DEFAULT_INSTANCE); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ + + void start_udp_process() + { + return; + } + /* + uint32_t lastseq; + uint32_t dropcnt; + uint32_t unordered; + uint32_t rcvcnt; + uint32_t dupcnt; + */ + void udp_get_app_stat(udpapp_stat_t *appstat) + { + unsigned int s = 0; + unsigned int r = 0; + unsigned int d = 0; + unsigned int i = 0; + + PRINTF("Stats Called on BR\n"); + dpkt_stat_t *ds; + for(i=0;ircvcnt){ + continue; + } + + s += ds->lastseq; + r += ds->rcvcnt; + d += ds->dupcnt; + } + + appstat->totalpktsent = s; + appstat->totalpktrecvd = r; + appstat->totalduppkt = d; + } diff --git a/examples/containers/simul-13-nodos.csc b/examples/containers/simul-13-nodos.csc new file mode 100644 index 00000000000..bdc908e364c --- /dev/null +++ b/examples/containers/simul-13-nodos.csc @@ -0,0 +1,309 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + My simulation + 123456 + 100000 + + se.sics.cooja.radiomediums.UDGM + 20.0 + 25.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.Z1MoteType + z11 + server + [CONFIG_DIR]/server.z1 + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.MspButton + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + se.sics.cooja.mspmote.interfaces.MspLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + + + se.sics.cooja.mspmote.Z1MoteType + z12 + client + [CONFIG_DIR]/client.z1 + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.MspButton + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + se.sics.cooja.mspmote.interfaces.MspLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + + + + + se.sics.cooja.interfaces.Position + 54.335467383479994 + 4.747565694681829 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + z11 + + + + + se.sics.cooja.interfaces.Position + 63.06567445836441 + 17.713731231936247 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + net~; + + z12 + + + + + false + [CONFIG_DIR]/../../core/net/rpl/rpl-mrhof.c + 168 + printf("Rank: %u, Rank pad: %u, link met: %u\n", new_rank,p->rank, p->link_metric/ RPL_DAG_MC_ETX_DIVISOR); + -16777216 + + + false + [CONFIG_DIR]/../../core/net/rpl/rpl-mrhof.c + 146 + if(p == NULL) { + -16777216 + + + + se.sics.cooja.interfaces.Position + 53.40562284295976 + 19.00518198265879 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 3 + + z12 + + + + + se.sics.cooja.interfaces.Position + 43.43562304738165 + 15.905700180924677 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 4 + + z12 + + + + + se.sics.cooja.interfaces.Position + 42.14417229665909 + 29.595078138583713 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 5 + + z12 + + + + + se.sics.cooja.interfaces.Position + 58.933032056052255 + 31.919689489884306 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 6 + + z12 + + + + + se.sics.cooja.interfaces.Position + 71.37342580791453 + 29.714458961784565 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 7 + + z12 + + + + + se.sics.cooja.interfaces.Position + 41.816206872869124 + 39.25897757622631 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 8 + + + se.sics.cooja.mspmote.interfaces.MspDefaultSerial + net~; + + z12 + + + + + se.sics.cooja.interfaces.Position + 53.82382706523132 + 39.25897757622631 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 9 + + z12 + + + + + se.sics.cooja.interfaces.Position + 63.98412107415318 + 41.106303759666645 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 10 + + z12 + + + + + se.sics.cooja.interfaces.Position + 58.44214252383217 + 46.648282309987664 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 11 + + z12 + + + + + se.sics.cooja.interfaces.Position + 52.59227627627109 + 53.11392395202884 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 12 + + z12 + + + + + se.sics.cooja.interfaces.Position + 68.76097629590274 + 34.65624934371747 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 13 + + z12 + + + + se.sics.cooja.plugins.SimControl + 280 + 0 + 160 + 184 + -15 + + + se.sics.cooja.plugins.Visualizer + + true + se.sics.cooja.plugins.skins.IDVisualizerSkin + 6.503393389095488 0.0 0.0 6.503393389095488 -258.05835444517754 -19.148014625817627 + + 231 + 3 + 400 + 1 + 1 + + + se.sics.cooja.plugins.LogListener + + ID:12 + + + + 658 + 1 + 458 + 236 + 71 + + + se.sics.cooja.plugins.collectview.CollectView + 0 + 233 + 2 + 72 + 585 + 7 + + + diff --git a/examples/containers/udp-app.h b/examples/containers/udp-app.h new file mode 100644 index 00000000000..eb45834fc5b --- /dev/null +++ b/examples/containers/udp-app.h @@ -0,0 +1,17 @@ +#ifndef __UDP_APP_H__ + +#include "contiki.h" +typedef struct _udpapp_stat{ + unsigned int totalpktsent; /*Requests*/ + unsigned int totalpktrecvd; /*Request/response received*/ + unsigned int totalduppkt; /*Duplicate request/response*/ + long minroudtriptime; + long maxroundtriptime; + long minupwardtime; + long maxupwardtime; +}udpapp_stat_t; + +void start_udp_process(); +void udp_get_app_stat(udpapp_stat_t *); + +#endif /*__UDP_APP_H__*/