wifi_manager.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  1. /*
  2. Copyright (c) 2017-2019 Tony Pottier
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in all
  10. copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17. SOFTWARE.
  18. @file wifi_manager.c
  19. @author Tony Pottier
  20. @brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis
  21. Contains the freeRTOS task and all necessary support
  22. @see https://idyl.io
  23. @see https://github.com/tonyp7/esp32-wifi-manager
  24. */
  25. #include "wifi_manager.h"
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdbool.h>
  30. #include "dns_server.h"
  31. #include "http_server.h"
  32. #include "json.h"
  33. #include "esp_system.h"
  34. #include "freertos/FreeRTOS.h"
  35. #include "freertos/task.h"
  36. #include "freertos/event_groups.h"
  37. #include "esp_event_loop.h"
  38. #include "esp_wifi.h"
  39. #include "esp_wifi_types.h"
  40. #include "esp_log.h"
  41. #include "nvs.h"
  42. #include "nvs_flash.h"
  43. #include "mdns.h"
  44. #include "lwip/api.h"
  45. #include "lwip/err.h"
  46. #include "lwip/netdb.h"
  47. #include "lwip/ip4_addr.h"
  48. #include "esp_ota_ops.h"
  49. #include "esp_app_format.h"
  50. #ifndef SQUEEZELITE_ESP32_RELEASE_URL
  51. #define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
  52. #endif
  53. #if RECOVERY_APPLICATION
  54. extern const char * ota_get_status();
  55. extern uint8_t ota_get_pct_complete();
  56. #endif
  57. /* objects used to manipulate the main queue of events */
  58. QueueHandle_t wifi_manager_queue;
  59. SemaphoreHandle_t wifi_manager_json_mutex = NULL;
  60. SemaphoreHandle_t wifi_manager_sta_ip_mutex = NULL;
  61. char *wifi_manager_sta_ip = NULL;
  62. uint16_t ap_num = MAX_AP_NUM;
  63. wifi_ap_record_t *accessp_records;
  64. char *accessp_json = NULL;
  65. char *ip_info_json = NULL;
  66. wifi_config_t* wifi_manager_config_sta = NULL;
  67. void (**cb_ptr_arr)(void*) = NULL;
  68. /* @brief tag used for ESP serial console messages */
  69. static const char TAG[] = "wifi_manager";
  70. /* @brief task handle for the main wifi_manager task */
  71. static TaskHandle_t task_wifi_manager = NULL;
  72. /**
  73. * The actual WiFi settings in use
  74. */
  75. struct wifi_settings_t wifi_settings = {
  76. .ap_ssid = DEFAULT_AP_SSID,
  77. .ap_pwd = DEFAULT_AP_PASSWORD,
  78. .ap_channel = DEFAULT_AP_CHANNEL,
  79. .ap_ssid_hidden = DEFAULT_AP_SSID_HIDDEN,
  80. .ap_bandwidth = DEFAULT_AP_BANDWIDTH,
  81. .sta_only = DEFAULT_STA_ONLY,
  82. .sta_power_save = DEFAULT_STA_POWER_SAVE,
  83. .sta_static_ip = 0,
  84. };
  85. const char wifi_manager_nvs_namespace[] = "espwifimgr";
  86. extern char current_namespace[];
  87. EventGroupHandle_t wifi_manager_event_group;
  88. /* @brief indicate that the ESP32 is currently connected. */
  89. const int WIFI_MANAGER_WIFI_CONNECTED_BIT = BIT0;
  90. const int WIFI_MANAGER_AP_STA_CONNECTED_BIT = BIT1;
  91. /* @brief Set automatically once the SoftAP is started */
  92. const int WIFI_MANAGER_AP_STARTED_BIT = BIT2;
  93. /* @brief When set, means a client requested to connect to an access point.*/
  94. const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT = BIT3;
  95. /* @brief This bit is set automatically as soon as a connection was lost */
  96. const int WIFI_MANAGER_STA_DISCONNECT_BIT = BIT4;
  97. /* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */
  98. const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT = BIT5;
  99. /* @brief When set, means a client requested to disconnect from currently connected AP. */
  100. const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT = BIT6;
  101. /* @brief When set, means a scan is in progress */
  102. const int WIFI_MANAGER_SCAN_BIT = BIT7;
  103. /* @brief When set, means user requested for a disconnect */
  104. const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT = BIT8;
  105. void wifi_manager_scan_async(){
  106. wifi_manager_send_message(ORDER_START_WIFI_SCAN, NULL);
  107. }
  108. void wifi_manager_disconnect_async(){
  109. wifi_manager_send_message(ORDER_DISCONNECT_STA, NULL);
  110. //xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT); TODO: delete
  111. }
  112. void wifi_manager_start(){
  113. /* disable the default wifi logging */
  114. esp_log_level_set("wifi", ESP_LOG_NONE);
  115. /* initialize flash memory */
  116. nvs_flash_init();
  117. /* memory allocation */
  118. wifi_manager_queue = xQueueCreate( 3, sizeof( queue_message) );
  119. wifi_manager_json_mutex = xSemaphoreCreateMutex();
  120. accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM);
  121. accessp_json = (char*)malloc(MAX_AP_NUM * JSON_ONE_APP_SIZE + 4); /* 4 bytes for json encapsulation of "[\n" and "]\0" */
  122. wifi_manager_clear_access_points_json();
  123. ip_info_json = (char*)malloc(sizeof(char) * JSON_IP_INFO_SIZE);
  124. wifi_manager_clear_ip_info_json();
  125. wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t));
  126. memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t));
  127. memset(&wifi_settings.sta_static_ip_config, 0x00, sizeof(tcpip_adapter_ip_info_t));
  128. cb_ptr_arr = malloc( sizeof( sizeof( void (*)( void* ) ) ) * MESSAGE_CODE_COUNT);
  129. for(int i=0; i<MESSAGE_CODE_COUNT; i++){
  130. cb_ptr_arr[i] = NULL;
  131. }
  132. wifi_manager_sta_ip_mutex = xSemaphoreCreateMutex();
  133. wifi_manager_sta_ip = (char*)malloc(sizeof(char) * IP4ADDR_STRLEN_MAX);
  134. wifi_manager_safe_update_sta_ip_string((uint32_t)0);
  135. /* start wifi manager task */
  136. xTaskCreate(&wifi_manager, "wifi_manager", 4096, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_wifi_manager);
  137. }
  138. uint8_t wifi_manager_get_flag(){
  139. uint8_t value=0;
  140. nvs_handle handle;
  141. esp_err_t esp_err;
  142. ESP_LOGI(TAG, "About to get config from flash");
  143. esp_err = nvs_open(current_namespace, NVS_READWRITE, &handle);
  144. if (esp_err != ESP_OK) return 0;
  145. esp_err= nvs_get_u8(handle, "autoexec", &value);
  146. nvs_close(handle);
  147. return value;
  148. }
  149. char * wifi_manager_alloc_get_config(char * name, size_t * l){
  150. size_t len=0;
  151. char * value=NULL;
  152. nvs_handle handle;
  153. ESP_LOGD(TAG, "About to get config value %s from flash",name);
  154. if (nvs_open(current_namespace, NVS_READWRITE, &handle) == ESP_OK) {
  155. if (nvs_get_str(handle, name, NULL, &len)==ESP_OK) {
  156. value=(char *)malloc(len);
  157. memset(value,0x0, len);
  158. nvs_get_str(handle, name, value, &len);
  159. *l=len;
  160. ESP_LOGD(TAG,"Found value %s, length %u = %s",name,*l,value);
  161. }
  162. else
  163. {
  164. ESP_LOGW(TAG, "Value %s does one exist in flash",name);
  165. }
  166. nvs_close(handle);
  167. }
  168. else
  169. {
  170. ESP_LOGE(TAG,"Unable to open nvs namespace %s",wifi_manager_nvs_namespace);
  171. }
  172. return value;
  173. }
  174. esp_err_t wifi_manager_save_autoexec_flag(uint8_t flag){
  175. nvs_handle handle;
  176. esp_err_t esp_err;
  177. ESP_LOGI(TAG, "About to save config to flash");
  178. esp_err=nvs_open(current_namespace, NVS_READWRITE, &handle);
  179. if (esp_err != ESP_OK) {
  180. ESP_LOGE(TAG,"Unable to open nvs namespace %s",wifi_manager_nvs_namespace);
  181. return esp_err;
  182. }
  183. esp_err = nvs_set_u8(handle, "autoexec", flag);
  184. if (esp_err != ESP_OK){
  185. ESP_LOGE(TAG,"Unable to save autoexec flag value %u",flag);
  186. nvs_close(handle);
  187. return esp_err;
  188. }
  189. esp_err = nvs_commit(handle);
  190. if (esp_err != ESP_OK){
  191. ESP_LOGE(TAG,"nvs commit error");
  192. return esp_err;
  193. }
  194. nvs_close(handle);
  195. ESP_LOGD(TAG, "wifi_manager_wrote autoexec flag value %u",flag);
  196. return ESP_OK;
  197. }
  198. esp_err_t wifi_manager_save_autoexec_config(char * value, char * name, int len){
  199. nvs_handle handle;
  200. esp_err_t esp_err;
  201. ESP_LOGI(TAG, "About to save config to flash");
  202. esp_err = nvs_open(current_namespace, NVS_READWRITE, &handle);
  203. if (esp_err != ESP_OK) {
  204. ESP_LOGE(TAG,"Unable to open nvs namespace %s",current_namespace);
  205. return esp_err;
  206. }
  207. esp_err = nvs_set_str(handle, name, value);
  208. if (esp_err != ESP_OK){
  209. ESP_LOGE(TAG,"Unable to save value %s=%s",name,value);
  210. nvs_close(handle);
  211. return esp_err;
  212. }
  213. esp_err = nvs_commit(handle);
  214. if (esp_err != ESP_OK){
  215. ESP_LOGE(TAG,"nvs commit error");
  216. return esp_err;
  217. }
  218. nvs_close(handle);
  219. ESP_LOGD(TAG, "wifi_manager_wrote %s=%s with length %i", name, value, len);
  220. return ESP_OK;
  221. }
  222. esp_err_t wifi_manager_save_sta_config(){
  223. nvs_handle handle;
  224. esp_err_t esp_err;
  225. ESP_LOGI(TAG, "About to save config to flash");
  226. if(wifi_manager_config_sta){
  227. esp_err = nvs_open(wifi_manager_nvs_namespace, NVS_READWRITE, &handle);
  228. if (esp_err != ESP_OK) return esp_err;
  229. esp_err = nvs_set_blob(handle, "ssid", wifi_manager_config_sta->sta.ssid, 32);
  230. if (esp_err != ESP_OK) return esp_err;
  231. esp_err = nvs_set_blob(handle, "password", wifi_manager_config_sta->sta.password, 64);
  232. if (esp_err != ESP_OK) return esp_err;
  233. esp_err = nvs_set_blob(handle, "settings", &wifi_settings, sizeof(wifi_settings));
  234. if (esp_err != ESP_OK) return esp_err;
  235. esp_err = nvs_commit(handle);
  236. if (esp_err != ESP_OK) return esp_err;
  237. nvs_close(handle);
  238. ESP_LOGD(TAG, "wifi_manager_wrote wifi_sta_config: ssid:%s password:%s",wifi_manager_config_sta->sta.ssid,wifi_manager_config_sta->sta.password);
  239. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: SoftAP_ssid: %s",wifi_settings.ap_ssid);
  240. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: SoftAP_pwd: %s",wifi_settings.ap_pwd);
  241. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: SoftAP_channel: %i",wifi_settings.ap_channel);
  242. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: SoftAP_hidden (1 = yes): %i",wifi_settings.ap_ssid_hidden);
  243. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: SoftAP_bandwidth (1 = 20MHz, 2 = 40MHz): %i",wifi_settings.ap_bandwidth);
  244. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_only (0 = APSTA, 1 = STA when connected): %i",wifi_settings.sta_only);
  245. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_power_save (1 = yes): %i",wifi_settings.sta_power_save);
  246. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_static_ip (0 = dhcp client, 1 = static ip): %i",wifi_settings.sta_static_ip);
  247. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_ip_addr: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.ip));
  248. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_gw_addr: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.gw));
  249. ESP_LOGD(TAG, "wifi_manager_wrote wifi_settings: sta_netmask: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.netmask));
  250. }
  251. return ESP_OK;
  252. }
  253. bool wifi_manager_fetch_wifi_sta_config(){
  254. nvs_handle handle;
  255. esp_err_t esp_err;
  256. if(nvs_open(wifi_manager_nvs_namespace, NVS_READONLY, &handle) == ESP_OK){
  257. if(wifi_manager_config_sta == NULL){
  258. wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t));
  259. }
  260. memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t));
  261. //memset(&wifi_settings, 0x00, sizeof(struct wifi_settings_t));
  262. /* allocate buffer */
  263. size_t sz = sizeof(wifi_settings);
  264. uint8_t *buff = (uint8_t*)malloc(sizeof(uint8_t) * sz);
  265. memset(buff, 0x00, sizeof(sz));
  266. /* ssid */
  267. sz = sizeof(wifi_manager_config_sta->sta.ssid);
  268. esp_err = nvs_get_blob(handle, "ssid", buff, &sz);
  269. if(esp_err != ESP_OK){
  270. free(buff);
  271. return false;
  272. }
  273. memcpy(wifi_manager_config_sta->sta.ssid, buff, sz);
  274. /* password */
  275. sz = sizeof(wifi_manager_config_sta->sta.password);
  276. esp_err = nvs_get_blob(handle, "password", buff, &sz);
  277. if(esp_err != ESP_OK){
  278. free(buff);
  279. return false;
  280. }
  281. memcpy(wifi_manager_config_sta->sta.password, buff, sz);
  282. /* memcpy(wifi_manager_config_sta->sta.password, "lewrong", strlen("lewrong")); this is debug to force a wrong password event. ignore! */
  283. /* settings */
  284. sz = sizeof(wifi_settings);
  285. esp_err = nvs_get_blob(handle, "settings", buff, &sz);
  286. if(esp_err != ESP_OK){
  287. free(buff);
  288. return false;
  289. }
  290. memcpy(&wifi_settings, buff, sz);
  291. free(buff);
  292. nvs_close(handle);
  293. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_sta_config: ssid:%s password:%s",wifi_manager_config_sta->sta.ssid,wifi_manager_config_sta->sta.password);
  294. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: SoftAP_ssid:%s",wifi_settings.ap_ssid);
  295. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: SoftAP_pwd:%s",wifi_settings.ap_pwd);
  296. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: SoftAP_channel:%i",wifi_settings.ap_channel);
  297. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: SoftAP_hidden (1 = yes):%i",wifi_settings.ap_ssid_hidden);
  298. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: SoftAP_bandwidth (1 = 20MHz, 2 = 40MHz)%i",wifi_settings.ap_bandwidth);
  299. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_only (0 = APSTA, 1 = STA when connected):%i",wifi_settings.sta_only);
  300. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_power_save (1 = yes):%i",wifi_settings.sta_power_save);
  301. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_static_ip (0 = dhcp client, 1 = static ip):%i",wifi_settings.sta_static_ip);
  302. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_static_ip_config: IP: %s , GW: %s , Mask: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.ip), ip4addr_ntoa(&wifi_settings.sta_static_ip_config.gw), ip4addr_ntoa(&wifi_settings.sta_static_ip_config.netmask));
  303. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_ip_addr: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.ip));
  304. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_gw_addr: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.gw));
  305. ESP_LOGI(TAG, "wifi_manager_fetch_wifi_settings: sta_netmask: %s", ip4addr_ntoa(&wifi_settings.sta_static_ip_config.netmask));
  306. return wifi_manager_config_sta->sta.ssid[0] != '\0';
  307. }
  308. else{
  309. return false;
  310. }
  311. }
  312. void wifi_manager_clear_ip_info_json(){
  313. strcpy(ip_info_json, "{}\n");
  314. }
  315. void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code){
  316. wifi_config_t *config = wifi_manager_get_wifi_sta_config();
  317. if(config){
  318. #if RECOVERY_APPLICATION
  319. const char ip_info_json_format[] = ",\"ip\":\"%s\",\"netmask\":\"%s\",\"gw\":\"%s\",\"urc\":%d,\"project_name\":\"%s\",\"version\":\"%s\", \"ota_dsc\":\"%s\", \"ota_pct\":%d}\n";
  320. #else
  321. const char ip_info_json_format[] = ",\"ip\":\"%s\",\"netmask\":\"%s\",\"gw\":\"%s\",\"urc\":%d,\"project_name\":\"%s\",\"version\":\"%s\"}\n";
  322. #endif
  323. memset(ip_info_json, 0x00, JSON_IP_INFO_SIZE);
  324. const esp_app_desc_t* desc = esp_ota_get_app_description();
  325. /* to avoid declaring a new buffer we copy the data directly into the buffer at its correct address */
  326. strcpy(ip_info_json, "{\"ssid\":");
  327. json_print_string(config->sta.ssid, (unsigned char*)(ip_info_json+strlen(ip_info_json)) );
  328. if(update_reason_code == UPDATE_CONNECTION_OK){
  329. /* rest of the information is copied after the ssid */
  330. tcpip_adapter_ip_info_t ip_info;
  331. ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
  332. char ip[IP4ADDR_STRLEN_MAX]; /* note: IP4ADDR_STRLEN_MAX is defined in lwip */
  333. char gw[IP4ADDR_STRLEN_MAX];
  334. char netmask[IP4ADDR_STRLEN_MAX];
  335. strcpy(ip, ip4addr_ntoa(&ip_info.ip));
  336. strcpy(netmask, ip4addr_ntoa(&ip_info.netmask));
  337. strcpy(gw, ip4addr_ntoa(&ip_info.gw));
  338. snprintf( (ip_info_json + strlen(ip_info_json)), JSON_IP_INFO_SIZE, ip_info_json_format,
  339. ip,
  340. netmask,
  341. gw,
  342. (int)update_reason_code,
  343. desc->project_name,
  344. desc->version
  345. #if RECOVERY_APPLICATION
  346. ,ota_get_status(),
  347. ota_get_pct_complete()
  348. #endif
  349. );
  350. }
  351. else{
  352. /* notify in the json output the reason code why this was updated without a connection */
  353. snprintf( (ip_info_json + strlen(ip_info_json)), JSON_IP_INFO_SIZE, ip_info_json_format,
  354. "0",
  355. "0",
  356. "0",
  357. (int)update_reason_code,
  358. desc->project_name,
  359. desc->version
  360. #if RECOVERY_APPLICATION
  361. ,"",
  362. 0
  363. #endif
  364. );
  365. }
  366. }
  367. else{
  368. wifi_manager_clear_ip_info_json();
  369. }
  370. }
  371. void wifi_manager_clear_access_points_json(){
  372. strcpy(accessp_json, "[]\n");
  373. }
  374. void wifi_manager_generate_acess_points_json(){
  375. strcpy(accessp_json, "[");
  376. const char oneap_str[] = ",\"chan\":%d,\"rssi\":%d,\"auth\":%d}%c\n";
  377. /* stack buffer to hold on to one AP until it's copied over to accessp_json */
  378. char one_ap[JSON_ONE_APP_SIZE];
  379. for(int i=0; i<ap_num;i++){
  380. wifi_ap_record_t ap = accessp_records[i];
  381. /* ssid needs to be json escaped. To save on heap memory it's directly printed at the correct address */
  382. strcat(accessp_json, "{\"ssid\":");
  383. json_print_string( (unsigned char*)ap.ssid, (unsigned char*)(accessp_json+strlen(accessp_json)) );
  384. /* print the rest of the json for this access point: no more string to escape */
  385. snprintf(one_ap, (size_t)JSON_ONE_APP_SIZE, oneap_str,
  386. ap.primary,
  387. ap.rssi,
  388. ap.authmode,
  389. i==ap_num-1?']':',');
  390. /* add it to the list */
  391. strcat(accessp_json, one_ap);
  392. }
  393. }
  394. bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait){
  395. if(wifi_manager_sta_ip_mutex){
  396. if( xSemaphoreTake( wifi_manager_sta_ip_mutex, xTicksToWait ) == pdTRUE ) {
  397. return true;
  398. }
  399. else{
  400. return false;
  401. }
  402. }
  403. else{
  404. return false;
  405. }
  406. }
  407. void wifi_manager_unlock_sta_ip_string(){
  408. xSemaphoreGive( wifi_manager_sta_ip_mutex );
  409. }
  410. void wifi_manager_safe_update_sta_ip_string(uint32_t ip){
  411. if(wifi_manager_lock_sta_ip_string(portMAX_DELAY)){
  412. struct ip4_addr ip4;
  413. ip4.addr = ip;
  414. strcpy(wifi_manager_sta_ip, ip4addr_ntoa(&ip4));
  415. ESP_LOGI(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip);
  416. wifi_manager_unlock_sta_ip_string();
  417. }
  418. }
  419. char* wifi_manager_get_sta_ip_string(){
  420. return wifi_manager_sta_ip;
  421. }
  422. bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait){
  423. if(wifi_manager_json_mutex){
  424. if( xSemaphoreTake( wifi_manager_json_mutex, xTicksToWait ) == pdTRUE ) {
  425. return true;
  426. }
  427. else{
  428. return false;
  429. }
  430. }
  431. else{
  432. return false;
  433. }
  434. }
  435. void wifi_manager_unlock_json_buffer(){
  436. xSemaphoreGive( wifi_manager_json_mutex );
  437. }
  438. char* wifi_manager_get_ap_list_json(){
  439. return accessp_json;
  440. }
  441. esp_err_t wifi_manager_event_handler(void *ctx, system_event_t *event)
  442. {
  443. switch(event->event_id) {
  444. case SYSTEM_EVENT_WIFI_READY:
  445. ESP_LOGI(TAG, "SYSTEM_EVENT_WIFI_READY");
  446. break;
  447. case SYSTEM_EVENT_SCAN_DONE:
  448. ESP_LOGD(TAG, "SYSTEM_EVENT_SCAN_DONE");
  449. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_SCAN_BIT);
  450. wifi_manager_send_message(EVENT_SCAN_DONE, NULL);
  451. break;
  452. case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
  453. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_AUTHMODE_CHANGE");
  454. break;
  455. case SYSTEM_EVENT_AP_START:
  456. ESP_LOGI(TAG, "SYSTEM_EVENT_AP_START");
  457. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_AP_STARTED_BIT);
  458. break;
  459. case SYSTEM_EVENT_AP_STOP:
  460. break;
  461. case SYSTEM_EVENT_AP_PROBEREQRECVED:
  462. break;
  463. case SYSTEM_EVENT_AP_STACONNECTED: /* a user disconnected from the SoftAP */
  464. ESP_LOGI(TAG, "SYSTEM_EVENT_AP_STACONNECTED");
  465. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_AP_STA_CONNECTED_BIT);
  466. break;
  467. case SYSTEM_EVENT_AP_STADISCONNECTED:
  468. ESP_LOGI(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED");
  469. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_AP_STA_CONNECTED_BIT);
  470. break;
  471. case SYSTEM_EVENT_STA_START:
  472. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
  473. break;
  474. case SYSTEM_EVENT_STA_STOP:
  475. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_STOP");
  476. break;
  477. case SYSTEM_EVENT_STA_GOT_IP:
  478. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
  479. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_WIFI_CONNECTED_BIT);
  480. wifi_manager_send_message(EVENT_STA_GOT_IP, (void*)event->event_info.got_ip.ip_info.ip.addr );
  481. break;
  482. case SYSTEM_EVENT_STA_CONNECTED:
  483. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_CONNECTED");
  484. break;
  485. case SYSTEM_EVENT_STA_DISCONNECTED:
  486. ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
  487. /* if a DISCONNECT message is posted while a scan is in progress this scan will NEVER end, causing scan to never work again. For this reason SCAN_BIT is cleared too */
  488. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_WIFI_CONNECTED_BIT | WIFI_MANAGER_SCAN_BIT);
  489. /* post disconnect event with reason code */
  490. wifi_manager_send_message(EVENT_STA_DISCONNECTED, (void*)( (uint32_t)event->event_info.disconnected.reason) );
  491. break;
  492. default:
  493. break;
  494. }
  495. return ESP_OK;
  496. }
  497. wifi_config_t* wifi_manager_get_wifi_sta_config(){
  498. return wifi_manager_config_sta;
  499. }
  500. void wifi_manager_connect_async(){
  501. /* in order to avoid a false positive on the front end app we need to quickly flush the ip json
  502. * There'se a risk the front end sees an IP or a password error when in fact
  503. * it's a remnant from a previous connection
  504. */
  505. if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
  506. wifi_manager_clear_ip_info_json();
  507. wifi_manager_unlock_json_buffer();
  508. }
  509. wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_USER);
  510. }
  511. char* wifi_manager_get_ip_info_json(){
  512. return ip_info_json;
  513. }
  514. void wifi_manager_destroy(){
  515. vTaskDelete(task_wifi_manager);
  516. task_wifi_manager = NULL;
  517. /* heap buffers */
  518. free(accessp_records);
  519. accessp_records = NULL;
  520. free(accessp_json);
  521. accessp_json = NULL;
  522. free(ip_info_json);
  523. ip_info_json = NULL;
  524. free(wifi_manager_sta_ip);
  525. wifi_manager_sta_ip = NULL;
  526. if(wifi_manager_config_sta){
  527. free(wifi_manager_config_sta);
  528. wifi_manager_config_sta = NULL;
  529. }
  530. /* RTOS objects */
  531. vSemaphoreDelete(wifi_manager_json_mutex);
  532. wifi_manager_json_mutex = NULL;
  533. vSemaphoreDelete(wifi_manager_sta_ip_mutex);
  534. wifi_manager_sta_ip_mutex = NULL;
  535. vEventGroupDelete(wifi_manager_event_group);
  536. wifi_manager_event_group = NULL;
  537. vQueueDelete(wifi_manager_queue);
  538. wifi_manager_queue = NULL;
  539. }
  540. void wifi_manager_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps) {
  541. int total_unique;
  542. wifi_ap_record_t * first_free;
  543. total_unique=*aps;
  544. first_free=NULL;
  545. for(int i=0; i<*aps-1;i++) {
  546. wifi_ap_record_t * ap = &aplist[i];
  547. /* skip the previously removed APs */
  548. if (ap->ssid[0] == 0) continue;
  549. /* remove the identical SSID+authmodes */
  550. for(int j=i+1; j<*aps;j++) {
  551. wifi_ap_record_t * ap1 = &aplist[j];
  552. if ( (strcmp((const char *)ap->ssid, (const char *)ap1->ssid)==0) &&
  553. (ap->authmode == ap1->authmode) ) { /* same SSID, different auth mode is skipped */
  554. /* save the rssi for the display */
  555. if ((ap1->rssi) > (ap->rssi)) ap->rssi=ap1->rssi;
  556. /* clearing the record */
  557. memset(ap1,0, sizeof(wifi_ap_record_t));
  558. }
  559. }
  560. }
  561. /* reorder the list so APs follow each other in the list */
  562. for(int i=0; i<*aps;i++) {
  563. wifi_ap_record_t * ap = &aplist[i];
  564. /* skipping all that has no name */
  565. if (ap->ssid[0] == 0) {
  566. /* mark the first free slot */
  567. if (first_free==NULL) first_free=ap;
  568. total_unique--;
  569. continue;
  570. }
  571. if (first_free!=NULL) {
  572. memcpy(first_free, ap, sizeof(wifi_ap_record_t));
  573. memset(ap,0, sizeof(wifi_ap_record_t));
  574. /* find the next free slot */
  575. for(int j=0; j<*aps;j++) {
  576. if (aplist[j].ssid[0]==0) {
  577. first_free=&aplist[j];
  578. break;
  579. }
  580. }
  581. }
  582. }
  583. /* update the length of the list */
  584. *aps = total_unique;
  585. }
  586. BaseType_t wifi_manager_send_message_to_front(message_code_t code, void *param){
  587. queue_message msg;
  588. msg.code = code;
  589. msg.param = param;
  590. return xQueueSendToFront( wifi_manager_queue, &msg, portMAX_DELAY);
  591. }
  592. BaseType_t wifi_manager_send_message(message_code_t code, void *param){
  593. queue_message msg;
  594. msg.code = code;
  595. msg.param = param;
  596. return xQueueSend( wifi_manager_queue, &msg, portMAX_DELAY);
  597. }
  598. void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) ){
  599. if(cb_ptr_arr && message_code < MESSAGE_CODE_COUNT){
  600. cb_ptr_arr[message_code] = func_ptr;
  601. }
  602. }
  603. void wifi_manager( void * pvParameters ){
  604. queue_message msg;
  605. BaseType_t xStatus;
  606. EventBits_t uxBits;
  607. uint8_t retries = 0;
  608. /* initialize the tcp stack */
  609. tcpip_adapter_init();
  610. /* event handler and event group for the wifi driver */
  611. wifi_manager_event_group = xEventGroupCreate();
  612. ESP_ERROR_CHECK(esp_event_loop_init(wifi_manager_event_handler, NULL));
  613. /* wifi scanner config */
  614. wifi_scan_config_t scan_config = {
  615. .ssid = 0,
  616. .bssid = 0,
  617. .channel = 0,
  618. .show_hidden = true
  619. };
  620. /* default wifi config */
  621. wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
  622. ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
  623. ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
  624. /* SoftAP - Wifi Access Point configuration setup */
  625. tcpip_adapter_ip_info_t info;
  626. memset(&info, 0x00, sizeof(info));
  627. wifi_config_t ap_config = {
  628. .ap = {
  629. .ssid_len = 0,
  630. .channel = wifi_settings.ap_channel,
  631. .authmode = WIFI_AUTH_WPA2_PSK,
  632. .ssid_hidden = wifi_settings.ap_ssid_hidden,
  633. .max_connection = DEFAULT_AP_MAX_CONNECTIONS,
  634. .beacon_interval = DEFAULT_AP_BEACON_INTERVAL,
  635. },
  636. };
  637. memcpy(ap_config.ap.ssid, wifi_settings.ap_ssid , sizeof(wifi_settings.ap_ssid));
  638. memcpy(ap_config.ap.password, wifi_settings.ap_pwd, sizeof(wifi_settings.ap_pwd));
  639. ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); /* stop AP DHCP server */
  640. inet_pton(AF_INET, DEFAULT_AP_IP, &info.ip); /* access point is on a static IP */
  641. inet_pton(AF_INET, DEFAULT_AP_GATEWAY, &info.gw);
  642. inet_pton(AF_INET, DEFAULT_AP_NETMASK, &info.netmask);
  643. ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info));
  644. ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP)); /* start AP DHCP server */
  645. ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
  646. ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
  647. ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_AP, wifi_settings.ap_bandwidth));
  648. ESP_ERROR_CHECK(esp_wifi_set_ps(wifi_settings.sta_power_save));
  649. /* STA - Wifi Station configuration setup */
  650. tcpip_adapter_dhcp_status_t status;
  651. if(wifi_settings.sta_static_ip) {
  652. ESP_LOGI(TAG, "Assigning static ip to STA interface. IP: %s , GW: %s , Mask: %s",
  653. ip4addr_ntoa(&wifi_settings.sta_static_ip_config.ip),
  654. ip4addr_ntoa(&wifi_settings.sta_static_ip_config.gw),
  655. ip4addr_ntoa(&wifi_settings.sta_static_ip_config.netmask));
  656. /* stop DHCP client*/
  657. ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
  658. /* assign a static IP to the STA network interface */
  659. ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &wifi_settings.sta_static_ip_config));
  660. }
  661. else {
  662. /* start DHCP client if not started*/
  663. ESP_LOGI(TAG, "wifi_manager: Start DHCP client for STA interface. If not already running");
  664. ESP_ERROR_CHECK(tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &status));
  665. if (status!=TCPIP_ADAPTER_DHCP_STARTED)
  666. ESP_ERROR_CHECK(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA));
  667. }
  668. /* by default the mode is STA because wifi_manager will not start the access point unless it has to! */
  669. ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
  670. ESP_ERROR_CHECK(esp_wifi_start());
  671. /* start http server */
  672. http_server_start();
  673. /* enqueue first event: load previous config */
  674. wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL);
  675. /* main processing loop */
  676. for(;;){
  677. xStatus = xQueueReceive( wifi_manager_queue, &msg, portMAX_DELAY );
  678. if( xStatus == pdPASS ){
  679. switch(msg.code){
  680. case EVENT_SCAN_DONE:
  681. /* As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns.
  682. * As a consequence, ap_num MUST be reset to MAX_AP_NUM at every scan */
  683. ap_num = MAX_AP_NUM;
  684. ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, accessp_records));
  685. /* make sure the http server isn't trying to access the list while it gets refreshed */
  686. if(wifi_manager_lock_json_buffer( pdMS_TO_TICKS(1000) )){
  687. /* Will remove the duplicate SSIDs from the list and update ap_num */
  688. wifi_manager_filter_unique(accessp_records, &ap_num);
  689. wifi_manager_generate_acess_points_json();
  690. wifi_manager_unlock_json_buffer();
  691. }
  692. else{
  693. ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan");
  694. }
  695. /* callback */
  696. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  697. break;
  698. case ORDER_START_WIFI_SCAN:
  699. ESP_LOGD(TAG, "MESSAGE: ORDER_START_WIFI_SCAN");
  700. /* if a scan is already in progress this message is simply ignored thanks to the WIFI_MANAGER_SCAN_BIT uxBit */
  701. uxBits = xEventGroupGetBits(wifi_manager_event_group);
  702. if(! (uxBits & WIFI_MANAGER_SCAN_BIT) ){
  703. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_SCAN_BIT);
  704. ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
  705. }
  706. /* callback */
  707. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  708. break;
  709. case ORDER_LOAD_AND_RESTORE_STA:
  710. ESP_LOGI(TAG, "MESSAGE: ORDER_LOAD_AND_RESTORE_STA");
  711. if(wifi_manager_fetch_wifi_sta_config()){
  712. ESP_LOGI(TAG, "Saved wifi found on startup. Will attempt to connect.");
  713. wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_RESTORE_CONNECTION);
  714. }
  715. else{
  716. /* no wifi saved: start soft AP! This is what should happen during a first run */
  717. ESP_LOGI(TAG, "No saved wifi found on startup. Starting access point.");
  718. wifi_manager_send_message(ORDER_START_AP, NULL);
  719. }
  720. /* callback */
  721. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  722. break;
  723. case ORDER_CONNECT_STA:
  724. ESP_LOGI(TAG, "MESSAGE: ORDER_CONNECT_STA");
  725. /* very important: precise that this connection attempt is specifically requested.
  726. * Param in that case is a boolean indicating if the request was made automatically
  727. * by the wifi_manager.
  728. * */
  729. if((BaseType_t)msg.param == CONNECTION_REQUEST_USER) {
  730. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT);
  731. }
  732. else if((BaseType_t)msg.param == CONNECTION_REQUEST_RESTORE_CONNECTION) {
  733. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT);
  734. }
  735. uxBits = xEventGroupGetBits(wifi_manager_event_group);
  736. if( uxBits & WIFI_MANAGER_WIFI_CONNECTED_BIT ){
  737. wifi_manager_send_message(ORDER_DISCONNECT_STA, NULL);
  738. /* todo: reconnect */
  739. }
  740. else{
  741. /* update config to latest and attempt connection */
  742. ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, wifi_manager_get_wifi_sta_config()));
  743. ESP_ERROR_CHECK(esp_wifi_connect());
  744. }
  745. /* callback */
  746. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  747. break;
  748. case EVENT_STA_DISCONNECTED:
  749. ESP_LOGI(TAG, "MESSAGE: EVENT_STA_DISCONNECTED with Reason code: %d", (uint32_t)msg.param);
  750. /* this even can be posted in numerous different conditions
  751. *
  752. * 1. SSID password is wrong
  753. * 2. Manual disconnection ordered
  754. * 3. Connection lost
  755. *
  756. * Having clear understand as to WHY the event was posted is key to having an efficient wifi manager
  757. *
  758. * With wifi_manager, we determine:
  759. * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, We consider it's a client that requested the connection.
  760. * When SYSTEM_EVENT_STA_DISCONNECTED is posted, it's probably a password/something went wrong with the handshake.
  761. *
  762. * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, it's a disconnection that was ASKED by the client (clicking disconnect in the app)
  763. * When SYSTEM_EVENT_STA_DISCONNECTED is posted, saved wifi is erased from the NVS memory.
  764. *
  765. * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT and WIFI_MANAGER_REQUEST_STA_CONNECT_BIT are NOT set, it's a lost connection
  766. *
  767. * In this version of the software, reason codes are not used. They are indicated here for potential future usage.
  768. *
  769. * REASON CODE:
  770. * 1 UNSPECIFIED
  771. * 2 AUTH_EXPIRE auth no longer valid, this smells like someone changed a password on the AP
  772. * 3 AUTH_LEAVE
  773. * 4 ASSOC_EXPIRE
  774. * 5 ASSOC_TOOMANY too many devices already connected to the AP => AP fails to respond
  775. * 6 NOT_AUTHED
  776. * 7 NOT_ASSOCED
  777. * 8 ASSOC_LEAVE
  778. * 9 ASSOC_NOT_AUTHED
  779. * 10 DISASSOC_PWRCAP_BAD
  780. * 11 DISASSOC_SUPCHAN_BAD
  781. * 12 <n/a>
  782. * 13 IE_INVALID
  783. * 14 MIC_FAILURE
  784. * 15 4WAY_HANDSHAKE_TIMEOUT wrong password! This was personnaly tested on my home wifi with a wrong password.
  785. * 16 GROUP_KEY_UPDATE_TIMEOUT
  786. * 17 IE_IN_4WAY_DIFFERS
  787. * 18 GROUP_CIPHER_INVALID
  788. * 19 PAIRWISE_CIPHER_INVALID
  789. * 20 AKMP_INVALID
  790. * 21 UNSUPP_RSN_IE_VERSION
  791. * 22 INVALID_RSN_IE_CAP
  792. * 23 802_1X_AUTH_FAILED wrong password?
  793. * 24 CIPHER_SUITE_REJECTED
  794. * 200 BEACON_TIMEOUT
  795. * 201 NO_AP_FOUND
  796. * 202 AUTH_FAIL
  797. * 203 ASSOC_FAIL
  798. * 204 HANDSHAKE_TIMEOUT
  799. *
  800. * */
  801. /* reset saved sta IP */
  802. wifi_manager_safe_update_sta_ip_string((uint32_t)0);
  803. uxBits = xEventGroupGetBits(wifi_manager_event_group);
  804. if( uxBits & WIFI_MANAGER_REQUEST_STA_CONNECT_BIT ){
  805. /* there are no retries when it's a user requested connection by design. This avoids a user hanging too much
  806. * in case they typed a wrong password for instance. Here we simply clear the request bit and move on */
  807. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT);
  808. if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
  809. wifi_manager_generate_ip_info_json( UPDATE_FAILED_ATTEMPT );
  810. wifi_manager_unlock_json_buffer();
  811. }
  812. }
  813. else if (uxBits & WIFI_MANAGER_REQUEST_DISCONNECT_BIT){
  814. /* user manually requested a disconnect so the lost connection is a normal event. Clear the flag and restart the AP */
  815. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT);
  816. if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
  817. wifi_manager_generate_ip_info_json( UPDATE_USER_DISCONNECT );
  818. wifi_manager_unlock_json_buffer();
  819. }
  820. /* erase configuration */
  821. if(wifi_manager_config_sta){
  822. memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t));
  823. }
  824. /* save NVS memory */
  825. wifi_manager_save_sta_config();
  826. /* start SoftAP */
  827. wifi_manager_send_message(ORDER_START_AP, NULL);
  828. }
  829. else{
  830. /* lost connection ? */
  831. if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
  832. wifi_manager_generate_ip_info_json( UPDATE_LOST_CONNECTION );
  833. wifi_manager_unlock_json_buffer();
  834. }
  835. if(retries < WIFI_MANAGER_MAX_RETRY){
  836. retries++;
  837. wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_AUTO_RECONNECT);
  838. }
  839. else{
  840. /* In this scenario the connection was lost beyond repair: kick start the AP! */
  841. retries = 0;
  842. /* if it was a restore attempt connection, we clear the bit */
  843. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT);
  844. /* erase configuration that could not be used to connect */
  845. if(wifi_manager_config_sta){
  846. memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t));
  847. }
  848. /* save empty connection info in NVS memory */
  849. wifi_manager_save_sta_config();
  850. /* start SoftAP */
  851. wifi_manager_send_message(ORDER_START_AP, NULL);
  852. }
  853. }
  854. /* callback */
  855. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  856. break;
  857. case ORDER_START_AP:
  858. ESP_LOGI(TAG, "MESSAGE: ORDER_START_AP");
  859. esp_wifi_set_mode(WIFI_MODE_APSTA);
  860. //http_server_start();
  861. dns_server_start();
  862. /* callback */
  863. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  864. break;
  865. case EVENT_STA_GOT_IP:
  866. ESP_LOGI(TAG, "MESSAGE: EVENT_STA_GOT_IP");
  867. uxBits = xEventGroupGetBits(wifi_manager_event_group);
  868. /* reset connection requests bits -- doesn't matter if it was set or not */
  869. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT);
  870. /* save IP as a string for the HTTP server host */
  871. wifi_manager_safe_update_sta_ip_string((uint32_t)msg.param);
  872. /* save wifi config in NVS if it wasn't a restored of a connection */
  873. if(uxBits & WIFI_MANAGER_REQUEST_RESTORE_STA_BIT){
  874. xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT);
  875. }
  876. else{
  877. wifi_manager_save_sta_config();
  878. }
  879. /* refresh JSON with the new IP */
  880. if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
  881. /* generate the connection info with success */
  882. wifi_manager_generate_ip_info_json( UPDATE_CONNECTION_OK );
  883. wifi_manager_unlock_json_buffer();
  884. }
  885. else { abort(); }
  886. /* bring down DNS hijack */
  887. dns_server_stop();
  888. /* callback */
  889. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  890. break;
  891. case ORDER_DISCONNECT_STA:
  892. ESP_LOGI(TAG, "MESSAGE: ORDER_DISCONNECT_STA");
  893. /* precise this is coming from a user request */
  894. xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT);
  895. /* order wifi discconect */
  896. ESP_ERROR_CHECK(esp_wifi_disconnect());
  897. /* callback */
  898. if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL);
  899. break;
  900. default:
  901. break;
  902. } /* end of switch/case */
  903. } /* end of if status=pdPASS */
  904. } /* end of for loop */
  905. vTaskDelete( NULL );
  906. }