WiFi-1827. Updates for RRM Channel Hop based on Noise Floor threshold

Average Noise Floor is calcluated for the last few samples based on the
configured Noise Floor time. This calculated avg Noise Floor is compared
against the configured Noise Floor threshold to decide if a Channel hop
is required. While calculating the average, each noise sample is first
converted from dBm to milliWatts, an avaerage of the all the noise
samples in milliWatt is calculated, then the average is converted back
to dBm.

Signed-off-by: ravi vaishnav <ravi.vaishnav@netexperience.com>
This commit is contained in:
ravi vaishnav
2021-04-28 14:53:34 -04:00
committed by Rick Sommerville
parent 3881ec638b
commit 7569b618ff
5 changed files with 119 additions and 36 deletions

View File

@@ -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

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#include <string.h>
#include <math.h>
#include <glob.h>
#include <libgen.h>
#include <fcntl.h>
@@ -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));
}

View File

@@ -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 */

View File

@@ -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));
}
}
}

View File

@@ -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);