Embedded ESP-IDF wifi事件环路即使在代码回滚后也会继续接收系统\u事件\u STA\u WPS\u ER\u PIN

Embedded ESP-IDF wifi事件环路即使在代码回滚后也会继续接收系统\u事件\u STA\u WPS\u ER\u PIN,embedded,esp32,esp-idf,Embedded,Esp32,Esp Idf,我一直在使用ESP32和ESP-IDF进行一个项目,该项目将在启动网络堆栈之前检查其NVS内存中的wifi凭据。如果它有上述凭据,它将以STA模式连接到wifi网络,如果没有凭据,它将作为自己的AP启动,以允许用户通过HTTP向其发送凭据 在手动将测试凭证放入NVS后,我开始编写AP代码。完成所有AP代码和逻辑后,我用esptool手动擦除闪存,以强制板以该模式启动。这样做效果很好,我能够通过HTTP向它发送更新的凭据 此时,电路板试图在复位时连接为STA,但是wifi事件环路一直捕捉到系统事件

我一直在使用ESP32和ESP-IDF进行一个项目,该项目将在启动网络堆栈之前检查其NVS内存中的wifi凭据。如果它有上述凭据,它将以STA模式连接到wifi网络,如果没有凭据,它将作为自己的AP启动,以允许用户通过HTTP向其发送凭据

在手动将测试凭证放入NVS后,我开始编写AP代码。完成所有AP代码和逻辑后,我用esptool手动擦除闪存,以强制板以该模式启动。这样做效果很好,我能够通过HTTP向它发送更新的凭据

此时,电路板试图在复位时连接为STA,但是wifi事件环路一直捕捉到
系统事件\u STA\u WPS\u ER\u PIN
事件。此后,董事会仅经历了这一事件,并且从那时起完全无法连接到wifi。更奇怪的是,即使使用git回滚到以前的版本,问题仍然存在

main.c

void app_main() {

    // Start NVS
    initNVS();
    // Init Wifi Controller
    initWifiController();
    // Get Credentials to send to wifi
    Creds creds = getCreds();
    // Start wifi in STA mode with gathered creds
    beginWifi(creds);

    initializePins();
    initializeTimers();
}
void initWifiController(){
    // * NVS must be initialized before wifi work can be done
    // Handle when connected to the network
    connectionSemaphore = xSemaphoreCreateBinary();
    // Begin network stack
    ESP_ERROR_CHECK(esp_netif_init());
    // Create event loop for handling callbacks
    ESP_ERROR_CHECK(esp_event_loop_create_default());
}

void beginWifi(Creds creds){
    if(creds.status == ESP_OK){
        ESP_LOGI(TAG, "Connection credentials have been found, connecting to network");
        connectSTA(creds);
    }
    else if(creds.status == ESP_ERR_NVS_NOT_FOUND){
        ESP_LOGW(TAG, "Missing credentials, starting as AP");
        connectAP();
    }
    else{
        ESP_LOGE(TAG, "ESP failed with error %s, not starting wifi", esp_err_to_name(creds.status));
    }

void connectSTA(Creds creds){
    
    ESP_LOGI(TAG, "Attempting to connect to wifi with following creds: %s | %s", creds.ssid, creds.pass);
    // Set netif to sta
    esp_netif_create_default_wifi_sta();

    // Prepare and initialize wifi_init_config_t
    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));

    // Register tracked events for event_handler
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));

    // TODO: Check if this can be used to avoid havng to use NVS manually
    esp_wifi_set_storage(WIFI_STORAGE_RAM);

    // Config struct for wifi details
    wifi_config_t wifi_config = {};

    // Copy casted info into wifi_config
    // * https://www.esp32.com/viewtopic.php?f=13&t=14611
    // * See above link for details on this
    strcpy((char *)wifi_config.sta.ssid, creds.ssid);
    strcpy((char *)wifi_config.sta.password, creds.pass);

    esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);

    ESP_ERROR_CHECK(esp_wifi_start());

    // ? Is this required to avoid a memory leak?
    free(creds.pass);
    free(creds.ssid);
}
void connectAP(){
    // ? How important is it that these be called in this order?
    ESP_LOGI(TAG, "Starting in AP Mode");
    esp_netif_create_default_wifi_ap();
    // TODO: maybe move this creation to initWifiController to avoid making it twice
    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
    
    // TODO: Consider moving this to init Wifi Controller to avoid running it twice as well
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

    // Configuration for AP
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = "Grow System",
            .password = "Password",
            .ssid_len = strlen("Grow System"),
            .max_connection = 4,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        }
    };

    // TODO: Enable password support on AP configuration

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "Wifi connectAP finished");
    registerEndPoints();
}
wifiController.c

void app_main() {

    // Start NVS
    initNVS();
    // Init Wifi Controller
    initWifiController();
    // Get Credentials to send to wifi
    Creds creds = getCreds();
    // Start wifi in STA mode with gathered creds
    beginWifi(creds);

    initializePins();
    initializeTimers();
}
void initWifiController(){
    // * NVS must be initialized before wifi work can be done
    // Handle when connected to the network
    connectionSemaphore = xSemaphoreCreateBinary();
    // Begin network stack
    ESP_ERROR_CHECK(esp_netif_init());
    // Create event loop for handling callbacks
    ESP_ERROR_CHECK(esp_event_loop_create_default());
}

