diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/inc/utils.h b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/inc/utils.h index f900f6aed..9d3de225e 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/inc/utils.h +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/inc/utils.h @@ -42,4 +42,6 @@ extern int net_get_mac(char *iface, char *mac); extern int net_is_bridge(char *iface); extern char* get_max_channel_bw_channel(int channel_freq, const char* htmode); int phy_find_hwmon_helper(char *dir, char *file, char *hwmon); +extern double dBm_to_mwatts(double dBm); +extern double mWatts_to_dBm(double mW); #endif diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/utils.c b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/utils.c index e0018746b..cf459fe16 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/utils.c +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/utils.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause */ #include +#include #include #include #include @@ -693,3 +694,14 @@ bool vif_get_key_for_key_distr(const char *secret, char *key_str) fclose(fp); return err; } + +double dBm_to_mwatts(double dBm) +{ + return (pow(10,(dBm/10))); +} + +double mWatts_to_dBm(double mW) +{ + return (10*log10(mW)); +} + diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/inc/rrm.h b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/inc/rrm.h index cc6da5526..1c8f98293 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/inc/rrm.h +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/inc/rrm.h @@ -48,6 +48,12 @@ typedef struct ds_tree_node_t node; } rrm_vif_state_t; +#define RRM_CHANNEL_INTERVAL 15 + +#define RRM_MAX_NF_SAMPLES 100 +#define RRM_OBSS_HOP_MODE_NON_WIFI 1 +#define RRM_OBSS_HOP_MODE_NON_WIFI_AND_OBSS 2 + typedef struct { // Cached data @@ -59,9 +65,17 @@ typedef struct uint32_t min_load; uint32_t beacon_rate; uint32_t mcast_rate; + int32_t noise_floor_thresh; + uint32_t noise_floor_time; + int32_t non_wifi_thresh; + uint32_t non_wifi_time; + uint32_t obss_hop_mode; // Internal state data - int32_t noise_lwm; + int32_t avg_nf; + int32_t rrm_chan_nf_next_el; + int32_t rrm_chan_nf_num_el; + double rrm_chan_nf_samples[RRM_MAX_NF_SAMPLES]; } rrm_entry_t; typedef struct @@ -80,5 +94,6 @@ void set_rrm_parameters(rrm_entry_t *rrm_data); ds_tree_t* rrm_get_rrm_config_list(void); ds_tree_t* rrm_get_radio_list(void); ds_tree_t* rrm_get_vif_list(void); +void rrm_reset_noise_floor_samples(rrm_entry_t *rrm_data); #endif /* RRM_H_INCLUDED */ diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_channel.c b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_channel.c index 5ad99bc82..c03c91be7 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_channel.c +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_channel.c @@ -9,8 +9,6 @@ #include "uci.h" #include "utils.h" -#define RRM_CHANNEL_INTERVAL 15.0 - struct blob_buf b = { }; struct blob_buf del = { }; struct uci_context *uci; @@ -103,6 +101,57 @@ void get_channel_bandwidth(const char* htmode, int *channel_bandwidth) else if(!strcmp(htmode, "HT80")) *channel_bandwidth=80; } +/* + * A simple average is calculated against the Noise floor samples. + * - Returns a zero, if there are not enough samples in the list. + * - Or, returns a calculated avg of the noise samples. + * - A circular buffer is considered for storing the samples. New elements replace the + * old ones in this buffer. + * - The number of samples required is an integer value calculated based on the + * configuration time and the sample time. + * Example: If the config_time is 120 sec, and sample time is 15 sec, then number of + * samples required for averaging is 120/15 = 8 samples. + */ +int rrm_calculate_avg_noise_floor(rrm_entry_t *rrm_data, int nf, int config_time, int sample_time) +{ + int ii; + double avg_mW = 0; + int num_samples = config_time/sample_time; + + if (num_samples >= RRM_MAX_NF_SAMPLES) + num_samples = RRM_MAX_NF_SAMPLES; + + /* + * Convert dBm to milliWatts, + * and replace the oldest element in the list with the new element + */ + rrm_data->rrm_chan_nf_samples[rrm_data->rrm_chan_nf_next_el] = dBm_to_mwatts(nf); + + /* Update the index to the oldest element index taking care of the boundary */ + rrm_data->rrm_chan_nf_next_el = (rrm_data->rrm_chan_nf_next_el+1)%num_samples; + + if (rrm_data->rrm_chan_nf_num_el < num_samples) + { + rrm_data->rrm_chan_nf_num_el++; + return 0; + } + + /* calculate average */ + for (ii = 0; ii < num_samples; ii++) + { + avg_mW += rrm_data->rrm_chan_nf_samples[ii]; + } + avg_mW = avg_mW/num_samples; + + /* convert the averaged milliWats back to dBm */ + return ((int)(mWatts_to_dBm(avg_mW))); +} + +void rrm_reset_noise_floor_samples(rrm_entry_t *rrm_data) +{ + rrm_data->rrm_chan_nf_next_el = 0; + rrm_data->rrm_chan_nf_num_el = 0; +} void rrm_nf_timer_handler(struct ev_loop *loop, ev_timer *timer, int revents) { @@ -113,7 +162,6 @@ void rrm_nf_timer_handler(struct ev_loop *loop, ev_timer *timer, int revents) rrm_radio_state_t *radio = NULL; uint32_t noise; int32_t nf; - int32_t nf_drop_threshold; rrm_config_t *rrm_config; ds_tree_t *radio_list = rrm_get_radio_list(); @@ -122,14 +170,13 @@ void rrm_nf_timer_handler(struct ev_loop *loop, ev_timer *timer, int revents) { noise = 0; rrm_config = NULL; - nf_drop_threshold = 0; if (ubus_get_noise(radio->config.if_name, &noise)) continue; nf = (int32_t)noise; - if (nf > -1 || nf < -120) + if ((nf > -10) || (nf < -120)) continue; rrm_config = rrm_get_rrm_config(radio->config.type); @@ -137,43 +184,39 @@ void rrm_nf_timer_handler(struct ev_loop *loop, ev_timer *timer, int revents) if (rrm_config == NULL) continue; - if (nf < rrm_config->rrm_data.noise_lwm ) - { - rrm_config->rrm_data.noise_lwm = nf; - LOGD("[%s] noise_lwm set to %d", radio->config.if_name, nf); - continue; - } - - if (rrm_config->rrm_data.snr_percentage_drop == 0) + if ((rrm_config->rrm_data.backup_channel == 0) || + (rrm_config->rrm_data.backup_channel == radio->config.chan)) continue; - if (rrm_config->rrm_data.backup_channel == 0) + if (rrm_config->rrm_data.noise_floor_thresh == 0) continue; - nf_drop_threshold = ((int32_t)(100 - rrm_config->rrm_data.snr_percentage_drop) * - rrm_config->rrm_data.noise_lwm) / 100; + if (rrm_config->rrm_data.noise_floor_time == 0) + continue; - LOGD("[%s] backup=%d nf=%d nf_lwm=%d drop=%d thresh=%d", + LOGD("[%s] backup=%d nf=%d nf_thresh=%d", radio->config.if_name, rrm_config->rrm_data.backup_channel, nf, - rrm_config->rrm_data.noise_lwm, - rrm_config->rrm_data.snr_percentage_drop, - nf_drop_threshold); + rrm_config->rrm_data.noise_floor_thresh); - if (nf > nf_drop_threshold) + rrm_config->rrm_data.avg_nf = rrm_calculate_avg_noise_floor(&(rrm_config->rrm_data), + nf, rrm_config->rrm_data.noise_floor_time, RRM_CHANNEL_INTERVAL); + + if (rrm_config->rrm_data.avg_nf && + (rrm_config->rrm_data.avg_nf > rrm_config->rrm_data.noise_floor_thresh)) { - LOGI("Interference detected on [%s], switching to backup_channel=%d nf=%d nf_lwm=%d drop=%d thresh=%d", + LOGI("Interference detected on [%s]," + " switching to backup_channel=%d avg_nf=%d nfthresh=%d", radio->config.if_name, rrm_config->rrm_data.backup_channel, - nf, - rrm_config->rrm_data.noise_lwm, - rrm_config->rrm_data.snr_percentage_drop, - nf_drop_threshold); + rrm_config->rrm_data.avg_nf, + rrm_config->rrm_data.noise_floor_thresh); int channel_bandwidth; int sec_chan_offset=0; - struct mode_map *m = mode_map_get_uci(radio->schema.freq_band, get_max_channel_bw_channel(ieee80211_channel_to_frequency(rrm_config->rrm_data.backup_channel), - radio->schema.ht_mode), radio->schema.hw_mode); + struct mode_map *m = mode_map_get_uci(radio->schema.freq_band, + get_max_channel_bw_channel(ieee80211_channel_to_frequency(rrm_config->rrm_data.backup_channel), + radio->schema.ht_mode), radio->schema.hw_mode); if (m) { sec_chan_offset = m->sec_channel_offset; } else @@ -183,6 +226,8 @@ void rrm_nf_timer_handler(struct ev_loop *loop, ev_timer *timer, int revents) radio->schema.ht_mode), &channel_bandwidth); ubus_set_channel_switch(radio->config.if_name, ieee80211_channel_to_frequency(rrm_config->rrm_data.backup_channel), channel_bandwidth, sec_chan_offset); + + rrm_reset_noise_floor_samples(&(rrm_config->rrm_data)); } } } diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_ovsdb.c b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_ovsdb.c index 44c71a78f..84defe101 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_ovsdb.c +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/rrm/src/rrm_ovsdb.c @@ -124,6 +124,21 @@ void rrm_config_update(void) rrm_data.min_load = rrm->schema.min_load; rrm_data.beacon_rate = rrm->schema.beacon_rate; rrm_data.mcast_rate = rrm->schema.mcast_rate; + rrm_data.noise_floor_thresh = rrm->schema.noise_floor_thresh; + rrm_data.noise_floor_time = rrm->schema.noise_floor_time; + if (rrm_data.noise_floor_time/RRM_CHANNEL_INTERVAL > RRM_MAX_NF_SAMPLES) + { + LOG(WARN, "RRM Config: Noise floor time too high." + " nf_time:%d, sampling_interval:%d, max_num_samples:%d", + rrm_data.noise_floor_time, RRM_CHANNEL_INTERVAL, + RRM_MAX_NF_SAMPLES); + } + rrm_data.non_wifi_thresh = rrm->schema.non_wifi_thresh; + rrm_data.non_wifi_time = rrm->schema.non_wifi_time; + rrm_data.obss_hop_mode = rrm->schema.obss_hop_mode; + + rrm_data.avg_nf = 0; + rrm_reset_noise_floor_samples(&rrm_data); /* Update cache config */ rrm->rrm_data = rrm_data; @@ -408,13 +423,7 @@ void rrm_update_rrm_config_cb(ovsdb_update_monitor_t *self) return; } /* Reset configuration */ - rrm_config->schema.backup_channel = 0; - rrm_config->schema.min_load = 0; - rrm_config->schema.beacon_rate = 0; - rrm_config->schema.mcast_rate = 0; - rrm_config->schema.snr_percentage_drop = 0; - rrm_config->schema.client_disconnect_threshold = 0; - rrm_config->schema.probe_resp_threshold = 0; + memset(&(rrm_config->schema), 0, sizeof(rrm_config->schema)); ds_tree_remove(&rrm_config_list, rrm_config); free(rrm_config);