Skip to content

Commit

Permalink
Rework the WiFi start and stop sequences. (#1804)
Browse files Browse the repository at this point in the history
Delay the call to esp_wifi_connect() until we've been told that the WiFi
has started.

Remember to call esp_wifi_disconnect() if we're connected when the WiFi
is being torn down.
  • Loading branch information
kasperl authored Sep 13, 2023
1 parent ec47005 commit 6366905
Showing 1 changed file with 92 additions and 49 deletions.
141 changes: 92 additions & 49 deletions src/resources/wifi_esp32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,16 @@ class WifiResourceGroup : public ResourceGroup {
err = esp_wifi_set_config(WIFI_IF_STA, &config);
if (err != ESP_OK) return err;

err = esp_wifi_start();
if (err != ESP_OK) return err;

// When connecting to Android mobile hotspot APs, we
// quite often get WIFI_REASON_AUTH_FAIL followed by
// WIFI_REASON_CONNECTION_FAIL. The next connect still
// has a good chance of succeeding, so we allow two
// reconnect attempts.
reconnects_remaining_ = 2;
return esp_wifi_connect();

// Request to start the WiFi stack. We will try to connect to
// the network when we get the WIFI_EVENT_STA_START callback.
return esp_wifi_start();
}

esp_err_t establish(const char* ssid, const char* password, bool broadcast, int channel) {
Expand Down Expand Up @@ -156,36 +156,17 @@ class WifiResourceGroup : public ResourceGroup {
~WifiResourceGroup() {
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] ~WifiResourceGroup()\n");
printf("[wifi] esp_wifi_deinit()\n");
#endif
esp_err_t err = esp_wifi_deinit();
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_deinit() -> done\n");
#endif
if (err == ESP_ERR_WIFI_NOT_STOPPED) {
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_stop()\n");
#endif
FATAL_IF_NOT_ESP_OK(esp_wifi_stop());
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_stop() -> done\n");
printf("[wifi] esp_wifi_deinit()\n");
#endif
FATAL_IF_NOT_ESP_OK(esp_wifi_deinit());
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_deinit() -> done\n");
#endif
} else {
FATAL_IF_NOT_ESP_OK(err);
}

#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_netif_destroy_default_wifi()\n");
printf("[wifi] esp_wifi_deinit()\n");
#endif
esp_netif_destroy_default_wifi(netif_);
esp_err_t err = esp_wifi_deinit();
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_netif_destroy_default_wifi() -> done\n");
printf("[wifi] esp_wifi_deinit() -> done: %d\n", err);
#endif
FATAL_IF_NOT_ESP_OK(err);
esp_netif_destroy_default_wifi(netif_);
wifi_pool.put(id_);
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] ~WifiResourceGroup() -> done\n");
Expand Down Expand Up @@ -219,21 +200,63 @@ class WifiResourceGroup : public ResourceGroup {

class WifiEvents : public SystemResource {
public:
enum State {
STOPPED,
STARTED,
CONNECTED
};

TAG(WifiEvents);
explicit WifiEvents(WifiResourceGroup* group)
: SystemResource(group, WIFI_EVENT)
, disconnect_reason_(WIFI_REASON_UNSPECIFIED) {}
, disconnect_reason_(WIFI_REASON_UNSPECIFIED)
, state_(STOPPED) {}

~WifiEvents() {
FATAL_IF_NOT_ESP_OK(esp_wifi_stop());
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] ~WifiEvents()\n");
#endif
State state = this->state();
if (state >= CONNECTED) {
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_disconnect\n");
#endif
esp_err_t err = esp_wifi_disconnect();
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_disconnect() -> done: %d\n", err);
#endif
FATAL_IF_NOT_ESP_OK(err);
}
if (state >= STARTED) {
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_stop()\n");
#endif
esp_err_t err = esp_wifi_stop();
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] esp_wifi_stop() -> done: %d\n", err);
#endif
FATAL_IF_NOT_ESP_OK(err);
}
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] ~WifiEvents() -> done\n");
#endif
}

uint8 disconnect_reason() const { return disconnect_reason_; }
void set_disconnect_reason(uint8 reason) { disconnect_reason_ = reason; }

State state() const { return state_; }
void set_state(State state) {
#if CONFIG_WPA_DEBUG_PRINT
printf("[wifi] state updated: %d->%d\n", state_, state);
#endif
state_ = state;
}

private:
friend class WifiResourceGroup;
uint8 disconnect_reason_;
State state_;
};

