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 FRESHNESS_HALF_LIFE 20
50 #define FRESHNESS_TARGET 4
52 #define FRESHNESS_MAX 16
54 #define FRESHNESS_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
57 #define EWMA_SCALE 100
59 #define EWMA_BOOTSTRAP_ALPHA 30
62 #define ETX_DIVISOR LINK_STATS_ETX_DIVISOR
64 #define ETX_NOACK_PENALTY 10
69 NBR_TABLE(
struct link_stats, link_stats);
72 struct ctimer periodic_timer;
78 #ifdef LINK_STATS_CONF_INIT_ETX
79 #define LINK_STATS_INIT_ETX(stats) LINK_STATS_CONF_INIT_ETX(stats)
81 #define LINK_STATS_INIT_ETX(stats) (ETX_INIT * ETX_DIVISOR)
86 const struct link_stats *
87 link_stats_from_lladdr(
const linkaddr_t *lladdr)
89 return nbr_table_get_from_lladdr(link_stats, lladdr);
94 link_stats_is_fresh(
const struct link_stats *stats)
96 return (stats !=
NULL)
97 &&
clock_time() - stats->last_tx_time < FRESHNESS_EXPIRATION_TIME
98 && stats->freshness >= FRESHNESS_TARGET;
102 guess_etx_from_rssi(
const struct link_stats *stats)
105 if(stats->rssi == 0) {
106 return ETX_INIT * ETX_DIVISOR;
115 #define ETX_INIT_MAX 3
116 #define RSSI_HIGH -60
118 #define RSSI_DIFF (RSSI_HIGH - RSSI_LOW)
120 int16_t bounded_rssi = stats->rssi;
121 bounded_rssi = MIN(bounded_rssi, RSSI_HIGH);
122 bounded_rssi = MAX(bounded_rssi, RSSI_LOW + 1);
123 etx = RSSI_DIFF * ETX_DIVISOR / (bounded_rssi - RSSI_LOW);
124 return MIN(etx, ETX_INIT_MAX * ETX_DIVISOR);
132 link_stats_packet_sent(
const linkaddr_t *lladdr,
int status,
int numtx)
134 struct link_stats *stats;
143 stats = nbr_table_get_from_lladdr(link_stats, lladdr);
146 stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS,
NULL);
148 stats->etx = LINK_STATS_INIT_ETX(stats);
156 stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX);
159 packet_etx = ((status ==
MAC_TX_NOACK) ? ETX_NOACK_PENALTY : numtx) * ETX_DIVISOR;
161 ewma_alpha = link_stats_is_fresh(stats) ? EWMA_ALPHA : EWMA_BOOTSTRAP_ALPHA;
164 stats->etx = ((uint32_t)stats->etx * (EWMA_SCALE - ewma_alpha) +
165 (uint32_t)packet_etx * ewma_alpha) / EWMA_SCALE;
170 link_stats_input_callback(
const linkaddr_t *lladdr)
172 struct link_stats *stats;
173 int16_t packet_rssi = packetbuf_attr(PACKETBUF_ATTR_RSSI);
175 stats = nbr_table_get_from_lladdr(link_stats, lladdr);
178 stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS,
NULL);
181 stats->rssi = packet_rssi;
182 stats->etx = LINK_STATS_INIT_ETX(stats);
188 stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) +
189 (int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE;
197 struct link_stats *stats;
199 for(stats = nbr_table_head(link_stats); stats !=
NULL; stats = nbr_table_next(link_stats, stats)) {
200 stats->freshness >>= 1;
206 link_stats_init(
void)
208 nbr_table_register(link_stats,
NULL);
The MAC layer deferred the transmission for a later time.
CCIF clock_time_t clock_time(void)
Get the current clock time.
Header file for the Rime buffer (packetbuf) management
The MAC layer transmission was OK.
#define NULL
The null pointer.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void ctimer_reset(struct ctimer *c)
Reset a callback timer with the same interval as was previously set.