diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 38e804ed97..eaea1e92c0 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -20,11 +20,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { //long vid = doc[F("vid")]; // 2010020 -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) JsonObject ethernet = doc[F("eth")]; CJSON(ethernetType, ethernet["type"]); // NOTE: Ethernet configuration takes priority over other use of pins - WLED::instance().initEthernet(); + initEthernet(); #endif JsonObject id = doc["id"]; @@ -53,9 +53,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonArray sn = wifi["sn"]; char ssid[33] = ""; char pass[65] = ""; + char bssid[13] = ""; IPAddress nIP = (uint32_t)0U, nGW = (uint32_t)0U, nSN = (uint32_t)0x00FFFFFF; // little endian getStringFromJson(ssid, wifi[F("ssid")], 33); getStringFromJson(pass, wifi["psk"], 65); // password is not normally present but if it is, use it + getStringFromJson(bssid, wifi[F("bssid")], 13); for (size_t i = 0; i < 4; i++) { CJSON(nIP[i], ip[i]); CJSON(nGW[i], gw[i]); @@ -63,6 +65,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } if (strlen(ssid) > 0) strlcpy(multiWiFi[n].clientSSID, ssid, 33); // this will keep old SSID intact if not present in JSON if (strlen(pass) > 0) strlcpy(multiWiFi[n].clientPass, pass, 65); // this will keep old password intact if not present in JSON + if (strlen(bssid) > 0) fillStr2MAC(multiWiFi[n].bssid, bssid); multiWiFi[n].staticIP = nIP; multiWiFi[n].staticGW = nGW; multiWiFi[n].staticSN = nSN; @@ -702,8 +705,8 @@ void deserializeConfigFromFS() { UsermodManager::readFromConfig(empty); serializeConfig(); // init Ethernet (in case default type is set at compile time) - #ifdef WLED_USE_ETHERNET - WLED::instance().initEthernet(); + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + initEthernet(); #endif return; } @@ -751,6 +754,9 @@ void serializeConfig() { JsonObject wifi = nw_ins.createNestedObject(); wifi[F("ssid")] = multiWiFi[n].clientSSID; wifi[F("pskl")] = strlen(multiWiFi[n].clientPass); + char bssid[13]; + fillMAC2Str(bssid, multiWiFi[n].bssid); + wifi[F("bssid")] = bssid; JsonArray wifi_ip = wifi.createNestedArray("ip"); JsonArray wifi_gw = wifi.createNestedArray("gw"); JsonArray wifi_sn = wifi.createNestedArray("sn"); @@ -786,7 +792,7 @@ void serializeConfig() { wifi[F("txpwr")] = txPower; #endif -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) JsonObject ethernet = root.createNestedObject("eth"); ethernet["type"] = ethernetType; if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 30b6600ae2..d944d938e5 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -109,12 +109,13 @@ gId("wifi_add").style.display = (i1) ? "inline":"none"; } - function addWiFi(ssid="",pass="",ip=0,gw=0,sn=0x00ffffff) { // little endian + function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian var i = gId("wifi_entries").childNodes.length; if (i >= maxNetworks) return; var b = `

Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
Network password:

+BSSID (optional):

Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
...
Static gateway:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index bc5206b7ae..1f9972a40e 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -52,6 +52,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau typedef struct WiFiConfig { char clientSSID[33]; char clientPass[65]; + uint8_t bssid[6]; IPAddress staticIP; IPAddress staticGW; IPAddress staticSN; @@ -62,6 +63,7 @@ typedef struct WiFiConfig { { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; + memset(bssid, 0, sizeof(bssid)); } } wifi_config; @@ -340,7 +342,12 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs #endif //network.cpp -int getSignalQuality(int rssi); +bool initEthernet(); // result is informational +int getSignalQuality(int rssi); +void fillMAC2Str(char *str, const uint8_t *mac); +void fillStr2MAC(uint8_t *mac, const char *str); +int findWiFi(bool doScan = false); +bool isWiFiConfigured(); void WiFiEvent(WiFiEvent_t event); //um_manager.cpp @@ -464,6 +471,7 @@ void userLoop(); #include "soc/wdev_reg.h" #define HW_RND_REGISTER REG_READ(WDEV_RND_REG) #endif +#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0) int getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) diff --git a/wled00/network.cpp b/wled00/network.cpp index 3bd589f944..79209ff5e9 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -3,7 +3,7 @@ #include "wled_ethernet.h" -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) // The following six pins are neither configurable nor // can they be re-assigned through IOMUX / GPIO matrix. // See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface @@ -146,6 +146,101 @@ const ethernet_settings ethernetBoards[] = { ETH_CLOCK_GPIO0_OUT // eth_clk_mode } }; + +bool initEthernet() +{ + static bool successfullyConfiguredEthernet = false; + + if (successfullyConfiguredEthernet) { + // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); + return false; + } + if (ethernetType == WLED_ETH_NONE) { + return false; + } + if (ethernetType >= WLED_NUM_ETH_TYPES) { + DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType); + return false; + } + + DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType); + + // Ethernet initialization should only succeed once -- else reboot required + ethernet_settings es = ethernetBoards[ethernetType]; + managed_pin_type pinsToAllocate[10] = { + // first six pins are non-configurable + esp32_nonconfigurable_ethernet_pins[0], + esp32_nonconfigurable_ethernet_pins[1], + esp32_nonconfigurable_ethernet_pins[2], + esp32_nonconfigurable_ethernet_pins[3], + esp32_nonconfigurable_ethernet_pins[4], + esp32_nonconfigurable_ethernet_pins[5], + { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory + { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory + { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use + { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory + }; + // update the clock pin.... + if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { + pinsToAllocate[9].pin = 0; + pinsToAllocate[9].isOutput = false; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { + pinsToAllocate[9].pin = 0; + pinsToAllocate[9].isOutput = true; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { + pinsToAllocate[9].pin = 16; + pinsToAllocate[9].isOutput = true; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { + pinsToAllocate[9].pin = 17; + pinsToAllocate[9].isOutput = true; + } else { + DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); + return false; + } + + if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { + DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); + return false; + } + + /* + For LAN8720 the most correct way is to perform clean reset each time before init + applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) + ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in + /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) + but ESP_IDF < V4 does not. Lets do it: + [not always needed, might be relevant in some EMI situations at startup and for hot resets] + */ + #if ESP_IDF_VERSION_MAJOR==3 + if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { + pinMode(es.eth_power, OUTPUT); + digitalWrite(es.eth_power, 0); + delayMicroseconds(150); + digitalWrite(es.eth_power, 1); + delayMicroseconds(10); + } + #endif + + if (!ETH.begin( + (uint8_t) es.eth_address, + (int) es.eth_power, + (int) es.eth_mdc, + (int) es.eth_mdio, + (eth_phy_type_t) es.eth_type, + (eth_clock_mode_t) es.eth_clk_mode + )) { + DEBUG_PRINTLN(F("initC: ETH.begin() failed")); + // de-allocate the allocated pins + for (managed_pin_type mpt : pinsToAllocate) { + PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet); + } + return false; + } + + successfullyConfiguredEthernet = true; + DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***")); + return true; +} #endif @@ -170,19 +265,136 @@ int getSignalQuality(int rssi) } +void fillMAC2Str(char *str, const uint8_t *mac) { + sprintf_P(str, PSTR("%02x%02x%02x%02x%02x%02x"), MAC2STR(mac)); + byte nul = 0; + for (int i = 0; i < 6; i++) nul |= *mac++; // do we have 0 + if (!nul) str[0] = '\0'; // empty string +} + +void fillStr2MAC(uint8_t *mac, const char *str) { + for (int i = 0; i < 6; i++) *mac++ = 0; // clear + if (!str) return; // null string + uint64_t MAC = strtoull(str, nullptr, 16); + for (int i = 0; i < 6; i++) { *--mac = MAC & 0xFF; MAC >>= 8; } +} + + +// performs asynchronous scan for available networks (which may take couple of seconds to finish) +// returns configured WiFi ID with the strongest signal (or default if no configured networks available) +int findWiFi(bool doScan) { + if (multiWiFi.size() <= 1) { + DEBUG_PRINTF_P(PSTR("WiFi: Defaulf SSID (%s) used.\n"), multiWiFi[0].clientSSID); + return 0; + } + + int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <6s with not very crowded air) + + if (doScan || status == WIFI_SCAN_FAILED) { + DEBUG_PRINTF_P(PSTR("WiFi: Scan started. @ %lus\n"), millis()/1000); + WiFi.scanNetworks(true); // start scanning in asynchronous mode (will delete old scan) + } else if (status >= 0) { // status contains number of found networks (including duplicate SSIDs with different BSSID) + DEBUG_PRINTF_P(PSTR("WiFi: Found %d SSIDs. @ %lus\n"), status, millis()/1000); + int rssi = -9999; + int selected = selectedWiFi; + for (int o = 0; o < status; o++) { + DEBUG_PRINTF_P(PSTR(" SSID: %s (BSSID: %s) RSSI: %ddB\n"), WiFi.SSID(o).c_str(), WiFi.BSSIDstr(o).c_str(), WiFi.RSSI(o)); + for (unsigned n = 0; n < multiWiFi.size(); n++) + if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) { + bool foundBSSID = memcmp(multiWiFi[n].bssid, WiFi.BSSID(o), 6) == 0; + // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big) + if (foundBSSID || (n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) { + rssi = foundBSSID ? 0 : WiFi.RSSI(o); // RSSI is only ever negative + selected = n; + } + break; + } + } + DEBUG_PRINTF_P(PSTR("WiFi: Selected SSID: %s RSSI: %ddB\n"), multiWiFi[selected].clientSSID, rssi); + return selected; + } + //DEBUG_PRINT(F("WiFi scan running.")); + return status; // scan is still running or there was an error +} + + +bool isWiFiConfigured() { + return multiWiFi.size() > 1 || (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp_P(multiWiFi[0].clientSSID, PSTR(DEFAULT_CLIENT_SSID)) != 0); +} + +#if defined(ESP8266) + #define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED WIFI_EVENT_SOFTAPMODE_STADISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_STACONNECTED WIFI_EVENT_SOFTAPMODE_STACONNECTED + #define ARDUINO_EVENT_WIFI_STA_GOT_IP WIFI_EVENT_STAMODE_GOT_IP + #define ARDUINO_EVENT_WIFI_STA_CONNECTED WIFI_EVENT_STAMODE_CONNECTED + #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED WIFI_EVENT_STAMODE_DISCONNECTED +#elif defined(ARDUINO_ARCH_ESP32) && !defined(ESP_ARDUINO_VERSION_MAJOR) //ESP_IDF_VERSION_MAJOR==3 + // not strictly IDF v3 but Arduino core related + #define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED SYSTEM_EVENT_AP_STADISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_STACONNECTED SYSTEM_EVENT_AP_STACONNECTED + #define ARDUINO_EVENT_WIFI_STA_GOT_IP SYSTEM_EVENT_STA_GOT_IP + #define ARDUINO_EVENT_WIFI_STA_CONNECTED SYSTEM_EVENT_STA_CONNECTED + #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_START SYSTEM_EVENT_AP_START + #define ARDUINO_EVENT_WIFI_AP_STOP SYSTEM_EVENT_AP_STOP + #define ARDUINO_EVENT_WIFI_SCAN_DONE SYSTEM_EVENT_SCAN_DONE + #define ARDUINO_EVENT_ETH_START SYSTEM_EVENT_ETH_START + #define ARDUINO_EVENT_ETH_CONNECTED SYSTEM_EVENT_ETH_CONNECTED + #define ARDUINO_EVENT_ETH_DISCONNECTED SYSTEM_EVENT_ETH_DISCONNECTED +#endif + //handle Ethernet connection event void WiFiEvent(WiFiEvent_t event) { switch (event) { -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) - case SYSTEM_EVENT_ETH_START: - DEBUG_PRINTLN(F("ETH Started")); + case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: + // AP client disconnected + if (--apClients == 0 && isWiFiConfigured()) forceReconnect = true; // no clients reconnect WiFi if awailable + DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Disconnected (%d) @ %lus.\n"), (int)apClients, millis()/1000); + break; + case ARDUINO_EVENT_WIFI_AP_STACONNECTED: + // AP client connected + apClients++; + DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Connected (%d) @ %lus.\n"), (int)apClients, millis()/1000); + break; + case ARDUINO_EVENT_WIFI_STA_GOT_IP: + DEBUG_PRINT(F("WiFi-E: IP address: ")); DEBUG_PRINTLN(Network.localIP()); + break; + case ARDUINO_EVENT_WIFI_STA_CONNECTED: + // followed by IDLE and SCAN_DONE + DEBUG_PRINTF_P(PSTR("WiFi-E: Connected! @ %lus\n"), millis()/1000); + wasConnected = true; + break; + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + if (wasConnected && interfacesInited) { + DEBUG_PRINTF_P(PSTR("WiFi-E: Disconnected! @ %lus\n"), millis()/1000); + if (interfacesInited && multiWiFi.size() > 1 && WiFi.scanComplete() >= 0) { + findWiFi(true); // reinit WiFi scan + forceReconnect = true; + } + interfacesInited = false; + } break; - case SYSTEM_EVENT_ETH_CONNECTED: + #ifdef ARDUINO_ARCH_ESP32 + case ARDUINO_EVENT_WIFI_SCAN_DONE: + // also triggered when connected to selected SSID + DEBUG_PRINTLN(F("WiFi-E: SSID scan completed.")); + break; + case ARDUINO_EVENT_WIFI_AP_START: + DEBUG_PRINTLN(F("WiFi-E: AP Started")); + break; + case ARDUINO_EVENT_WIFI_AP_STOP: + DEBUG_PRINTLN(F("WiFi-E: AP Stopped")); + break; + #if defined(WLED_USE_ETHERNET) + case ARDUINO_EVENT_ETH_START: + DEBUG_PRINTLN(F("ETH-E: Started")); + break; + case ARDUINO_EVENT_ETH_CONNECTED: { - DEBUG_PRINTLN(F("ETH Connected")); + DEBUG_PRINTLN(F("ETH-E: Connected")); if (!apActive) { - WiFi.disconnect(true); + WiFi.disconnect(true); // disable WiFi entirely } if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) { ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress); @@ -196,18 +408,20 @@ void WiFiEvent(WiFiEvent_t event) showWelcomePage = false; break; } - case SYSTEM_EVENT_ETH_DISCONNECTED: - DEBUG_PRINTLN(F("ETH Disconnected")); + case ARDUINO_EVENT_ETH_DISCONNECTED: + DEBUG_PRINTLN(F("ETH-E: Disconnected")); // This doesn't really affect ethernet per se, // as it's only configured once. Rather, it // may be necessary to reconnect the WiFi when // ethernet disconnects, as a way to provide // alternative access to the device. + if (interfacesInited && WiFi.scanComplete() >= 0) findWiFi(true); // reinit WiFi scan forceReconnect = true; break; -#endif + #endif + #endif default: - DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event); + DEBUG_PRINTF_P(PSTR("WiFi-E: Event %d\n"), (int)event); break; } } diff --git a/wled00/set.cpp b/wled00/set.cpp index 160eb48f07..6152ba0bdd 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -23,6 +23,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password + char bs[4] = "BS"; bs[2] = 48+n; bs[3] = 0; //BSSID char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask @@ -39,6 +40,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65); forceReconnect = true; } + fillStr2MAC(multiWiFi[n].bssid, request->arg(bs).c_str()); for (size_t i = 0; i < 4; i++) { ip[3] = 48+i; gw[3] = 48+i; @@ -93,9 +95,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strlwr(linked_remote); //Normalize MAC format to lowercase #endif - #ifdef WLED_USE_ETHERNET + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) ethernetType = request->arg(F("ETH")).toInt(); - WLED::instance().initEthernet(); + initEthernet(); #endif } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39b4..d4da106a71 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -632,146 +632,6 @@ void WLED::initAP(bool resetAP) apActive = true; } -bool WLED::initEthernet() -{ -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) - - static bool successfullyConfiguredEthernet = false; - - if (successfullyConfiguredEthernet) { - // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); - return false; - } - if (ethernetType == WLED_ETH_NONE) { - return false; - } - if (ethernetType >= WLED_NUM_ETH_TYPES) { - DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType); - return false; - } - - DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType); - - // Ethernet initialization should only succeed once -- else reboot required - ethernet_settings es = ethernetBoards[ethernetType]; - managed_pin_type pinsToAllocate[10] = { - // first six pins are non-configurable - esp32_nonconfigurable_ethernet_pins[0], - esp32_nonconfigurable_ethernet_pins[1], - esp32_nonconfigurable_ethernet_pins[2], - esp32_nonconfigurable_ethernet_pins[3], - esp32_nonconfigurable_ethernet_pins[4], - esp32_nonconfigurable_ethernet_pins[5], - { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory - { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory - { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use - { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory - }; - // update the clock pin.... - if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = false; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { - pinsToAllocate[9].pin = 16; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { - pinsToAllocate[9].pin = 17; - pinsToAllocate[9].isOutput = true; - } else { - DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); - return false; - } - - if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { - DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); - return false; - } - - /* - For LAN8720 the most correct way is to perform clean reset each time before init - applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) - ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in - /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) - but ESP_IDF < V4 does not. Lets do it: - [not always needed, might be relevant in some EMI situations at startup and for hot resets] - */ - #if ESP_IDF_VERSION_MAJOR==3 - if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { - pinMode(es.eth_power, OUTPUT); - digitalWrite(es.eth_power, 0); - delayMicroseconds(150); - digitalWrite(es.eth_power, 1); - delayMicroseconds(10); - } - #endif - - if (!ETH.begin( - (uint8_t) es.eth_address, - (int) es.eth_power, - (int) es.eth_mdc, - (int) es.eth_mdio, - (eth_phy_type_t) es.eth_type, - (eth_clock_mode_t) es.eth_clk_mode - )) { - DEBUG_PRINTLN(F("initC: ETH.begin() failed")); - // de-allocate the allocated pins - for (managed_pin_type mpt : pinsToAllocate) { - PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet); - } - return false; - } - - successfullyConfiguredEthernet = true; - DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***")); - return true; -#else - return false; // Ethernet not enabled for build -#endif -} - -// performs asynchronous scan for available networks (which may take couple of seconds to finish) -// returns configured WiFi ID with the strongest signal (or default if no configured networks available) -int8_t WLED::findWiFi(bool doScan) { - if (multiWiFi.size() <= 1) { - DEBUG_PRINTLN(F("Defaulf WiFi used.")); - return 0; - } - - if (doScan) WiFi.scanDelete(); // restart scan - - int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <3s with not very crowded air) - - if (status == WIFI_SCAN_FAILED) { - DEBUG_PRINTLN(F("WiFi scan started.")); - WiFi.scanNetworks(true); // start scanning in asynchronous mode - } else if (status >= 0) { // status contains number of found networks - DEBUG_PRINT(F("WiFi scan completed: ")); DEBUG_PRINTLN(status); - int rssi = -9999; - unsigned selected = selectedWiFi; - for (int o = 0; o < status; o++) { - DEBUG_PRINT(F(" WiFi available: ")); DEBUG_PRINT(WiFi.SSID(o)); - DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(WiFi.RSSI(o)); DEBUG_PRINTLN(F("dB")); - for (unsigned n = 0; n < multiWiFi.size(); n++) - if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) { - // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big) - if ((n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) { - rssi = WiFi.RSSI(o); - selected = n; - } - break; - } - } - DEBUG_PRINT(F("Selected: ")); DEBUG_PRINT(multiWiFi[selected].clientSSID); - DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(rssi); DEBUG_PRINTLN(F("dB")); - return selected; - } - //DEBUG_PRINT(F("WiFi scan running.")); - return status; // scan is still running or there was an error -} - void WLED::initConnection() { DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); diff --git a/wled00/wled.h b/wled00/wled.h index d0cee80d2c..847810108d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -355,7 +355,7 @@ WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CO #define noWifiSleep wifiOpt.noWifiSleep #define force802_3g wifiOpt.force802_3g #else -WLED_GLOBAL uint8_t selectedWiFi _INIT(0); +WLED_GLOBAL int8_t selectedWiFi _INIT(0); WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default @@ -373,9 +373,9 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); #endif #endif -#define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0) +#define WLED_WIFI_CONFIGURED isWiFiConfigured() -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type #else @@ -567,6 +567,7 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i // internal global variable declarations // wifi WLED_GLOBAL bool apActive _INIT(false); +WLED_GLOBAL byte apClients _INIT(0); WLED_GLOBAL bool forceReconnect _INIT(false); WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0); WLED_GLOBAL bool interfacesInited _INIT(false); @@ -1038,11 +1039,9 @@ class WLED { void beginStrip(); void handleConnection(); - bool initEthernet(); // result is informational void initAP(bool resetAP = false); void initConnection(); void initInterfaces(); - int8_t findWiFi(bool doScan = false); #if defined(STATUSLED) void handleStatusLED(); #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2a19cdfabc..4898858d05 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -110,7 +110,7 @@ void appendGPIOinfo(Print& settingsScript) { settingsScript.print(hardwareTX); // debug output (TX) pin firstPin = false; #endif - #ifdef WLED_USE_ETHERNET + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (!firstPin) settingsScript.print(','); for (unsigned p=0; p