34 #include "sys/clock.h" 36 #include "net/nbr-table.h" 37 #include "net/link-stats.h" 42 #define PRINTF(...) printf(__VA_ARGS__) 48 #define TX_COUNT_MAX 32 51 #define FRESHNESS_EXPIRATION_TIME (10 * 60 * (clock_time_t)CLOCK_SECOND) 53 #define FRESHNESS_HALF_LIFE (15 * 60 * (clock_time_t)CLOCK_SECOND) 55 #define FRESHNESS_TARGET 4 57 #define FRESHNESS_MAX 16 60 #define EWMA_SCALE 100 62 #define EWMA_BOOTSTRAP_ALPHA 25 65 #define ETX_DIVISOR LINK_STATS_ETX_DIVISOR 67 #define ETX_NOACK_PENALTY 12 72 NBR_TABLE(
struct link_stats, link_stats);
75 struct ctimer periodic_timer;
79 const struct link_stats *
80 link_stats_from_lladdr(
const linkaddr_t *lladdr)
82 return nbr_table_get_from_lladdr(link_stats, lladdr);
87 link_stats_is_fresh(
const struct link_stats *stats)
89 return (stats != NULL)
90 &&
clock_time() - stats->last_tx_time < FRESHNESS_EXPIRATION_TIME
91 && stats->freshness >= FRESHNESS_TARGET;
94 #if LINK_STATS_INIT_ETX_FROM_RSSI 96 guess_etx_from_rssi(
const struct link_stats *stats)
99 if(stats->rssi == 0) {
100 return ETX_DEFAULT * ETX_DIVISOR;
109 #define ETX_INIT_MAX 3 110 #define RSSI_HIGH -60 112 #define RSSI_DIFF (RSSI_HIGH - RSSI_LOW) 114 int16_t bounded_rssi = stats->rssi;
115 bounded_rssi = MIN(bounded_rssi, RSSI_HIGH);
116 bounded_rssi = MAX(bounded_rssi, RSSI_LOW + 1);
117 etx = RSSI_DIFF * ETX_DIVISOR / (bounded_rssi - RSSI_LOW);
118 return MIN(etx, ETX_INIT_MAX * ETX_DIVISOR);
127 link_stats_packet_sent(
const linkaddr_t *lladdr,
int status,
int numtx)
129 struct link_stats *stats;
130 #if !LINK_STATS_ETX_FROM_PACKET_COUNT 140 stats = nbr_table_get_from_lladdr(link_stats, lladdr);
143 stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS, NULL);
145 #if LINK_STATS_INIT_ETX_FROM_RSSI 146 stats->etx = guess_etx_from_rssi(stats);
148 stats->etx = ETX_DEFAULT * ETX_DIVISOR;
157 stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX);
161 numtx += ETX_NOACK_PENALTY;
164 #if LINK_STATS_ETX_FROM_PACKET_COUNT 167 if(stats->tx_count + numtx > TX_COUNT_MAX) {
168 stats->tx_count /= 2;
169 stats->ack_count /= 2;
172 stats->tx_count += numtx;
177 if(stats->ack_count > 0) {
178 stats->etx = ((uint16_t)stats->tx_count * ETX_DIVISOR) / stats->ack_count;
180 stats->etx = (uint16_t)MAX(ETX_NOACK_PENALTY, stats->tx_count) * ETX_DIVISOR;
186 packet_etx = numtx * ETX_DIVISOR;
188 ewma_alpha = link_stats_is_fresh(stats) ? EWMA_ALPHA : EWMA_BOOTSTRAP_ALPHA;
191 stats->etx = ((uint32_t)stats->etx * (EWMA_SCALE - ewma_alpha) +
192 (uint32_t)packet_etx * ewma_alpha) / EWMA_SCALE;
198 link_stats_input_callback(
const linkaddr_t *lladdr)
200 struct link_stats *stats;
201 int16_t packet_rssi = packetbuf_attr(PACKETBUF_ATTR_RSSI);
203 stats = nbr_table_get_from_lladdr(link_stats, lladdr);
206 stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS, NULL);
209 stats->rssi = packet_rssi;
210 #if LINK_STATS_INIT_ETX_FROM_RSSI 211 stats->etx = guess_etx_from_rssi(stats);
213 stats->etx = ETX_DEFAULT * ETX_DIVISOR;
220 stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) +
221 (int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE;
229 struct link_stats *stats;
231 for(stats = nbr_table_head(link_stats); stats != NULL; stats = nbr_table_next(link_stats, stats)) {
232 stats->freshness >>= 1;
238 link_stats_reset(
void)
240 struct link_stats *stats;
241 stats = nbr_table_head(link_stats);
242 while(stats != NULL) {
243 nbr_table_remove(link_stats, stats);
244 stats = nbr_table_next(link_stats, stats);
250 link_stats_init(
void)
252 nbr_table_register(link_stats, NULL);
253 ctimer_set(&periodic_timer, FRESHNESS_HALF_LIFE, periodic, NULL);
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.
The MAC layer transmission was OK.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
clock_time_t clock_time(void)
Get the current clock time.
Header file for the Packet buffer (packetbuf) management
The MAC layer deferred the transmission for a later time.