Sync from fork #3

Open
CommanderRedYT wants to merge 4 commits from CommanderRedYT/main into main
6 changed files with 50 additions and 43 deletions

View File

@@ -24,7 +24,6 @@ set(dependencies
cpputils cpputils
espchrono espchrono
espcpputils espcpputils
fmt
) )
idf_component_register( idf_component_register(

View File

@@ -44,4 +44,9 @@ config WIFI_LOG_WORKAROUND
bool "Enable disabled-log bug workaround (by enabling certain log statements)" bool "Enable disabled-log bug workaround (by enabling certain log statements)"
default false default false
config WIFI_STA_CONFIG_COUNT
int "Maximum number of STA configurations"
default 5
range 1 10
endmenu endmenu

View File

@@ -19,6 +19,8 @@
#include <functional> #include <functional>
#include <atomic> #include <atomic>
#include <utility> #include <utility>
#include <format>
#include <cstring>
// esp-idf includes // esp-idf includes
#include <esp_log.h> #include <esp_log.h>
@@ -44,7 +46,6 @@
#endif #endif
// 3rdparty lib includes // 3rdparty lib includes
#include <fmt/core.h>
#include <strutils.h> #include <strutils.h>
#include <delayedconstruction.h> #include <delayedconstruction.h>
#include <wrappers/event_group.h> #include <wrappers/event_group.h>
@@ -817,7 +818,7 @@ void update(const config &config)
std::string sta_error_t::toString() const std::string sta_error_t::toString() const
{ {
return fmt::format("{} WIFI_STA_DISCONNECTED ssid=\"{}\" bssid={} reason={}({})", return std::format("{} WIFI_STA_DISCONNECTED ssid=\"{}\" bssid={} reason={}({})",
timestamp.time_since_epoch().count(), timestamp.time_since_epoch().count(),
ssid, wifi_stack::toString(bssid), ssid, wifi_stack::toString(bssid),
std::to_underlying(reason), wifi_stack::toString(reason)); std::to_underlying(reason), wifi_stack::toString(reason));
@@ -880,7 +881,7 @@ std::expected<void, std::string> begin_scan(const sta_config &sta_config)
return std::unexpected("invalid scan settings (not active nor passive)!"); return std::unexpected("invalid scan settings (not active nor passive)!");
if (const auto result = esp_wifi_scan_start(&scan_config, false) != ESP_OK) if (const auto result = esp_wifi_scan_start(&scan_config, false) != ESP_OK)
return std::unexpected(fmt::format("esp_wifi_scan_start() failed with: {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_wifi_scan_start() failed with: {}", esp_err_to_name(result)));
scanStarted = espchrono::millis_clock::now(); scanStarted = espchrono::millis_clock::now();
@@ -936,7 +937,7 @@ std::expected<wifi_ap_record_t, std::string> get_sta_ap_info()
else else
{ {
ESP_LOGW(TAG, "esp_wifi_sta_get_ap_info() failed with %s", esp_err_to_name(result)); ESP_LOGW(TAG, "esp_wifi_sta_get_ap_info() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_wifi_sta_get_ap_info() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_wifi_sta_get_ap_info() failed with {}", esp_err_to_name(result)));
} }
} }
@@ -948,7 +949,7 @@ mac_or_error get_mac_addr(wifi_interface_t ifx)
else else
{ {
ESP_LOGW(TAG, "esp_wifi_get_mac() failed with %s", esp_err_to_name(result)); ESP_LOGW(TAG, "esp_wifi_get_mac() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_wifi_get_mac() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_wifi_get_mac() failed with {}", esp_err_to_name(result)));
} }
} }
@@ -961,7 +962,7 @@ mac_or_error get_default_mac_addr()
else else
{ {
//ESP_LOGE(TAG, "esp_efuse_mac_get_default() failed with %s", esp_err_to_name(result)); //ESP_LOGE(TAG, "esp_efuse_mac_get_default() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_efuse_mac_get_default() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_efuse_mac_get_default() failed with {}", esp_err_to_name(result)));
} }
}(); }();
@@ -977,7 +978,7 @@ mac_or_error get_custom_mac_addr()
else else
{ {
//ESP_LOGE(TAG, "esp_efuse_mac_get_custom() failed with %s", esp_err_to_name(result)); //ESP_LOGE(TAG, "esp_efuse_mac_get_custom() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_efuse_mac_get_custom() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_efuse_mac_get_custom() failed with {}", esp_err_to_name(result)));
} }
}(); }();
@@ -992,7 +993,7 @@ mac_or_error get_base_mac_addr()
else else
{ {
ESP_LOGE(TAG, "esp_base_mac_addr_get() failed with %s", esp_err_to_name(result)); ESP_LOGE(TAG, "esp_base_mac_addr_get() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_base_mac_addr_get() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_base_mac_addr_get() failed with {}", esp_err_to_name(result)));
} }
} }
@@ -1003,7 +1004,7 @@ std::expected<void, std::string> set_base_mac_addr(mac_t mac_addr)
else else
{ {
ESP_LOGE(TAG, "esp_base_mac_addr_set() failed with %s", esp_err_to_name(result)); ESP_LOGE(TAG, "esp_base_mac_addr_set() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("esp_base_mac_addr_set() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_base_mac_addr_set() failed with {}", esp_err_to_name(result)));
} }
} }
@@ -1015,7 +1016,7 @@ std::expected<esp_netif_ip_info_t, std::string> get_ip_info(esp_netif_t *esp_net
else else
{ {
ESP_LOGE(TAG, "esp_netif_get_ip_info() failed with %s", esp_err_to_name(result)); ESP_LOGE(TAG, "esp_netif_get_ip_info() failed with %s", esp_err_to_name(result));
return std::unexpected(fmt::format("tcpip_adapter_get_ip_info() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("tcpip_adapter_get_ip_info() failed with {}", esp_err_to_name(result)));
} }
} }
@@ -1024,14 +1025,14 @@ std::expected<std::string_view, std::string> get_hostname_for_interface(esp_inte
if (const auto netif = esp_netifs[interf]) if (const auto netif = esp_netifs[interf])
return get_hostname_for_interface(netif); return get_hostname_for_interface(netif);
else else
return std::unexpected(fmt::format("netif for {} is invalid", std::to_underlying(interf))); return std::unexpected(std::format("netif for {} is invalid", std::to_underlying(interf)));
} }
std::expected<std::string_view, std::string> get_hostname_for_interface(esp_netif_t *esp_netif) std::expected<std::string_view, std::string> get_hostname_for_interface(esp_netif_t *esp_netif)
{ {
const char *hostname{}; const char *hostname{};
if (const auto result = esp_netif_get_hostname(esp_netif, &hostname)) if (const auto result = esp_netif_get_hostname(esp_netif, &hostname))
return std::unexpected(fmt::format("esp_netif_get_hostname() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_netif_get_hostname() failed with {}", esp_err_to_name(result)));
if (!hostname) if (!hostname)
return std::unexpected("esp_netif_get_hostname() returned a nullptr string"); return std::unexpected("esp_netif_get_hostname() returned a nullptr string");
@@ -2128,7 +2129,7 @@ std::expected<void, std::string> applyBaseMac(const mac_t &mac)
return {}; return {};
else else
{ {
const auto msg = fmt::format("set_base_mac_addr() {} failed: {}", toString(mac), result.error()); const auto msg = std::format("set_base_mac_addr() {} failed: {}", toString(mac), result.error());
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
return std::unexpected(msg); return std::unexpected(msg);
} }
@@ -2153,7 +2154,7 @@ std::expected<mac_t, std::string> expectedBaseMac(const config &config)
return *mac; return *mac;
else else
{ {
const auto msg = fmt::format("no base mac fuse or override set and get_default_mac_addr() failed: {}", mac.error()); const auto msg = std::format("no base mac fuse or override set and get_default_mac_addr() failed: {}", mac.error());
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
return std::unexpected(msg); return std::unexpected(msg);
} }
@@ -2820,7 +2821,7 @@ std::expected<void, std::string> eth_begin(const config &config, const eth_confi
if (const auto result = esp_eth_driver_install(&eth_config, &eth_handle); result != ESP_OK) if (const auto result = esp_eth_driver_install(&eth_config, &eth_handle); result != ESP_OK)
{ {
auto msg = fmt::format("esp_eth_driver_install() failed with {}", esp_err_to_name(result)); auto msg = std::format("esp_eth_driver_install() failed with {}", esp_err_to_name(result));
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
return std::unexpected(std::move(msg)); return std::unexpected(std::move(msg));
} }
@@ -2843,7 +2844,7 @@ std::expected<void, std::string> eth_begin(const config &config, const eth_confi
if (const auto result = esp_netif_attach(esp_netifs[ESP_IF_ETH], ptr); result != ESP_OK) if (const auto result = esp_netif_attach(esp_netifs[ESP_IF_ETH], ptr); result != ESP_OK)
{ {
auto msg = fmt::format("esp_netif_attach() failed with {}", esp_err_to_name(result)); auto msg = std::format("esp_netif_attach() failed with {}", esp_err_to_name(result));
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
return std::unexpected(std::move(msg)); return std::unexpected(std::move(msg));
} }
@@ -2854,7 +2855,7 @@ std::expected<void, std::string> eth_begin(const config &config, const eth_confi
{ {
if (const auto result = esp_eth_start(eth_handle); result != ESP_OK) if (const auto result = esp_eth_start(eth_handle); result != ESP_OK)
{ {
auto msg = fmt::format("esp_eth_start() failed with {}", esp_err_to_name(result)); auto msg = std::format("esp_eth_start() failed with {}", esp_err_to_name(result));
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
return std::unexpected(std::move(msg)); return std::unexpected(std::move(msg));
} }

View File

@@ -163,7 +163,7 @@ struct dual_ant_config
struct sta_config struct sta_config
{ {
std::string hostname; std::string hostname;
std::array<wifi_entry, 10> wifis; std::array<wifi_entry, CONFIG_WIFI_STA_CONFIG_COUNT> wifis;
int8_t min_rssi = -90; int8_t min_rssi = -90;
bool long_range = false; bool long_range = false;
wifi_bandwidth_t bandwidth = WIFI_BW_HT20; wifi_bandwidth_t bandwidth = WIFI_BW_HT20;

View File

@@ -4,13 +4,11 @@
#include <cstdio> #include <cstdio>
#include <bitset> #include <bitset>
#include <utility> #include <utility>
#include <format>
// esp-idf includes // esp-idf includes
#include <esp_log.h> #include <esp_log.h>
// 3rdparty lib includes
#include <fmt/core.h>
namespace wifi_stack { namespace wifi_stack {
namespace { namespace {
constexpr const char * const TAG = "WIFI_STACK"; constexpr const char * const TAG = "WIFI_STACK";
@@ -68,9 +66,11 @@ std::string toString(wifi_auth_mode_t authMode)
case WIFI_AUTH_WAPI_PSK: return "WAPI_PSK"; case WIFI_AUTH_WAPI_PSK: return "WAPI_PSK";
case WIFI_AUTH_OWE: return "OWE"; case WIFI_AUTH_OWE: return "OWE";
case WIFI_AUTH_MAX: return "MAX"; case WIFI_AUTH_MAX: return "MAX";
case WIFI_AUTH_WPA3_ENT_192: return "WPA3_ENT_192";
default:;
} }
ESP_LOGW(TAG, "Unknown wifi_auth_mode_t(%i)", std::to_underlying(authMode)); ESP_LOGW(TAG, "Unknown wifi_auth_mode_t(%i)", std::to_underlying(authMode));
return fmt::format("Unknown wifi_auth_mode_t({})", std::to_underlying(authMode)); return std::format("Unknown wifi_auth_mode_t({})", std::to_underlying(authMode));
} }
std::string toString(wifi_cipher_type_t cipherType) std::string toString(wifi_cipher_type_t cipherType)
@@ -92,7 +92,7 @@ std::string toString(wifi_cipher_type_t cipherType)
case WIFI_CIPHER_TYPE_UNKNOWN: return "UNKNOWN"; case WIFI_CIPHER_TYPE_UNKNOWN: return "UNKNOWN";
} }
ESP_LOGW(TAG, "Unknown wifi_cipher_type_t(%i)", std::to_underlying(cipherType)); ESP_LOGW(TAG, "Unknown wifi_cipher_type_t(%i)", std::to_underlying(cipherType));
return fmt::format("Unknown wifi_cipher_type_t({})", std::to_underlying(cipherType)); return std::format("Unknown wifi_cipher_type_t({})", std::to_underlying(cipherType));
} }
std::string toString(wifi_bandwidth_t bandwidth) std::string toString(wifi_bandwidth_t bandwidth)
@@ -101,9 +101,10 @@ std::string toString(wifi_bandwidth_t bandwidth)
{ {
case WIFI_BW_HT20: return "HT20"; case WIFI_BW_HT20: return "HT20";
case WIFI_BW_HT40: return "HT40"; case WIFI_BW_HT40: return "HT40";
default:;
} }
ESP_LOGW(TAG, "Unknown wifi_bandwidth_t(%i)", std::to_underlying(bandwidth)); ESP_LOGW(TAG, "Unknown wifi_bandwidth_t(%i)", std::to_underlying(bandwidth));
return fmt::format("Unknown wifi_bandwidth_t({})", std::to_underlying(bandwidth)); return std::format("Unknown wifi_bandwidth_t({})", std::to_underlying(bandwidth));
} }
std::string toString(esp_interface_t interface) std::string toString(esp_interface_t interface)
@@ -117,7 +118,7 @@ std::string toString(esp_interface_t interface)
case ESP_IF_MAX: return "MAX"; case ESP_IF_MAX: return "MAX";
} }
ESP_LOGW(TAG, "Unknown esp_interface_t(%i)", std::to_underlying(interface)); ESP_LOGW(TAG, "Unknown esp_interface_t(%i)", std::to_underlying(interface));
return fmt::format("Unknown esp_interface_t({})", std::to_underlying(interface)); return std::format("Unknown esp_interface_t({})", std::to_underlying(interface));
} }
std::string toString(esp_netif_dhcp_status_t status) std::string toString(esp_netif_dhcp_status_t status)
@@ -130,7 +131,7 @@ std::string toString(esp_netif_dhcp_status_t status)
case ESP_NETIF_DHCP_STATUS_MAX: return "STATUS_MAX"; case ESP_NETIF_DHCP_STATUS_MAX: return "STATUS_MAX";
} }
ESP_LOGW(TAG, "Unknown esp_netif_dhcp_status_t(%i)", std::to_underlying(status)); ESP_LOGW(TAG, "Unknown esp_netif_dhcp_status_t(%i)", std::to_underlying(status));
return fmt::format("Unknown esp_netif_dhcp_status_t({})", std::to_underlying(status)); return std::format("Unknown esp_netif_dhcp_status_t({})", std::to_underlying(status));
} }
const char * toString(wifi_err_reason_t reason) const char * toString(wifi_err_reason_t reason)
@@ -194,6 +195,7 @@ const char * toString(wifi_err_reason_t reason)
case WIFI_REASON_ROAMING: return "ROAMING"; case WIFI_REASON_ROAMING: return "ROAMING";
case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: return "ASSOC_COMEBACK_TIME_TOO_LONG"; case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: return "ASSOC_COMEBACK_TIME_TOO_LONG";
case WIFI_REASON_SA_QUERY_TIMEOUT: return "SA_QUERY_TIMEOUT"; case WIFI_REASON_SA_QUERY_TIMEOUT: return "SA_QUERY_TIMEOUT";
default:;
} }
ESP_LOGE(TAG, "unknown reason %" PRIu8, reason); ESP_LOGE(TAG, "unknown reason %" PRIu8, reason);
@@ -225,12 +227,12 @@ template<> std::expected<mac_t, std::string> fromString<mac_t>(std::string_view
&result[0], &result[1], &result[2], &result[3], &result[4], &result[5]) == 6) &result[0], &result[1], &result[2], &result[3], &result[4], &result[5]) == 6)
return result; return result;
return std::unexpected(fmt::format("invalid format ({})", str)); return std::unexpected(std::format("invalid format ({})", str));
} }
std::string toString(const mac_t &val) std::string toString(const mac_t &val)
{ {
return fmt::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", return std::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
val.at(0), val.at(1), val.at(2), val.at(3), val.at(4), val.at(5)); val.at(0), val.at(1), val.at(2), val.at(3), val.at(4), val.at(5));
} }
@@ -279,7 +281,7 @@ template<> std::expected<ip_address_t, std::string> fromString<ip_address_t>(std
std::string toString(ip_address_t val) std::string toString(ip_address_t val)
{ {
return fmt::format("{}.{}.{}.{}", val[0], val[1], val[2], val[3]); return std::format("{}.{}.{}.{}", val[0], val[1], val[2], val[3]);
} }
std::string toString(const std::optional<ip_address_t> &val) std::string toString(const std::optional<ip_address_t> &val)
@@ -330,9 +332,10 @@ std::string toString(ip_addr_t val)
{ {
case IPADDR_TYPE_V4: return toString(val.u_addr.ip4); case IPADDR_TYPE_V4: return toString(val.u_addr.ip4);
case IPADDR_TYPE_V6: return toString(val.u_addr.ip6); case IPADDR_TYPE_V6: return toString(val.u_addr.ip6);
default:;
} }
//ESP_LOGW(TAG, "Unknown ipv%hhu", val.type); //ESP_LOGW(TAG, "Unknown ipv%hhu", val.type);
return fmt::format("Unknown ipv{}", val.type); return std::format("Unknown ipv{}", val.type);
} }
std::string toString(const esp_ip_addr_t &val) std::string toString(const esp_ip_addr_t &val)
@@ -341,9 +344,10 @@ std::string toString(const esp_ip_addr_t &val)
{ {
case IPADDR_TYPE_V4: return toString(val.u_addr.ip4); case IPADDR_TYPE_V4: return toString(val.u_addr.ip4);
case IPADDR_TYPE_V6: return toString(val.u_addr.ip6); case IPADDR_TYPE_V6: return toString(val.u_addr.ip6);
default:;
} }
ESP_LOGW(TAG, "Unknown ipv%hhu", val.type); ESP_LOGW(TAG, "Unknown ipv%hhu", val.type);
return fmt::format("Unknown ipv{}", val.type); return std::format("Unknown ipv{}", val.type);
} }
} // namespace wifi_stack } // namespace wifi_stack

