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 = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * RPL_MIN_HOPRANKINC; } else { /* multiply first, then scale down to avoid truncation effects */ rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric * p->dag->instance->min_hoprankinc); 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_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 = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * DEFAULT_MIN_HOPRANKINC; } else { rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric) * p->dag->min_hoprankinc; 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 void update_metric(const rimeaddr_t *dest, int packet_metric) { link_metric_t *metricp; link_metric_t recorded_metric, new_metric; unsigned long time; int first_update = 0; metricp = (link_metric_t *)neighbor_attr_get_data(&attr_etx, dest); packet_metric = NEIGHBOR_INFO_ETX2FIX(packet_metric); if(metricp == NULL || *metricp == 0) { recorded_metric = packet_metric; new_metric = ((uint16_t)recorded_metric * 5 + (uint16_t)packet_metric * (ETX_SCALE - 5)) / ETX_SCALE; first_update = 1; } else { recorded_metric = *metricp; /* Update the EWMA of the ETX for the neighbor. */ if(packet_metric != NEIGHBOR_INFO_ETX2FIX(ETX_NOACK_PENALTY)) { new_metric = ((uint16_t)recorded_metric * ETX_ALPHA + (uint16_t)packet_metric * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE; } else { new_metric = ((uint16_t)recorded_metric * 5 + (uint16_t)packet_metric * 5) / ETX_SCALE; } } printf("neighbor-info: ETX of %u changed from %d to %d (packet ETX = %d)\n", node_id_from_rimeaddr(dest), NEIGHBOR_INFO_FIX2ETX(recorded_metric), NEIGHBOR_INFO_FIX2ETX(new_metric), NEIGHBOR_INFO_FIX2ETX(packet_metric) ); if(neighbor_attr_has_neighbor(dest)) { time = clock_seconds(); neighbor_attr_set_data(&attr_etx, dest, &new_metric); neighbor_attr_set_data(&attr_timestamp, dest, &time); if(/*(first_update || new_metric != recorded_metric) &&*/ subscriber_callback != NULL) { subscriber_callback(dest, 1, new_metric); } } }
/*---------------------------------------------------------------------------*/ static void update_metric(const rimeaddr_t *dest, int packet_metric) { static link_metric_t *metricp; static link_metric_t recorded_metric; static link_metric_t new_metric; unsigned long time; int first_update = 0; metricp = (link_metric_t *)neighbor_attr_get_data(&attr_etx, dest); packet_metric = NEIGHBOR_INFO_ETX2FIX(packet_metric); if(metricp == NULL || *metricp == 0) { recorded_metric = NEIGHBOR_INFO_ETX2FIX(ETX_LIMIT); new_metric = packet_metric; first_update = 1; } else { recorded_metric = *metricp; /* Update the EWMA of the ETX for the neighbor. */ new_metric = ((uint16_t)recorded_metric * ETX_ALPHA + (uint16_t)packet_metric * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE; } PRINTF("neighbor-info: ETX changed from %d to %d (packet ETX = %d) %d\n", NEIGHBOR_INFO_FIX2ETX(recorded_metric), NEIGHBOR_INFO_FIX2ETX(new_metric), NEIGHBOR_INFO_FIX2ETX(packet_metric), dest->u8[7]); if(neighbor_attr_has_neighbor(dest)) { time = clock_seconds(); neighbor_attr_set_data(&attr_etx, dest, &new_metric); neighbor_attr_set_data(&attr_timestamp, dest, &time); if((first_update || new_metric != recorded_metric) && subscriber_callback != NULL) { subscriber_callback(dest, 1, new_metric); } } }
static void rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx) { uip_ipaddr_t ipaddr; rpl_dag_t *dag; rpl_parent_t *parent; uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr); PRINTF("RPL: Neighbor "); PRINT6ADDR(&ipaddr); PRINTF(" is %sknown. ETX = %u\n", known ? "" : "no longer ", NEIGHBOR_INFO_FIX2ETX(etx)); dag = rpl_get_dag(RPL_DEFAULT_INSTANCE); if(dag == NULL) { return; } parent = rpl_find_parent(dag, &ipaddr); if(parent == NULL) { if(!known) { PRINTF("RPL: Deleting routes installed by DAOs received from "); PRINT6ADDR(&ipaddr); PRINTF("\n"); uip_ds6_route_rm_by_nexthop(&ipaddr); } return; } /* Trigger DAG rank recalculation. */ parent->updated = 1; parent->link_metric = etx; if(dag->of->parent_state_callback != NULL) { dag->of->parent_state_callback(parent, known, etx); } if(!known) { PRINTF("RPL: Removing parent "); PRINT6ADDR(&parent->addr); PRINTF(" because of bad connectivity (ETX %d)\n", etx); parent->rank = INFINITE_RANK; } }