/****************************************************************************** * 2016 IdeasX v0.3.1 Module Firmware * * File Name: wifi.c * Author: Tyler Berezowsky * Description: This file is going to need alot of help by a C wizard, but it currently works...I think. * * 2016/8/8, v1.0 created this file *******************************************************************************/ #include "interface/wifi_interface.h" #include "log/esp_log.h" #include "esp_common.h" static const char* TAG = "WiFi Interface"; static wifi_config_t wifi_config; static struct bss_info *bss_link, *head_bss_link; /****************************************************************************** * FunctionName : destory_linked_list * Description : * Parameters : * Returns : *******************************************************************************/ static bool ICACHE_FLASH_ATTR destory_linked_list(void) { if(head_bss_link != NULL) { while(head_bss_link != NULL) { bss_link = head_bss_link; head_bss_link = head_bss_link->next.stqe_next; os_free(bss_link); } return TRUE; } else { return FALSE; } } /****************************************************************************** * FunctionName : copy_linked_list * Description : * Parameters : * Returns : *******************************************************************************/ static struct bss_info* ICACHE_FLASH_ATTR copy_linked_list(struct bss_info *ptr_original_node) { struct bss_info *ptr_new_head, *ptr_new_node; if(ptr_original_node != NULL) { ptr_new_head = (struct bss_info *)os_malloc(sizeof(struct bss_info)); if (ptr_new_head == NULL) { ESP_LOGE(TAG, "no RAM!"); return NULL; } } else return NULL; os_memcpy(ptr_new_head, ptr_original_node, sizeof(struct bss_info)); ptr_original_node = ptr_original_node->next.stqe_next; ptr_new_node = ptr_new_head; while(ptr_original_node != NULL) { ptr_new_node->next.stqe_next = (struct bss_info *)os_malloc(sizeof(struct bss_info)); ptr_new_node = ptr_new_node->next.stqe_next; os_memcpy(ptr_new_node, ptr_original_node, sizeof(struct bss_info)); if (ptr_new_node == NULL) { ESP_LOGE(TAG, "No RAM!"); while(ptr_new_head != NULL) { ptr_new_node = ptr_new_head; ptr_new_head = ptr_new_head->next.stqe_next; os_free(ptr_new_node); } ESP_LOGE(TAG, "deleted linked list"); return NULL; } ptr_original_node = ptr_original_node->next.stqe_next; } return ptr_new_head; } /****************************************************************************** * FunctionName : wifi_timeout_cb * Description : * Parameters : * Returns : *******************************************************************************/ static void ICACHE_FLASH_ATTR wifi_timeout_cb(void) { ESP_LOGI(TAG, "wifi connection timed out"); wifi_config.wifi_process = false; if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_TIMEOUT_FAILURE); } /****************************************************************************** * FunctionName : wifi_event_handler_cb * Description : * Parameters : * Returns : *******************************************************************************/ static void ICACHE_FLASH_ATTR wifi_event_handler_cb(System_Event_t *evt) { switch (evt->event) { case EVENT_STAMODE_CONNECTED: { wifi_config.ap_flag = true; ESP_LOGD(TAG, "connected to ssid %s, channel %d", evt->event_info.connected.ssid, evt->event_info.connected.channel); break; } case EVENT_STAMODE_DISCONNECTED: { wifi_config.ap_flag = false; wifi_config.ip_flag = false; ESP_LOGD(TAG, "disconnected from ssid %s, reason %d", evt->event_info.disconnected.ssid, evt->event_info.disconnected.reason); if (wifi_config.wifi_process == false) { wifi_station_disconnect(); if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_AP_DISCONNECTED); } break; } case EVENT_STAMODE_AUTHMODE_CHANGE: { wifi_config.ap_flag = false; wifi_config.ip_flag = false; ESP_LOGD(TAG, "mode: %d -> %d", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); if (wifi_config.wifi_process == false) { if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_AP_AUTHMODE_CHANGE); } break; } case EVENT_STAMODE_GOT_IP: { wifi_config.ip_flag = true; os_timer_disarm(&wifi_config.timeout_timer); ESP_LOGD(TAG, "ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR, IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw)); wifi_config.wifi_process = false; if (wifi_config.success_cb != NULL) wifi_config.success_cb(); break; } default: { ESP_LOGD(TAG, "unknown Wi-Fi failure code"); break; } } } /****************************************************************************** * FunctionName : wifi_process * Description : * Parameters : * Returns : *******************************************************************************/ static ICACHE_FLASH_ATTR wifi_process(void) { uint8_t ssid[33]; uint8_t ap_index; struct station_config stationConfig[5]; // retrive stations stored in flash uint8_t num = wifi_station_get_ap_info(stationConfig); if (num == 0) { if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_NO_STORED_APS_FAILURE); return; } // loop through every value in the RSSI sorted linked list ESP_LOGD(TAG, "searching stored access points") while(bss_link != NULL) { // feed SW watch dog timer to prevent rest system_soft_wdt_feed(); // retrive SSID from RSSI sorted linked list os_memset(ssid, 0, 33); if (os_strlen(bss_link->ssid) <= 32) { os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid)); } else { os_memcpy(ssid, bss_link->ssid, 32); } // search the linked list for an AP stored in the cache which was also // found in the access point scan for (ap_index=0;ap_indexnext.stqe_next; // stop looping through RSSI sorted scan results and start connection // timeout timer if (wifi_config.ap_found) { break; } } if (!wifi_config.ap_found) { if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_NO_AVAILABLE_APS_FAILURE); ESP_LOGD(TAG, "access point not found") } destory_linked_list(); } /****************************************************************************** * FunctionName : wifi_scan_done * Description : * Parameters : * Returns : *******************************************************************************/ static void ICACHE_FLASH_ATTR wifi_scan_done(void *arg, STATUS status) { uint8_t ssid[33]; uint8_t bssid[6]; if (status == OK) // if the scan was sucessful { bss_link = (struct bss_info *)arg; struct bss_info *bss_link_next, *bss_link_curr, *bss_link_prev, *bss_link_head; uint32_t i,numAP,j; if (bss_link == NULL) { if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_NO_AVAILABLE_APS_FAILURE); return; } // copy linked list because SDK will end up destorying it bss_link = copy_linked_list(bss_link); bss_link_head = bss_link; // get len of linked list numAP=0; while(bss_link != NULL) { numAP++; bss_link = bss_link->next.stqe_next; } ESP_LOGD(TAG, "number of APs found: %d", numAP); bss_link = bss_link_head; // reset to head // sort linked list by rssi for(i=0;inext.stqe_next; for(j=0; jrssi > bss_link_curr->rssi) { if (bss_link_prev == NULL) { // swap node position and head position bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next; bss_link_next->next.stqe_next = bss_link_curr; bss_link = bss_link_next; // store new head bss_link_prev = bss_link_next; bss_link_next = bss_link_curr->next.stqe_next; } else { // swap node positions bss_link_prev->next.stqe_next = bss_link_next; bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next; // could be null bss_link_next->next.stqe_next = bss_link_curr; bss_link_prev = bss_link_next; bss_link_next = bss_link_curr->next.stqe_next; } } else { // move along like nothing happened bss_link_prev = bss_link_curr; bss_link_curr = bss_link_next; bss_link_next = bss_link_next->next.stqe_next; } } } bss_link_head = bss_link; // store head // print sorted list of stations while (bss_link != NULL) { os_memset(ssid, 0, 33); os_memset(bssid, 0, 6); if (os_strlen(bss_link->ssid) <= 32) { os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid)); } else { os_memcpy(ssid, bss_link->ssid, 32); } ESP_LOGD(TAG, "(%d,\"%s\",%x, %d)", bss_link->authmode, ssid, bssid, bss_link->rssi); bss_link = bss_link->next.stqe_next; } bss_link = bss_link_head; // reset to head head_bss_link = bss_link_head; // ahhh, this is lazy. wifi_set_event_handler_cb(wifi_event_handler_cb); wifi_process(); } else // if scan was unsuccessful { ESP_LOGD(TAG, "scan failed"); if (wifi_config.fail_cb != NULL) wifi_config.fail_cb(WIFI_SCAN_FAILURE); wifi_config.wifi_process = false; } } /****************************************************************************** * FunctionName : WiFi_Initialize * Description : * Parameters : * Returns : *******************************************************************************/ void ICACHE_FLASH_ATTR WiFi_Initialize(void) { wifi_set_opmode(STATION_MODE); wifi_station_ap_number_set(5); wifi_station_disconnect(); wifi_station_set_auto_connect(false); wifi_config.fail_cb = NULL; wifi_config.success_cb = NULL; } /****************************************************************************** * FunctionName : WiFi_Disconnect * Description : * Parameters : * Returns : *******************************************************************************/ void ICACHE_FLASH_ATTR WiFi_Disconnect(void) { wifi_config.ip_flag = false; wifi_config.ap_flag = false; wifi_station_disconnect(); } /****************************************************************************** * FunctionName : WiFi_SetCallbacks * Description : * Parameters : * Returns : *******************************************************************************/ void ICACHE_FLASH_ATTR WiFi_SetCallbacks(wifi_success_function_t success_cb, wifi_fail_function_t fail_cb) { wifi_config.success_cb = success_cb; wifi_config.fail_cb = fail_cb; } /****************************************************************************** * FunctionName : WiFi_Connect * Description : * Parameters : * Returns : *******************************************************************************/ void ICACHE_FLASH_ATTR WiFi_Connect(uint32_t timeout_delay) { wifi_config.timeout_delay = timeout_delay; wifi_config.ip_flag = false; wifi_config.ap_flag = false; wifi_config.ap_found = false; wifi_config.wifi_process = true; wifi_set_event_handler_cb(NULL); os_timer_disarm(&wifi_config.timeout_timer); os_timer_setfn(&wifi_config.timeout_timer, (os_timer_func_t *)wifi_timeout_cb, NULL); // check for stored APs // if none call no_credentials_cb(), shutdown WIFI, return ESP_LOGI(TAG, "starting Wi-Fi scan"); wifi_station_scan(NULL, wifi_scan_done); // start Wi-Fi scan. }