View File

@@ -2,6 +2,7 @@
// system // system
#include <utility> #include <utility>
#include <format>
// esp-idf includes // esp-idf includes
#include <lwip/sockets.h> #include <lwip/sockets.h>
@@ -9,9 +10,6 @@
#include <errno.h> #include <errno.h>
#include <esp_log.h> #include <esp_log.h>
// 3rdparty lib includes
#include <fmt/core.h>
// local includes // local includes
#include "espwifistack.h" #include "espwifistack.h"
@@ -42,7 +40,7 @@ std::expected<void, std::string> UdpSender::send(esp_interface_t interf, uint16_
{ {
const auto interfPtr = esp_netifs[interf]; const auto interfPtr = esp_netifs[interf];
if (!interfPtr) if (!interfPtr)
return std::unexpected(fmt::format("esp_netifs[{}] is invalid", std::to_underlying(interf))); return std::unexpected(std::format("esp_netifs[{}] is invalid", std::to_underlying(interf)));
return send(interfPtr, port, buf); return send(interfPtr, port, buf);
} }
@@ -54,7 +52,7 @@ std::expected<void, std::string> UdpSender::send(esp_netif_t *interf, uint16_t p
esp_netif_ip_info_t ip; esp_netif_ip_info_t ip;
if (const auto result = esp_netif_get_ip_info(interf, &ip); result != ESP_OK) if (const auto result = esp_netif_get_ip_info(interf, &ip); result != ESP_OK)
return std::unexpected(fmt::format("esp_netif_get_ip_info() failed with {}", esp_err_to_name(result))); return std::unexpected(std::format("esp_netif_get_ip_info() failed with {}", esp_err_to_name(result)));
return send(ip, port, buf); return send(ip, port, buf);
} }
@@ -77,9 +75,9 @@ std::expected<void, std::string> UdpSender::send(const struct sockaddr_in &recip
return std::unexpected("initializing failed, not ready to send"); return std::unexpected("initializing failed, not ready to send");
if (const ssize_t sent = sendto(m_udp_server, buf.data(), buf.size(), 0, (const struct sockaddr*)&recipient, sizeof(recipient)); sent < 0) if (const ssize_t sent = sendto(m_udp_server, buf.data(), buf.size(), 0, (const struct sockaddr*)&recipient, sizeof(recipient)); sent < 0)
return std::unexpected(fmt::format("send failed with {} (errno={})", sent, errno)); return std::unexpected(std::format("send failed with {} (errno={})", sent, errno));
else if (sent != buf.size()) else if (sent != buf.size())
return std::unexpected(fmt::format("sent bytes does not match, expected={}, sent={}", buf.size(), sent)); return std::unexpected(std::format("sent bytes does not match, expected={}, sent={}", buf.size(), sent));
return {}; return {};
} }
@@ -90,9 +88,9 @@ std::expected<void, std::string> UdpSender::send(const struct sockaddr_in6 &reci
return std::unexpected("initializing failed, not ready to send"); return std::unexpected("initializing failed, not ready to send");
if (const ssize_t sent = sendto(m_udp_server, buf.data(), buf.size(), 0, (const struct sockaddr*)&recipient, sizeof(recipient)); sent < 0) if (const ssize_t sent = sendto(m_udp_server, buf.data(), buf.size(), 0, (const struct sockaddr*)&recipient, sizeof(recipient)); sent < 0)
return std::unexpected(fmt::format("send failed with {} (errno={})", sent, errno)); return std::unexpected(std::format("send failed with {} (errno={})", sent, errno));
else if (sent != buf.size()) else if (sent != buf.size())
return std::unexpected(fmt::format("sent bytes does not match, expected={}, sent={}", buf.size(), sent)); return std::unexpected(std::format("sent bytes does not match, expected={}, sent={}", buf.size(), sent));
return {}; return {};
} }
@@ -122,7 +120,7 @@ std::expected<void, std::string> UdpSender::send(ip_addr_t ip, uint16_t port, st
return send(recipient, buf); return send(recipient, buf);
} }
} }
return std::unexpected(fmt::format("unsupported ip type {}", ip.type)); return std::unexpected(std::format("unsupported ip type {}", ip.type));
} }
std::expected<void, std::string> UdpSender::send(esp_ip_addr_t ip, uint16_t port, std::string_view buf) std::expected<void, std::string> UdpSender::send(esp_ip_addr_t ip, uint16_t port, std::string_view buf)
@@ -150,7 +148,7 @@ std::expected<void, std::string> UdpSender::send(esp_ip_addr_t ip, uint16_t port
return send(recipient, buf); return send(recipient, buf);
} }
} }
return std::unexpected(fmt::format("unsupported ip type {}", ip.type)); return std::unexpected(std::format("unsupported ip type {}", ip.type));
} }
} // namespace wifi_stack } // namespace wifi_stack