|
1 /** |
|
2 * @file task_wifi.c |
|
3 * @brief WiFi task. Connect to the known AP with the strongest signal. |
|
4 */ |
|
5 |
|
6 |
|
7 #include "dcf77tx.h" |
|
8 |
|
9 #define MAX_AP_NUM 10 |
|
10 |
|
11 static const char *TAG = "task_wifi"; |
|
12 |
|
13 |
|
14 SemaphoreHandle_t xSemaphoreWiFi = NULL; ///< Semaphore WiFi task. |
|
15 EventGroupHandle_t xEventGroupWifi; ///< Events WiFi task. |
|
16 uint16_t ap_num = MAX_AP_NUM; ///< Scan counter. |
|
17 wifi_ap_record_t *accessp_records; ///< [MAX_AP_NUM] records array with scan results. |
|
18 wifi_config_t *task_wifi_ConfigSTA = NULL; ///< Current STA configuration. |
|
19 WIFI_State *wifi_state = NULL; ///< Public state for other tasks. |
|
20 esp_netif_t *sta_netif = NULL; ///< Station interface |
|
21 |
|
22 |
|
23 wifi_scan_config_t scan_config = { ///< WiFi scanner configuration. |
|
24 .ssid = (uint8_t *)CONFIG_ESP_WIFI_SSID, |
|
25 .bssid = 0, |
|
26 .channel = 0, |
|
27 .show_hidden = false |
|
28 }; |
|
29 |
|
30 bool _wifi_ScanDone = false; ///< Scan ready |
|
31 bool _wifi_BetterAP = false; ///< If better AP available. |
|
32 int8_t _wifi_RSSI = -127; ///< Latest RSSI level. |
|
33 uint16_t _wifi_Scanned = 0; ///< Total scanned APs. |
|
34 |
|
35 extern char hostname[]; ///< Generated hostname |
|
36 |
|
37 |
|
38 |
|
39 const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT0; ///< When set, means a client requested to disconnect from currently connected AP. |
|
40 const int TASK_WIFI_REQUEST_STA_CONNECT = BIT1; ///< When set, means a client requested to connect to an access point. |
|
41 const int TASK_WIFI_REQUEST_STA_SCAN = BIT2; ///< When set, means a client requested a AP scan. |
|
42 const int TASK_WIFI_REQUEST_STA_STATUS = BIT3; ///< When set, means a client requested to update the connection status. |
|
43 |
|
44 const int TASK_WIFI_HAS_IP = BIT4; ///< Indicate that we have an IP address |
|
45 const int TASK_WIFI_STA_FAILED = BIT5; ///< Indicate that we could not get a connection to AP as station. |
|
46 const int TASK_WIFI_STA_DISCONNECTED = BIT6; ///< Indicate that we are disconnected from an ap station. |
|
47 const int TASK_WIFI_STA_CONNECTED = BIT7; ///< Indicate that we are connected to AP as station, flip of BIT5. |
|
48 |
|
49 |
|
50 |
|
51 /** |
|
52 * @brief Array with AP security names |
|
53 */ |
|
54 const char *apsec[] = { "Open", "WEP", "WPA", "WPA2", "WPA WPA2", "Enterprise" }; |
|
55 |
|
56 |
|
57 /****************************************************************************/ |
|
58 |
|
59 |
|
60 bool ready_WiFi(void) |
|
61 { |
|
62 if (wifi_state->STA_connected && wifi_state->STA_online) |
|
63 return true; |
|
64 return false; |
|
65 } |
|
66 |
|
67 |
|
68 |
|
69 void status_WiFi(void) |
|
70 { |
|
71 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_STATUS); |
|
72 } |
|
73 |
|
74 |
|
75 |
|
76 void request_WiFi(void) |
|
77 { |
|
78 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
79 } |
|
80 |
|
81 |
|
82 void scan_WiFi(void) |
|
83 { |
|
84 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN); |
|
85 } |
|
86 |
|
87 |
|
88 void disconnect_WiFi(void) |
|
89 { |
|
90 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); |
|
91 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
92 } |
|
93 |
|
94 |
|
95 static void print_servers(void) |
|
96 { |
|
97 ESP_LOGI(TAG, "List of configured NTP servers:"); |
|
98 |
|
99 for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){ |
|
100 if (esp_sntp_getservername(i)){ |
|
101 ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i)); |
|
102 } else { |
|
103 // we have either IPv4 or IPv6 address, let's print it |
|
104 char buff[64]; |
|
105 ip_addr_t const *ip = esp_sntp_getserver(i); |
|
106 if (ipaddr_ntoa_r(ip, buff, 64) != NULL) |
|
107 ESP_LOGI(TAG, "server %d: %s", i, buff); |
|
108 } |
|
109 } |
|
110 } |
|
111 |
|
112 |
|
113 static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
114 { |
|
115 switch (event_id) { |
|
116 |
|
117 case WIFI_EVENT_SCAN_DONE: |
|
118 { |
|
119 /* Get the results so the memory used is freed. */ |
|
120 ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, accessp_records)); |
|
121 ESP_LOGI(TAG, "Event wifi Scane done, %d records", ap_num); |
|
122 _wifi_BetterAP = false; |
|
123 for (int i = 0; i < ap_num; i++) { |
|
124 wifi_ap_record_t ap = accessp_records[i]; |
|
125 ESP_LOGI(TAG, "AP:%d bssid:%02x:%02x:%02x:%02x:%02x:%02x ssid:%s ch:%d rssi:%d", |
|
126 i, ap.bssid[0], ap.bssid[1], ap.bssid[2], ap.bssid[3], ap.bssid[4], ap.bssid[5], |
|
127 ap.ssid, ap.primary, ap.rssi); |
|
128 if (ap.rssi > CONFIG_ESP_WIFI_ROAMING_LEVEL && ap.rssi > (_wifi_RSSI + 3)) { |
|
129 _wifi_BetterAP = true; |
|
130 ESP_LOGI(TAG, "AP:%d is a better AP", i); |
|
131 } |
|
132 } |
|
133 _wifi_Scanned = ap_num; |
|
134 _wifi_ScanDone = true; |
|
135 if (_wifi_BetterAP) { |
|
136 ESP_LOGI(TAG, "Disconnect current AP"); |
|
137 disconnect_WiFi(); |
|
138 } |
|
139 break; |
|
140 } |
|
141 |
|
142 case WIFI_EVENT_STA_START: |
|
143 { |
|
144 ESP_LOGI(TAG, "Event wifi START"); |
|
145 // Set the configured hostname for the dhcp client. |
|
146 ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, hostname)); |
|
147 esp_wifi_connect(); |
|
148 _wifi_BetterAP = false; |
|
149 break; |
|
150 } |
|
151 |
|
152 case WIFI_EVENT_STA_CONNECTED: |
|
153 { |
|
154 wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data; |
|
155 wifi_ap_record_t ap_info; |
|
156 esp_wifi_sta_get_ap_info(&ap_info); |
|
157 ESP_LOGI(TAG, "Event STA connected, ssid:%s, bssid:" MACSTR ", channel:%d, rssi: %d, authmode:%s", |
|
158 ap_info.ssid, MAC2STR(ap_info.bssid), event->channel, ap_info.rssi, apsec[event->authmode]); |
|
159 if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { |
|
160 wifi_state->STA_connected = true; |
|
161 wifi_state->STA_rssi = ap_info.rssi; |
|
162 wifi_state->STA_channel = ap_info.primary; |
|
163 sprintf(wifi_state->STA_ssid, "%s", ap_info.ssid); |
|
164 snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
165 ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]); |
|
166 xSemaphoreGive(xSemaphoreWiFi); |
|
167 } else { |
|
168 ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_CONNECTED"); |
|
169 } |
|
170 print_servers(); |
|
171 _wifi_BetterAP = false; |
|
172 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); |
|
173 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
174 break; |
|
175 } |
|
176 |
|
177 case WIFI_EVENT_STA_DISCONNECTED: |
|
178 { |
|
179 wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data; |
|
180 |
|
181 ESP_LOGI(TAG, "Event STA disconnected, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", |
|
182 disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason); |
|
183 if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { |
|
184 wifi_state->STA_connected = false; |
|
185 wifi_state->STA_online = false; |
|
186 wifi_state->STA_rssi = 0; |
|
187 xSemaphoreGive(xSemaphoreWiFi); |
|
188 } else { |
|
189 ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_DISCONNECTED"); |
|
190 } |
|
191 _wifi_BetterAP = false; |
|
192 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); |
|
193 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
194 break; |
|
195 } |
|
196 |
|
197 default: |
|
198 ESP_LOGW(TAG, "Unknown WiFi event %ld", event_id); |
|
199 break; |
|
200 } |
|
201 } |
|
202 |
|
203 |
|
204 |
|
205 static void got_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
206 { |
|
207 switch (event_id) { |
|
208 |
|
209 case IP_EVENT_STA_GOT_IP: |
|
210 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_HAS_IP); |
|
211 ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
|
212 if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) { |
|
213 wifi_state->STA_online = true; |
|
214 snprintf(wifi_state->STA_ip, 16, IPSTR, IP2STR(&event->ip_info.ip)); |
|
215 snprintf(wifi_state->STA_nm, 16, IPSTR, IP2STR(&event->ip_info.netmask)); |
|
216 snprintf(wifi_state->STA_gw, 16, IPSTR, IP2STR(&event->ip_info.gw)); |
|
217 xSemaphoreGive(xSemaphoreWiFi); |
|
218 } else { |
|
219 ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP"); |
|
220 } |
|
221 |
|
222 // ESP_LOGI(TAG, "Starting SNTP"); |
|
223 // esp_netif_sntp_start(); |
|
224 |
|
225 break; |
|
226 |
|
227 case IP_EVENT_STA_LOST_IP: |
|
228 ESP_LOGW(TAG, "Lost IP address"); |
|
229 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_HAS_IP); |
|
230 if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) { |
|
231 wifi_state->STA_ip[0] = '\0'; |
|
232 wifi_state->STA_nm[0] = '\0'; |
|
233 wifi_state->STA_gw[0] = '\0'; |
|
234 wifi_state->STA_online = false; |
|
235 xSemaphoreGive(xSemaphoreWiFi); |
|
236 } else { |
|
237 ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP"); |
|
238 } |
|
239 break; |
|
240 |
|
241 case IP_EVENT_AP_STAIPASSIGNED: |
|
242 ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED"); |
|
243 break; |
|
244 |
|
245 default: |
|
246 ESP_LOGW(TAG, "Unknown IP event %ld", event_id); |
|
247 break; |
|
248 } |
|
249 } |
|
250 |
|
251 |
|
252 void time_sync_notification_cb(struct timeval *tv) |
|
253 { |
|
254 time_t now; |
|
255 char strftime_buf[64]; |
|
256 struct tm timeinfo; |
|
257 |
|
258 ESP_LOGI(TAG, "Notification of a time synchronization event"); |
|
259 int rc = sntp_get_sync_status(); |
|
260 |
|
261 if (rc == SNTP_SYNC_STATUS_COMPLETED) { |
|
262 time(&now); |
|
263 localtime_r(&now, &timeinfo); |
|
264 // System_TimeOk = true; |
|
265 strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); |
|
266 ESP_LOGI(TAG, "NTP time is set: %s", strftime_buf); |
|
267 } else { |
|
268 ESP_LOGI(TAG, "NTP unknown time sync event rc=%d", rc); |
|
269 } |
|
270 } |
|
271 |
|
272 |
|
273 void task_wifi( void * pvParameters ) |
|
274 { |
|
275 ESP_LOGI(TAG, "Starting WiFi"); |
|
276 |
|
277 /* event handler and event group for the wifi driver */ |
|
278 xEventGroupWifi = xEventGroupCreate(); |
|
279 /* initialize the tcp stack */ |
|
280 ESP_ERROR_CHECK(esp_netif_init()); |
|
281 ESP_ERROR_CHECK(esp_event_loop_create_default()); |
|
282 |
|
283 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
|
284 ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
|
285 |
|
286 sta_netif = esp_netif_create_default_wifi_sta(); |
|
287 assert(sta_netif); |
|
288 |
|
289 /* |
|
290 * Setup SNTP configuration |
|
291 */ |
|
292 /** |
|
293 * NTP server address could be acquired via DHCP, |
|
294 * see following menuconfig options: |
|
295 * 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP |
|
296 * 'LWIP_SNTP_DEBUG' - enable debugging messages |
|
297 * |
|
298 * NOTE: This call should be made BEFORE esp acquires IP address from DHCP, |
|
299 * otherwise NTP option would be rejected by default. |
|
300 */ |
|
301 ESP_LOGI(TAG, "Initializing SNTP"); |
|
302 esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); |
|
303 config.start = false; // start SNTP service explicitly (after connecting) |
|
304 config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting) |
|
305 config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease |
|
306 config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact |
|
307 config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; |
|
308 config.sync_cb = time_sync_notification_cb; // only if we need the notification function |
|
309 esp_netif_sntp_init(&config); |
|
310 ESP_LOGI(TAG, "Starting SNTP"); |
|
311 esp_netif_sntp_start(); |
|
312 |
|
313 |
|
314 /* |
|
315 * memory allocation of objects used by the task |
|
316 */ |
|
317 accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM); |
|
318 xSemaphoreWiFi = xSemaphoreCreateMutex(); |
|
319 wifi_state = malloc(sizeof(WIFI_State)); |
|
320 memset(wifi_state, 0x00, sizeof(WIFI_State)); |
|
321 |
|
322 /* |
|
323 * init wifi as station |
|
324 */ |
|
325 esp_event_handler_instance_t instance_any_id; |
|
326 esp_event_handler_instance_t instance_got_ip; |
|
327 ESP_ERROR_CHECK( esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id) ); |
|
328 ESP_ERROR_CHECK( esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, &got_ip_event_handler, NULL, &instance_got_ip) ); |
|
329 |
|
330 wifi_config_t wifi_config = { |
|
331 .sta = { |
|
332 .ssid = CONFIG_ESP_WIFI_SSID, |
|
333 .password = CONFIG_ESP_WIFI_PASSWORD, |
|
334 #if CONFIG_WIFI_ALL_CHANNEL_SCAN |
|
335 .scan_method = WIFI_ALL_CHANNEL_SCAN, |
|
336 #elif CONFIG_WIFI_FAST_SCAN |
|
337 .scan_method = WIFI_FAST_SCAN, |
|
338 #endif |
|
339 .failure_retry_cnt = 3, |
|
340 .sort_method = WIFI_CONNECT_AP_BY_SIGNAL, |
|
341 .threshold.rssi = CONFIG_ESP_FAST_SCAN_MINIMUM_SIGNAL, |
|
342 .threshold.authmode = WIFI_AUTH_WPA2_PSK, |
|
343 }, |
|
344 }; |
|
345 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); |
|
346 ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); |
|
347 ESP_ERROR_CHECK(esp_wifi_start()); |
|
348 |
|
349 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
350 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); |
|
351 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
352 EventBits_t uxBits; |
|
353 |
|
354 for(;;) { |
|
355 |
|
356 /* actions that can trigger: request a connection, a scan, or a disconnection */ |
|
357 uxBits = xEventGroupWaitBits(xEventGroupWifi, |
|
358 TASK_WIFI_REQUEST_STA_CONNECT | TASK_WIFI_REQUEST_STA_DISCONNECT | TASK_WIFI_REQUEST_STA_SCAN | TASK_WIFI_REQUEST_STA_STATUS, |
|
359 pdFALSE, pdFALSE, portMAX_DELAY ); |
|
360 |
|
361 if (uxBits & TASK_WIFI_REQUEST_STA_DISCONNECT) { |
|
362 /* |
|
363 * user requested a disconnect, this will in effect disconnect the wifi |
|
364 */ |
|
365 ESP_LOGI(TAG, "Request STA disconnect"); |
|
366 ESP_ERROR_CHECK(esp_wifi_disconnect()); |
|
367 xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY ); |
|
368 |
|
369 /* finally: release the scan request bit */ |
|
370 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); |
|
371 ESP_LOGI(TAG, "Request STA disconnect is done"); |
|
372 |
|
373 } else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) { |
|
374 |
|
375 ESP_LOGI(TAG, "Request STA connect"); |
|
376 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); |
|
377 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
378 |
|
379 ESP_LOGI(TAG, "Connecting to `%s'", CONFIG_ESP_WIFI_SSID); |
|
380 esp_err_t wifierror = esp_wifi_connect(); |
|
381 if (wifierror != ESP_OK) { |
|
382 ESP_LOGE(TAG, "esp_wifi_connect() `%s' rc=%04x", CONFIG_ESP_WIFI_SSID, (int)wifierror); |
|
383 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); |
|
384 } |
|
385 uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS); |
|
386 |
|
387 } else if (uxBits & TASK_WIFI_REQUEST_STA_STATUS) { |
|
388 /* |
|
389 * Request WiFi update status, refresh the rssi. |
|
390 */ |
|
391 ESP_LOGD(TAG, "Request STA status"); |
|
392 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_STATUS); |
|
393 wifi_ap_record_t ap_info; |
|
394 esp_wifi_sta_get_ap_info(&ap_info); |
|
395 ESP_LOGI(TAG, "Event STA status, ssid:%s, bssid:" MACSTR ", rssi: %d", ap_info.ssid, MAC2STR(ap_info.bssid), ap_info.rssi); |
|
396 _wifi_RSSI = ap_info.rssi; |
|
397 _wifi_BetterAP = false; |
|
398 if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { |
|
399 wifi_state->STA_rssi = ap_info.rssi; |
|
400 wifi_state->STA_channel = ap_info.primary; |
|
401 snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
402 ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]); |
|
403 xSemaphoreGive(xSemaphoreWiFi); |
|
404 } else { |
|
405 ESP_LOGE(TAG, "lock error TASK_WIFI_REQUEST_STA_STATUS"); |
|
406 } |
|
407 |
|
408 } else if (uxBits & TASK_WIFI_REQUEST_STA_SCAN) { |
|
409 |
|
410 ESP_LOGI(TAG, "Request STA scan"); |
|
411 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN); |
|
412 /* safe guard against overflow */ |
|
413 ap_num = MAX_AP_NUM; |
|
414 _wifi_ScanDone = false; |
|
415 _wifi_BetterAP = false; |
|
416 ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false)); |
|
417 } |
|
418 |
|
419 } /* for(;;) */ |
|
420 } |
|
421 |
|
422 |