Skip to content

Commit

Permalink
STA scan and connection rewrite
Browse files Browse the repository at this point in the history
Implement our own AP selection algorithm, do not rely on SDK.
The algorithm tries to connect to AP with best signal but doesn't get
stuck on one (or a subset) of them. If there is an AP that can be
connected to, it should eventually be found.

Also implement roaming: if device is connected to an AP with RSII less
than wifi.sta_roam_rssi_thr, it will periodically
(wifi.sta_roam_interval) scan for a better AP and try to reconnect.
AP must be at least 5 dbm better than the one we are connected to.
Roaming is not seamless, i.e. connection is lost during attempt.
Scanning also introduces blips, so if connection stability is more
important, roaming should not be used.
  • Loading branch information
rojer committed May 22, 2021
1 parent a981536 commit ee72310
Show file tree
Hide file tree
Showing 9 changed files with 772 additions and 262 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ which contains configuration settings for the Access Point mode, and

#### Multiple Station Configurations

Station configurations will be tried starting from `sta_cfg_idx` and each one that is enabled will be given `sta_connect_timeout` seconds to connect. Successfully connected station's index will be saved in `sta_cfg_idx` so next boot will start with previously used configuration.

Setting `sta_connect_timeout` to 0 disables this logic.
Up to 3 different station configurations are allowed and those that are enabled will be considered for connection.

### Access Point configuration

Expand Down
9 changes: 3 additions & 6 deletions include/mgos_wifi_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@
* HAL wifi interface, to be implemented by ports.
*/

#ifndef CS_MOS_LIBS_WIFI_SRC_MGOS_WIFI_HAL_H_
#define CS_MOS_LIBS_WIFI_SRC_MGOS_WIFI_HAL_H_
#pragma once

#include "mgos_net.h"
#include "mgos_wifi.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif

bool mgos_wifi_dev_ap_setup(const struct mgos_config_wifi_ap *cfg);

Expand Down Expand Up @@ -66,6 +65,4 @@ void mgos_wifi_dev_deinit(void);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* CS_MOS_LIBS_WIFI_SRC_MGOS_WIFI_HAL_H_ */
#endif
32 changes: 32 additions & 0 deletions include/mgos_wifi_sta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) Mongoose OS Contributors
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include "mgos_sys_config.h"

#ifdef __cplusplus
extern "C" {
#endif

bool mgos_wifi_sta_add_cfg(const struct mgos_config_wifi_sta *cfg);
void mgos_wifi_sta_clear_cfgs(void);
void mgos_wifi_sta_init(void);

#ifdef __cplusplus
}
#endif
13 changes: 5 additions & 8 deletions mos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ config_schema:
- ["wifi.sta.enable", "b", {title: "Connect to existing WiFi"}]
- ["wifi.sta.ssid", "s", {title: "SSID"}]
- ["wifi.sta.pass", "s", {title: "Password", type: "password"}]
- ["wifi.sta.bssid", "s", {title: "Specific AP to connect to"}]
- ["wifi.sta.user", "s", {title: "Username for WPA-PEAP mode"}]
- ["wifi.sta.anon_identity", "s", {title: "Anonymous identity for WPA mode"}]
- ["wifi.sta.cert", "s", {title: "Client certificate for WPA-TTLS mode"}]
Expand All @@ -49,12 +50,10 @@ config_schema:
- ["wifi.sta1.enable", false]
- ["wifi.sta2", "wifi.sta", {title: "WiFi Station Config 2"}]
- ["wifi.sta2.enable", false]
# Station configurations will be tried starting from sta_cfg_idx and each one that is enabled
# will be given sta_connect_timeout seconds to connect. Successfully connected station's index
# will be saved in sta_cfg_idx so next boot will start with previously used configuration.
# Setting sta_connect_timeout to 0 will disable this logic.
- ["wifi.sta_cfg_idx", "i", 0, {title: "WiFi station config index to use, 0, 1 or 2"}]
- ["wifi.sta_connect_timeout", "i", 30, {title: "Timeout for connection, seconds"}]
- ["wifi.sta_rssi_thr", "i", -95, {title: "Do not consider APs with weaker signal"}]
- ["wifi.sta_connect_timeout", "i", 15, {title: "Timeout for connection, seconds"}]
- ["wifi.sta_roam_rssi_thr", "i", -80, {title: "If connected to AP with weaker signal, try to find a better one."}]
- ["wifi.sta_roam_interval", "i", 900, {title: "Scan for better APs at this interval. Set to 0 to disable."}]

