/* * wifi_Init.c * * Created on: 1/8/2023 * Author: Sword */ #include "esp_system.h" #include "esp_event.h" #include "esp_netif.h" #include "esp_wifi.h" #include "esp_mac.h" #include "lwip/ip4_addr.h" #include "freertos/event_groups.h" #include "wifi_Init.h" #include "wifi_Client.h" #include "string.h" #include "main.h" #include "nvm.h" #include "data_processing.h" #if (WIFI_NEEDED == 1) static const char* TAG = "WIFI"; #define LOG_LOCAL_LEVEL ESP_LOG_INFO #include "esp_log.h" #define ESP_MAXIMUM_RETRY 5 #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 #define WIFI_SCAN_DONE_BIT BIT2 #define WIFI_AP_CONNECTED_BIT BIT3 #define WIFI_AP_DISCONNECTED_BIT BIT4 #define WIFI_DISCONNECTED_BIT BIT5 #define WIFI_AP_SSID "Sensor Setup " static char g_pWifiSsidA[MAX_SSID_LEN]; static char g_pWifiPasswordA[MAX_PASSPHRASE_LEN]; static char g_pWifiSsidB[MAX_SSID_LEN]; static char g_pWifiPasswordB[MAX_PASSPHRASE_LEN]; /* WIFI connection TIME */ uint32_t g_wifiStartTime; extern uint32_t g_wifiConnectTime; /* WIFI SSID's & PASSWORDS */ static char Sta_Ssid[MAX_SSID_LEN]; static char Sta_Pwd[MAX_PASSPHRASE_LEN] = {0}; RTC_DATA_ATTR uint32_t wifiSelection; wifi_ap_record_t scanned_networks[20]; uint8_t device_wifi_onboarded; /* WIFI RSSI & STATUS */ static uint8_t isStaConnected; static bool isStarted; static bool isInitialized; static bool isHandlerRegister; /* FreeRTOS event group to signal when we are connected*/ static EventGroupHandle_t s_wifi_event_group; static bool set_wifi_bits; static int s_retry_num = 0; static bool turnOffStation; /* This structure holds the WIFI configurations (modes, ip's, ssid&pwd ...etc )*/ esp_netif_t *sta_netif; esp_netif_t *ap_netif; wifi_config_t wifi_config; esp_netif_ip_info_t wifi_sta_ip_infos; /* This is the handler that will be executed when receiving any WIFI-events or IP-events */ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { /* This Log will be printed as a result of esp_wifi_start (when the wifi mode is STA or AP&STA )*/ ESP_LOGI(TAG, " -----> Station(Client) mode Start"); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_START) { /* This Log will be printed as a result of esp_wifi_start (when the wifi mode is AP or AP&STA )*/ ESP_LOGI(TAG, " -----> ACCESS-POINT Start"); } else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) { /* This Log will be printed as a result of esp_wifi_connect (when the wifi mode is STA or AP&STA ) * Indicates successful connection to the wifi-network or to the access point */ ESP_LOGI(TAG, " -----> Station(client) Connected to the registered AP"); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if(turnOffStation) { if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_DISCONNECTED_BIT); } ESP_LOGI(TAG, " ---> Disconnecting wifi-station successfully"); } else { isStaConnected = 0; if (s_retry_num < ESP_MAXIMUM_RETRY) { esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAG, " ---> Retry to connect to the AP !!!"); } else { if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } } ESP_LOGI(TAG, " ---> Connecting to the registered AP failed !!!"); } } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "------> The Device got the ip-address:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } /* 1- Take and store the ip-address infos */ data_set_local_ip_addr(&event->ip_info); } else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) { if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_SCAN_DONE_BIT); } } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED) { wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid); if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_AP_CONNECTED_BIT); } } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid); if(set_wifi_bits) { xEventGroupSetBits(s_wifi_event_group, WIFI_AP_DISCONNECTED_BIT); } } } /* Functions for Starting WIFI as Client, Server and Scan nearby networks */ esp_err_t Connect_wifi_sta(uint8_t mode) { /* Create the return variable */ esp_err_t retval = ESP_FAIL; time_t timeNow; time(&timeNow); uint32_t temp_time=0; g_wifiStartTime = (uint32_t)timeNow; /* Check if the esp-32 was connected to network before. If so then disconnect it and reconnect again after 3sec */ if(isStaConnected) { wifi_sta_disconnecting(); vTaskDelay(3000/portTICK_PERIOD_MS); } /* Create a WIFI-event group and create its corresponding bits */ s_wifi_event_group = xEventGroupCreate(); set_wifi_bits = true; EventBits_t bits; /* Set the wifi_disconnecting flag to be false */ turnOffStation = false; // 2 - Wi-Fi Configuration Phase /* Assign a handler that will be executed when receiving any WIFI-events */ //esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL); /* Update the SSID and Password that ESP32 will use them to connect to the network when acting acting as WIFI-STATION */ /*if(wifiSelection) { strcpy((char *)wifi_config.sta.ssid, g_pWifiSsidB); strcpy((char *)wifi_config.sta.password, g_pWifiPasswordB); } else*/ { #ifdef STORING_TO_NVM //device_wifi_onboarded = nvm_read_onboarding_flag(WIFI_ONBOARDING_KEY); if(device_wifi_onboarded) { /* Connecting to the network that has been registered since the last onboarding process * This if-block will be executed when doing the CHECK-IN process */ nvm_read_wifi_credentials(Sta_Ssid,Sta_Pwd); } #endif /* Copying the network credentials to the wifi_config structure so that the esp-client can connect to */ strcpy((char *)wifi_config.sta.ssid, Sta_Ssid); strcpy((char *)wifi_config.sta.password, Sta_Pwd); } /* Make sure that there's a valid entered SSID to connect to */ if((Sta_Ssid[0] == 0)) { //ESP_LOGE(TAG,"----> There's no valid SSID to connect to"); return ESP_FAIL; } /* Set the WIFI-mode & WIFI-configs then start and connect to the WIFI network */ ESP_LOGI(TAG," Initializing and starting WIFI-Client "); ESP_ERROR_CHECK(esp_wifi_set_mode(mode)); wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); if(!isStarted) ESP_ERROR_CHECK(esp_wifi_start()); /**/ ESP_ERROR_CHECK(esp_wifi_connect()); //ESP_LOGI(TAG, "wifi_init_sta finished."); ESP_LOGI(TAG, "WIFI STA connection Start..."); /* block to wait for one or more bits to be set within a previously created event group (s_wifi_event_group) */ bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_CONNECTED_BIT) { /* Set the WIFI connect Time */ time(&timeNow); temp_time = (timeNow - g_wifiStartTime); g_wifiConnectTime = (uint8_t)((temp_time > 255)? 255 : temp_time); /* Get the RSSI value of WIFI */ /*int wifi_rssi; esp_wifi_sta_get_rssi((int*)&wifi_rssi);*/ wifi_ap_record_t ap_info; esp_wifi_sta_get_ap_info(&ap_info); data_set_wifi_rssi(ap_info.rssi); ESP_LOGI(TAG, "Connected to AP SSID:%s password:%s", Sta_Ssid, Sta_Pwd); /* 2- Take and store the dns-server info */ esp_netif_dns_info_t dns1, dns2; esp_netif_get_dns_info(sta_netif,ESP_NETIF_DNS_MAIN,&dns1); esp_netif_get_dns_info(sta_netif,ESP_NETIF_DNS_BACKUP,&dns2); data_set_main_and_backup_dns(&dns1,&dns2); /* 3- Take and store the mac-address of connected AP */ data_set_ap_mac_addr((uint8_t*)&wifi_config.sta.bssid); /* 4- Take and store the wifi-channel */ data_set_wifi_channel(wifi_config.sta.channel); /* Set the connection flag */ isStaConnected = 1; /* set the return value to be ESP_OK */ retval = ESP_OK; } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", Sta_Ssid, Sta_Pwd); isStaConnected = 0; /* set the return value to be ESP_FAIL */ retval = ESP_FAIL; } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } /* Delete the created event group after receiving the required bits or "UNEXPECTED EVENT" */ vEventGroupDelete(s_wifi_event_group); set_wifi_bits = false; /* return this value */ return retval; } void Wifi_Init_SoftAp(void) { char ap_ssid[32]; char mac_str[15]; uint8_t mac_base[6] = {0}; /* Check if the onboarded-flag is false (Don't start AP unless the device hasn't been on-boarded) */ //if(!device_wifi_onboarded) { /* Read the device mac-address */ esp_efuse_mac_get_default(mac_base); esp_read_mac(mac_base, ESP_MAC_WIFI_SOFTAP); /* Set the SSID-name of the esp32-AP (Sensor Setup -deviceID-) */ strcpy(ap_ssid, WIFI_AP_SSID); sprintf(mac_str, "%02X%02X%02X", mac_base[3], mac_base[4], mac_base[5]); strcat(ap_ssid, mac_str); ESP_LOGI(TAG, "AP SSID: %s", ap_ssid); /* Start event group to read the connection bits */ s_wifi_event_group = xEventGroupCreate(); set_wifi_bits = true; /* Set the configurations for the esp-32 AP */ wifi_config.ap.max_connection = 3; wifi_config.ap.authmode = WIFI_AUTH_OPEN; strcpy((char *)wifi_config.sta.ssid, ""); strcpy((char *)wifi_config.sta.password, ""); wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; /* Set the SSID and PASSWORD of the esp-32 AP */ strcpy((char *)wifi_config.ap.ssid, ap_ssid); wifi_config.ap.ssid_len = strlen(ap_ssid); /* Set the WIFI-mode to be AP&STA */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); isStarted = true; ESP_LOGI(TAG, "Access-Point Initialization finished."); /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_AP_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_AP_CONNECTED_BIT) { ESP_LOGI(TAG, "AP Connected"); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "AP failed to connect"); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } vEventGroupDelete(s_wifi_event_group); set_wifi_bits = false; } } void wifi_scan_start(uint16_t *apCount, wifi_ap_record_t **list) { s_wifi_event_group = xEventGroupCreate(); set_wifi_bits = true; wifi_scan_config_t scan_config = { .ssid = NULL, .bssid = NULL, .channel = 0, .show_hidden = true, .scan_type = WIFI_SCAN_TYPE_ACTIVE, .scan_time.active.min = 10, .scan_time.active.max = 10000 }; ESP_LOGI(TAG, "Start Scan"); esp_wifi_scan_start(&scan_config, true); EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_SCAN_DONE_BIT, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS); esp_wifi_scan_stop(); ESP_LOGI(TAG, "Stop Scan"); vTaskDelay(100/portTICK_PERIOD_MS); if (bits & WIFI_SCAN_DONE_BIT) { esp_wifi_scan_get_ap_num(apCount); if(apCount) { //*list = (wifi_ap_record_t *)pvPortMalloc(sizeof(wifi_ap_record_t) * (*apCount)); *list = scanned_networks; if((*apCount)<20) ESP_ERROR_CHECK((esp_wifi_scan_get_ap_records(apCount, *list))); else { *apCount = 20; ESP_ERROR_CHECK((esp_wifi_scan_get_ap_records(apCount, *list))); } } } vEventGroupDelete(s_wifi_event_group); set_wifi_bits = false; } /* Update the wifi credentials (SSID&PWD) of the target network */ void wifi_update_credentials(char *ssid, char *pwd) { /* Update the SSID and password that the ESP will use when acting as wifi-client (station) */ strcpy(Sta_Ssid, ssid); strcpy(Sta_Pwd, pwd); } uint8_t wifi_station_connected(void) { return isStaConnected; } bool wifi_isStarted(void) { return isStarted; } char *wifi_get_ssid(void) { return Sta_Ssid; } char *wifi_get_pswd(void) { return Sta_Pwd; } void wifi_switchToPrimaryNetwork(void) { if(0 != wifiSelection) { wifiSelection = 0; // Primary WiFi data_clearWifiConnectionSettings(); } } // End of switchToPrimaryWifiNetwork() /* Functions to Set/get WIFI-credentials of networkA */ char *wifi_get_ssidA(void) { return g_pWifiSsidA; } char *wifi_get_pswdA(void) { return g_pWifiPasswordA; } void wifi_set_ssidA(char* ssid) { strcpy(g_pWifiSsidA,ssid); } void wifi_set_pswdA(char* pswd) { strcpy(g_pWifiPasswordA,pswd); } /* Functions to Set/get WIFI-credentials of networkA */ char *wifi_get_ssidB(void) { return g_pWifiSsidB; } char *wifi_get_pswdB(void) { return g_pWifiPasswordB; } void wifi_set_ssidB(char* ssid) { strcpy(g_pWifiSsidB,ssid); } void wifi_set_pswdB(char* pswd) { strcpy(g_pWifiPasswordB,pswd); } /* WIFI functions for Initialization and De-initialization */ esp_err_t wifi_first_init(void) { /* Create the return variable */ esp_err_t retval = ESP_FAIL; if(isInitialized) { return ESP_OK; } /* Initialize the underlying TCP/IP stack */ retval = esp_netif_init(); /* Create default event loop */ retval = esp_event_loop_create_default(); /* Do the required initialization for setting the device -esp32- to act as WiFi-station and WIFI-AP */ sta_netif = esp_netif_create_default_wifi_sta(); // if(!device_wifi_onboarded) { esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); /* Stop the DHCP server to change the IP address of AP-gateway */ retval = esp_netif_dhcps_stop(ap_netif); /* Create the structure of the new IP-address of the AP */ esp_netif_ip_info_t ip_info; /* Set the IP-address to [10.10.1.1] and the same thing for gateway and subnet-mask is [255.255.255.0] */ IP4_ADDR(&ip_info.ip, 10, 10, 1, 1); IP4_ADDR(&ip_info.gw, 10, 10, 1, 1); IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0); /* Update the IP-address info with the new ones */ retval = esp_netif_set_ip_info(ap_netif, &ip_info); ESP_LOGI(TAG, "esp_netif_set_ip_info(): 0x%X", retval); /* Restart the DHCP server again */ retval = esp_netif_dhcps_start(ap_netif); } /* Load the default init_configurations */ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); retval = esp_wifi_init(&cfg); /* Set the initialization flag */ isInitialized = true; /* Initialize and register the wifi and ip event-handler */ wifi_register_event_handlers(); /* return the result */ return retval; } /* function for registering the handler for the received wifi or ip events (called once at the beginning of the program)*/ void wifi_register_event_handlers(void) { if(!isHandlerRegister) { /* 1- Assign the handler for receiving any wifi-event */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); /* 2- Assign a handler that will be executed when receiving the STA_GOT_IP event (when the ESP32 receive an IP from the DHCP of the router or the Access-Point) */ esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL); isHandlerRegister = true; } } esp_err_t wifi_stop(void) { /* Create the return variable */ esp_err_t retval = ESP_FAIL; /* Create a WIFI-event group and create its corresponding bits */ s_wifi_event_group = xEventGroupCreate(); set_wifi_bits = true; EventBits_t bits; //esp_wifi_restore(); //esp_wifi_deinit(); esp_wifi_stop(); /* block to wait for one or more bits to be set within a previously created event group (s_wifi_event_group) */ bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_AP_DISCONNECTED_BIT) { ESP_LOGI(TAG, "WIFI has been Stopped"); retval = ESP_OK; } else { ESP_LOGE(TAG, "Failed to Stop WIFI. UNEXPECTED EVENT"); retval = ESP_FAIL; } /* Delete the created event group after receiving the required bits or "UNEXPECTED EVENT" */ vEventGroupDelete(s_wifi_event_group); set_wifi_bits = false; //ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); isStaConnected = 0; isStarted = false; ap_netif = NULL; //isInitialized = false; /* return the result */ return retval; } void wifi_sta_disconnecting(void) { EventBits_t bits; if(isStaConnected) { /* Create a WIFI-event group and create its corresponding bits */ s_wifi_event_group = xEventGroupCreate(); set_wifi_bits = true; /* Set the station turn-off flag to be true */ turnOffStation = true; /* Disconnect the WIFI-Station */ ESP_ERROR_CHECK(esp_wifi_disconnect()); /* block to wait for one or more bits to be set within a previously created event group (s_wifi_event_group) */ bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_DISCONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_DISCONNECTED_BIT) { ESP_LOGI(TAG, "WIFI has been disconnected"); //ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,&event_handler)); //isHandlerRegister = false; isStaConnected = 0; } else { ESP_LOGE(TAG, "Failed to disconnect WIFI-Station. UNEXPECTED EVENT"); } /* Delete the created event group after receiving the required bits or "UNEXPECTED EVENT" */ vEventGroupDelete(s_wifi_event_group); set_wifi_bits = false; } } bool safeStrCat(char *dest, uint16_t destSize, char *source) { if(strlen(source) > (destSize - 1 - strlen(dest))) return(false); strcat(dest, source); return(true); } // End of safeStrCat #endif