Closed khoih-prog closed 2 years ago
Thanks for the report and MCVE.
The RSSI reporting 0dbm while connected or disconnected is actually a limitation of the CYW43 driver. It doesn't report common things like that. It doesn't even report BSSID or channel. Nothing we can do here unless the driver gets fixed (it talks to a undocumented proprietary blob).
The incorrect connected()
report, though, we should be able to work on here.
On the WL_CONNECTED side, the code here also seems correct:
The logic simply polls the CYW43 blob driver and uses that to determine connected or not. If the CYW43 driver reports the connection is still up, there's not much we can do here.
As you probably are guessing, I've found the CYW43 driver something of a work in progress. We've even had to patch it to support simple things like multicast.
--edit--- Digging into the driver, while the link status call seems not to work: https://github.com/earlephilhower/cyw43-driver/blob/02533c10a018c6550e9f66f7699e21356f5e4609/src/cyw43_ctrl.c#L565-L582
We may be able to hook into the event callbacks and track the link state on our own, ignoring what the driver says: https://github.com/earlephilhower/cyw43-driver/blob/02533c10a018c6550e9f66f7699e21356f5e4609/src/cyw43_ctrl.c#L379-L392
As you probably are guessing, I've found the CYW43 driver something of a work in progress. We've even had to patch it to support simple things like multicast.
I totally understand and post the issue here so that we can work on a patch similar to multicast
We may be able to hook into the event callbacks and track the link state on our own, ignoring what the driver says: https://github.com/earlephilhower/cyw43-driver/blob/02533c10a018c6550e9f66f7699e21356f5e4609/src/cyw43_ctrl.c#L379-L392
This seems the best way to fix.
I just did a quick test to patch in some logic based on the callbacks and it seems like the event is not actually being received on associate/disassociate. :disappointed:
I probably need to instrument it and dump all events while adding/removing to see exactly what is happening and where it might be overridden.
diff --git a/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c b/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c
index 07ef28a9f..a95bd110e 100644
--- a/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c
+++ b/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c
@@ -316,6 +316,9 @@ void cyw43_arch_poll() {
// }
}
+
+bool _cyw43_cb_link_up = false;
+
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
void __attribute__((weak)) cyw43_cb_tcpip_init(cyw43_t *self, int itf);
void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
@@ -331,11 +334,15 @@ void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
(void) self;
(void) itf;
+ printf("\nlu\n");
+ _cyw43_cb_link_up = true;
}
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
(void) self;
(void) itf;
+ printf("\nld\n");
+ _cyw43_cb_link_up = false;
}
void __attribute__((weak)) cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf);
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
--- a/libraries/WiFi/src/WiFiClass.cpp
+++ b/libraries/WiFi/src/WiFiClass.cpp
@@ -469,13 +469,14 @@ int32_t WiFiClass::RSSI(uint8_t networkItem) {
return: one of the value defined in wl_status_t
*/
+extern "C" bool _cyw43_cb_link_up;
uint8_t WiFiClass::status() {
if (_apMode && _wifiHWInitted) {
return WL_CONNECTED;
}
switch (cyw43_wifi_link_status(&cyw43_state, _apMode ? 1 : 0)) {
case CYW43_LINK_DOWN: return WL_IDLE_STATUS;
- case CYW43_LINK_JOIN: return localIP().isSet() ? WL_CONNECTED : WL_DISCONNECTED;
+ case CYW43_LINK_JOIN: return (_cyw43_cb_link_up && localIP().isSet()) ? WL_CONNECTED : WL_DISCONNECTED;
case CYW43_LINK_FAIL: return WL_CONNECT_FAILED;
case CYW43_LINK_NONET: return WL_CONNECT_FAILED;
case CYW43_LINK_BADAUTH: return WL_CONNECT_FAILED;
This is just a temporary and inefficient kludge using WiFiClient.connect()
to test or use (if necessary) while waiting for the real fix
#include <WiFi.h>
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "YOUR_SSID"; // your network SSID (name)
char pass[] = "YOUR_PASSWORD"; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
void printWifiStatus()
{
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
}
void setup()
{
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial && millis() < 5000);
Serial.print(F("\nStarting RP2040W_WiFi_Bug on ")); Serial.println(BOARD_NAME);
// check for the WiFi module:
if (WiFi.status() == WL_NO_SHIELD)
{
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 3 seconds for connection:
delay(3000);
}
}
// Use any public host or your local host, such as ADSL/Cable modem, router, server
//const char* host = "arduino.tips";
const char* host = "192.168.2.1";
const uint16_t port = 80;
bool isWiFiConnected()
{
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, port))
{
Serial.print("connection failed. Local IP = "); Serial.println(client.localIP());
Serial.print("connection failed. WiFi IP = "); Serial.println(WiFi.localIP());
return false;
}
Serial.print("Client connected, Local IP = "); Serial.println(client.localIP());
return true;
}
void loop()
{
//if (WiFi.status() == WL_CONNECTED)
// Temporary kludge to get around
if (isWiFiConnected())
{
Serial.println("Connected to wifi");
printWifiStatus();
}
else
{
Serial.println("Not connected to wifi");
}
delay(5000);
}
Terminal output
Starting RP2040W_WiFi_Bug on RASPBERRY_PI_PICO_W
Attempting to connect to SSID: HueNet1
Client connected, Local IP = 192.168.2.180
Connected to wifi
SSID: HueNet1
IP Address: 192.168.2.180
Client connected, Local IP = 192.168.2.180
Connected to wifi
SSID: HueNet1
IP Address: 192.168.2.180
Client connected, Local IP = 192.168.2.180
... <========= Power OFF WiFi AP
connection failed. Local IP = (IP unset)
connection failed. WiFi IP = 192.168.2.180
Not connected to wifi
connection failed. Local IP = (IP unset)
connection failed. WiFi IP = 192.168.2.180
Not connected to wifi
... <========= Power ON WiFi AP
Client connected, Local IP = 192.168.2.180
Connected to wifi
SSID: HueNet1
IP Address: 192.168.2.180
Client connected, Local IP = 192.168.2.180
Connected to wifi
SSID: HueNet1
IP Address: 192.168.2.180
Client connected, Local IP = 192.168.2.180
Why not make it something more universal? If you ping 1.1.1.1
(CloudFlare DNS) or 8.8.8.8
(Google DNS) it should theoretically work everywhere except behind the Great Firewall of China. No need for users to adjust in the common case.
In the meantime, I'll leave this open as something to work on. I'm not sure how much progress we can make, but I'll give it a try since it's such a basic operation.
I first tried ping()
, but somehow it didn't work correctly. That's why I had to use the worse and extreme WiFiClient.connect()
.
I'll try again later to see what's really wrong with ping()
I hope I'll have a look at the cyw43 driver, but not sure if I can spend time there to understand. Hopefully @oddstr13 can help here.
@khoih-prog unfortunately I don't have any inside knowledge of how the firmware works, all I have to go by is the public git repo.
I don't have time right now (and likely not for a good while) to have a deeper dive into this.
The pico doxygen might be helpful for discovering what's available. https://raspberrypi.github.io/pico-sdk-doxygen/group__cyw43__driver.html#ga71e656d02aabca214ae344f29ae1d033
I'd suggest submitting issues upstream, even tho they seem to be slow at responding right now.
YEah, that document suggests that the existing code is correctly calling the right API, but the API is returning "connected" when the AP itself is down.
@khoih-prog how long after the AP is shut off do you wait before checking the connected
status? There may be some internal timeout where the CYW43 doesn't report disconnected, just because WiFi sometimes has short dropouts . If it's still reporting connected 30 seconds after the AP is powered off, though, we definitely have an issue. I haven't tried yet since I need to dig up and config a dummy AP.
If it's still reporting connected 30 seconds after the AP is powered off, though, we definitely have an issue.
I've tried to power off AP, after many minutes, still connected
.
I've retested using ping()
and OK now to use ping
to local gateway (auto detected, no user intervention) to detect WiFi lost.
The ttl is configurable, according to network
#include <WiFi.h>
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "YOUR_SSID"; // your network SSID (name)
char pass[] = "YOUR_PASSWORD"; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
void printWifiStatus()
{
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
}
void setup()
{
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial && millis() < 5000);
Serial.print(F("\nStarting RP2040W_WiFi_Bug on ")); Serial.println(BOARD_NAME);
// check for the WiFi module:
if (WiFi.status() == WL_NO_SHIELD)
{
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 3 seconds for connection:
delay(3000);
}
}
bool isWiFiConnected()
{
// You can change longer or shorter depending on your network response
// Shorter => more responsive, but more ping traffic
static uint8_t theTTL = 10;
// Use ping() to test TCP connections
if (WiFi.ping(WiFi.gatewayIP(), theTTL) == theTTL)
{
return true;
}
return false;
}
void check_status()
{
static uint32_t checkwifi_timeout = 0;
static uint32_t current_millis;
// You can change longer or shorter depending on your network response
// Shorter => more responsive, but more ping traffic
#define WIFICHECK_INTERVAL 1000L
current_millis = millis();
// Check WiFi every WIFICHECK_INTERVAL (1) seconds.
if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0))
{
//if (WiFi.status() == WL_CONNECTED)
// Temporary fix to get around
if (isWiFiConnected())
{
Serial.println("Connected to wifi");
printWifiStatus();
}
else
{
Serial.println("Not connected to wifi");
}
checkwifi_timeout = current_millis + WIFICHECK_INTERVAL;
}
}
void loop()
{
check_status();
}
21:51:24.060 -> Starting RP2040W_WiFi_Bug on RASPBERRY_PI_PICO_W
21:51:24.060 -> Attempting to connect to SSID: HueNet2
21:51:41.109 -> Connected to wifi
21:51:41.109 -> SSID: HueNet2
21:51:41.109 -> IP Address: 192.168.2.180
...
21:51:44.128 -> Connected to wifi
21:51:44.128 -> SSID: HueNet2
21:51:44.128 -> IP Address: 192.168.2.180 <==== Power OFF AP
21:51:55.078 -> Not connected to wifi <===== WiFi lost
21:52:05.066 -> Not connected to wifi
21:52:05.099 -> Connected to wifi <==== Power ON AP
21:52:05.099 -> SSID: HueNet2
21:52:05.099 -> IP Address: 192.168.2.180
21:52:06.128 -> Connected to wifi
...
@khoih-prog can you give #774 a try and report back? A simple "print connected()" loop now seems to work properly for me.
Oh yeah, it takes ~5 seconds to notice a link drop in my experience with this chip.
@earlephilhower
I've tested and can confirm that WiFi.status()
WL_CONNECTED is working OK now, with 5s delay from link drop / power off.
Auto-reconnect is working OK after powering on the AP.
Great work, please merge the PR #774
Bug Description
WiFi.status()
still reportsWL_CONNECTED
https://github.com/earlephilhower/arduino-pico/blob/5787b4c02bdd58911f7eca8e46615b48be7abdcd/libraries/WiFi/src/WiFiClass.cpp#L472-L484
0 dBm
, even WiFi is connectedhttps://github.com/earlephilhower/arduino-pico/blob/5787b4c02bdd58911f7eca8e46615b48be7abdcd/libraries/WiFi/src/WiFiClass.cpp#L320-L323
This bug is very similar to [Portenta_H7] WiFi.status() wrongly reports WL_CONNECTED even when WiFi is lost #381
MRE
Using the following sketch
Arduino IDE v1.8.19, arduino-pico core v2.4.0 RASPBERRY_PI_PICO_W using CYW43439 WiFi
Terminal output