libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
esp_wifi_client.cpp
1#include "esp_wifi_client.hpp"
2
3#include <cstring>
4
5#include "esp_event.h"
6#include "esp_log.h"
7#include "esp_netif.h"
8#include "esp_timer.h"
9#include "esp_wifi.h"
10#include "nvs_flash.h"
11
12namespace LibXR
13{
14namespace
15{
16constexpr uint32_t kWifiConnectTimeoutMs = 15000U;
17constexpr uint32_t kWifiDhcpTimeoutMs = 15000U;
18constexpr uint32_t kWifiDisconnectTimeoutMs = 5000U;
19constexpr uint16_t kMaxScanResults = 20U;
20
21template <typename Predicate>
22bool WaitForPredicate(Semaphore& semaphore, uint32_t timeout_ms, Predicate&& predicate)
23{
24 if (predicate())
25 {
26 return true;
27 }
28
29 if (timeout_ms == UINT32_MAX)
30 {
31 while (!predicate())
32 {
33 (void)semaphore.Wait(UINT32_MAX);
34 }
35 return true;
36 }
37
38 const int64_t start_us = esp_timer_get_time();
39 const int64_t timeout_us = static_cast<int64_t>(timeout_ms) * 1000LL;
40 while (!predicate())
41 {
42 const int64_t remaining_us = timeout_us - (esp_timer_get_time() - start_us);
43 if (remaining_us <= 0)
44 {
45 return predicate();
46 }
47
48 const uint32_t wait_ms = static_cast<uint32_t>((remaining_us + 999LL) / 1000LL);
49 if ((semaphore.Wait(wait_ms) != ErrorCode::OK) && !predicate())
50 {
51 return false;
52 }
53 }
54 return true;
55}
56
57size_t BoundedStringLength(const char* text, size_t max_len)
58{
59 if (text == nullptr) return 0;
60 size_t len = 0;
61 while (len < max_len && text[len] != '\0')
62 {
63 ++len;
64 }
65 return len;
66}
67
68void CopyToWifiField(uint8_t* dst, size_t dst_size, const char* src)
69{
70 if (dst_size == 0) return;
71 const size_t copy_len = BoundedStringLength(src, dst_size - 1);
72 if (copy_len > 0)
73 {
74 std::memcpy(dst, src, copy_len);
75 }
76 dst[copy_len] = 0;
77}
78
79void CopyToCharField(char* dst, size_t dst_size, const char* src)
80{
81 if (dst_size == 0) return;
82 const size_t copy_len = BoundedStringLength(src, dst_size - 1);
83 if (copy_len > 0)
84 {
85 std::memcpy(dst, src, copy_len);
86 }
87 dst[copy_len] = '\0';
88}
89
90} // namespace
91
92ESP32WifiClient::ESP32WifiClient()
93{
95 {
96 init_ok_ = true;
97 return;
98 }
99
100 esp_err_t err = nvs_flash_init();
101 if ((err == ESP_ERR_NVS_NO_FREE_PAGES) || (err == ESP_ERR_NVS_NEW_VERSION_FOUND))
102 {
103 if (nvs_flash_erase() != ESP_OK)
104 {
105 return;
106 }
107 err = nvs_flash_init();
108 }
109 if (err != ESP_OK)
110 {
111 return;
112 }
113
114 err = esp_netif_init();
115 if ((err != ESP_OK) && (err != ESP_ERR_INVALID_STATE))
116 {
117 return;
118 }
119
120 err = esp_event_loop_create_default();
121 if ((err != ESP_OK) && (err != ESP_ERR_INVALID_STATE))
122 {
123 return;
124 }
125
126 netif_ = esp_netif_create_default_wifi_sta();
127 if (netif_ == nullptr)
128 {
129 return;
130 }
131
132 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
133 err = esp_wifi_init(&cfg);
134 if ((err != ESP_OK) && (err != ESP_ERR_INVALID_STATE))
135 {
136 return;
137 }
138
139 is_initialized_ = true;
140 init_ok_ = true;
141}
142
144{
145 if (enabled_) return true;
146
147 if (!init_ok_)
148 {
149 return false;
150 }
151
152 if (!RegisterHandlers())
153 {
154 return false;
155 }
156
157 if (esp_wifi_set_mode(WIFI_MODE_STA) != ESP_OK)
158 {
159 UnregisterHandlers();
160 return false;
161 }
162
163 ResetConnectionState();
164 DrainEvents();
165 if (esp_wifi_start() != ESP_OK)
166 {
167 UnregisterHandlers();
168 return false;
169 }
170 enabled_ = true;
171 return true;
172}
173
175{
176 if (!enabled_) return;
177
178 (void)esp_wifi_stop();
179 enabled_ = false;
180 ResetConnectionState();
181 UnregisterHandlers();
182}
183
185{
186 if (!enabled_) return WifiError::NOT_ENABLED;
187
188 ResetConnectionState();
189 DrainEvents();
190
191 wifi_config_t wifi_config{};
192 CopyToWifiField(wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), config.ssid);
193 CopyToWifiField(wifi_config.sta.password, sizeof(wifi_config.sta.password),
194 config.password);
195 if (esp_wifi_set_config(WIFI_IF_STA, &wifi_config) != ESP_OK)
196 {
198 }
199 if (esp_wifi_connect() != ESP_OK)
200 {
202 }
203
204 if (!WaitForPredicate(semaphore_, kWifiConnectTimeoutMs, [&]() { return connected_; }))
205 {
207 }
208
209 if (!WaitForPredicate(semaphore_, kWifiDhcpTimeoutMs,
210 [&]() { return got_ip_ || !connected_; }))
211 {
213 }
215 if (!got_ip_) return WifiError::DHCP_FAILED;
216
217 return WifiError::NONE;
218}
219
221{
222 if (!enabled_) return WifiError::NOT_ENABLED;
223 if (!connected_) return WifiError::NONE;
224
225 DrainEvents();
226 if (esp_wifi_disconnect() != ESP_OK)
227 {
229 }
230
231 if (!WaitForPredicate(semaphore_, kWifiDisconnectTimeoutMs,
232 [&]() { return !connected_; }))
233 {
234 return WifiError::UNKNOWN;
235 }
236
237 return WifiError::NONE;
238}
239
241
243{
244 return IPAddressRaw::FromString(ip_str_);
245}
246
248{
249 uint8_t mac[6] = {};
250 esp_wifi_get_mac(WIFI_IF_STA, mac);
251 MACAddressRaw result;
252 std::memcpy(result.bytes, mac, 6);
253 return result;
254}
255
257 size_t& out_found)
258{
259 out_found = 0;
260 if (!enabled_)
261 {
263 }
264 if ((out_list == nullptr) && (max_count != 0U))
265 {
267 }
268
269 wifi_scan_config_t scan_config = {};
270 if (esp_wifi_scan_start(&scan_config, true) != ESP_OK)
271 {
273 }
274
275 uint16_t ap_num = 0;
276 if (esp_wifi_scan_get_ap_num(&ap_num) != ESP_OK)
277 {
279 }
280
281 uint16_t copy_count = ap_num;
282 if (copy_count > max_count)
283 {
284 copy_count = static_cast<uint16_t>(max_count);
285 }
286 if (copy_count > kMaxScanResults)
287 {
288 copy_count = kMaxScanResults;
289 }
290
291 wifi_ap_record_t ap_records[kMaxScanResults] = {};
292 if ((copy_count > 0U) &&
293 (esp_wifi_scan_get_ap_records(&copy_count, ap_records) != ESP_OK))
294 {
296 }
297
298 out_found = copy_count;
299 for (uint16_t i = 0; i < copy_count; ++i)
300 {
301 CopyToCharField(out_list[i].ssid, sizeof(out_list[i].ssid),
302 reinterpret_cast<const char*>(ap_records[i].ssid));
303 out_list[i].rssi = ap_records[i].rssi;
304 out_list[i].security = (ap_records[i].authmode == WIFI_AUTH_OPEN) ? Security::OPEN
305 : (ap_records[i].authmode == WIFI_AUTH_WPA2_PSK)
308 }
309
310 return WifiError::NONE;
311}
312
313void ESP32WifiClient::EventHandler(void* arg, esp_event_base_t event_base,
314 int32_t event_id, void* event_data)
315{
316 auto* self = static_cast<ESP32WifiClient*>(arg);
317
318 if (event_base == WIFI_EVENT)
319 {
320 switch (event_id)
321 {
322 case WIFI_EVENT_STA_CONNECTED:
323 self->connected_ = true;
324 self->semaphore_.Post();
325 break;
326 case WIFI_EVENT_STA_DISCONNECTED:
327 self->connected_ = false;
328 self->got_ip_ = false;
329 self->ip_str_[0] = '\0';
330 self->semaphore_.Post();
331 break;
332 default:
333 break;
334 }
335 }
336
337 if (event_base == IP_EVENT)
338 {
339 switch (event_id)
340 {
341 case IP_EVENT_STA_GOT_IP:
342 {
343 ip_event_got_ip_t* event = reinterpret_cast<ip_event_got_ip_t*>(event_data);
344 self->got_ip_ = true;
345 esp_ip4addr_ntoa(&event->ip_info.ip, self->ip_str_, sizeof(self->ip_str_));
346 self->semaphore_.Post();
347 break;
348 }
349 case IP_EVENT_STA_LOST_IP:
350 self->got_ip_ = false;
351 self->ip_str_[0] = '\0';
352 self->semaphore_.Post();
353 break;
354 default:
355 break;
356 }
357 }
358}
359
361{
362 if (!connected_) return -127;
363
364 wifi_ap_record_t ap_info;
365 if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK)
366 {
367 return ap_info.rssi;
368 }
369 return -127;
370}
371
372bool ESP32WifiClient::RegisterHandlers()
373{
374 if (handlers_registered_)
375 {
376 return true;
377 }
378
379 if ((esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
380 &EventHandler, this,
381 &wifi_connected_handler_) != ESP_OK) ||
382 (esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
383 &EventHandler, this,
384 &wifi_disconnected_handler_) != ESP_OK) ||
385 (esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &EventHandler,
386 this, &got_ip_handler_) != ESP_OK) ||
387 (esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_LOST_IP, &EventHandler,
388 this, &lost_ip_handler_) != ESP_OK))
389 {
390 UnregisterHandlers();
391 return false;
392 }
393
394 handlers_registered_ = true;
395 return true;
396}
397
398void ESP32WifiClient::UnregisterHandlers()
399{
400 if ((wifi_connected_handler_ == nullptr) && (wifi_disconnected_handler_ == nullptr) &&
401 (got_ip_handler_ == nullptr) && (lost_ip_handler_ == nullptr))
402 {
403 handlers_registered_ = false;
404 return;
405 }
406
407 if (wifi_connected_handler_ != nullptr)
408 {
409 (void)esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
410 wifi_connected_handler_);
411 wifi_connected_handler_ = nullptr;
412 }
413 if (wifi_disconnected_handler_ != nullptr)
414 {
415 (void)esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
416 wifi_disconnected_handler_);
417 wifi_disconnected_handler_ = nullptr;
418 }
419 if (got_ip_handler_ != nullptr)
420 {
421 (void)esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
422 got_ip_handler_);
423 got_ip_handler_ = nullptr;
424 }
425 if (lost_ip_handler_ != nullptr)
426 {
427 (void)esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_LOST_IP,
428 lost_ip_handler_);
429 lost_ip_handler_ = nullptr;
430 }
431 handlers_registered_ = false;
432}
433
434void ESP32WifiClient::ResetConnectionState()
435{
436 connected_ = false;
437 got_ip_ = false;
438 ip_str_[0] = '\0';
439}
440
441void ESP32WifiClient::DrainEvents()
442{
443 while (semaphore_.Wait(0) == ErrorCode::OK)
444 {
445 }
446}
447
448} // namespace LibXR
ESP32 Wi-Fi 客户端实现 / ESP32 Wi-Fi client implementation.
MACAddressRaw GetMACAddress() const override
获取当前 MAC 地址 / Get MAC address
static bool is_initialized_
ESP 网络是否已初始化 / Netif initialized.
bool connected_
是否连接 / Whether WiFi is connected
IPAddressRaw GetIPAddress() const override
获取当前 IP 地址 / Get current IP address
LibXR::Semaphore semaphore_
状态同步信号量 / Event wait semaphore
WifiError Connect(const Config &config) override
连接到指定 WiFi 网络 / Connect to a WiFi network
void Disable() override
禁用网络接口(WiFi) / Disable the network interface
static esp_netif_t * netif_
ESP 默认 netif 对象 / Default netif.
bool enabled_
是否启用 / Whether WiFi is enabled
int GetRSSI() const override
获取当前 WiFi 信号强度(RSSI) / Get current signal strength
bool got_ip_
是否获取 IP / Whether IP is acquired
bool Enable() override
启用网络接口(WiFi) / Enable the network interface
WifiError Disconnect() override
断开当前 WiFi 连接 / Disconnect from the WiFi network
bool IsConnected() const override
检查是否已连接 / Check if currently connected
static void EventHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
事件处理回调 / Event handler callback
WifiError Scan(ScanResult *out_list, size_t max_count, size_t &out_found) override
扫描可用网络 / Scan for available WiFi networks
char ip_str_[16]
当前 IP 字符串 / Current IP string
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:53
@ WPA2_PSK
WPA2-PSK / WPA2-PSK.
@ UNKNOWN
未知类型 / Unknown type
@ OPEN
开放网络 / Open network
WifiError
WiFi 错误码 / Enumeration of WiFi error codes.
@ DHCP_FAILED
DHCP 获取失败 / DHCP acquisition failed.
@ INVALID_CONFIG
配置无效 / Invalid configuration
@ UNKNOWN
未知错误 / Unknown error
@ HARDWARE_FAILURE
硬件故障 / Hardware failure
@ SCAN_FAILED
扫描失败 / Scan failed
@ NOT_ENABLED
未启用 / Not enabled
@ NONE
无错误 / No error
@ CONNECTION_TIMEOUT
连接超时 / Connection timeout
LibXR 命名空间
Definition ch32_can.hpp:14
@ OK
操作成功 | Operation successful
原始 IPv4 地址 / Raw IPv4 address
Definition net.hpp:19
原始 MAC 地址 / Raw MAC address
Definition net.hpp:65
WiFi 连接配置 / WiFi connection configuration.
char ssid[33]
SSID 名称 / SSID name.
char password[64]
密码 / Password
WiFi 扫描结果 / WiFi scan result.
int rssi
信号强度 / Signal strength (RSSI)
Security security
安全类型 / Security type