void beginWifi(Creds creds){
    if(creds.status == ESP_OK){
        ESP_LOGI(TAG, "Connection credentials have been found, connecting to network");
        connectSTA(creds);
    }
    else if(creds.status == ESP_ERR_NVS_NOT_FOUND){
        ESP_LOGW(TAG, "Missing credentials, starting as AP");
        connectAP();
    }
    else{
        ESP_LOGE(TAG, "ESP failed with error %s, not starting wifi", esp_err_to_name(creds.status));
    }

void connectSTA(Creds creds){
    
    ESP_LOGI(TAG, "Attempting to connect to wifi with following creds: %s | %s", creds.ssid, creds.pass);
    // Set netif to sta
    esp_netif_create_default_wifi_sta();

    // Prepare and initialize wifi_init_config_t
    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));

    // Register tracked events for event_handler
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));

    // TODO: Check if this can be used to avoid havng to use NVS manually
    esp_wifi_set_storage(WIFI_STORAGE_RAM);

    // Config struct for wifi details
    wifi_config_t wifi_config = {};

    // Copy casted info into wifi_config
    // * https://www.esp32.com/viewtopic.php?f=13&t=14611
    // * See above link for details on this
    strcpy((char *)wifi_config.sta.ssid, creds.ssid);
    strcpy((char *)wifi_config.sta.password, creds.pass);

    esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);

    ESP_ERROR_CHECK(esp_wifi_start());

    // ? Is this required to avoid a memory leak?
    free(creds.pass);
    free(creds.ssid);
}
void connectAP(){
    // ? How important is it that these be called in this order?
    ESP_LOGI(TAG, "Starting in AP Mode");
    esp_netif_create_default_wifi_ap();
    // TODO: maybe move this creation to initWifiController to avoid making it twice
    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
    
    // TODO: Consider moving this to init Wifi Controller to avoid running it twice as well
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

    // Configuration for AP
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = "Grow System",
            .password = "Password",
            .ssid_len = strlen("Grow System"),
            .max_connection = 4,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        }
    };

    // TODO: Enable password support on AP configuration

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "Wifi connectAP finished");
    registerEndPoints();
}
代码本质上是检查NVS的凭据,如果找到它们,则返回一个包含这两个凭据以及
ESP\u OK
的结构。如果其中一个未找到,则结构将包含
ESP\u ERR\u NVS\u not\u found
wifiController.c
然后接收此
creds
结构并调用
beginWifi()
,然后根据结构的
状态调用
connectSTA()
connectAP()
。当凭据存在时,调用
connectSTA()
,但由于未知原因,事件循环始终只接收
SYSTEM\u event\u STA\u WPS\u ER\u PIN
事件。正如我前面提到的,即使将代码回滚到没有
connectAP()
函数的版本,这种行为仍然存在

因此,我有一种预感,这个问题可能与我手动擦除闪存时有关,而不是与代码有关

头文件的typedef中包含以下行以定义此事件

SYSTEM_EVENT_STA_WPS_ER_PIN,           /*!< ESP32 station wps pin code in enrollee mode */
SYSTEM\u EVENT\u STA\u WPS\u ER\u PIN,/*!
我不知道这意味着什么,因为我没有故意在这个项目中包含任何关于wps的内容


到目前为止,我的研究还没有得到任何令人难以置信的有用信息,因此如果有人知道什么是
系统事件
,或者什么可能导致我的问题,我将非常感激。如果您认为更多细节有助于解决此问题,请告诉我,我将非常乐意提供。

有助于解决此问题。 我正在学习使用ESP32 wifi,查看您的邮件,ESP idf和ESP-32技术手册。没有多少信息,我找到了这个URI

问候


更新:对照示例地图中的sdkconfig文件检查项目地图中的sdkconfig文件,查看wifi配置设置。

我已经深入研究这个问题好几天了,我还没有找到根本原因,但已经找到了一个解决方法和有关该问题的一些详细信息。持续出现的
SYSTEM\u EVENT\u STA\u WPS\u ER\u PIN
事件实际上是由芯片试图使用WPS注册PIN模式连接到路由器引起的。据推测,这会产生一个八位数长的pin,可以放入路由器,让它能够连接。我真的不知道它为什么这样做,但我相信这可能与我如何设置AP模式有关。我现在主要的困惑是为什么回滚代码并没有修复它

对于“解决方法”,我发现闪动Espressif的示例STA wifi连接代码成功地解决了这个问题。芯片一旦闪现,就正确地连接到了我的网络,我可以重新刷新自己的代码,而不会出现任何问题。这对我来说似乎非常奇怪,所以我的一部分人认为可能芯片因为某种原因无法连接到我的网络,代码中的一个边缘案例导致它进入了注册模式

以下是我用来“修复”问题的代码的链接:

我会将此答案标记为正确,并继续查找根本问题。如果其他人知道这可能是什么原因,请随时发布,我将更新正确答案。如果我发现了根本问题,我也会更新这个答案


编辑:在继续挖掘之后,我认为问题实际上是由于我的代码中存在大量错误造成的。特别是,我打电话给esp\u netif\u create\u default\u wifi\u sta()
,然后没有设置WI-FI模式。我需要添加
esp\u wifi\u set\u mode(wifi\u mode\u STA)
,这在我的程序中是不存在的。我相信在不改变wifi模式的情况下将网络堆栈设置为sta是导致我的问题的原因。

虽然链接的文档可能有用,但其中的摘录或解决原始问题的摘要将更有用。