build_vars:
MGOS_WIFI_ENABLE_AP_STA: 0
Expand Down Expand Up @@ -84,7 +83,6 @@ conds:
- origin: https://github.com/mongoose-os-libs/lwip
config_schema:
- ["wifi.ap.keep_enabled", "b", true, {title: "Keep AP enabled when station is on"}]
- ["wifi.sta_all_chan_scan", "b", true, {title: "true to scan all channels or false to perform fast scan"}]
# min/max values are from enum RATE_11{B,G,N}_ID in the SDK, see user_interface.h for declarations.
- ["wifi.tx_rate_limit_11b", "i", -1, {title: "TX rate limit for 11B mode, ((max << 8) | min)"}]
- ["wifi.tx_rate_limit_11g", "i", -1, {title: "TX rate limit for 11G mode, ((max << 8) | min)"}]
Expand All @@ -99,7 +97,6 @@ conds:
- ["wifi.ap.bandwidth_20mhz", "b", false, {title: "enable 20MHz bandwidth AP operation"}]
- ["wifi.ap.protocol", "s", "BGN", {title: "802.11 Wi-Fi Protocol for AP Mode, defaults to BGN, can be any combination of BGNLR. Note LR only works between 2 ESP32 devices."}]
- ["wifi.sta_ps_mode", "i", 0, {title: "Power save mode for station: 0 - none, 1 - min, 2 - max."}]
- ["wifi.sta_all_chan_scan", "b", true, {title: "true to scan all channels or false to perform fast scan"}]
- ["wifi.sta.protocol", "s", "BGN", {title: "802.11 Wi-Fi Protocol for STA Mode, defaults to BGN, can be any combination of BGNLR. Note LR only works between 2 ESP32 devices."}]
- ["wifi.sta.listen_interval_ms", "i", 0, {title: "DTIM Listen Interval (ms)"}]
cdefs:
Expand Down
4 changes: 4 additions & 0 deletions src/cc32xx/cc32xx_wifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ static bool ensure_role_sta(void) {
if (s_current_role == ROLE_STA) return true;
if (!restart_nwp(ROLE_STA)) return false;
_u32 scan_interval = WIFI_SCAN_INTERVAL_SECONDS;
/* Setting scan policy also initiates scan. */
sl_WlanPolicySet(SL_WLAN_POLICY_SCAN, 1 /* enable */, (_u8 *) &scan_interval,
sizeof(scan_interval));
return true;
Expand Down Expand Up @@ -620,6 +621,9 @@ bool mgos_wifi_dev_start_scan(void) {

if (!ensure_role_sta()) goto out;

/* TODO: Set scan policy to initate scan, right now we are getting
* results from a previous scan. */

for (i = 0; (n = sl_WlanGetNetworkList(i, 2, info)) > 0; i += 2) {
res = (struct mgos_wifi_scan_result *) realloc(
res, (num_res + n) * sizeof(*res));
Expand Down
38 changes: 19 additions & 19 deletions src/esp32/esp32_wifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,7 @@ static esp_err_t wifi_sta_set_host_name(
bool mgos_wifi_dev_sta_setup(const struct mgos_config_wifi_sta *cfg) {
bool result = false;
esp_err_t r;
wifi_config_t wcfg;
memset(&wcfg, 0, sizeof(wcfg));
wifi_config_t wcfg = {0};
wifi_sta_config_t *stacfg = &wcfg.sta;

s_user_sta_enabled = cfg->enable;
Expand All @@ -321,10 +320,21 @@ bool mgos_wifi_dev_sta_setup(const struct mgos_config_wifi_sta *cfg) {
/* In case already connected, disconnect. */
esp_wifi_disconnect();

stacfg->scan_method =
(wifi_scan_method_t) mgos_sys_config_get_wifi_sta_all_chan_scan();

strncpy((char *) stacfg->ssid, cfg->ssid, sizeof(stacfg->ssid));

if (!mgos_conf_str_empty(cfg->bssid)) {
unsigned int bssid[6] = {0};
if (sscanf(cfg->bssid, "%02x:%02x:%02x:%02x:%02x:%02x", &bssid[0],
&bssid[1], &bssid[2], &bssid[3], &bssid[4], &bssid[5]) != 6) {
LOG(LL_ERROR, ("Invalid BSSID!"));
return false;
}
for (int i = 0; i < 6; i++) {
stacfg->bssid[i] = bssid[i];
}
stacfg->bssid_set = true;
}

if (mgos_conf_str_empty(cfg->user) /* Not using EAP */ &&
!mgos_conf_str_empty(cfg->pass)) {
strncpy((char *) stacfg->password, cfg->pass, sizeof(stacfg->password));
Expand Down Expand Up @@ -618,23 +628,13 @@ int mgos_wifi_sta_get_rssi(void) {
}

bool mgos_wifi_dev_start_scan(void) {
esp_err_t r = ESP_OK;
wifi_mode_t cur_mode = esp32_wifi_get_mode();
if (cur_mode != WIFI_MODE_STA && cur_mode != WIFI_MODE_APSTA) {
r = esp32_wifi_add_mode(WIFI_MODE_STA);
if (r == ESP_OK) r = esp32_wifi_ensure_start();
}
esp_err_t r = esp32_wifi_add_mode(WIFI_MODE_STA);
if (r == ESP_OK) r = esp32_wifi_ensure_start();
if (r == ESP_OK) {
wifi_scan_config_t scan_cfg = {
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time =
{
.active =
{
.min = 150,
.max = 200,
},
},
.scan_time.active.min = 100,
.scan_time.active.max = 150,
};
if (s_connecting) {
esp_wifi_disconnect();
Expand Down
50 changes: 31 additions & 19 deletions src/esp8266/esp_wifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,7 @@ static void esp_wifi_set_rate_limits(const struct mgos_config_wifi *cfg) {
}

bool mgos_wifi_dev_sta_setup(const struct mgos_config_wifi_sta *cfg) {
struct station_config sta_cfg = {
#if ESP_SDK_VERSION_MAJOR >= 3
.all_channel_scan = mgos_sys_config_get_wifi_sta_all_chan_scan(),
#else
0
#endif
};
struct station_config sta_cfg = {0};

if (!cfg->enable) {
return mgos_wifi_remove_mode(STATION_MODE);
Expand All @@ -254,7 +248,18 @@ bool mgos_wifi_dev_sta_setup(const struct mgos_config_wifi_sta *cfg) {

if (!mgos_wifi_add_mode(STATION_MODE)) return false;

sta_cfg.bssid_set = 0;
if (cfg->bssid != NULL) {
unsigned int bssid[6] = {0};
if (sscanf(cfg->bssid, "%02x:%02x:%02x:%02x:%02x:%02x", &bssid[0],
&bssid[1], &bssid[2], &bssid[3], &bssid[4], &bssid[5]) != 6) {
LOG(LL_ERROR, ("Invalid BSSID!"));
return false;
}
for (int i = 0; i < 6; i++) {
sta_cfg.bssid[i] = bssid[i];
}
sta_cfg.bssid_set = true;
}
strncpy((char *) sta_cfg.ssid, cfg->ssid, sizeof(sta_cfg.ssid));

if (!mgos_conf_str_empty(cfg->ip) && !mgos_conf_str_empty(cfg->netmask)) {
Expand Down Expand Up @@ -470,19 +475,23 @@ void wifi_scan_done(void *arg, STATUS status) {
mgos_wifi_dev_scan_cb(-1, NULL);
return;
}
STAILQ_HEAD(, bss_info) *info = arg;
struct mgos_wifi_scan_result *res = NULL;
struct bss_info *p;
int n = 0;
STAILQ_FOREACH(p, info, next) n++;
res = calloc(n, sizeof(*res));
if (n > 0 && res == NULL) {
struct bss_info *info = (struct bss_info *) arg;
for (struct bss_info *p = info; p != NULL; p = p->next.stqe_next) {
n++;
}
if (n == 0) {
mgos_wifi_dev_scan_cb(0, NULL);
return;
}
struct mgos_wifi_scan_result *res = calloc(n, sizeof(*res));
if (res == NULL) {
LOG(LL_ERROR, ("Out of memory"));
mgos_wifi_dev_scan_cb(-1, NULL);
return;
}
struct mgos_wifi_scan_result *r = res;
STAILQ_FOREACH(p, info, next) {
for (struct bss_info *p = info; p != NULL; p = p->next.stqe_next) {
strncpy(r->ssid, (const char *) p->ssid, sizeof(r->ssid));
memcpy(r->bssid, p->bssid, sizeof(r->bssid));
r->ssid[sizeof(r->ssid) - 1] = '\0';
Expand Down Expand Up @@ -514,10 +523,13 @@ void wifi_scan_done(void *arg, STATUS status) {

bool mgos_wifi_dev_start_scan(void) {
/* Scanning requires station. If in AP-only mode, switch to AP+STA. */
if (wifi_get_opmode() == SOFTAP_MODE) {
wifi_set_opmode_current(STATIONAP_MODE);
}
return wifi_station_scan(NULL, wifi_scan_done);
if (!mgos_wifi_add_mode(STATION_MODE)) return false;
struct scan_config cfg = {
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 100,
.scan_time.active.max = 150,
};
return wifi_station_scan(&cfg, wifi_scan_done);
}

void mgos_wifi_dev_init(void) {
Expand Down
Loading

0 comments on commit ee72310

Please sign in to comment.