cpu/esp_common: stop WiFi interface before sleep/reboot

The WiFi interface should be stopped before reboot or sleep. But stopping the WiFi interface disconnects an existing connection. Usually, esp_wifi_netdev tries to reconnect on an disconnect event. However, trying reconnect with a stopped WiFi interface may lead to a crash. Therefore, the stop event has to be handled.
This commit is contained in:
Gunar Schorcht 2020-03-23 12:33:45 +01:00
parent 09899e4b8d
commit 4f977316fe
2 changed files with 51 additions and 12 deletions

View File

@ -34,6 +34,23 @@
#include "soc/rtc.h" #include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_reg.h"
static inline esp_sleep_wakeup_cause_t pm_get_wakeup_cause(void)
{
return esp_sleep_get_wakeup_cause();
}
/* function that is required by pm_set if esp_now and esp_wifi are not used */
esp_err_t __attribute__((weak)) esp_wifi_start(void)
{
return ESP_OK;
}
/* function that is required by pm_set if esp_now and esp_wifi are not used */
esp_err_t __attribute__((weak)) esp_wifi_stop(void)
{
return ESP_OK;
}
static inline void pm_set_lowest_normal(void) static inline void pm_set_lowest_normal(void)
{ {
/* reset system watchdog timer */ /* reset system watchdog timer */
@ -65,6 +82,11 @@ void pm_reboot(void)
{ {
DEBUG ("%s\n", __func__); DEBUG ("%s\n", __func__);
if (IS_USED(MODULE_ESP_WIFI_ANY)) {
/* stop WiFi if necessary */
esp_wifi_stop();
}
/* suspend and flush UARTs */ /* suspend and flush UARTs */
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
@ -121,6 +143,10 @@ void pm_set(unsigned mode)
UNREACHABLE(); UNREACHABLE();
} }
else if (mode == ESP_PM_LIGHT_SLEEP) { else if (mode == ESP_PM_LIGHT_SLEEP) {
if (IS_USED(MODULE_ESP_WIFI_ANY)) {
/* stop WiFi if necessary */
esp_wifi_stop();
}
esp_light_sleep_start(); esp_light_sleep_start();
@ -130,6 +156,10 @@ void pm_set(unsigned mode)
DEBUG ("%s exit from power mode %d @%u with reason %d\n", __func__, DEBUG ("%s exit from power mode %d @%u with reason %d\n", __func__,
mode, system_get_time(), wakeup_reason); mode, system_get_time(), wakeup_reason);
/* restart WiFi if necessary */
if (IS_USED(MODULE_ESP_WIFI_ANY) && (esp_wifi_start() != ESP_OK)) {
LOG_ERROR("esp_wifi_start failed\n");
} }
} }
} }

View File

@ -398,6 +398,8 @@ static const char *_esp_wifi_disc_reasons [] = {
"HANDSHAKE_TIMEOUT" /* 204 */ "HANDSHAKE_TIMEOUT" /* 204 */
}; };
static unsigned _esp_wifi_started = 0;
/* /*
* Event handler for esp system events. * Event handler for esp system events.
*/ */
@ -412,6 +414,7 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
switch(event->event_id) { switch(event->event_id) {
case SYSTEM_EVENT_STA_START: case SYSTEM_EVENT_STA_START:
_esp_wifi_started = 1;
ESP_WIFI_DEBUG("WiFi started"); ESP_WIFI_DEBUG("WiFi started");
result = esp_wifi_connect(); result = esp_wifi_connect();
if (result != ESP_OK) { if (result != ESP_OK) {
@ -420,6 +423,11 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
} }
break; break;
case SYSTEM_EVENT_STA_STOP:
_esp_wifi_started = 0;
ESP_WIFI_DEBUG("WiFi stopped");
break;
case SYSTEM_EVENT_SCAN_DONE: case SYSTEM_EVENT_SCAN_DONE:
ESP_WIFI_DEBUG("WiFi scan done"); ESP_WIFI_DEBUG("WiFi scan done");
break; break;
@ -457,19 +465,20 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
_esp_wifi_dev.event_disc++; _esp_wifi_dev.event_disc++;
netdev_trigger_event_isr(&_esp_wifi_dev.netdev); netdev_trigger_event_isr(&_esp_wifi_dev.netdev);
/* call disconnect to reset internal state */ if (reason != WIFI_REASON_ASSOC_LEAVE) {
result = esp_wifi_disconnect(); /* call disconnect to reset internal state */
if (result != ESP_OK) { result = esp_wifi_disconnect();
ESP_WIFI_LOG_ERROR("esp_wifi_disconnect failed with " if (result != ESP_OK) {
"return value %d", result); ESP_WIFI_LOG_ERROR("esp_wifi_disconnect failed with "
return result; "return value %d", result);
} return result;
}
/* try to reconnect */ /* try to reconnect */
result = esp_wifi_connect(); if (_esp_wifi_started && ((result = esp_wifi_connect()) != ESP_OK)) {
if (result != ESP_OK) { ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with "
ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with " "return value %d", result);
"return value %d", result); }
} }
break; break;