From e79c5ed9dbfe602085dbb02ebc561751eca70c76 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 12 Jun 2026 22:08:01 +0500 Subject: [PATCH 1/3] make wifi drive connect asynchronous --- aether/access_points/wifi_access_point.cpp | 62 ++- aether/access_points/wifi_access_point.h | 23 +- aether/adapters/wifi_adapter.cpp | 2 +- aether/channels/wifi_channel.cpp | 4 +- aether/wifi/esp_wifi_driver.cpp | 528 ++++++++++++--------- aether/wifi/esp_wifi_driver.h | 70 ++- aether/wifi/wifi_driver.h | 24 +- aether/wifi/wifi_driver_factory.cpp | 7 +- aether/wifi/wifi_driver_factory.h | 3 +- aether/wifi/wifi_driver_types.h | 8 +- 10 files changed, 444 insertions(+), 287 deletions(-) diff --git a/aether/access_points/wifi_access_point.cpp b/aether/access_points/wifi_access_point.cpp index 21a81c4c..38f4a32e 100644 --- a/aether/access_points/wifi_access_point.cpp +++ b/aether/access_points/wifi_access_point.cpp @@ -27,19 +27,24 @@ # include "aether/channels/wifi_channel.h" # include "aether/access_points/filter_endpoints.h" +# include "aether/tele/tele.h" + namespace ae { -WifiConnectAction::WifiConnectAction(AeContext const& ae_context, - WifiDriver& driver, WiFiAp wifi_ap, - WiFiPowerSaveParam psp, - WiFiBaseStation& base_station) +WifiConnectAction::WifiConnectAction( + AeContext const& ae_context, WifiAccessPoint& access_point, + WifiDriver& driver, WiFiAp wifi_ap, std::optional psp, + std::optional base_station) : ae_context_{ae_context}, + access_point_{&access_point}, driver_{&driver}, wifi_ap_{std::move(wifi_ap)}, psp_{std::move(psp)}, - base_station_{base_station}, + base_station_{std::move(base_station)}, scheduler_sub_{ - ae_context_.scheduler().Task([this]() { EnsureConnected(); })} {} + ae_context_.scheduler().Task([this]() { EnsureConnected(); })} { + AE_TELED_DEBUG("WifiConnectAction created"); +} WifiConnectAction::ConnectionEvent::Subscriber WifiConnectAction::connection_event() { @@ -48,10 +53,37 @@ WifiConnectAction::connection_event() { void WifiConnectAction::EnsureConnected() { auto connected_to = driver_->connected_to(); - if (connected_to.ssid != wifi_ap_.creds.ssid) { - driver_->Connect(wifi_ap_, psp_, base_station_); + AE_TELED_DEBUG("Driver connected to {}", connected_to.value_or("NOT CONNECTED")); + // if already connected + if (connected_to && (*connected_to == wifi_ap_.creds.ssid)) { + SetConnected(true); + return; } - SetConnected(true); + Connect(); +} + +void WifiConnectAction::Connect() { + connect_sub_ = driver_->connect_res_event().Subscribe( + [&](Result&& res) { + connect_sub_.Reset(); + if (res) { + AE_TELED_INFO("Wifi connected"); + // save base station to access point + access_point_->SetWifiBaseStation(std::move(res).value()); + SetConnected(true); + } else { + // retry without base station + if (base_station_) { + base_station_.reset(); + scheduler_sub_ = ae_context_.scheduler().Task([&]() { Connect(); }); + return; + } + AE_TELED_ERROR("Wifi did not connected with error {}", res.error()); + SetConnected(false); + } + }); + + driver_->Connect(wifi_ap_, psp_, base_station_); } void WifiConnectAction::SetConnected(bool is_connected) { @@ -65,7 +97,7 @@ WifiAccessPoint::WifiAccessPoint(ObjProp prop, ObjPtr aether, ObjPtr adapter, ObjPtr poller, ObjPtr resolver, WiFiAp wifi_ap, - WiFiPowerSaveParam psp) + std::optional psp) : AccessPoint{prop}, aether_{std::move(aether)}, adapter_{std::move(adapter)}, @@ -105,8 +137,8 @@ WifiConnectAction& WifiAccessPoint::Connect() { [](auto const& a) { return &a->driver(); }); assert(driver.has_value()); - connect_action_.emplace(*aether_.Load().as(), **driver, wifi_ap_, - psp_, base_station_); + connect_action_.emplace(*aether_.Load().as(), *this, **driver, + wifi_ap_, psp_, base_station_); } return *connect_action_; } @@ -116,9 +148,13 @@ bool WifiAccessPoint::IsConnected() { .WithLoaded([this](auto const& a) { auto& driver = a->driver(); auto connected_to = driver.connected_to(); - return connected_to.ssid == wifi_ap_.creds.ssid; + return connected_to && (*connected_to == wifi_ap_.creds.ssid); }) .value_or(false); } + +void WifiAccessPoint::SetWifiBaseStation(WiFiBaseStation&& wifi_base_station) { + base_station_.emplace(std::move(wifi_base_station)); +} } // namespace ae #endif diff --git a/aether/access_points/wifi_access_point.h b/aether/access_points/wifi_access_point.h index 79ff4112..05765df2 100644 --- a/aether/access_points/wifi_access_point.h +++ b/aether/access_points/wifi_access_point.h @@ -35,28 +35,33 @@ class Aether; class WifiAdapter; class IPoller; class DnsResolver; +class WifiAccessPoint; class WifiConnectAction final : public Action { public: using ConnectionEvent = Event; - WifiConnectAction(AeContext const& ae_context, WifiDriver& driver, - WiFiAp wifi_ap, WiFiPowerSaveParam psp, - WiFiBaseStation& base_station); + WifiConnectAction(AeContext const& ae_context, WifiAccessPoint& access_point, + WifiDriver& driver, WiFiAp wifi_ap, + std::optional psp, + std::optional base_station); ConnectionEvent::Subscriber connection_event(); private: void EnsureConnected(); + void Connect(); void SetConnected(bool is_connected); AeContext ae_context_; + WifiAccessPoint* access_point_; WifiDriver* driver_; WiFiAp wifi_ap_; - WiFiPowerSaveParam psp_; - WiFiBaseStation& base_station_; + std::optional psp_; + std::optional base_station_; ConnectionEvent connection_event_; TaskSubscription scheduler_sub_; + Subscription connect_sub_; }; class WifiAccessPoint final : public AccessPoint { @@ -67,7 +72,7 @@ class WifiAccessPoint final : public AccessPoint { WifiAccessPoint(ObjProp prop, ObjPtr aether, ObjPtr adapter, ObjPtr poller, ObjPtr resolver, WiFiAp wifi_ap, - WiFiPowerSaveParam psp); + std::optional psp); AE_OBJECT_REFLECT(AE_MMBRS(aether_, adapter_, poller_, resolver_, wifi_ap_, base_station_)) @@ -82,14 +87,16 @@ class WifiAccessPoint final : public AccessPoint { bool IsConnected(); + void SetWifiBaseStation(WiFiBaseStation&& wifi_base_station); + private: ObjPtr aether_; Obj::ptr adapter_; ObjPtr poller_; ObjPtr resolver_; WiFiAp wifi_ap_{}; - WiFiPowerSaveParam psp_{}; - WiFiBaseStation base_station_{}; + std::optional psp_; + std::optional base_station_; std::optional connect_action_; }; } // namespace ae diff --git a/aether/adapters/wifi_adapter.cpp b/aether/adapters/wifi_adapter.cpp index ba73b136..ce5e9cd9 100644 --- a/aether/adapters/wifi_adapter.cpp +++ b/aether/adapters/wifi_adapter.cpp @@ -56,7 +56,7 @@ std::vector WifiAdapter::access_points() { WifiDriver& WifiAdapter::driver() { if (!wifi_driver_) { - wifi_driver_ = WifiDriverFactory::CreateWifiDriver(); + wifi_driver_ = WifiDriverFactory::CreateWifiDriver(*aether_); } return *wifi_driver_; } diff --git a/aether/channels/wifi_channel.cpp b/aether/channels/wifi_channel.cpp index 63203e3d..2806c713 100644 --- a/aether/channels/wifi_channel.cpp +++ b/aether/channels/wifi_channel.cpp @@ -38,10 +38,10 @@ namespace wifi_channel_internal { ex::sender auto WifiConnect(Ptr const& access_point) { return ex::create( [ap{PtrView{access_point}}, - connect_sub{Subscription{}}](auto& ctx) mutable noexcept { + connect_sub_ = Subscription{}](auto& ctx) mutable noexcept { auto access_point = ap.Lock(); assert(access_point && "Wifi access point is not loaded"); - connect_sub = access_point->Connect().connection_event().Subscribe( + connect_sub_ = access_point->Connect().connection_event().Subscribe( [&](bool is_connected) mutable noexcept { if (is_connected) { ex::set_value(std::move(ctx.receiver)); diff --git a/aether/wifi/esp_wifi_driver.cpp b/aether/wifi/esp_wifi_driver.cpp index 6470b0bf..b2e1c913 100644 --- a/aether/wifi/esp_wifi_driver.cpp +++ b/aether/wifi/esp_wifi_driver.cpp @@ -28,10 +28,6 @@ # include "esp_system.h" # include "esp_private/wifi.h" -# include "freertos/task.h" -# include "freertos/FreeRTOS.h" -# include "freertos/event_groups.h" - # include "lwip/err.h" # include "lwip/sys.h" # include "lwip/ip4_addr.h" @@ -49,115 +45,189 @@ namespace ae { # define WIFI_CONNECTED_BIT BIT0 # define WIFI_FAIL_BIT BIT1 -struct ConnectionState { - EventGroupHandle_t event_group; - std::size_t retry_count{}; -}; - namespace esp_wifi_driver_internal { static constexpr int kMaxRetry = 10; void EventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, - void* event_data) { - ConnectionState* connection_state = static_cast(arg); - if ((event_base == WIFI_EVENT) && (event_id == WIFI_EVENT_STA_START)) { - esp_wifi_connect(); - } else if ((event_base == WIFI_EVENT) && - (event_id == WIFI_EVENT_STA_DISCONNECTED)) { - if (connection_state->retry_count < kMaxRetry) { - esp_wifi_connect(); - connection_state->retry_count++; - } else { - xEventGroupSetBits(connection_state->event_group, WIFI_FAIL_BIT); + [[maybe_unused]] void* event_data) { + auto base_type = [](esp_event_base_t event_base) { + if (event_base == WIFI_EVENT) { + return "WIFI_EVENT"; } - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - xEventGroupSetBits(connection_state->event_group, WIFI_CONNECTED_BIT); + if (event_base == IP_EVENT) { + return "IP_EVENT"; + } + return "UNKNOWN_EVENT"; + }; + + ESP_LOGI("EspWiFiEventHandler", "Event handler event_base %s event_id %d", + base_type(event_base), event_id); + + auto* driver = static_cast(arg); + switch (driver->connection_state_.state) { + case EspWifiDriver::State::kDisconnected: + driver->DisconnectedEventHandler(event_base, event_id, event_data); + break; + case EspWifiDriver::State::kDisconnecring: + driver->DisconnectingEventHandler(event_base, event_id, event_data); + break; + case EspWifiDriver::State::kConnecting: + driver->ConnectingEventHandler(event_base, event_id, event_data); + break; + case EspWifiDriver::State::kConnected: + driver->ConnectedEventHandler(event_base, event_id, event_data); + break; } } -} // namespace esp_wifi_driver_internal -int EspWifiDriver::initialized_ = 0; -void* EspWifiDriver::espt_init_sta_ = nullptr; +void SetupBssid(wifi_config_t& wifi_config, + WiFiBaseStation const& base_station) { + std::array debug_bssid; + memcpy(debug_bssid.data(), base_station.target_bssid, + sizeof(base_station.target_bssid)); + AE_TELED_DEBUG("Restored from cash BSSID:{} CHN:{}", debug_bssid, + static_cast(base_station.target_channel)); + + wifi_config.sta.scan_method = WIFI_FAST_SCAN; // Fast scan + wifi_config.sta.bssid_set = true; // Enable BSSID binding + wifi_config.sta.channel = base_station.target_channel; // Set channel + // Copy the BSSID to the configuration + memcpy(wifi_config.sta.bssid, base_station.target_bssid, + sizeof(base_station.target_bssid)); + ESP_ERROR_CHECK( + esp_wifi_set_channel(base_station.target_channel, WIFI_SECOND_CHAN_NONE)); +} -EspWifiDriver::EspWifiDriver() { - if (initialized_++ > 0) { - return; - } - Init(); +void SetupCredentials(wifi_config_t& wifi_config, WifiCreds const& creds) { +# ifdef DEBUG + // for debug purpose only, it's private data + AE_TELED_DEBUG("Connecting to ap SSID:{} PSWD:{}", creds.ssid, + creds.password); +# endif // DEBUG + + strncpy(reinterpret_cast(wifi_config.sta.ssid), creds.ssid.data(), + sizeof(wifi_config.sta.ssid)); + strncpy(reinterpret_cast(wifi_config.sta.password), + creds.password.data(), sizeof(wifi_config.sta.password)); } -EspWifiDriver::~EspWifiDriver() { - if (connected_to_) { - Disconnect(); +void MakeIp4Addr(esp_ip4_addr_t& to, IpV4Addr const& from) { + IP4_ADDR(&to, from.ipv4_value[0], from.ipv4_value[1], from.ipv4_value[2], + from.ipv4_value[3]); +} + +esp_err_t SetStaticIp(esp_netif_t* netif, WiFiIP const& config) { + esp_err_t err = ESP_OK; + +# if AE_SUPPORT_IPV4 == 1 + esp_netif_ip_info_t ip_info; + esp_netif_dns_info_t dns_info1; + esp_netif_dns_info_t dns_info2; + + // Conversion to IP addresses + memset(&ip_info, 0, sizeof(esp_netif_ip_info_t)); + memset(&dns_info1, 0, sizeof(esp_netif_dns_info_t)); + memset(&dns_info2, 0, sizeof(esp_netif_dns_info_t)); + + MakeIp4Addr(ip_info.ip, config.static_ip_v4); + MakeIp4Addr(ip_info.gw, config.gateway_v4); + MakeIp4Addr(ip_info.netmask, config.netmask_v4); + + if (config.primary_dns_v4) { + MakeIp4Addr(dns_info1.ip.u_addr.ip4, config.primary_dns_v4.value()); } - if (--initialized_ > 0) { - return; + if (config.secondary_dns_v4) { + MakeIp4Addr(dns_info2.ip.u_addr.ip4, config.secondary_dns_v4.value()); } - Deinit(); -} +# endif +# if AE_SUPPORT_IPV6 == 1 + if (config.static_ip_v6.has_value()) { + esp_netif_ip6_info_t ip_info_v6; -void EspWifiDriver::Connect(WiFiAp const& wifi_ap, - WiFiPowerSaveParam const& psp, - WiFiBaseStation& base_station) { - std::vector bssid_vector; + memset(&ip_info_v6, 0, sizeof(esp_netif_ip6_info_t)); - if (connected_to_) { - Disconnect(); + std::array ip6_parts{}; + for (auto i = 0; i < 4; ++i) { + ip6_parts[i] = reinterpret_cast( + &config.static_ip_v6.value().ipv6_value[i * 4]); + } + IP6_ADDR(&ip_info_v6.ip, PP_HTONL(*ip6_parts[0]), PP_HTONL(*ip6_parts[1]), + PP_HTONL(*ip6_parts[2]), PP_HTONL(*ip6_parts[3])); } +# endif - connected_to_.reset(); + // Stopping the DHCP client + err = esp_netif_dhcpc_stop(netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { + AE_TELED_ERROR("Failed to stop DHCP client: {}", esp_err_to_name(err)); + return err; + } - connection_state_ = std::make_unique(); - connection_state_->event_group = xEventGroupCreate(); +# if AE_SUPPORT_IPV4 == 1 + // Setting a static IP + err = esp_netif_set_ip_info(netif, &ip_info); + if (err != ESP_OK) { + AE_TELED_ERROR("Failed to set IP info: {}", esp_err_to_name(err)); + return err; + } - esp_event_handler_instance_t instance_any_id; - esp_event_handler_instance_t instance_got_ip; - ESP_ERROR_CHECK(esp_event_handler_instance_register( - WIFI_EVENT, ESP_EVENT_ANY_ID, esp_wifi_driver_internal::EventHandler, - connection_state_.get(), &instance_any_id)); - ESP_ERROR_CHECK(esp_event_handler_instance_register( - IP_EVENT, IP_EVENT_STA_GOT_IP, esp_wifi_driver_internal::EventHandler, - connection_state_.get(), &instance_got_ip)); + // Installing DNS servers + if (config.primary_dns_v4) { + err = esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_info1); + if (err != ESP_OK) { + AE_TELED_ERROR("Failed to set primary DNS: {}", esp_err_to_name(err)); + return err; + } + } - wifi_scan_threshold_t wifi_threshold{}; - wifi_threshold.rssi = 0; - wifi_threshold.authmode = WIFI_AUTH_WPA2_PSK; + if (config.secondary_dns_v4) { + err = esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_info2); + if (err != ESP_OK) { + AE_TELED_ERROR("Failed to set secondary DNS: {}", esp_err_to_name(err)); + return err; + } + } - wifi_config_t wifi_config{}; - wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); + AE_TELED_DEBUG("Static IP V4 configured: {}", config.static_ip_v4); +# endif +# if AE_SUPPORT_IPV6 == 1 + if (config.static_ip_v6.has_value()) { + err = esp_netif_set_ip6_global(netif, &ip_info_v6.ip); + if (err != ESP_OK) { + AE_TELED_ERROR("Failed to set IP V6 info: {}", esp_err_to_name(err)); + return err; + } - // Restore saved Base Station - if (base_station.connected) { - bssid_vector.assign(std::begin(base_station.target_bssid), - std::end(base_station.target_bssid)); - AE_TELED_DEBUG("Restored from cash BSSID:{} CHN:{}", bssid_vector, - static_cast(base_station.target_channel)); - wifi_config.sta.scan_method = WIFI_FAST_SCAN; // Fast scan - wifi_config.sta.bssid_set = true; // Enable BSSID binding - wifi_config.sta.channel = base_station.target_channel; // Set channel - // Copy the BSSID to the configuration - memcpy(wifi_config.sta.bssid, base_station.target_bssid, 6); - ESP_ERROR_CHECK(esp_wifi_set_channel(base_station.target_channel, - WIFI_SECOND_CHAN_NONE)); + AE_TELED_DEBUG("Static IP V6 configured: {}", config.static_ip_v6); } +# endif - wifi_config.sta.threshold = wifi_threshold; - if (psp.ps_enabled) { - wifi_config.sta.listen_interval = psp.listen_interval; + return ESP_OK; +} + +void StartWifiConnection(esp_netif_t* espt_init_sta, WiFiAp const& wifi_ap, + std::optional const& psp, + std::optional const& base_station) { + wifi_config_t wifi_config{}; + if (base_station) { + // Restore saved Base Station + esp_wifi_driver_internal::SetupBssid(wifi_config, *base_station); } - // for debug purpose only, it's private data - AE_TELED_DEBUG("Connecting to ap SSID:{} PSWD:{}", wifi_ap.creds.ssid, - wifi_ap.creds.password); + wifi_scan_threshold_t wifi_threshold{}; + wifi_threshold.rssi = 0; + wifi_threshold.authmode = WIFI_AUTH_WPA2_PSK; - strncpy(reinterpret_cast(wifi_config.sta.ssid), - wifi_ap.creds.ssid.data(), sizeof(wifi_config.sta.ssid)); - strncpy(reinterpret_cast(wifi_config.sta.password), - wifi_ap.creds.password.data(), sizeof(wifi_config.sta.password)); + wifi_config.sta.threshold = wifi_threshold; + if (psp) { + wifi_config.sta.listen_interval = psp->listen_interval; + } + + esp_wifi_driver_internal::SetupCredentials(wifi_config, wifi_ap.creds); // Setting up a static IP, if required if (wifi_ap.static_ip.has_value()) { - esp_err_t err = SetStaticIp(static_cast(espt_init_sta_), - wifi_ap.static_ip.value()); + auto err = esp_wifi_driver_internal::SetStaticIp(espt_init_sta, + wifi_ap.static_ip.value()); if (err != ESP_OK) { AE_TELED_ERROR("Failed to set static IP, falling back to DHCP"); // If an error occurs, switch to DHCP @@ -166,6 +236,7 @@ void EspWifiDriver::Connect(WiFiAp const& wifi_ap, AE_TELED_DEBUG("Using DHCP for IP configuration"); } + wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); // We disable aggregation so that the packages go out one by one and quickly wifi_init_config.ampdu_rx_enable = 0; wifi_init_config.ampdu_tx_enable = 0; @@ -174,84 +245,61 @@ void EspWifiDriver::Connect(WiFiAp const& wifi_ap, ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); - if (psp.ps_enabled) { + if (psp) { ESP_ERROR_CHECK( - esp_wifi_set_ps(static_cast(psp.wifi_ps_type))); - ESP_ERROR_CHECK(esp_wifi_set_protocol(WIFI_IF_STA, psp.protocol_bitmap)); + esp_wifi_set_ps(static_cast(psp->wifi_ps_type))); + ESP_ERROR_CHECK(esp_wifi_set_protocol(WIFI_IF_STA, psp->protocol_bitmap)); } ESP_ERROR_CHECK(esp_wifi_start()); - if (psp.ps_enabled) { + if (psp) { ESP_ERROR_CHECK(esp_wifi_internal_set_fix_rate( - WIFI_IF_STA, true, static_cast(psp.fix_rate))); + WIFI_IF_STA, true, static_cast(psp->fix_rate))); ESP_ERROR_CHECK( - esp_wifi_internal_set_retry_counter(psp.short_retry, psp.long_retry)); - ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(psp.power)); + esp_wifi_internal_set_retry_counter(psp->short_retry, psp->long_retry)); + ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(psp->power)); } AE_TELED_DEBUG("WifiInitSta finished."); +} - bool connected = false; - while (!connected) { - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) - * or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT). - * The bits are set by EventHandler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(connection_state_->event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, pdFALSE, portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we - * can test which event actually happened. */ - if (bits & WIFI_CONNECTED_BIT) { - AE_TELED_DEBUG("Connected to AP"); - connected_to_ = wifi_ap.creds; - // Save Base Station - wifi_ap_record_t ap_info{}; - esp_wifi_sta_get_ap_info(&ap_info); - - base_station.connected = true; - base_station.target_channel = ap_info.primary; // Set channel - // Copy the BSSID to the configuration - memcpy(base_station.target_bssid, ap_info.bssid, 6); - bssid_vector.assign(std::begin(base_station.target_bssid), - std::end(base_station.target_bssid)); - AE_TELED_DEBUG("Storing to cash BSSID:{} CHN:{}", bssid_vector, - static_cast(base_station.target_channel)); - connected = true; - } else if (bits & WIFI_FAIL_BIT) { - Disconnect(); - if (wifi_config.sta.bssid_set == true) { // Enable BSSID binding - AE_TELED_DEBUG( - "Failed to connect to the AP, trying to reset the BSSID"); - wifi_config.sta.bssid_set = false; - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); - ESP_ERROR_CHECK(esp_wifi_start()); - AE_TELED_DEBUG("WifiInitSta restarted."); - } else { - AE_TELED_DEBUG("Failed to connect to the AP, trying the next AP"); - connected = true; - } - } else { - AE_TELED_DEBUG("UNEXPECTED EVENT {}", static_cast(bits)); - connected = true; - } - } +} // namespace esp_wifi_driver_internal - /* The event will not be processed after unregister */ - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip)); - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); - vEventGroupDelete(connection_state_->event_group); - connection_state_.reset(); +EspWifiDriver::EspWifiDriver(AeContext const& ae_context) + : ae_context_{ae_context} { + Init(); } -WifiCreds EspWifiDriver::connected_to() const { - if (!connected_to_) { - return {}; +EspWifiDriver::~EspWifiDriver() { + if (connected_to_) { + Disconnect(); } - return *connected_to_; + Deinit(); +} + +void EspWifiDriver::Connect( + WiFiAp const& wifi_ap, std::optional const& psp, + std::optional const& base_station) { + if (connected_to_) { + Disconnect(); + } + connected_to_.reset(); + + connection_state_ = {}; + connection_state_.state = State::kConnecting; + + esp_wifi_driver_internal::StartWifiConnection( + static_cast(espt_init_sta_), wifi_ap, psp, base_station); + // the connection result will be handled in ConnectingEventHandler +} + +EspWifiDriver::ConnectResEvent::Subscriber EspWifiDriver::connect_res_event() { + return EventSubscriber{connect_res_event_}; +} + +std::optional EspWifiDriver::connected_to() const { + return connected_to_; } void EspWifiDriver::Init() { @@ -264,6 +312,13 @@ void EspWifiDriver::Init() { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, + esp_wifi_driver_internal::EventHandler, this); + esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, + esp_wifi_driver_internal::EventHandler, this); + connection_state_ = {}; + connection_state_.state = State::kDisconnected; } void EspWifiDriver::InitNvs() { @@ -279,108 +334,111 @@ void EspWifiDriver::InitNvs() { void EspWifiDriver::Deinit() { esp_wifi_deinit(); esp_netif_destroy_default_wifi(static_cast(espt_init_sta_)); + + esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, + esp_wifi_driver_internal::EventHandler); + esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, + esp_wifi_driver_internal::EventHandler); } void EspWifiDriver::Disconnect() { + connection_state_.state = State::kDisconnecring; + connected_to_.reset(); esp_wifi_disconnect(); esp_wifi_stop(); } -esp_err_t EspWifiDriver::SetStaticIp(esp_netif_t* netif, WiFiIP const& config) { - esp_err_t err = ESP_OK; - -# if AE_SUPPORT_IPV4 == 1 - esp_netif_ip_info_t ip_info; - esp_netif_dns_info_t dns_info1, dns_info2; - - // Conversion to IP addresses - memset(&ip_info, 0, sizeof(esp_netif_ip_info_t)); - memset(&dns_info1, 0, sizeof(esp_netif_dns_info_t)); - memset(&dns_info2, 0, sizeof(esp_netif_dns_info_t)); - - auto static_ip = config.static_ip_v4; - IP4_ADDR(&ip_info.ip, static_ip.ipv4_value[0], static_ip.ipv4_value[1], - static_ip.ipv4_value[2], static_ip.ipv4_value[3]); - auto gateway = config.gateway_v4; - IP4_ADDR(&ip_info.gw, gateway.ipv4_value[0], gateway.ipv4_value[1], - gateway.ipv4_value[2], gateway.ipv4_value[3]); - auto netmask = config.netmask_v4; - IP4_ADDR(&ip_info.netmask, netmask.ipv4_value[0], netmask.ipv4_value[1], - netmask.ipv4_value[2], netmask.ipv4_value[3]); - if (config.primary_dns_v4.has_value()) { - auto primary_dns = config.primary_dns_v4.value(); - IP4_ADDR(&dns_info1.ip.u_addr.ip4, primary_dns.ipv4_value[0], - primary_dns.ipv4_value[1], primary_dns.ipv4_value[2], - primary_dns.ipv4_value[3]); - } - if (config.secondary_dns_v4.has_value()) { - auto secondary_dns = config.secondary_dns_v4.value(); - IP4_ADDR(&dns_info2.ip.u_addr.ip4, secondary_dns.ipv4_value[0], - secondary_dns.ipv4_value[1], secondary_dns.ipv4_value[2], - secondary_dns.ipv4_value[3]); - } -# endif -# if AE_SUPPORT_IPV6 == 1 - if (config.static_ip_v6.has_value()) { - esp_netif_ip6_info_t ip_info_v6; - - memset(&ip_info_v6, 0, sizeof(esp_netif_ip6_info_t)); - - std::array ip6_parts{}; - for (auto i = 0; i < 4; ++i) { - ip6_parts[i] = reinterpret_cast( - &config.static_ip_v6.value().ipv6_value[i * 4]); +void EspWifiDriver::ConnectingEventHandler(esp_event_base_t event_base, + int32_t event_id, + [[maybe_unused]] void* event_data) { + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_START: + esp_wifi_connect(); + break; + case WIFI_EVENT_STA_DISCONNECTED: { + auto* event = static_cast(event_data); + AE_TELED_DEBUG("Wifi event disconnected, reasone {}", + static_cast(event->reason)); + if (connection_state_.retry_count < + esp_wifi_driver_internal::kMaxRetry) { + esp_wifi_connect(); + connection_state_.retry_count++; + } else { + event_task_sub_ = ae_context_.scheduler().Task([&]() { + Disconnect(); + // connection failed + connect_res_event_.Emit(Error(1)); + }); + } + break; + } + default: + break; } - IP6_ADDR(&ip_info_v6.ip, PP_HTONL(*ip6_parts[0]), PP_HTONL(*ip6_parts[1]), - PP_HTONL(*ip6_parts[2]), PP_HTONL(*ip6_parts[3])); - } -# endif - - // Stopping the DHCP client - err = esp_netif_dhcpc_stop(netif); - if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - AE_TELED_ERROR("Failed to stop DHCP client: {}", esp_err_to_name(err)); - return err; - } - -# if AE_SUPPORT_IPV4 == 1 - // Setting a static IP - err = esp_netif_set_ip_info(netif, &ip_info); - if (err != ESP_OK) { - AE_TELED_ERROR("Failed to set IP info: {}", esp_err_to_name(err)); - return err; - } - - // Installing DNS servers - if (config.primary_dns_v4.has_value()) { - err = esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_info1); - if (err != ESP_OK) { - AE_TELED_ERROR("Failed to set primary DNS: {}", esp_err_to_name(err)); + } else if (event_base == IP_EVENT) { + switch (event_id) { + case IP_EVENT_STA_GOT_IP: + case IP_EVENT_GOT_IP6: { + // Successfully connected + // get AP info + wifi_ap_record_t ap_info{}; + esp_wifi_sta_get_ap_info(&ap_info); + // save real SSID + connected_to_ = std::string(reinterpret_cast(ap_info.ssid)); + AE_TELED_DEBUG("Connected to AP {}", *connected_to_); + + WiFiBaseStation base_station{}; + base_station.target_channel = ap_info.primary; // Set channel + // Copy the BSSID to the configuration + memcpy(base_station.target_bssid, ap_info.bssid, + sizeof(base_station.target_bssid)); + std::array debug_bssid; + memcpy(debug_bssid.data(), base_station.target_bssid, + sizeof(base_station.target_bssid)); + AE_TELED_DEBUG("Storing to cash BSSID:{} CHN:{}", debug_bssid, + static_cast(base_station.target_channel)); + + connection_state_.state = State::kConnected; + event_task_sub_ = ae_context_.scheduler().Task( + [&]() { connect_res_event_.Emit(Ok{base_station}); }); + break; + } + default: + break; } } - - if (config.secondary_dns_v4.has_value()) { - err = esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_info2); - if (err != ESP_OK) { - AE_TELED_ERROR("Failed to set secondary DNS: {}", esp_err_to_name(err)); +} +void EspWifiDriver::ConnectedEventHandler(esp_event_base_t event_base, + int32_t event_id, void* event_data) { + AE_TELED_DEBUG("Wifi event on Connected"); + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_DISCONNECTED: { + auto* event = static_cast(event_data); + AE_TELED_DEBUG("Wifi event disconnected, reasone {}", + static_cast(event->reason)); + break; + } + default: + break; } } + // TODO: +} - AE_TELED_DEBUG("Static IP V4 configured: {}", config.static_ip_v4); -# endif -# if AE_SUPPORT_IPV6 == 1 - if (config.static_ip_v6.has_value()) { - err = esp_netif_set_ip6_global(netif, &ip_info_v6.ip); - if (err != ESP_OK) { - AE_TELED_ERROR("Failed to set IP V6 info: {}", esp_err_to_name(err)); - return err; - } - - AE_TELED_DEBUG("Static IP V6 configured: {}", config.static_ip_v6); - } -# endif +void EspWifiDriver::DisconnectingEventHandler(esp_event_base_t /* event_base */, + int32_t /* event_id */, + void* /* event_data */) { + AE_TELED_DEBUG("Wifi event on Disconnecting"); + // TODO: +} - return ESP_OK; +void EspWifiDriver::DisconnectedEventHandler(esp_event_base_t /* event_base */, + int32_t /* event_id */, + void* /* event_data */) { + AE_TELED_DEBUG("Wifi event on Disconnected"); + // TODO: } } // namespace ae diff --git a/aether/wifi/esp_wifi_driver.h b/aether/wifi/esp_wifi_driver.h index 3f5130c2..f17df6f7 100644 --- a/aether/wifi/esp_wifi_driver.h +++ b/aether/wifi/esp_wifi_driver.h @@ -21,36 +21,80 @@ #if (defined(ESP_PLATFORM)) && AE_SUPPORT_WIFIS && AE_ENABLE_ESP32_WIFI # define ESP_WIFI_DRIVER_ENABLED 1 -# include # include -# include "aether/wifi/wifi_driver.h" +# include "freertos/FreeRTOS.h" + +# include "freertos/task.h" +# include "freertos/event_groups.h" # include "esp_err.h" # include "esp_netif_types.h" +# include "aether/ae_context.h" +# include "aether/wifi/wifi_driver.h" + namespace ae { +namespace esp_wifi_driver_internal { +void EventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, + void* event_data); +} + class EspWifiDriver final : public WifiDriver { + // friend with wifi event handler + friend void esp_wifi_driver_internal::EventHandler( + void* arg, esp_event_base_t event_base, int32_t event_id, + void* event_data); + public: - EspWifiDriver(); + enum class State : char { + kDisconnected, + kDisconnecring, + kConnecting, + kConnected, + }; + + struct ConnectionState { + State state; + std::size_t retry_count{}; + }; + + explicit EspWifiDriver(AeContext const& ae_context); ~EspWifiDriver() override; - void Connect(WiFiAp const& wifi_ap, WiFiPowerSaveParam const& psp, - WiFiBaseStation& base_station_) override; - WifiCreds connected_to() const override; + void Connect(WiFiAp const& wifi_ap, + std::optional const& psp, + std::optional const& base_station_) override; + + ConnectResEvent::Subscriber connect_res_event() override; + + std::optional connected_to() const override; private: - void Disconnect(); void Init(); - void InitNvs(); + static void InitNvs(); void Deinit(); - esp_err_t SetStaticIp(esp_netif_t* netif, WiFiIP const& config); - static int initialized_; - static void* espt_init_sta_; + void Disconnect(); + + void ConnectingEventHandler(esp_event_base_t event_base, int32_t event_id, + void* event_data); + void ConnectedEventHandler(esp_event_base_t event_base, int32_t event_id, + void* event_data); + void DisconnectingEventHandler(esp_event_base_t event_base, int32_t event_id, + void* event_data); + void DisconnectedEventHandler(esp_event_base_t event_base, int32_t event_id, + void* event_data); + + AeContext ae_context_; + ConnectResEvent connect_res_event_; + + ConnectionState connection_state_; + std::optional connected_to_; + TaskSubscription event_task_sub_; - std::optional connected_to_; - std::unique_ptr connection_state_; + // driver could be initialized only once + void* espt_init_sta_ = nullptr; }; } // namespace ae #endif diff --git a/aether/wifi/wifi_driver.h b/aether/wifi/wifi_driver.h index 1e551193..43fb8852 100644 --- a/aether/wifi/wifi_driver.h +++ b/aether/wifi/wifi_driver.h @@ -20,7 +20,8 @@ #include "aether/config.h" #if AE_SUPPORT_WIFIS -# include "aether/reflect/reflect.h" +# include "aether/types/result.h" +# include "aether/events/events.h" # include "aether/wifi/wifi_driver_types.h" namespace ae { @@ -29,18 +30,29 @@ namespace ae { */ class WifiDriver { public: + /** + * \brief Wifi connection result. + * \param res - AP parameters or error code + */ + using ConnectResEvent = Event&& res)>; + virtual ~WifiDriver() = default; /** * \brief Connect to an access point with creds. */ - virtual void Connect(WiFiAp const& wifi_ap, WiFiPowerSaveParam const& psp, - WiFiBaseStation& base_station_) = 0; + virtual void Connect(WiFiAp const& wifi_ap, + std::optional const& psp, + std::optional const& base_station) = 0; + + virtual ConnectResEvent::Subscriber connect_res_event() = 0; + /** - * \brief Get creds for currently connected access point. - * \return if connected WifiCreds with filled at least ssid, otherwise empty. + * \brief Get the AP ssid if connected */ - virtual WifiCreds connected_to() const = 0; + virtual std::optional connected_to() const = 0; + + // TODO: add disconnected event }; } // namespace ae diff --git a/aether/wifi/wifi_driver_factory.cpp b/aether/wifi/wifi_driver_factory.cpp index eb48dae5..fb265466 100644 --- a/aether/wifi/wifi_driver_factory.cpp +++ b/aether/wifi/wifi_driver_factory.cpp @@ -22,9 +22,10 @@ // IWYU pragma: end_keeps namespace ae { -std::unique_ptr WifiDriverFactory::CreateWifiDriver() { -# if defined ESP_WIFI_DRIVER_ENABLED - return std::make_unique(); +std::unique_ptr WifiDriverFactory::CreateWifiDriver( + [[maybe_unused]] AeContext const& ae_context) { +# if ESP_WIFI_DRIVER_ENABLED + return std::make_unique(ae_context); # else return nullptr; # endif diff --git a/aether/wifi/wifi_driver_factory.h b/aether/wifi/wifi_driver_factory.h index 7323593f..29ad07fb 100644 --- a/aether/wifi/wifi_driver_factory.h +++ b/aether/wifi/wifi_driver_factory.h @@ -21,12 +21,13 @@ #if AE_SUPPORT_WIFIS # include +# include "aether/ae_context.h" # include "aether/wifi/wifi_driver.h" namespace ae { class WifiDriverFactory { public: - static std::unique_ptr CreateWifiDriver(); + static std::unique_ptr CreateWifiDriver(AeContext const& ae_context); }; } // namespace ae #endif diff --git a/aether/wifi/wifi_driver_types.h b/aether/wifi/wifi_driver_types.h index c64401b0..af741096 100644 --- a/aether/wifi/wifi_driver_types.h +++ b/aether/wifi/wifi_driver_types.h @@ -56,9 +56,8 @@ struct WiFiAp { }; struct WiFiPowerSaveParam { - AE_REFLECT_MEMBERS(ps_enabled, wifi_ps_type, protocol_bitmap, listen_interval, + AE_REFLECT_MEMBERS(wifi_ps_type, protocol_bitmap, listen_interval, beacon_interval, fix_rate, short_retry, long_retry, power); - bool ps_enabled{false}; uint8_t wifi_ps_type; uint8_t protocol_bitmap; int16_t listen_interval; @@ -70,8 +69,7 @@ struct WiFiPowerSaveParam { }; struct WiFiBaseStation { - AE_REFLECT_MEMBERS(connected, target_bssid, target_channel) - bool connected{false}; + AE_REFLECT_MEMBERS(target_bssid, target_channel) uint8_t target_bssid[6]; uint8_t target_channel; }; @@ -79,7 +77,7 @@ struct WiFiBaseStation { struct WiFiInit { AE_REFLECT_MEMBERS(wifi_ap, psp) std::vector wifi_ap; - WiFiPowerSaveParam psp; + std::optional psp; }; } // namespace ae From d15d475f71ca9761a9bfca5971a375415a6e5846 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 12 Jun 2026 22:08:32 +0500 Subject: [PATCH 2/3] make use less memory for esp --- config/user_config_hydrogen.h | 5 +++++ config/user_config_optimized.h | 3 +++ config/user_config_sodium.h | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/config/user_config_hydrogen.h b/config/user_config_hydrogen.h index 629c7b6a..e20dacfa 100644 --- a/config/user_config_hydrogen.h +++ b/config/user_config_hydrogen.h @@ -24,6 +24,11 @@ #define AE_SIGNATURE AE_HYDRO_SIGNATURE #define AE_KDF AE_HYDRO_KDF +#if ESP_PLATFORM +# define AE_CLOUD_MAX_SERVER_CONNECTIONS 1 +# define AE_SAFE_STREAM_CAPACITY 2 * 1024 +#endif + #if !ESP_PLATFORM # define AE_SUPPORT_WIFIS 0 #endif diff --git a/config/user_config_optimized.h b/config/user_config_optimized.h index b1e61084..00b8a117 100644 --- a/config/user_config_optimized.h +++ b/config/user_config_optimized.h @@ -26,6 +26,9 @@ #define AE_SUPPORT_UDP 0 +#if ESP_PLATFORM +# define AE_SAFE_STREAM_CAPACITY 2 * 1024 +#endif #if !ESP_PLATFORM # define AE_SUPPORT_WIFIS 0 #endif diff --git a/config/user_config_sodium.h b/config/user_config_sodium.h index 08233d3c..1795a132 100644 --- a/config/user_config_sodium.h +++ b/config/user_config_sodium.h @@ -24,6 +24,11 @@ #define AE_SIGNATURE AE_ED25519 #define AE_KDF AE_SODIUM_KDF +#if ESP_PLATFORM +# define AE_CLOUD_MAX_SERVER_CONNECTIONS 1 +# define AE_SAFE_STREAM_CAPACITY 2 * 1024 +#endif + #if !ESP_PLATFORM # define AE_SUPPORT_WIFIS 0 #endif From 998ce0b5375d1e8fa08dc159d66e1fba95db6b4f Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 12 Jun 2026 22:08:59 +0500 Subject: [PATCH 3/3] fix psp config --- examples/cloud/aether_construct_esp_wifi.h | 5 ++--- tools/registrator/registrator.cpp | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/cloud/aether_construct_esp_wifi.h b/examples/cloud/aether_construct_esp_wifi.h index 53fa2975..363e19fa 100644 --- a/examples/cloud/aether_construct_esp_wifi.h +++ b/examples/cloud/aether_construct_esp_wifi.h @@ -28,8 +28,8 @@ static const std::string kWifi1Pass = "Test1234"; static const std::string kWifi2Ssid = "Test2345"; static const std::string kWifi2Pass = "Test2345"; -static IpV4Addr my_static_ip_v4{192, 168, 1, 215}; -static IpV4Addr my_gateway_ip_v4{192, 168, 1, 1}; +static IpV4Addr my_static_ip_v4{192, 168, 0, 215}; +static IpV4Addr my_gateway_ip_v4{192, 168, 0, 1}; static IpV4Addr my_netmask_ip_v4{255, 255, 255, 0}; static IpV4Addr my_dns1_ip_v4{8, 8, 8, 8}; static IpV4Addr my_dns2_ip_v4{8, 8, 4, 4}; @@ -54,7 +54,6 @@ ae::WiFiAp wifi2_ap{my_wifi2, wifi_ip}; std::vector wifi_ap_vec{wifi1_ap, wifi2_ap}; static WiFiPowerSaveParam wifi_psp{ - true, AE_WIFI_PS_MAX_MODEM, // Power save type AE_WIFI_PROTOCOL_11B | AE_WIFI_PROTOCOL_11G | AE_WIFI_PROTOCOL_11N, // Protocol bitmap diff --git a/tools/registrator/registrator.cpp b/tools/registrator/registrator.cpp index 6a89d264..db51add1 100644 --- a/tools/registrator/registrator.cpp +++ b/tools/registrator/registrator.cpp @@ -126,7 +126,6 @@ int AetherRegistrator(const std::string& ini_file, std::vector wifi_ap_vec{wifi_ap}; static ae::WiFiPowerSaveParam wifi_psp{ - true, AE_WIFI_PS_MAX_MODEM, // Power save type AE_WIFI_PROTOCOL_11B | AE_WIFI_PROTOCOL_11G | AE_WIFI_PROTOCOL_11N, // Protocol bitmap