Wed, 29 Mar 2023 21:39:07 +0200
Added Wifi task.
4 | 1 | /** |
2 | * @file task_wifi.c | |
3 | * @brief WiFi task. Connects to a known Access Point. | |
4 | */ | |
5 | ||
6 | ||
7 | #include "config.h" | |
8 | ||
9 | ||
10 | static const char *TAG = "task_wifi"; | |
11 | ||
12 | #define ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID | |
13 | #define ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD | |
14 | ||
15 | SemaphoreHandle_t xSemaphoreWiFi = NULL; ///< Semaphore WiFi task. | |
16 | EventGroupHandle_t xEventGroupWifi; ///< Events WiFi task. | |
17 | wifi_config_t wifi_Config = { ///< Current STA configuration. | |
18 | .sta = { | |
19 | .ssid = ESP_WIFI_SSID, | |
20 | .password = ESP_WIFI_PASS, | |
21 | .scan_method = WIFI_FAST_SCAN, | |
22 | .sort_method = WIFI_CONNECT_AP_BY_SECURITY, | |
23 | .threshold.rssi = -127, | |
24 | .threshold.authmode = WIFI_AUTH_WPA2_PSK, | |
25 | }, | |
26 | }; | |
27 | WIFI_State *wifi_state = NULL; ///< Public state for other tasks. | |
28 | esp_netif_t *sta_netif = NULL; ///< Station interface | |
29 | ||
30 | ||
31 | const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT1; ///< When set, means a client requested to disconnect from currently connected AP. | |
32 | const int TASK_WIFI_REQUEST_STA_CONNECT = BIT2; ///< When set, means a client requested to connect to an access point. | |
33 | ||
34 | const int TASK_WIFI_HAS_IP = BIT3; ///< Indicate that we have an IP address | |
35 | const int TASK_WIFI_STA_FAILED = BIT5; ///< Indicate that we could not get a connection to AP as station. | |
36 | const int TASK_WIFI_STA_DISCONNECTED = BIT6; ///< Indicate that we are disconnected from an ap station. | |
37 | const int TASK_WIFI_STA_CONNECTED = BIT7; ///< Indicate that we are connected to AP as station, flip of BIT6. | |
38 | ||
39 | ||
40 | /****************************************************************************/ | |
41 | ||
42 | ||
43 | bool ready_WiFi(void) | |
44 | { | |
45 | if (wifi_state->STA_connected && wifi_state->STA_online) | |
46 | return true; | |
47 | return false; | |
48 | } | |
49 | ||
50 | ||
51 | ||
52 | void request_WiFi(bool connect) | |
53 | { | |
54 | if (connect) | |
55 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); | |
56 | else | |
57 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); | |
58 | } | |
59 | ||
60 | ||
61 | ||
62 | static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) | |
63 | { | |
64 | switch (event_id) { | |
65 | ||
66 | case WIFI_EVENT_STA_START: | |
67 | ESP_LOGI(TAG, "Event wifi START"); | |
68 | // Set the hostname for the dhcp client. | |
69 | #ifdef CONFIG_CODE_PRODUCTION | |
70 | ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, "balkon")); | |
71 | #endif | |
72 | #ifdef CONFIG_CODE_TESTING | |
73 | ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, "wemos")); | |
74 | #endif | |
75 | // ESP_ERROR_CHECK(esp_wifi_connect()); | |
76 | break; | |
77 | ||
78 | case WIFI_EVENT_STA_CONNECTED: { | |
79 | // system_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data; | |
80 | wifi_ap_record_t ap_info; | |
81 | esp_wifi_sta_get_ap_info(&ap_info); | |
82 | ESP_LOGI(TAG, "Event STA connected rssi=%d", ap_info.rssi); | |
83 | if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { | |
84 | wifi_state->STA_connected = true; | |
85 | wifi_state->STA_rssi = ap_info.rssi; | |
86 | xSemaphoreGive(xSemaphoreWiFi); | |
87 | } else { | |
88 | ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_CONNECTED"); | |
89 | } | |
90 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); | |
91 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); | |
92 | break; | |
93 | } | |
94 | ||
95 | case WIFI_EVENT_STA_DISCONNECTED: { | |
96 | ESP_LOGI(TAG, "Event STA disconnected"); | |
97 | // wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data; | |
98 | // ESP_LOGI(TAG, "Event STA disconnected, reason:%d", disconnected->reason); | |
99 | if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { | |
100 | wifi_state->STA_connected = false; | |
101 | wifi_state->STA_online = false; | |
102 | //wifi_state->STA_rssi = 0; | |
103 | xSemaphoreGive(xSemaphoreWiFi); | |
104 | } else { | |
105 | ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_DISCONNECTED"); | |
106 | } | |
107 | // connect_mqtt(false); | |
108 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); | |
109 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); | |
110 | break; | |
111 | } | |
112 | ||
113 | default: | |
114 | ESP_LOGW(TAG, "Unknown WiFi event %d", (int)event_id); | |
115 | break; | |
116 | } | |
117 | } | |
118 | ||
119 | ||
120 | ||
121 | static void got_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) | |
122 | { | |
123 | switch (event_id) { | |
124 | ||
125 | case IP_EVENT_STA_GOT_IP: | |
126 | ESP_LOGE(TAG, "got_ip_event_handler()"); | |
127 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_HAS_IP); | |
128 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; | |
129 | if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) { | |
130 | wifi_state->STA_online = true; | |
131 | snprintf(wifi_state->STA_ip, 16, IPSTR, IP2STR(&event->ip_info.ip)); | |
132 | snprintf(wifi_state->STA_nm, 16, IPSTR, IP2STR(&event->ip_info.netmask)); | |
133 | snprintf(wifi_state->STA_gw, 16, IPSTR, IP2STR(&event->ip_info.gw)); | |
134 | xSemaphoreGive(xSemaphoreWiFi); | |
135 | } else { | |
136 | ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP"); | |
137 | } | |
138 | // connect_mqtt(true); | |
139 | break; | |
140 | ||
141 | case IP_EVENT_STA_LOST_IP: | |
142 | ESP_LOGW(TAG, "Lost IP address"); | |
143 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_HAS_IP); | |
144 | if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) { | |
145 | wifi_state->STA_ip[0] = '\0'; | |
146 | wifi_state->STA_nm[0] = '\0'; | |
147 | wifi_state->STA_gw[0] = '\0'; | |
148 | wifi_state->STA_online = false; | |
149 | xSemaphoreGive(xSemaphoreWiFi); | |
150 | } else { | |
151 | ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP"); | |
152 | } | |
153 | // connect_mqtt(false); | |
154 | break; | |
155 | ||
156 | case IP_EVENT_AP_STAIPASSIGNED: | |
157 | ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED"); | |
158 | break; | |
159 | ||
160 | default: | |
161 | ESP_LOGW(TAG, "Unknown IP event %d", (int)event_id); | |
162 | break; | |
163 | } | |
164 | } | |
165 | ||
166 | ||
167 | ||
168 | void task_wifi( void * pvParameters ) | |
169 | { | |
170 | ESP_LOGI(TAG, "Start WiFi"); | |
171 | ||
172 | /* | |
173 | * Initialize NVS | |
174 | */ | |
175 | esp_err_t ret = nvs_flash_init(); | |
176 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { | |
177 | ESP_ERROR_CHECK(nvs_flash_erase()); | |
178 | ret = nvs_flash_init(); | |
179 | } | |
180 | ESP_ERROR_CHECK(ret); | |
181 | ||
182 | /* event handler and event group for the wifi driver */ | |
183 | xEventGroupWifi = xEventGroupCreate(); | |
184 | /* initialize the tcp stack */ | |
185 | ESP_ERROR_CHECK(esp_netif_init()); | |
186 | ESP_ERROR_CHECK(esp_event_loop_create_default()); | |
187 | sta_netif = esp_netif_create_default_wifi_sta(); | |
188 | assert(sta_netif); | |
189 | ||
190 | /* | |
191 | * memory allocation of objects used by the task | |
192 | */ | |
193 | xSemaphoreWiFi = xSemaphoreCreateMutex(); | |
194 | wifi_state = malloc(sizeof(WIFI_State)); | |
195 | memset(wifi_state, 0x00, sizeof(WIFI_State)); | |
196 | sprintf(wifi_state->STA_ssid, "%s", ESP_WIFI_SSID); | |
197 | ||
198 | /* | |
199 | * init wifi as station | |
200 | */ | |
201 | wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); | |
202 | ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config)); | |
203 | ||
204 | esp_event_handler_instance_t instance_any_id; | |
205 | esp_event_handler_instance_t instance_got_ip; | |
206 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id) ); | |
207 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, /*IP_EVENT_STA_GOT_IP*/ ESP_EVENT_ANY_ID, &got_ip_event_handler, NULL, &instance_got_ip) ); | |
208 | ||
209 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); | |
210 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_Config) ); | |
211 | ESP_ERROR_CHECK(esp_wifi_start()); | |
212 | ||
213 | //xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); | |
214 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); | |
215 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); | |
216 | EventBits_t uxBits; | |
217 | ||
218 | ESP_LOGI(TAG, "Startup completed, enter task loop"); | |
219 | ||
220 | for(;;) { | |
221 | ||
222 | /* actions that can trigger: request a connection or a disconnection */ | |
223 | uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT | TASK_WIFI_REQUEST_STA_DISCONNECT, | |
224 | pdFALSE, pdFALSE, portMAX_DELAY ); | |
225 | ||
226 | if (uxBits & TASK_WIFI_REQUEST_STA_DISCONNECT) { | |
227 | /* | |
228 | * user requested a disconnect, this will in effect disconnect the wifi | |
229 | */ | |
230 | // connect_mqtt(false); | |
231 | ESP_LOGI(TAG, "Request STA disconnect"); | |
232 | ESP_ERROR_CHECK(esp_wifi_disconnect()); | |
233 | xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY ); | |
234 | ||
235 | /* finally: release the request bit */ | |
236 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); | |
237 | ||
238 | } else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) { | |
239 | ||
240 | ESP_LOGI(TAG, "Request STA connect `%s' `%s'", wifi_Config.sta.ssid, wifi_Config.sta.password); | |
241 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); | |
242 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_Config)); | |
243 | ||
244 | esp_err_t wifierror = esp_wifi_connect(); | |
245 | if (wifierror != ESP_OK) { | |
246 | ESP_LOGE(TAG, "esp_wifi_connect() rc=%04x", (int)wifierror); | |
247 | xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); | |
248 | } else { | |
249 | ESP_LOGI(TAG, "Connected Ok"); | |
250 | } | |
251 | ||
252 | /* | |
253 | * 3 scenarios here: connection is successful and TASK_WIFI_STA_CONNECTED will be posted | |
254 | * or it's a failure and we get a TASK_WIFI_STA_FAILED with a reason code. | |
255 | * Or, option 3, the 5 seconds timeout is reached. This happens when the AP is not in range. | |
256 | * Note that the reason code is not exploited. For all intent and purposes a failure is a failure. | |
257 | */ | |
258 | uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS); | |
259 | ||
260 | if (uxBits & (TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED)) { | |
261 | /* | |
262 | * only save the config if the connection was successful! | |
263 | */ | |
264 | if (uxBits & TASK_WIFI_STA_CONNECTED) { | |
265 | /* save wifi config */ | |
266 | //SaveStaConfig(); | |
267 | } else { | |
268 | ESP_LOGI(TAG, "No AP found"); | |
269 | vTaskDelay(3000 / portTICK_PERIOD_MS); | |
270 | ESP_LOGW(TAG, "Connection failed"); | |
271 | /* failed attempt to connect regardles of the reason */ | |
272 | ||
273 | /* otherwise: reset the config */ | |
274 | //memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t)); | |
275 | } | |
276 | } | |
277 | ||
278 | /* finally: release the request bit */ | |
279 | xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); | |
280 | } | |
281 | ||
282 | } /* for(;;) */ | |
283 | vTaskDelay(10 / portTICK_PERIOD_MS); | |
284 | } | |
285 | ||
286 |