UtilitechAS.amsreader-firmware/lib/ConnectionHandler/src/WiFiClientConnectionHandler.cpp
Gunnar Skjold 766849d6fc Adjustment
2024-03-26 13:39:29 +01:00

390 lines
12 KiB
C++

/**
* @copyright Utilitech AS 2023
* License: Fair Source
*
*/
#include "WiFiClientConnectionHandler.h"
#if defined(ESP32)
#include <esp_wifi.h>
#include <lwip/dns.h>
#endif
WiFiClientConnectionHandler::WiFiClientConnectionHandler(RemoteDebug* debugger) {
this->debugger = debugger;
this->mode = NETWORK_MODE_WIFI_CLIENT;
}
bool WiFiClientConnectionHandler::connect(NetworkConfig config, SystemConfig sys) {
if(lastRetry > 0 && (millis() - lastRetry) < timeout) {
delay(50);
return false;
}
lastRetry = millis();
if (WiFi.status() != WL_CONNECTED) {
if(config.mode != this->mode || strlen(config.ssid) == 0) {
return false;
}
if(WiFi.getMode() != WIFI_OFF) {
if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Not connected to WiFi, closing resources\n"));
disconnect(RECONNECT_TIMEOUT);
return false;
}
timeout = CONNECTION_TIMEOUT;
if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Connecting to WiFi network: %s\n"), config.ssid);
switch(sys.boardType) {
case 2: // spenceme
case 3: // Pow-K UART0
case 4: // Pow-U UART0
case 5: // Pow-K+
case 6: // Pow-P1
case 7: // Pow-U+
case 8: // dbeinder: HAN mosquito
busPowered = true;
break;
default:
busPowered = false;
}
firstConnect = sys.dataCollectionConsent == 0;
#if defined(ESP32)
if(strlen(config.hostname) > 0) {
WiFi.setHostname(config.hostname);
}
#endif
WiFi.mode(WIFI_STA);
if(strlen(config.ip) > 0) {
IPAddress ip, gw, sn(255,255,255,0), dns1, dns2;
ip.fromString(config.ip);
gw.fromString(config.gateway);
sn.fromString(config.subnet);
if(strlen(config.dns1) > 0) {
dns1.fromString(config.dns1);
} else if(strlen(config.gateway) > 0) {
dns1.fromString(config.gateway); // If no DNS, set gateway by default
}
if(strlen(config.dns2) > 0) {
dns2.fromString(config.dns2);
} else if(dns1.toString().isEmpty()) {
dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured
}
if(!WiFi.config(ip, gw, sn, dns1, dns2)) {
debugger->printf_P(PSTR("Static IP configuration is invalid, not using\n"));
}
}
#if defined(ESP8266)
if(strlen(config.hostname) > 0) {
WiFi.hostname(config.hostname);
}
//wifi_set_phy_mode(PHY_MODE_11N);
if(!config.use11b) {
wifi_set_user_sup_rate(RATE_11G6M, RATE_11G54M);
wifi_set_user_rate_limit(RC_LIMIT_11G, 0x00, RATE_11G_G54M, RATE_11G_G6M);
wifi_set_user_rate_limit(RC_LIMIT_11N, 0x00, RATE_11N_MCS7S, RATE_11N_MCS0);
wifi_set_user_limit_rate_mask(LIMIT_RATE_MASK_ALL);
}
#endif
WiFi.setAutoReconnect(true);
#if defined(ESP32)
if(begin(config.ssid, config.psk)) {
#else
if(WiFi.begin(config.ssid, config.psk)) {
#endif
if(config.sleep <= 2) {
switch(config.sleep) {
case 0:
WiFi.setSleep(WIFI_PS_NONE);
break;
case 1:
WiFi.setSleep(WIFI_PS_MIN_MODEM);
break;
case 2:
WiFi.setSleep(WIFI_PS_MAX_MODEM);
break;
}
}
yield();
} else {
if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Unable to start WiFi\n"));
}
this->config = config;
return true;
}
return false;
}
#if defined(ESP32)
wl_status_t WiFiClientConnectionHandler::begin(const char* ssid, const char* passphrase) {
if(!WiFi.enableSTA(true)) {
log_e("STA enable failed!");
return WL_CONNECT_FAILED;
}
if(!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
log_e("SSID too long or missing!");
return WL_CONNECT_FAILED;
}
if(passphrase && strlen(passphrase) > 64) {
log_e("passphrase too long!");
return WL_CONNECT_FAILED;
}
wifi_config_t conf;
memset(&conf, 0, sizeof(wifi_config_t));
wifi_sta_config(&conf, ssid, passphrase, NULL, 0, WIFI_AUTH_WPA2_PSK, WIFI_ALL_CHANNEL_SCAN, WIFI_CONNECT_AP_BY_SIGNAL);
wifi_config_t current_conf;
if(esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf) != ESP_OK){
log_e("get current config failed!");
return WL_CONNECT_FAILED;
}
if(memcmp(&current_conf, &conf, sizeof(wifi_config_t)) == 0) {
if(esp_wifi_disconnect()){
log_e("disconnect failed!");
return WL_CONNECT_FAILED;
}
if(esp_wifi_set_config((wifi_interface_t)ESP_IF_WIFI_STA, &conf) != ESP_OK){
log_e("set config failed!");
return WL_CONNECT_FAILED;
}
} else if(WiFi.status() == WL_CONNECTED){
return WL_CONNECTED;
} else {
if(esp_wifi_set_config((wifi_interface_t)ESP_IF_WIFI_STA, &conf) != ESP_OK){
log_e("set config failed!");
return WL_CONNECT_FAILED;
}
}
if(strlen(config.ip) > 0){
if(set_esp_interface_ip(ESP_IF_WIFI_STA) != ESP_OK) {
return WL_CONNECT_FAILED;
}
}
if(esp_wifi_connect() != ESP_OK) {
log_e("connect failed!");
return WL_CONNECT_FAILED;
}
return WiFi.status();
}
void WiFiClientConnectionHandler::wifi_sta_config(wifi_config_t * wifi_config, const char * ssid, const char * password, const uint8_t * bssid, uint8_t channel, wifi_auth_mode_t min_security, wifi_scan_method_t scan_method, wifi_sort_method_t sort_method, uint16_t listen_interval, bool pmf_required){
wifi_config->sta.channel = channel;
wifi_config->sta.listen_interval = listen_interval;
wifi_config->sta.scan_method = scan_method;//WIFI_ALL_CHANNEL_SCAN or WIFI_FAST_SCAN
wifi_config->sta.sort_method = sort_method;//WIFI_CONNECT_AP_BY_SIGNAL or WIFI_CONNECT_AP_BY_SECURITY
wifi_config->sta.threshold.rssi = -127;
wifi_config->sta.pmf_cfg.capable = true;
wifi_config->sta.pmf_cfg.required = pmf_required;
wifi_config->sta.bssid_set = 0;
memset(wifi_config->sta.bssid, 0, 6);
wifi_config->sta.threshold.authmode = WIFI_AUTH_OPEN;
wifi_config->sta.ssid[0] = 0;
wifi_config->sta.password[0] = 0;
if(ssid != NULL && ssid[0] != 0){
strncpy((char*)wifi_config->sta.ssid, ssid, 32);
if(password != NULL && password[0] != 0){
wifi_config->sta.threshold.authmode = min_security;
strncpy((char*)wifi_config->sta.password, password, 64);
}
if(bssid != NULL){
wifi_config->sta.bssid_set = 1;
memcpy(wifi_config->sta.bssid, bssid, 6);
}
}
wifi_config->sta.rm_enabled = true;
wifi_config->sta.btm_enabled = true;
wifi_config->sta.mbo_enabled = true;
}
#endif
void WiFiClientConnectionHandler::disconnect(unsigned long reconnectDelay) {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Disconnecting!\n"));
#if defined(ESP8266)
WiFiClient::stopAll();
#endif
WiFi.disconnect(true);
WiFi.softAPdisconnect(true);
WiFi.enableAP(false);
WiFi.mode(WIFI_OFF);
yield();
timeout = reconnectDelay;
}
bool WiFiClientConnectionHandler::isConnected() {
return WiFi.status() == WL_CONNECTED;
}
#if defined(ESP32)
void WiFiClientConnectionHandler::eventHandler(WiFiEvent_t event, WiFiEventInfo_t info) {
switch(event) {
case ARDUINO_EVENT_WIFI_READY:
if (!config.use11b) {
esp_wifi_config_11b_rate(WIFI_IF_AP, true);
esp_wifi_config_11b_rate(WIFI_IF_STA, true);
}
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Successfully connected to WiFi!\n"));
if(config.ipv6 && !WiFi.enableIpV6()) {
debugger->printf_P(PSTR("Unable to enable IPv6\n"));
}
#if defined(ESP32)
if(firstConnect && config.use11b) {
// If first boot and phyMode is better than 11b, disable 11b for BUS powered devices
if(busPowered) {
wifi_phy_mode_t phyMode;
if(esp_wifi_sta_get_negotiated_phymode(&phyMode) == ESP_OK) {
if(phyMode > WIFI_PHY_MODE_11B) {
if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("WiFi supports better rates than 802.11b, disabling\n"));
config.use11b = false;
configChanged = true;
return;
}
}
}
}
if(config.power >= 195)
WiFi.setTxPower(WIFI_POWER_19_5dBm);
else if(config.power >= 190)
WiFi.setTxPower(WIFI_POWER_19dBm);
else if(config.power >= 185)
WiFi.setTxPower(WIFI_POWER_18_5dBm);
else if(config.power >= 170)
WiFi.setTxPower(WIFI_POWER_17dBm);
else if(config.power >= 150)
WiFi.setTxPower(WIFI_POWER_15dBm);
else if(config.power >= 130)
WiFi.setTxPower(WIFI_POWER_13dBm);
else if(config.power >= 110)
WiFi.setTxPower(WIFI_POWER_11dBm);
else if(config.power >= 85)
WiFi.setTxPower(WIFI_POWER_8_5dBm);
else if(config.power >= 70)
WiFi.setTxPower(WIFI_POWER_7dBm);
else if(config.power >= 50)
WiFi.setTxPower(WIFI_POWER_5dBm);
else if(config.power >= 20)
WiFi.setTxPower(WIFI_POWER_2dBm);
else
WiFi.setTxPower(WIFI_POWER_MINUS_1dBm);
#elif defined(ESP8266)
WiFi.setOutputPower(config.power / 10.0);
#endif
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: {
if(debugger->isActive(RemoteDebug::INFO)) {
debugger->printf_P(PSTR("IP: %s\n"), getIP().toString().c_str());
debugger->printf_P(PSTR("GW: %s\n"), getGateway().toString().c_str());
for(uint8_t i = 0; i < 3; i++) {
IPAddress dns4 = getDns(i);
if(!dns4.isAny()) debugger->printf_P(PSTR("DNS: %s\n"), dns4.toString().c_str());
}
}
break;
}
case ARDUINO_EVENT_WIFI_STA_GOT_IP6: {
if(debugger->isActive(RemoteDebug::INFO)) {
IPv6Address ipv6 = getIPv6();
if(ipv6 == IPv6Address()) {
// No IP
} else {
debugger->printf_P(PSTR("IPv6: %s\n"), ipv6.toString().c_str());
}
for(uint8_t i = 0; i < 3; i++) {
IPv6Address dns6 = getDNSv6(i);
if(dns6 == IPv6Address()) {
// No IP
} else {
debugger->printf_P(PSTR("DNSv6: %s\n"), dns6.toString().c_str());
}
}
}
break;
}
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: {
wifi_err_reason_t reason = (wifi_err_reason_t) info.wifi_sta_disconnected.reason;
const char* descr = WiFi.disconnectReasonName(reason);
switch(reason) {
case WIFI_REASON_ASSOC_LEAVE:
break;
default:
if(strlen(descr) > 0) {
if(debugger->isActive(RemoteDebug::WARNING)) {
debugger->printf_P(PSTR("WiFi disconnected, reason %s\n"), descr);
}
disconnect(RECONNECT_TIMEOUT);
}
}
break;
}
}
}
#endif
bool WiFiClientConnectionHandler::isConfigChanged() {
return configChanged;
}
void WiFiClientConnectionHandler::getCurrentConfig(NetworkConfig& networkConfig) {
networkConfig = this->config;
}
IPAddress WiFiClientConnectionHandler::getIP() {
return WiFi.localIP();
}
IPAddress WiFiClientConnectionHandler::getSubnetMask() {
return WiFi.subnetMask();
}
IPAddress WiFiClientConnectionHandler::getGateway() {
return WiFi.gatewayIP();
}
IPAddress WiFiClientConnectionHandler::getDns(uint8_t idx) {
#if defined(ESP32)
for(uint8_t i = 0; i < 3; i++) {
const ip_addr_t * dns = dns_getserver(i);
if(dns->type == IPADDR_TYPE_V4) {
if(idx-- == 0) return IPAddress(dns->u_addr.ip4.addr);
}
}
#else
return WiFi.dnsIP(idx);
#endif
return IPAddress();
}
#if defined(ESP32)
IPv6Address WiFiClientConnectionHandler::getIPv6() {
esp_ip6_addr_t addr;
if(esp_netif_get_ip6_global(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr) == ESP_OK) {
return IPv6Address(addr.addr);
}
return IPv6Address();
}
IPv6Address WiFiClientConnectionHandler::getDNSv6(uint8_t idx) {
for(uint8_t i = 0; i < 3; i++) {
const ip_addr_t * dns = dns_getserver(i);
if(dns->type == IPADDR_TYPE_V6) {
if(idx-- == 0) return IPv6Address(dns->u_addr.ip6.addr);
}
}
return IPv6Address();
}
#endif