class WifiIpEvents : public SystemResource {
Expand All @@ -245,17 +268,21 @@ class WifiIpEvents : public SystemResource {

uint32 WifiResourceGroup::on_event_wifi(Resource* resource, word data, uint32 state) {
SystemEvent* system_event = reinterpret_cast<SystemEvent*>(data);
WifiEvents* events = static_cast<WifiEvents*>(resource);

switch (system_event->id) {
case WIFI_EVENT_STA_CONNECTED:
case WIFI_EVENT_STA_CONNECTED: {
events->set_state(WifiEvents::CONNECTED);
reconnects_remaining_ = 0;
state |= WIFI_CONNECTED;
cache_wifi_channel();
break;
}

case WIFI_EVENT_STA_DISCONNECTED: {
events->set_state(WifiEvents::STARTED);
uint8 reason = reinterpret_cast<wifi_event_sta_disconnected_t*>(system_event->event_data)->reason;
static_cast<WifiEvents*>(resource)->set_disconnect_reason(reason);
events->set_disconnect_reason(reason);

bool reconnect = false;
uint32 outcome = WIFI_DISCONNECTED;
Expand Down Expand Up @@ -292,16 +319,30 @@ uint32 WifiResourceGroup::on_event_wifi(Resource* resource, word data, uint32 st
break;
}

case WIFI_EVENT_STA_START:
case WIFI_EVENT_STA_STOP:
case WIFI_EVENT_STA_START: {
events->set_state(WifiEvents::STARTED);
// If connecting fails here, we do not want to retry
// because something is seriously wrong. We let the
// higher level code know that we're disconnected and
// clean up from there.
if (esp_wifi_connect() != ESP_OK) {
reconnects_remaining_ = 0;
state |= WIFI_DISCONNECTED;
}
break;
}

case WIFI_EVENT_STA_STOP: {
events->set_state(WifiEvents::STOPPED);
break;
}

case WIFI_EVENT_SCAN_DONE: {
state |= WIFI_SCAN_DONE;
break;
}

case WIFI_EVENT_STA_BEACON_TIMEOUT:
case WIFI_EVENT_STA_BEACON_TIMEOUT: {
// The beacon timeout mechanism is used by ESP32 station to detect whether the AP
// is alive or not. If the station continuously loses 60 beacons of the connected
// AP, the beacon timeout happens.
Expand All @@ -310,26 +351,29 @@ uint32 WifiResourceGroup::on_event_wifi(Resource* resource, word data, uint32 st
// still no probe response or beacon is received from AP, the station disconnects
// from the AP and raises the WIFI_EVENT_STA_DISCONNECTED event.
break;
}

case WIFI_EVENT_AP_START:
case WIFI_EVENT_AP_START: {
events->set_state(WifiEvents::STARTED);
state |= WIFI_CONNECTED;
break;
}

case WIFI_EVENT_AP_STOP:
case WIFI_EVENT_AP_STOP: {
events->set_state(WifiEvents::STOPPED);
state |= WIFI_DISCONNECTED;
break;
}

case WIFI_EVENT_AP_STACONNECTED:
case WIFI_EVENT_AP_STADISCONNECTED: {
break;
}

case WIFI_EVENT_AP_STADISCONNECTED:
default: {
printf("[wifi] unhandled Wi-Fi event: %" PRId32 "\n", system_event->id);
break;

default:
printf(
"unhandled Wi-Fi event: %" PRId32 "\n",
system_event->id
);
}
}

return state;
Expand All @@ -354,11 +398,10 @@ uint32 WifiResourceGroup::on_event_ip(Resource* resource, word data, uint32 stat
break;
}

default:
printf(
"unhandled IP event: %" PRId32 "\n",
system_event->id
);
default: {
printf("[wifi] unhandled IP event: %" PRId32 "\n", system_event->id);
break;
}
}

return state;
Expand Down

0 comments on commit 6366905

Please sign in to comment.