|
1 /** |
|
2 * @file task_wifi.c |
|
3 * @brief WiFi task. Connect to the known AP with the strongest signal. |
|
4 */ |
|
5 |
|
6 |
|
7 #include "config.h" |
|
8 |
|
9 |
|
10 static const char *TAG = "task_wifi"; |
|
11 |
|
12 |
|
13 SemaphoreHandle_t xSemaphoreWiFi = NULL; ///< Semaphore WiFi task. |
|
14 EventGroupHandle_t xEventGroupWifi; ///< Events WiFi task. |
|
15 uint16_t ap_num = MAX_AP_NUM; ///< Scan counter. |
|
16 wifi_ap_record_t *accessp_records; ///< [MAX_AP_NUM] records array with scan results. |
|
17 wifi_config_t *task_wifi_ConfigSTA = NULL; ///< Current STA configuration. |
|
18 WIFI_State *wifi_state = NULL; ///< Public state for other tasks. |
|
19 |
|
20 wifi_scan_config_t scan_config = { ///< WiFi scanner configuration. |
|
21 .ssid = 0, |
|
22 .bssid = 0, |
|
23 .channel = 0, |
|
24 .show_hidden = false, |
|
25 .scan_time.passive = 130 ///< Beacons are usually sent every 100 mSec. |
|
26 }; |
|
27 |
|
28 uint8_t _wifi_ssid[33]; ///< Current SSID |
|
29 bool _wifi_ScanAPs = false; ///< Scanning |
|
30 bool _wifi_ScanDone = false; ///< Scan ready |
|
31 uint16_t _wifi_Scanned = 0; ///< Total scanned APs. |
|
32 |
|
33 extern uint32_t TimeSpent; ///< Counter that is increased each second. |
|
34 extern bool System_TimeOk; |
|
35 extern time_t now; |
|
36 extern char strftime_buf[64]; |
|
37 extern struct tm timeinfo; |
|
38 |
|
39 const int TASK_WIFI_REQUEST_WIFI_SCAN = BIT0; ///< When set, means a client requested to scan wireless networks. |
|
40 const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT1; ///< When set, means a client requested to disconnect from currently connected AP. |
|
41 const int TASK_WIFI_REQUEST_STA_CONNECT = BIT2; ///< When set, means a client requested to connect to an access point. |
|
42 |
|
43 const int TASK_WIFI_HAS_IP = BIT3; ///< Indicate that we have an IP address |
|
44 const int TASK_WIFI_STA_FAILED = BIT4; ///< Indicate that we could not get a connection to AP as station. |
|
45 const int TASK_WIFI_STA_DISCONNECTED = BIT5; ///< Indicate that we are disconnected from an ap station. |
|
46 const int TASK_WIFI_STA_CONNECTED = BIT6; ///< Indicate that we are connected to AP as station, flip of BIT6. |
|
47 |
|
48 const int TASK_WIFI_REQUEST_SYSTEM = BIT8; ///< The system needs a connection |
|
49 const int TASK_WIFI_REQUEST_USER = BIT9; ///< The user needs a connection |
|
50 |
|
51 |
|
52 /** |
|
53 * @brief local callback function. Is called when the timesync is valid |
|
54 * from a timeserver. Sets the global boolean System_TimeOk value. |
|
55 * @param tv is the received time. Not used. |
|
56 */ |
|
57 void time_sync_notification_cb(struct timeval *tv); |
|
58 |
|
59 /** |
|
60 * @brief Array with AP security names |
|
61 */ |
|
62 const char *apsec[] = { "Open", "WEP", "WPA", "WPA2", "WPA WPA2", "Enterprise" }; |
|
63 |
|
64 |
|
65 /****************************************************************************/ |
|
66 |
|
67 |
|
68 |
|
69 void requestWiFi_system(bool state) |
|
70 { |
|
71 if (state) |
|
72 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_SYSTEM); |
|
73 else |
|
74 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_SYSTEM); |
|
75 |
|
76 if (xEventGroupGetBits(xEventGroupWifi) & (TASK_WIFI_REQUEST_SYSTEM | TASK_WIFI_REQUEST_USER)) |
|
77 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
78 else |
|
79 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); |
|
80 } |
|
81 |
|
82 |
|
83 |
|
84 void requestWiFi_user(bool state) |
|
85 { |
|
86 if (state) |
|
87 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_USER); |
|
88 else |
|
89 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_USER); |
|
90 |
|
91 if (xEventGroupGetBits(xEventGroupWifi) & (TASK_WIFI_REQUEST_SYSTEM | TASK_WIFI_REQUEST_USER)) |
|
92 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); |
|
93 else |
|
94 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); |
|
95 } |
|
96 |
|
97 |
|
98 |
|
99 bool ready_WiFi(void) |
|
100 { |
|
101 if (wifi_state->STA_connected && wifi_state->STA_online) |
|
102 return true; |
|
103 return false; |
|
104 } |
|
105 |
|
106 |
|
107 |
|
108 static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
109 { |
|
110 switch (event_id) { |
|
111 |
|
112 case WIFI_EVENT_SCAN_DONE: |
|
113 // Get the results so the memory used is freed. |
|
114 ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, accessp_records)); |
|
115 _wifi_Scanned = ap_num; |
|
116 _wifi_ScanDone = true; |
|
117 break; |
|
118 |
|
119 case WIFI_EVENT_STA_START: |
|
120 ESP_LOGI(TAG, "Event wifi START"); |
|
121 // Set the configured hostname for the dhcp client. |
|
122 ESP_ERROR_CHECK(tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, config.hostname)); |
|
123 esp_wifi_connect(); |
|
124 break; |
|
125 |
|
126 case WIFI_EVENT_STA_CONNECTED: |
|
127 { |
|
128 wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data; |
|
129 wifi_ap_record_t ap_info; |
|
130 esp_wifi_sta_get_ap_info(&ap_info); |
|
131 ESP_LOGI(TAG, "Event STA connected, ssid:%s, bssid:" MACSTR ", channel:%d, rssi: %d, authmode:%s", |
|
132 ap_info.ssid, MAC2STR(ap_info.bssid), event->channel, ap_info.rssi, apsec[event->authmode]); |
|
133 if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) { |
|
134 wifi_state->STA_connected = true; |
|
135 wifi_state->STA_rssi = ap_info.rssi; |
|
136 sprintf(wifi_state->STA_ssid, "%s", ap_info.ssid); |
|
137 xSemaphoreGive(xSemaphoreWiFi); |
|
138 } |
|
139 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); |
|
140 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
141 break; |
|
142 } |
|
143 |
|
144 case WIFI_EVENT_STA_DISCONNECTED: |
|
145 { |
|
146 wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data; |
|
147 |
|
148 ESP_LOGI(TAG, "Event STA disconnected, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", |
|
149 disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason); |
|
150 if (xSemaphoreTake(xSemaphoreWiFi, 10) == pdTRUE) { |
|
151 wifi_state->STA_connected = false; |
|
152 wifi_state->STA_online = false; |
|
153 wifi_state->STA_rssi = 0; |
|
154 xSemaphoreGive(xSemaphoreWiFi); |
|
155 } |
|
156 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); |
|
157 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
158 break; |
|
159 } |
|
160 |
|
161 default: |
|
162 ESP_LOGI(TAG, "Unknown WiFi event %d", event_id); |
|
163 break; |
|
164 } |
|
165 } |
|
166 |
|
167 |
|
168 |
|
169 static void got_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
170 { |
|
171 switch (event_id) { |
|
172 |
|
173 case IP_EVENT_STA_GOT_IP: |
|
174 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_HAS_IP); |
|
175 ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
|
176 if (xSemaphoreTake(xSemaphoreWiFi, 10) == pdTRUE) { |
|
177 wifi_state->STA_online = true; |
|
178 snprintf(wifi_state->STA_ip, 16, "%s", ip4addr_ntoa(&event->ip_info.ip)); |
|
179 snprintf(wifi_state->STA_nm, 16, "%s", ip4addr_ntoa(&event->ip_info.netmask)); |
|
180 snprintf(wifi_state->STA_gw, 16, "%s", ip4addr_ntoa(&event->ip_info.gw)); |
|
181 xSemaphoreGive(xSemaphoreWiFi); |
|
182 } |
|
183 break; |
|
184 |
|
185 case IP_EVENT_STA_LOST_IP: |
|
186 ESP_LOGW(TAG, "Lost IP address"); |
|
187 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_HAS_IP); |
|
188 if (xSemaphoreTake(xSemaphoreWiFi, 10) == pdTRUE) { |
|
189 wifi_state->STA_ip[0] = '\0'; |
|
190 wifi_state->STA_nm[0] = '\0'; |
|
191 wifi_state->STA_gw[0] = '\0'; |
|
192 wifi_state->STA_online = false; |
|
193 xSemaphoreGive(xSemaphoreWiFi); |
|
194 } |
|
195 break; |
|
196 |
|
197 default: |
|
198 ESP_LOGI(TAG, "Unknown IP event %d", event_id); |
|
199 break; |
|
200 } |
|
201 } |
|
202 |
|
203 |
|
204 |
|
205 void task_wifi( void * pvParameters ) |
|
206 { |
|
207 ESP_LOGI(TAG, "Starting WiFi"); |
|
208 |
|
209 /* event handler and event group for the wifi driver */ |
|
210 xEventGroupWifi = xEventGroupCreate(); |
|
211 /* initialize the tcp stack */ |
|
212 tcpip_adapter_init(); |
|
213 ESP_ERROR_CHECK(esp_event_loop_create_default()); |
|
214 |
|
215 /* |
|
216 * memory allocation of objects used by the task |
|
217 */ |
|
218 accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM); |
|
219 task_wifi_ConfigSTA = (wifi_config_t*)malloc(sizeof(wifi_config_t)); |
|
220 memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t)); |
|
221 |
|
222 xSemaphoreWiFi = xSemaphoreCreateMutex(); |
|
223 wifi_state = malloc(sizeof(WIFI_State)); |
|
224 wifi_state->STA_connected = false; |
|
225 wifi_state->STA_online = false; |
|
226 wifi_state->STA_rssi = 0; |
|
227 |
|
228 /* stop dhcp server and start dhcp client */ |
|
229 ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); |
|
230 ESP_ERROR_CHECK(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA)); |
|
231 |
|
232 /* |
|
233 * init wifi as station |
|
234 */ |
|
235 wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); |
|
236 ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config)); |
|
237 |
|
238 ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL) ); |
|
239 ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &got_ip_event_handler, NULL) ); |
|
240 |
|
241 ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); |
|
242 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); |
|
243 ESP_ERROR_CHECK(esp_wifi_start()); |
|
244 |
|
245 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); |
|
246 EventBits_t uxBits; |
|
247 |
|
248 for(;;) { |
|
249 |
|
250 /* actions that can trigger: request a connection, a scan, or a disconnection */ |
|
251 uxBits = xEventGroupWaitBits(xEventGroupWifi, |
|
252 TASK_WIFI_REQUEST_STA_CONNECT | TASK_WIFI_REQUEST_WIFI_SCAN | TASK_WIFI_REQUEST_STA_DISCONNECT, |
|
253 pdFALSE, pdFALSE, portMAX_DELAY ); |
|
254 |
|
255 if (uxBits & TASK_WIFI_REQUEST_STA_DISCONNECT) { |
|
256 /* |
|
257 * user requested a disconnect, this will in effect disconnect the wifi |
|
258 */ |
|
259 ESP_LOGI(TAG, "Request STA disconnect"); |
|
260 ESP_ERROR_CHECK(esp_wifi_disconnect()); |
|
261 xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY ); |
|
262 |
|
263 /* finally: release the scan request bit */ |
|
264 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); |
|
265 |
|
266 } else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) { |
|
267 |
|
268 ESP_LOGI(TAG, "Request STA connect"); |
|
269 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); |
|
270 _wifi_ScanAPs = true; |
|
271 _wifi_ScanDone = false; |
|
272 ap_num = MAX_AP_NUM; |
|
273 ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false)); |
|
274 while (_wifi_ScanDone == false) { |
|
275 vTaskDelay(10 / portTICK_PERIOD_MS); |
|
276 } |
|
277 ESP_LOGI(TAG, "Scan done %d APs", _wifi_Scanned); |
|
278 bool found = false; |
|
279 |
|
280 // Available Access Points. |
|
281 for (int i = 0; i < _wifi_Scanned; i++) { |
|
282 wifi_ap_record_t ap = accessp_records[i]; |
|
283 // Check if we know this AP in the database. |
|
284 // ESP_LOGI(TAG, "%d %-20s ch: %2d rssi: %d %s", i, ap.ssid, ap.primary, ap.rssi, apsec[ap.authmode]); |
|
285 if ((read_station(ap.ssid) >= 0)) { |
|
286 /* ssid */ |
|
287 size_t sz = sizeof(task_wifi_ConfigSTA->sta.ssid); |
|
288 memcpy(task_wifi_ConfigSTA->sta.ssid, wifiStation.SSID, sz); |
|
289 /* password */ |
|
290 sz = sizeof(task_wifi_ConfigSTA->sta.password); |
|
291 memcpy(task_wifi_ConfigSTA->sta.password, wifiStation.Password, sz); |
|
292 found = true; |
|
293 break; |
|
294 } |
|
295 } |
|
296 if (found) { |
|
297 /* |
|
298 * Now connect to the known SSID |
|
299 */ |
|
300 // ESP_LOGI(TAG, "Connecting to `%s'", task_wifi_ConfigSTA->sta.ssid); |
|
301 ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, task_wifi_ConfigSTA)); |
|
302 esp_err_t wifierror = esp_wifi_connect(); |
|
303 if (wifierror != ESP_OK) { |
|
304 ESP_LOGE(TAG, "esp_wifi_connect() `%s' rc=%04x", task_wifi_ConfigSTA->sta.ssid, (int)wifierror); |
|
305 xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); |
|
306 } |
|
307 uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS); |
|
308 if (uxBits & TASK_WIFI_STA_CONNECTED) |
|
309 xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); // Only clear when connected. |
|
310 } else { |
|
311 ESP_LOGI(TAG, "No known AP found, scan again"); |
|
312 vTaskDelay(3000 / portTICK_PERIOD_MS); |
|
313 } |
|
314 } |
|
315 |
|
316 } /* for(;;) */ |
|
317 vTaskDelay(10 / portTICK_PERIOD_MS); |
|
318 } |
|
319 |
|
320 |