-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wifi_set_opmode_current return true but failing? #4372
Comments
hmm so there is a delay setting mode, and I have no idea where it comes from, so its some kind of race condition, and I have no idea what causes it yet. Is there a doc that says wtf the debugging means ?
|
Ok I can repoduce it now, and it only happens the first time after loop() then works again..wierd but not in test sketch so still checking user code. |
Reproduction#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
}
const char* const modes[] PROGMEM = { "NULL", "STA", "AP", "STA+AP" };
void setup() {
Serial.begin(115200);
delay(1000);
Serial.setDebugOutput(true);
Serial.println(F("\n Starting"));
// Serial.println(modes[WiFi.getMode()]);
// WiFi.printDiag(Serial);
// WiFi.mode(WIFI_STA);
// WiFi.setAutoConnect(true);
// WiFi.setAutoReconnect(true);
}
void debugSoftAPConfig(){
softap_config config;
wifi_softap_get_config(&config);
Serial.println(F("SoftAP Configuration"));
Serial.println(F("-----------------------------"));
Serial.print(F("ssid: "));Serial.println((char *) config.ssid);
Serial.print(F("password: "));Serial.println((char *) config.password);
Serial.print(F("ssid_len: "));Serial.println(config.ssid_len);
Serial.print(F("channel: "));Serial.println(config.channel);
Serial.print(F("authmode: "));Serial.println(config.authmode);
Serial.print(F("ssid_hidden: "));Serial.println(config.ssid_hidden);
Serial.print(F("max_connection: "));Serial.println(config.max_connection);
Serial.print(F("beacon_interval: "));Serial.println((String)config.beacon_interval + "(ms)");
Serial.println(F("-----------------------------"));
}
void startap(){
bool ret;
ret = WiFi.softAP("esptestap");
if(!ret)Serial.println(F("softAP failed BOOOM"));
debugSoftAPConfig();
ret = WiFi.softAPdisconnect(true);
if(!ret)Serial.println(F("softAPdisconnect failed"));
ret = WiFi.mode(WIFI_STA);
if(!ret)Serial.println(F("set mode failed"));
delay(1000);
}
void loop(){
startap();
startap();
} |
maybe someone can make sense of this, it seems that the second run takes much longer and is asynchronous, I also see more dhcp start than there should be , no idea what the other debugging means. I am timing the RUN call to set opmode, and the SET of when getmode actually changed, those are the times in micros, there is a yield in there though Logging
I should have messed with GDB instead and actually tried to debug this properly, oh well. solution for now is to delay after, or while loop it shrug dirty workaround/**
* set new mode
* @param m WiFiMode_t
*/
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
if(wifi_get_opmode() == (uint8) m) {
return true;
}
bool ret = false;
DEBUG_WIFI_GENERIC("[mode] wifi_get_opmode BEFORE\n");
DEBUG_WIFI(String(wifi_get_opmode()).c_str());
DEBUG_WIFI_GENERIC("\n");
bool testing = true;
uint32_t mark;
uint32_t end;
uint32_t start = micros();
ETS_UART_INTR_DISABLE();
if(_persistent) {
ret = wifi_set_opmode(m);
} else {
// DEBUG_WIFI_GENERIC("[mode] wifi_set_opmode_current to\n");
// DEBUG_WIFI_GENERIC(String(m).c_str());
// DEBUG_WIFI_GENERIC("\n");
ret = wifi_set_opmode_current(m);
}
ETS_UART_INTR_ENABLE();
mark = micros();
if(wifi_get_opmode() != (uint8) m) {
DEBUG_WIFI_GENERIC("[mode] ERROR MODE SET FAILED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
if(testing){
while(wifi_get_opmode() != (uint8) m){
yield();
}
end = micros();
DEBUG_WIFI_GENERIC("[WIFI_SET_OPMODE_CURRENT] ran in ");
DEBUG_WIFI_GENERIC(String(mark-start).c_str());
DEBUG_WIFI_GENERIC("\n");
DEBUG_WIFI_GENERIC("[WIFI_SET_OPMODE_CURRENT] set in ");
DEBUG_WIFI_GENERIC(String(end-start).c_str());
DEBUG_WIFI_GENERIC("\n");
// DEBUG_WIFI_GENERIC("[mode] wifi_get_opmode AFTER\n");
// DEBUG_WIFI(String(wifi_get_opmode()).c_str());
// DEBUG_WIFI_GENERIC("\n");
}
return ret;
} |
@devyte if you could assign someone to take a glance and let me know about this, thanks. |
Could you give a summary of your findings ? |
SUMMARYRace condition, |
I am not entirely sure why it takes longer SOMETIMES but it might be an sdk thing. Issue contains logs and reproduction info. Someone might be able to glean more info from the hardware output above, i have no idea how to decipher that to see a pattern. Sometimes defined as the difference between these 2 delays seems to be the factor ( includes a yield() ) good bad actual bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden, int max_connection) {
if(!WiFi.enableAP(true)) {
// enable AP failed
DEBUG_WIFI("[AP] enableAP failed!\n");
return false;
}
// ruh roh NOT SO FAST!, mode still not AP here! |
So the workaround to wait for opmode to be set to the real value is always working ? I'm not saying that the workaround should be used or adopted, but if it works, that information would help debugging (here or for espressif's SDK). |
It appears to be, yes ESP8266WiFiGenericClass::mode() while(wifi_get_opmode() != (uint8) m){
yield();
} |
I am not seeing this anymore, it just takes 30-50micros now, it was 6,000+ before
I will close after real testing |
yup |
Please share when your reproducing sketch is ready |
I will , forgot all about it, needed a break from this issue..lol |
#include "ESP8266WiFi.h"
// #include "user_interface.h"
extern "C" {
#include "user_interface.h"
}
const char SSID[] = "SSID";
const char PSK[] = "";
unsigned long sinceSerialPrint = 0;
unsigned long lastChange = 0;
void setup() {
Serial.begin(115200);
delay(3000);
Serial.setDebugOutput(true);
WiFi.printDiag(Serial);
// WiFi.persistent(true);
// WiFi.mode(WIFI_STA);
// // ESP.eraseConfig();
// // WiFi.begin(SSID,PSK);
// int intvl = 0;
// if(WiFi.SSID() != ""){
// while(WiFi.status() != WL_CONNECTED && intvl<10)
// {
// delay(500);
// Serial.print(".");
// intvl++;
// }
// Serial.println(WiFi.localIP());
// }
// lastChange = millis();
}
void debugSoftAPConfig(){
softap_config config;
wifi_softap_get_config(&config);
Serial.println(F("SoftAP Configuration"));
Serial.println(F("-----------------------------"));
Serial.print(F("ssid: "));Serial.println((char *) config.ssid);
Serial.print(F("password: "));Serial.println((char *) config.password);
Serial.print(F("ssid_len: "));Serial.println(config.ssid_len);
Serial.print(F("channel: "));Serial.println(config.channel);
Serial.print(F("authmode: "));Serial.println(config.authmode);
Serial.print(F("ssid_hidden: "));Serial.println(config.ssid_hidden);
Serial.print(F("max_connection: "));Serial.println(config.max_connection);
Serial.print(F("beacon_interval: "));Serial.println((String)config.beacon_interval + "(ms)");
Serial.println(F("-----------------------------"));
}
void doBreakAP(){
// run 1
Serial.println(!WiFi.softAP("esptestap") ? "SET AP FAILED !!!!!!!!!!!!" : "SET AP SUCCESS");
debugSoftAPConfig();
delay(500);
Serial.println(WiFi.softAPdisconnect(true));
delay(500);
WiFi.mode(WIFI_STA);
// run 2
delay(500);
Serial.println(!WiFi.softAP("esptestap") ? "SET AP FAILED !!!!!!!!!!!!" : "SET AP SUCCESS");
debugSoftAPConfig();
delay(500);
Serial.println(WiFi.softAPdisconnect(true));
delay(500);
WiFi.mode(WIFI_STA);
}
void loop() {
//if (millis() - sinceSerialPrint > 1000) {
// Serial.print(F("WiFi Status: "));
// Serial.print(WiFi.status());
// Serial.print(F(" - last change: "));
// Serial.println((long)(lastChange - millis()));
// sinceSerialPrint = millis();
// }
#define DO(x...) Serial.println(F( #x )); x; lastChange=millis(); break
if (Serial.available())
{
switch (Serial.read())
{
case 'd': DO(WiFi.disconnect());
case 'b': DO(WiFi.begin());
case 'B': DO(WiFi.begin(SSID, PSK));
case 'r': DO(WiFi.reconnect());
case 'c': DO(wifi_station_connect());
case 'a': DO(WiFi.setAutoReconnect(false));
case 'A': DO(WiFi.setAutoReconnect(true));
case 'n': DO(WiFi.setSleepMode(WIFI_NONE_SLEEP));
case 'l': DO(WiFi.setSleepMode(WIFI_LIGHT_SLEEP));
case 'm': DO(WiFi.setSleepMode(WIFI_MODEM_SLEEP));
case 'p': DO(WiFi.printDiag(Serial));
case 'P': DO(debugSoftAPConfig());
case 'E': DO(ESP.eraseConfig());
case 'R': DO(ESP.restart());
// TEST
case '1': DO(WiFi.mode(WIFI_STA));
case '2': DO(WiFi.begin(SSID, PSK));
case '3': DO(doBreakAP());
}
}
}
// OPTIONAL E // erase config, R restart
// 1 // mode WIFI_STA
// 2 // begin STA real ssid (MUST EXIST and CONNECT)
// 3 // run test ( should say [AP] set_config failed! )
// 3 // may have to run test again if necessary to get failure Out
|
softap struct may or may not exception out, it depends, usually it just fails to start ap at least in this test |
This is still a problem I think
|
I wonder if the reproduction problems has to do with autoreconnect... |
Demo sketch still works, bug still exists. |
Nope not affected by autoconnect or reconnect |
@tablatronix thanks for the feedback. @d-a-v is out for a few days, but any additional info you find in the meantime can help. |
I can reproduce a problem I believe is related to this. When using persistence false, when the mode is switched to AP, calling AP config will not work correctly. First, make sure to set the IDE to erase wifi config on upload. Then set the persistent to false. At some point...
While the AP will be started, it will not be the SSID passed in. Add a simple wait for getMode after the mode call like this....
and the correct AP is actived |
sounds like the same issue, just in a different flow, there are several places in the code that use a similar action of setting mode and using return value true, or just assuming mode has changed. |
This rings a bell for what I have observed in my own app from time to time: bringing up the AP and immediately configuring it will fail sometimes. Adding a delay(10) will fix it for me. |
Yup, its still an issue and definitely a race condition in esp lib, but probably some async state in sdk |
@tablatronix I like your solution of: while(wifi_get_opmode() != (uint8) m){
yield();
} But it could get stuck forever. //only wait if in CONT context. If this were called from SYS, it's up to the user to serialize correctly.
if(cont_can_yield()) {
oneshot timeout(1000);
while(wifi_get_opmode() != (uint8) m && !timeout)
delay(5);
//if at this point mode still not reached, disconnect and give up
if(wifi_get_opmode() != (uint8) m) {
disconnect();
return DISCONNECTED; //or maybe a new TIMEOUT or something
}
} |
Yeah it needs a real solution, that was a workaround for testing my proof. |
I would push this upstream to sdk and see if they know why it does this. I mean there is a return value! Heh |
They can't wait for the mode change by yielding or delaying like we do. They'd have to set up a periodic timer that queues a task that runs the check, then calls some callback, or something along those lines. I don't want to add complexity to the sdk libs, our workaround is minor enough. |
Sounds good, I bet this workaround would fix alot of edge case issues that have never been identified. Worth testing |
Hmm I've getting reports about ESPEasy starting AP mode even though it is connected to another AP and working fine. I've looked at the code to set the wifi mode and it claims to be using a timeout of 1 sec (in the comments), but it looks like it is only using a timeout of 1 msec (1000 usec) constexpr unsigned int timeoutValue = 1000; //1 second
if(can_yield()) {
using oneShot = esp8266::polledTimeout::oneShotFastUs; What should it be? 1 msec sounds a bit short. |
@TD-er Do you have an example scenario for reproducing this? |
Typo from me. The polledTimeout should be oneShotFastMs. |
Basic Infos
Hardware
Hardware: ESP-12?
Core Version: staging
Description
Let me know if this sounds familiar or like a known issue or something
I am having an issue with mode, I am setting mode and it returns true, but the mode does not actually change
I will try to produce a sketch, it is very odd, does anyone know how I can debug this further, from my understanding this sounds like an SDK bug (or memory bounds issue?), but maybe I am missing something or we are missing some crucial check before wifi_set_opmode_current().
I am (essentially) doing this
which is essentially
lots of boom here (enableSTA, enableAP all fail catastrophically
since there is no sanity checks here, since they return true must be true,
so set config struct blows up )
Could this be a memory issue, where is this memory ?
Settings in IDE
Module: ?Generic ESP8266 Module?
Flash Size: ?4MB/1MB?
CPU Frequency: ?80Mhz?
Flash Mode: ?qio?
Flash Frequency: ?40Mhz?
Upload Using: ?OTA / SERIAL?
Reset Method: ?ck / nodemcu?
The text was updated successfully, but these errors were encountered: