wifi.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /******************************************************************************
  2. * 2016 IdeasX v0.3.1 Module Firmware
  3. *
  4. * File Name: wifi.c
  5. * Author: Tyler Berezowsky
  6. * Description: This file is going to need alot of help by a C wizard, but it currently works...I think.
  7. *
  8. * 2016/8/8, v1.0 created this file
  9. *******************************************************************************/
  10. #include "util/wifi.h"
  11. #include "esp_common.h"
  12. #define WIFI_TIMEOUT 30*1000 // time waited before swiping left in seconds
  13. #define WIFI_RECONNECT_LIMIT 5 // number of times connection to AP is attempted before moving on
  14. MQTT_Client mqttClient; // setup in user_main.c
  15. static struct station_config stationConf;
  16. static WIFI_PROCESS_FLAGS wifi_process_flags;
  17. static ETSTimer wifi_process_timer;
  18. static struct bss_info *bss_link, *head_bss_link;
  19. static void ICACHE_FLASH_ATTR wifi_process(void);
  20. static void ICACHE_FLASH_ATTR wifi_process_timer_cb(void);
  21. /******************************************************************************
  22. * FunctionName : destory_linked_list
  23. * Description :
  24. * Parameters :
  25. * Returns :
  26. *******************************************************************************/
  27. static bool ICACHE_FLASH_ATTR destory_linked_list(void)
  28. {
  29. if(head_bss_link != NULL)
  30. {
  31. while(head_bss_link != NULL)
  32. {
  33. bss_link = head_bss_link;
  34. head_bss_link = head_bss_link->next.stqe_next;
  35. os_free(bss_link);
  36. }
  37. return TRUE;
  38. }
  39. else
  40. {
  41. return FALSE;
  42. }
  43. }
  44. /******************************************************************************
  45. * FunctionName : copy_linked_list
  46. * Description :
  47. * Parameters :
  48. * Returns :
  49. *******************************************************************************/
  50. static struct bss_info* ICACHE_FLASH_ATTR copy_linked_list(struct bss_info *ptr_original_node)
  51. {
  52. struct bss_info *ptr_new_head, *ptr_new_node;
  53. if(ptr_original_node != NULL)
  54. {
  55. ptr_new_head = (struct bss_info *)os_malloc(sizeof(struct bss_info));
  56. if (ptr_new_head == NULL)
  57. {
  58. os_printf("WIFI PROCESS: No RAM!\r\n");
  59. return NULL;
  60. }
  61. }
  62. else
  63. return NULL;
  64. os_memcpy(ptr_new_head, ptr_original_node, sizeof(struct bss_info));
  65. ptr_original_node = ptr_original_node->next.stqe_next;
  66. ptr_new_node = ptr_new_head;
  67. while(ptr_original_node != NULL)
  68. {
  69. ptr_new_node->next.stqe_next = (struct bss_info *)os_malloc(sizeof(struct bss_info));
  70. ptr_new_node = ptr_new_node->next.stqe_next;
  71. os_memcpy(ptr_new_node, ptr_original_node, sizeof(struct bss_info));
  72. if (ptr_new_node == NULL)
  73. {
  74. os_printf("WIFI PROCESS: No RAM!\r\n");
  75. while(ptr_new_head != NULL)
  76. {
  77. ptr_new_node = ptr_new_head;
  78. ptr_new_head = ptr_new_head->next.stqe_next;
  79. os_free(ptr_new_node);
  80. }
  81. os_printf("WIFI PROCESS: Cleaned up list\r\n");
  82. return NULL;
  83. }
  84. ptr_original_node = ptr_original_node->next.stqe_next;
  85. }
  86. return ptr_new_head;
  87. }
  88. /******************************************************************************
  89. * FunctionName : wifi_set_station
  90. * Description :
  91. * Parameters :
  92. * Returns :
  93. *******************************************************************************/
  94. void ICACHE_FLASH_ATTR wifi_set_station(uint8_t* ssid, uint8_t* pass)
  95. {
  96. bss_link = NULL;
  97. os_sprintf(stationConf.ssid, "%s", ssid); // load ssid into stationConf.ssid
  98. os_sprintf(stationConf.password, "%s", pass); // load pass into stationConf.password
  99. wifi_station_set_config_current(&stationConf); // connect to AP specified in stationConf
  100. wifi_station_set_auto_connect(TRUE);
  101. wifi_station_connect();
  102. }
  103. /******************************************************************************
  104. * FunctionName : disable_wifi_reconnect
  105. * Description :
  106. * Parameters :
  107. * Returns :
  108. *******************************************************************************/
  109. void ICACHE_FLASH_ATTR disable_wifi_reconnect(void)
  110. {
  111. wifi_station_disconnect();
  112. wifi_station_set_auto_connect(FALSE);
  113. }
  114. /******************************************************************************
  115. * FunctionName : show_wifi_config
  116. * Description : print current wifi configurations
  117. * Parameters :
  118. * Returns :
  119. *******************************************************************************/
  120. void ICACHE_FLASH_ATTR show_wifi_config(void)
  121. {
  122. uint8_t i, j;
  123. j = sysCfg.registered_stations;
  124. os_printf("Number of APs stored: %d\r\n", j);
  125. for (i=0;i<j;i++)
  126. os_printf("AP: %d\n\tSSID: %s\n\tPASS: %s\n", i, sysCfg.sta_ssid[i], sysCfg.sta_pwd[i]);
  127. /* This is not accurate. If the module is not connected to an AP it should display unconnected for
  128. current station
  129. */
  130. i = sysCfg.current_station;
  131. j = wifi_station_get_connect_status();
  132. os_printf("Current AP: %d\r\nWiFi Status %d\r\n", i, j);
  133. }
  134. /******************************************************************************
  135. * FunctionName : wifi_process_timer_cb
  136. * Description :
  137. * Parameters :
  138. * Returns :
  139. *******************************************************************************/
  140. static void ICACHE_FLASH_ATTR wifi_process_timer_cb()
  141. {
  142. os_printf("WIFI PROCESS: Wi-Fi connection timed out.\r\n");
  143. wifi_process_flags.wifi_flag = FALSE;
  144. wifi_station_set_auto_connect(FALSE);
  145. wifi_station_disconnect();
  146. wifi_process();
  147. }
  148. /******************************************************************************
  149. * FunctionName : wifi_process
  150. * Description : Looks for AP stored in bss_link
  151. * Parameters :
  152. * Returns :
  153. *******************************************************************************/
  154. static void ICACHE_FLASH_ATTR wifi_process(void)
  155. {
  156. uint8_t ssid[33];
  157. uint8_t i;
  158. os_timer_disarm(&wifi_process_timer); // disarm timeout timer
  159. if ((wifi_process_flags.wifi_flag == FALSE) && (bss_link != NULL)) // if AP connection failed and bss_link is not empty
  160. {
  161. while(bss_link != NULL) // do this until bss_link is empty or break
  162. {
  163. // ssid could be missing null character
  164. os_memset(ssid, 0, 33);
  165. if (os_strlen(bss_link->ssid) <= 32)
  166. {
  167. os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
  168. }
  169. else
  170. {
  171. os_memcpy(ssid, bss_link->ssid, 32);
  172. }
  173. // compare current ssid from bss_link to registered stations
  174. for(i=0;i<sysCfg.registered_stations;i++)
  175. {
  176. //os_printf("Comparing %s and %s\r\n", ssid, sysCfg.sta_ssid[i]);
  177. if (!strcmp(ssid, sysCfg.sta_ssid[i]))
  178. {
  179. wifi_process_flags.wifi_flag = TRUE; // set connect attempt flag
  180. wifi_process_flags.wifi_count = 0; // rst connect attempt count
  181. os_sprintf(stationConf.ssid, "%s", sysCfg.sta_ssid[i]);
  182. os_sprintf(stationConf.password, "%s", sysCfg.sta_pwd[i]); // if AUTH_OPEN pwd should be NULL
  183. sysCfg.current_station = i; // store current station number for sysCfg save and UART operations
  184. wifi_station_set_config_current(&stationConf); // load stationConf into SDK, but don't save in SDK flash
  185. wifi_station_set_auto_connect(TRUE);
  186. wifi_station_connect();
  187. bss_link = bss_link->next.stqe_next; // inc to next station in case process fails
  188. //set wifi_process_timer for timeout.
  189. os_timer_setfn(&wifi_process_timer, (os_timer_func_t *)wifi_process_timer_cb, NULL);
  190. os_timer_arm(&wifi_process_timer, WIFI_TIMEOUT, 0); // arm timeout timer
  191. break; // break for loop
  192. }
  193. }
  194. // break while if station found, otherwise look for another station.
  195. if (wifi_process_flags.wifi_flag == TRUE)
  196. {
  197. break; // break while loop
  198. }
  199. else
  200. {
  201. bss_link = bss_link->next.stqe_next;
  202. }
  203. }
  204. }
  205. if ((wifi_process_flags.wifi_flag == FALSE) && (bss_link == NULL))
  206. {
  207. // this is called twice...which could be a problem.
  208. sysCfg.module_state.searching = FALSE;
  209. sysCfg.module_state.asleep = FALSE;
  210. destory_linked_list();
  211. os_printf("WIFI PROCESS: Station list removed\r\n");
  212. os_printf("WIFI PROCESS: No Wi-Fi APs available.\r\n");
  213. // try again in a second....three times...if motion flag is set keep trying otherwise you should goto sleep.
  214. if (lsm6ds3_read_motion()) // change this to a poll on the LSM6DS3 line.
  215. start_wifi_process();
  216. else
  217. {
  218. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 0xFFFFFFFF); // clear pending interrupts
  219. sysCfg.module_state.asleep = TRUE;
  220. ETS_GPIO_INTR_ENABLE(); // enable interrupts to permit PB and LSM6DS3 to wake ESP from sleep.
  221. /*
  222. * The ESP8266 should be placed into light sleep or modem sleep here
  223. */
  224. }
  225. }
  226. }
  227. /******************************************************************************
  228. * FunctionName : wifi_handle_event_cb
  229. * Description : callback function for wifi events.
  230. * Parameters :
  231. * Returns :
  232. *******************************************************************************/
  233. static void ICACHE_FLASH_ATTR wifi_handle_event_cb(System_Event_t *evt)
  234. {
  235. switch (evt->event)
  236. {
  237. case EVENT_STAMODE_CONNECTED:
  238. {
  239. wifi_process_flags.wifi_count = 0; // rst wifi connection cnt
  240. os_printf("WIFI PROCESS: connect to ssid %s, channel %d\n",
  241. evt->event_info.connected.ssid,
  242. evt->event_info.connected.channel);
  243. break;
  244. }
  245. case EVENT_STAMODE_DISCONNECTED:
  246. {
  247. /*
  248. There is an issue where if the module is connected to an AP and then loses it, it continously scans for the
  249. last access point it attempted to connect to.
  250. */
  251. sysCfg.module_state.connected = FALSE; // set global connected flag false
  252. sysCfg.module_state.searching = TRUE;
  253. /*
  254. The only way to cancel the auto-connect functionaity of the SDK's OS is to
  255. send the command wifi_station_disconnect(), this ALWAYS calles the wifi event
  256. handler. Checking for this flag lets us ignore it.
  257. */
  258. if (wifi_process_flags.wifi_flag == TRUE)
  259. {
  260. MQTT_Disconnect(&mqttClient);
  261. wifi_process_flags.wifi_count++;
  262. os_printf("WIFI PROCESS: disconnect from ssid %s, reason %d, attempt %d/%d\r\n",
  263. evt->event_info.disconnected.ssid,
  264. evt->event_info.disconnected.reason,
  265. wifi_process_flags.wifi_count,
  266. WIFI_RECONNECT_LIMIT);
  267. if (wifi_process_flags.wifi_count >= WIFI_RECONNECT_LIMIT) // allow WIFI_RECONNECT_LIMIT for reconnect and 1st attempts
  268. {
  269. if (wifi_process_flags.ip_flag == TRUE) // if was connected, but then lost connection
  270. {
  271. start_wifi_process(); // rst apd mode process, flags will automatically be reset
  272. }
  273. else // if never got a connection finish looking at all the available stations.
  274. {
  275. wifi_process_flags.wifi_flag = FALSE;
  276. wifi_station_set_auto_connect(FALSE);
  277. wifi_station_disconnect();
  278. wifi_process();
  279. }
  280. }
  281. }
  282. break;
  283. }
  284. case EVENT_STAMODE_AUTHMODE_CHANGE:
  285. {
  286. os_printf("WIFI PROCESS: mode: %d -> %d\n",
  287. evt->event_info.auth_change.old_mode,
  288. evt->event_info.auth_change.new_mode);
  289. break;
  290. }
  291. case EVENT_STAMODE_GOT_IP:
  292. {
  293. os_timer_disarm(&wifi_process_timer); // disarm timeout timer
  294. wifi_process_flags.ip_flag = TRUE;
  295. sysCfg.module_state.connected = TRUE; // set global connected flag
  296. sysCfg.module_state.searching = FALSE; // set global searching flag false
  297. os_printf("WIFI PROCESS: ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR,
  298. IP2STR(&evt->event_info.got_ip.ip),
  299. IP2STR(&evt->event_info.got_ip.mask),
  300. IP2STR(&evt->event_info.got_ip.gw));
  301. destory_linked_list();
  302. os_printf("\r\nWIFI PROCESS: Station list removed\r\n");
  303. lsm6ds3_motion_disable(); // disable LSM6DS3 significant motion functionality
  304. MQTT_Connect(&mqttClient); // start MQTT client
  305. break;
  306. }
  307. default:
  308. {
  309. os_printf("WIFI PROCESS: Oh, crap. I have no idea what is going on,\r\n");
  310. break;
  311. }
  312. }
  313. }
  314. /******************************************************************************
  315. * FunctionName : wifi_station_scan_done
  316. * Description : Cb function of scan, organizes a linked list of stations
  317. from scan function. Make sure to free linked list when done.
  318. * Parameters :
  319. * Returns :
  320. *******************************************************************************/
  321. static void ICACHE_FLASH_ATTR wifi_station_scan_done(void *arg, STATUS status)
  322. {
  323. uint8_t ssid[33];
  324. uint8_t bssid[6];
  325. if (status == OK) // if the scan was sucessful
  326. {
  327. bss_link = (struct bss_info *)arg;
  328. struct bss_info *bss_link_next, *bss_link_curr, *bss_link_prev, *bss_link_head;
  329. uint32_t i,numAP,j;
  330. bss_link = copy_linked_list(bss_link); // SDK provived linked list will be destroyed automatically
  331. bss_link_head = bss_link; // store head for traversing list
  332. // get len of linked list
  333. numAP=0;
  334. while(bss_link != NULL) {
  335. numAP++;
  336. bss_link = bss_link->next.stqe_next;
  337. }
  338. os_printf("Number of APs found: %d\r\n", numAP);
  339. bss_link = bss_link_head; // reset to head
  340. // sort linked list by rssi
  341. for(i=0;i<numAP-1;i++)
  342. {
  343. bss_link_prev = NULL;
  344. bss_link_curr = bss_link;
  345. bss_link_next = bss_link->next.stqe_next;
  346. for(j=0; j<numAP-1-i; j++)
  347. {
  348. system_soft_wdt_feed(); // reset sw watchdog timer
  349. if (bss_link_next->rssi > bss_link_curr->rssi) {
  350. if (bss_link_prev == NULL) {
  351. // swap node position and head position
  352. bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next;
  353. bss_link_next->next.stqe_next = bss_link_curr;
  354. bss_link = bss_link_next; // store new head
  355. bss_link_prev = bss_link_next;
  356. bss_link_next = bss_link_curr->next.stqe_next;
  357. } else {
  358. // swap node positions
  359. bss_link_prev->next.stqe_next = bss_link_next;
  360. bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next; // could be null
  361. bss_link_next->next.stqe_next = bss_link_curr;
  362. bss_link_prev = bss_link_next;
  363. bss_link_next = bss_link_curr->next.stqe_next;
  364. }
  365. } else {
  366. // move along like nothing happened
  367. bss_link_prev = bss_link_curr;
  368. bss_link_curr = bss_link_next;
  369. bss_link_next = bss_link_next->next.stqe_next;
  370. }
  371. }
  372. }
  373. bss_link_head = bss_link; // store head
  374. // print sorted list of stations
  375. while (bss_link != NULL) {
  376. os_memset(ssid, 0, 33);
  377. os_memset(bssid, 0, 6);
  378. if (os_strlen(bss_link->ssid) <= 32) {
  379. os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
  380. } else {
  381. os_memcpy(ssid, bss_link->ssid, 32);
  382. }
  383. os_printf("WiFi Scan: (%d,\"%s\",%x, %d)\n", bss_link->authmode, ssid, bssid, bss_link->rssi);
  384. bss_link = bss_link->next.stqe_next;
  385. }
  386. bss_link = bss_link_head; // reset to head
  387. head_bss_link = bss_link_head; // ahhh, this is lazy.
  388. os_printf("Activating event handler\r\n");
  389. wifi_set_event_handler_cb(wifi_handle_event_cb);
  390. os_printf("Analysis scan results\r\n");
  391. wifi_process();
  392. }
  393. else // if scan was unsuccessful
  394. {
  395. sysCfg.module_state.searching = FALSE;
  396. os_printf("Scan Failed\r\n");
  397. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 0xFFFFFFFF); // clear pending interrupts
  398. sysCfg.module_state.asleep = TRUE;
  399. ETS_GPIO_INTR_ENABLE(); // enable interrupts to permit PB and LSM6DS3 to wake ESP from sleep.
  400. }
  401. }
  402. /******************************************************************************
  403. * FunctionName : start_wifi_process
  404. * Description : scans for available AP and attempts to connect to the AP with
  405. the highest RSSI.
  406. * Parameters : restart - resets wifi_process_count
  407. * Returns :
  408. *******************************************************************************/
  409. void ICACHE_FLASH_ATTR start_wifi_process(void)
  410. {
  411. ETS_GPIO_INTR_DISABLE(); // disable I/O interrupts
  412. lsm6ds3_motion_enable(); // enable LSM6DS3 Significant Motion Process
  413. wifi_process_flags.process_count = 0;
  414. wifi_process_flags.wifi_flag = FALSE; // clear wifi_process_flags
  415. wifi_process_flags.ip_flag = FALSE;
  416. wifi_process_flags.wifi_count = 0;
  417. sysCfg.module_state.searching = TRUE; // setup global flags for searching
  418. sysCfg.module_state.connected = FALSE;
  419. sysCfg.module_state.broker = FALSE;
  420. wifi_station_set_auto_connect(FALSE); // disable wifi auto connect
  421. wifi_station_ap_number_set(0); // don't store Wi-Fi configurations in SDK flash
  422. os_printf("Start Wi-Fi Scan\r\n");
  423. wifi_set_opmode(STATION_MODE);
  424. wifi_station_scan(NULL, wifi_station_scan_done); // start Wi-Fi scan.
  425. }