diff --git a/src/acs.c b/src/acs.c index 4a97a8ab8f5e5d18c62871286410547e01d54f43..3a313bcc38d7836ffa2864aecf9e85fd970d0475 100644 --- a/src/acs.c +++ b/src/acs.c @@ -21,6 +21,7 @@ #include "utils/utils.h" #include "wifi_dataelements.h" #include "wifi_opclass.h" +#include "timer.h" #include "sta.h" @@ -701,7 +702,6 @@ void cntlr_dfs_radio_cleanup(struct node *node, struct netif_radio *radio) if (!cntlr_dfs_get_cac_data(radio->radio_el, &cac_data, 20)) { cntlr_dbg(LOG_CHANNEL, "dfs radio preCAC cleanup no channels left\n"); radio->radio_el->last_cac_data.status = WIFI_ACS_CLEANUP_STATUS_ALL_CLEAN; - radio->radio_el->last_acs.recalc = true; return; } } @@ -929,3 +929,85 @@ void cntlr_acs_channel_pref_report(struct node *n, struct netif_radio *r) cntlr_acs_node_channel_recalc(n, BAND_ANY, 0, 0, skip_dfs, prevent_cac, false); } } + +static uint8_t ewma(uint8_t cur, uint8_t prev, uint8_t alpha) +{ + uint8_t new; + + if (alpha > 100) + alpha = 100; + + new = (alpha * cur)/100 + ((100 - alpha) * prev) / 100; + + return new; +} + +static bool cntlr_acs_radio_add_and_check_metrics(struct netif_radio *r, uint8_t anpi, uint8_t obss) +{ + struct wifi_radio_metrics *m = &r->radio_el->metrics; + struct wifi_radio_metrics_entry *last, *next; + + timestamp_update(&m->time); + m->anpi = ewma(anpi, m->anpi, 60); + m->obss = ewma(obss, m->obss, 60); + + last = &m->entry[m->idx]; + + cntlr_trace(LOG_CHANNEL, "radio ewma metrics " MACFMT " anpi %u obss %u\n", + MAC2STR(r->radio_el->macaddr), m->anpi, m->obss); + + /* Update ring buffer */ + if (timestamp_invalid(&last->time)) { + timestamp_update(&last->time); + last->anpi = m->anpi; + last->obss = m->obss; + } + + /* Save/check data each 300 seconds */ + if (timestamp_elapsed_sec(&last->time) >= 300) { + m->idx++; + m->idx %= ARRAY_SIZE(m->entry); + + next = &m->entry[m->idx]; + + timestamp_update(&next->time); + next->anpi = m->anpi; + next->obss = m->obss; + + cntlr_dbg(LOG_CHANNEL, "metrics[%u] radio " MACFMT " anpi %u (%d) obss %u (%d)\n", + m->idx, MAC2STR(r->radio_el->macaddr), next->anpi, + next->anpi - last->anpi, next->obss, next->obss - last->obss); + + /* If other BSS busy increase - worth to check it - 100% = 255 */ + if (next->obss - last->obss > 30) + return true; + + /* If noise level worst - worth to check it - in 0.5 dBm */ + if (next->anpi - last->anpi > 20) + return true; + } + + return false; +} + +void cntlr_acs_radio_metrics(struct node *n, struct netif_radio *r, + uint8_t anpi, uint8_t obss) +{ + struct wifi_acs_params *acs = &r->radio_el->last_acs; + + cntlr_trace(LOG_CHANNEL, "new radio metrics node " MACFMT " radio " MACFMT " anpi %u busy %u\n", + MAC2STR(n->almacaddr), MAC2STR(r->radio_el->macaddr), anpi, obss); + + if (!n->cntlr->cfg.acs_timeout) + return; + + /* Store data for future use/compare */ + if (!cntlr_acs_radio_add_and_check_metrics(r, anpi, obss)) + return; + + /* Smth changed in current channel noise/busy */ + cntlr_dbg(LOG_CHANNEL, "issue ACS recalc due to metrics " MACFMT " radio " MACFMT "\n", + MAC2STR(n->almacaddr), MAC2STR(r->radio_el->macaddr)); + + acs->recalc = true; +} diff --git a/src/acs.h b/src/acs.h index fc264c1bb66512e8709e783b02fd68104b958309..1fb9e781ec99a4e92e42a6d96e0aec249d45d777 100644 --- a/src/acs.h +++ b/src/acs.h @@ -48,4 +48,6 @@ void cntlr_acs_oper_channel_report(struct netif_radio *r); void cntlr_acs_cac_completion(struct netif_radio *r, uint8_t classid, uint8_t channel, uint8_t status); void cntlr_acs_channel_pref_report(struct node *n, struct netif_radio *r); +void cntlr_acs_radio_metrics(struct node *n, struct netif_radio *r, + uint8_t anpi, uint8_t obss); #endif diff --git a/src/cntlr_map.c b/src/cntlr_map.c index 24cbbac3fe6c8700c688068a76c8118d7bbc5e6e..76f61ec61d8cecf90b7bce472b92847be904fba8 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -1853,6 +1853,10 @@ int handle_channel_pref_report(void *cntlr, struct cmdu_buff *cmdu, struct node } cntlr_radio_pref_opclass_dump(r->radio_el); + + /* Kick ACS code - for 5GHz we will send from CAC status */ + if (r->radio_el->band != BAND_5) + cntlr_acs_channel_pref_report(n, r); } idx = 0; @@ -2270,6 +2274,9 @@ int handle_ap_metrics_response(void *cntlr, struct cmdu_buff *cmdu, struct node radio = cntlr_find_radio(c, p->radio); if (radio) { + /* Kick ACS code */ + cntlr_acs_radio_metrics(n, radio, p->noise, p->receive_other); + radio->radio_el->anpi = p->noise; radio->radio_el->tx_utilization = p->transmit; radio->radio_el->rx_utilization = p->receive_self; diff --git a/src/wifi_dataelements.h b/src/wifi_dataelements.h index d07588d9f39185fea1d05e894f4beb1b3c82bbba..4a1381f3d2fce345780599a6b8c5f6990ef1c045 100644 --- a/src/wifi_dataelements.h +++ b/src/wifi_dataelements.h @@ -138,6 +138,24 @@ struct wifi_cac_data { uint32_t cac_time; }; +struct wifi_radio_metrics_entry { + struct timespec time; + + uint8_t anpi; + uint8_t obss; +}; + +struct wifi_radio_metrics { + struct timespec time; + + uint8_t anpi; /* EWMA value */ + uint8_t obss; /* EWMA value */ + + /* Ring buffer for more data */ + uint8_t idx; + struct wifi_radio_metrics_entry entry[16]; +}; + struct wifi_sta_meas_report { struct list_head list; @@ -699,6 +717,9 @@ struct wifi_radio_element { uint8_t tx_utilization; uint8_t rx_utilization; uint8_t other_utilization; + + struct wifi_radio_metrics metrics; + uint8_t tx_streams; uint8_t rx_streams; char country_code[4];