| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251 | #ifdef NETWORK_WIFI_LOG_LEVEL#define LOG_LOCAL_LEVEL NETWORK_WIFI_LOG_LEVEL#endif#include "network_wifi.h"#include <string.h>#include "cJSON.h"#include "dns_server.h"#include "esp_event.h"#include "esp_log.h"#include "esp_system.h"#include "esp_wifi.h"#include "esp_wifi_types.h"#include "lwip/sockets.h"#include "messaging.h"#include "network_status.h"#include "nvs.h"#include "nvs_flash.h"#include "nvs_utilities.h"#include "platform_config.h"#include "platform_esp32.h"#include "tools.h"#include "trace.h"static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);static char* get_disconnect_code_desc(uint8_t reason);esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key);static inline const char* ssid_string(const wifi_sta_config_t* sta);static inline const char* password_string(const wifi_sta_config_t* sta);cJSON* accessp_cjson = NULL;static const char TAG[] = "network_wifi";const char network_wifi_nvs_namespace[] = "config";const char ap_list_nsv_namespace[] = "aplist";/* rrm ctx *///Roaming support - int rrm_ctx = 0;uint16_t ap_num = 0;esp_netif_t* wifi_netif;esp_netif_t* wifi_ap_netif;wifi_ap_record_t* accessp_records = NULL;#define UINT_TO_STRING(val)                \    static char loc[sizeof(val) + 1];      \    memset(loc, 0x00, sizeof(loc));        \    strlcpy(loc, (char*)val, sizeof(loc)); \    return loc;static inline const char* ssid_string(const wifi_sta_config_t* sta) {    UINT_TO_STRING(sta->ssid);}static inline const char* password_string(const wifi_sta_config_t* sta) {    UINT_TO_STRING(sta->password);}static inline const char* ap_ssid_string(const wifi_ap_record_t* ap) {    UINT_TO_STRING(ap->ssid);}typedef struct known_access_point {    char* ssid;    char* password;    bool found;    uint8_t bssid[6];          /**< MAC address of AP */    uint8_t primary;           /**< channel of AP */    wifi_auth_mode_t authmode; /**< authmode of AP */    uint32_t phy_11b : 1;      /**< bit: 0 flag to identify if 11b mode is enabled or not */    uint32_t phy_11g : 1;      /**< bit: 1 flag to identify if 11g mode is enabled or not */    uint32_t phy_11n : 1;      /**< bit: 2 flag to identify if 11n mode is enabled or not */    uint32_t phy_lr : 1;       /**< bit: 3 flag to identify if low rate is enabled or not */    time_t last_try;    SLIST_ENTRY(known_access_point)    next;  //!< next callback} known_access_point_t;/** linked list of command structures */static EXT_RAM_ATTR SLIST_HEAD(ap_list, known_access_point) s_ap_list;known_access_point_t* network_wifi_get_ap_entry(const char* ssid) {    known_access_point_t* it;    if (!ssid || strlen(ssid) == 0) {        ESP_LOGW(TAG, "network_wifi_get_ap_entry Invalid SSID %s", !ssid ? "IS NULL" : "IS BLANK");        return NULL;    }    SLIST_FOREACH(it, &s_ap_list, next) {        ESP_LOGD(TAG, "Looking for SSID %s = %s ?", ssid, it->ssid);        if (strcmp(it->ssid, ssid) == 0) {            ESP_LOGD(TAG, "network_wifi_get_ap_entry SSID %s found! ", ssid);            return it;        }    }    return NULL;}void network_wifi_remove_ap_entry(const char* ssid) {    if (!ssid || strlen(ssid) == 0) {        ESP_LOGE(TAG, "network_wifi_remove_ap_entry error empty SSID");    }    known_access_point_t* it = network_wifi_get_ap_entry(ssid);    if (it) {        ESP_LOGW(TAG, "Removing %s from known list of access points", ssid);        FREE_AND_NULL(it->ssid);        FREE_AND_NULL(it->password);        SLIST_REMOVE(&s_ap_list, it, known_access_point, next);        FREE_AND_NULL(it);    }}void network_wifi_empty_known_list() {    known_access_point_t* it;    while ((it = SLIST_FIRST(&s_ap_list)) != NULL) {        network_wifi_remove_ap_entry(it->ssid);    }}const wifi_sta_config_t* network_wifi_get_active_config() {    static wifi_config_t config;    esp_err_t err = ESP_OK;    memset(&config, 0x00, sizeof(config));    if ((err = esp_wifi_get_config(WIFI_IF_STA, &config)) == ESP_OK) {        return &config.sta;    } else {        ESP_LOGD(TAG, "Could not get wifi STA config: %s", esp_err_to_name(err));    }    return NULL;}size_t network_wifi_get_known_count() {    size_t count = 0;    known_access_point_t* it;    SLIST_FOREACH(it, &s_ap_list, next) {        count++;    }    return count;}size_t network_wifi_get_known_count_in_range() {    size_t count = 0;    known_access_point_t* it;    SLIST_FOREACH(it, &s_ap_list, next) {        if(it->found) count++;    }    return count;}esp_err_t network_wifi_add_ap(known_access_point_t* item) {    known_access_point_t* last = SLIST_FIRST(&s_ap_list);    if (last == NULL) {        SLIST_INSERT_HEAD(&s_ap_list, item, next);    } else {        known_access_point_t* it;        while ((it = SLIST_NEXT(last, next)) != NULL) {            last = it;        }        SLIST_INSERT_AFTER(last, item, next);    }    return ESP_OK;}esp_err_t network_wifi_add_ap_copy(const known_access_point_t* known_ap) {    known_access_point_t* item = NULL;    esp_err_t err = ESP_OK;        if (!known_ap) {        ESP_LOGE(TAG, "Invalid access point entry");        return ESP_ERR_INVALID_ARG;    }    if (!known_ap->ssid || strlen(known_ap->ssid) == 0) {        ESP_LOGE(TAG, "Invalid access point ssid");        return ESP_ERR_INVALID_ARG;    }    item = malloc_init_external(sizeof(known_access_point_t));    if (item == NULL) {        ESP_LOGE(TAG, "Memory allocation failed");        return ESP_ERR_NO_MEM;    }    item->ssid = strdup_psram(known_ap->ssid);    item->password = strdup_psram(known_ap->password);    memcpy(&item->bssid, known_ap->bssid, sizeof(item->bssid));    item->primary = known_ap->primary;    item->authmode = known_ap->authmode;    item->phy_11b = known_ap->phy_11b;    item->phy_11g = known_ap->phy_11g;    item->phy_11n = known_ap->phy_11n;    item->phy_lr = known_ap->phy_lr;    err = network_wifi_add_ap(item);    return err;}const wifi_ap_record_t* network_wifi_get_ssid_info(const char* ssid) {    if (!accessp_records)        return NULL;    for (int i = 0; i < ap_num; i++) {        if (strcmp(ap_ssid_string(&accessp_records[i]), ssid) == 0) {            return &accessp_records[i];        }    }    return NULL;}esp_err_t network_wifi_add_ap_from_sta_copy(const wifi_sta_config_t* sta) {    known_access_point_t* item = NULL;    esp_err_t err = ESP_OK;    if (!sta) {        ESP_LOGE(TAG, "Invalid access point entry");        return ESP_ERR_INVALID_ARG;    }    if (!sta->ssid || strlen((char*)sta->ssid) == 0) {        ESP_LOGE(TAG, "Invalid access point ssid");        return ESP_ERR_INVALID_ARG;    }    item = malloc_init_external(sizeof(known_access_point_t));    if (item == NULL) {        ESP_LOGE(TAG, "Memory allocation failed");        return ESP_ERR_NO_MEM;    }    item->ssid = strdup_psram(ssid_string(sta));    item->password = strdup_psram(password_string(sta));    memcpy(&item->bssid, sta->bssid, sizeof(item->bssid));    item->primary = sta->channel;    const wifi_ap_record_t* seen = network_wifi_get_ssid_info(item->ssid);    if (seen) {        item->authmode = seen->authmode;        item->phy_11b = seen->phy_11b;        item->phy_11g = seen->phy_11g;        item->phy_11n = seen->phy_11n;        item->phy_lr = seen->phy_lr;    }    err = network_wifi_add_ap(item);    return err;}bool network_wifi_is_known_ap(const char* ssid) {    return network_wifi_get_ap_entry(ssid) != NULL;}static bool network_wifi_was_ssid_seen(const char* ssid) {    if (!accessp_records || ap_num == 0 || ap_num == MAX_AP_NUM) {        return false;    }    for (int i = 0; i < ap_num; i++) {        if (strcmp(ap_ssid_string(&accessp_records[i]), ssid) == 0) {            return true;        }    }    return false;}void network_wifi_set_found_ap() {    known_access_point_t* it;    SLIST_FOREACH(it, &s_ap_list, next) {        if (network_wifi_was_ssid_seen(it->ssid)) {            it->found = true;        } else {            it->found = false;        }    }}bool network_wifi_known_ap_in_range(){    known_access_point_t* it;    SLIST_FOREACH(it, &s_ap_list, next) {        if (it->found) {            return true;        }    }    return false;}const char * network_wifi_get_next_ap_in_range(){    known_access_point_t* it;    time_t last_try_min=(esp_timer_get_time() / 1000);    SLIST_FOREACH(it, &s_ap_list, next) {        if (it->found && it->last_try < last_try_min) {            last_try_min = it->last_try;        }    }    SLIST_FOREACH(it, &s_ap_list, next) {        if (it->found && it->last_try == last_try_min) {            return it->ssid;        }    }    return NULL;}esp_err_t network_wifi_alloc_ap_json(known_access_point_t* item, char** json_string) {    esp_err_t err = ESP_OK;    if (!item || !json_string) {        return ESP_ERR_INVALID_ARG;    }    cJSON* cjson_item = cJSON_CreateObject();    if (!cjson_item) {        ESP_LOGE(TAG, "Memory allocation failure. Cannot save ap json");        return ESP_ERR_NO_MEM;    }    cJSON_AddStringToObject(cjson_item, "ssid", item->ssid);    cJSON_AddStringToObject(cjson_item, "pass", item->password);    cJSON_AddNumberToObject(cjson_item, "chan", item->primary);    cJSON_AddNumberToObject(cjson_item, "auth", item->authmode);    char* bssid = network_manager_alloc_get_mac_string(item->bssid);    if (bssid) {        cJSON_AddItemToObject(cjson_item, "bssid", cJSON_CreateString(STR_OR_BLANK(bssid)));    }    FREE_AND_NULL(bssid);    cJSON_AddNumberToObject(cjson_item, "b", item->phy_11b ? 1 : 0);    cJSON_AddNumberToObject(cjson_item, "g", item->phy_11g ? 1 : 0);    cJSON_AddNumberToObject(cjson_item, "n", item->phy_11n ? 1 : 0);    cJSON_AddNumberToObject(cjson_item, "low_rate", item->phy_lr ? 1 : 0);    *json_string = cJSON_PrintUnformatted(cjson_item);    if (!*json_string) {        ESP_LOGE(TAG, "Memory allocaiton failed. Cannot save ap entry.");        err = ESP_ERR_NO_MEM;    }    cJSON_Delete(cjson_item);    return err;}bool network_wifi_str2mac(const char* mac, uint8_t* values) {    if (6 == sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5])) {        return true;    } else {        return false;    }}esp_err_t network_wifi_add_json_entry(const char* json_text) {    esp_err_t err = ESP_OK;    known_access_point_t known_ap;    if (!json_text || strlen(json_text) == 0) {        ESP_LOGE(TAG, "Invalid access point json");        return ESP_ERR_INVALID_ARG;    }    cJSON* cjson_item = cJSON_Parse(json_text);    if (!cjson_item) {        ESP_LOGE(TAG, "Invalid JSON %s", json_text);        return ESP_ERR_INVALID_ARG;    }    cJSON* value = cJSON_GetObjectItemCaseSensitive(cjson_item, "ssid");    if (!value || !cJSON_IsString(value) || strlen(cJSON_GetStringValue(value)) == 0) {        ESP_LOGE(TAG, "Missing ssid in : %s", json_text);        err = ESP_ERR_INVALID_ARG;    } else {        if (!network_wifi_get_ap_entry(cJSON_GetStringValue(value))) {            known_ap.ssid = strdup_psram(cJSON_GetStringValue(value));            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "pass");            if (value && cJSON_IsString(value) && strlen(cJSON_GetStringValue(value)) > 0) {                known_ap.password = strdup_psram(cJSON_GetStringValue(value));            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "chan");            if (value) {                known_ap.primary = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "auth");            if (value) {                known_ap.authmode = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "b");            if (value) {                known_ap.phy_11b = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "g");            if (value) {                known_ap.phy_11g = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "n");            if (value) {                known_ap.phy_11n = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "low_rate");            if (value) {                known_ap.phy_lr = value->valueint;            }            value = cJSON_GetObjectItemCaseSensitive(cjson_item, "bssid");            if (value && cJSON_IsString(value) && strlen(cJSON_GetStringValue(value)) > 0) {                network_wifi_str2mac(cJSON_GetStringValue(value), known_ap.bssid);            }            err = network_wifi_add_ap_copy(&known_ap);        } else {            ESP_LOGE(TAG, "Duplicate ssid %s found in storage", cJSON_GetStringValue(value));        }    }    cJSON_Delete(cjson_item);    return err;}esp_err_t network_wifi_delete_ap(const char* key) {    esp_err_t esp_err = ESP_OK;    if (!key || strlen(key) == 0) {        ESP_LOGE(TAG, "SSID Empty. Cannot remove ");        return ESP_ERR_INVALID_ARG;    }    known_access_point_t* it = network_wifi_get_ap_entry(key);    if (!it) {        ESP_LOGE(TAG, "Unknown AP entry");        return ESP_ERR_INVALID_ARG;    }    /*      * Check if we're deleting the active network     */    ESP_LOGD(TAG, "Deleting AP %s. Checking if this is the active AP", key);    const wifi_sta_config_t* config = network_wifi_load_active_config();    if (config && strlen(ssid_string(config)) > 0 && strcmp(ssid_string(config), it->ssid) == 0) {        ESP_LOGD(TAG, "Confirmed %s to be the active network. Removing it from flash.", key);        esp_err = network_wifi_erase_legacy();        if (esp_err != ESP_OK) {            ESP_LOGW(TAG, "Legacy network details could not be removed from flash : %s", esp_err_to_name(esp_err));        }    }    ESP_LOGD(TAG, "Removing network %s from the flash AP list", key);    esp_err = erase_nvs_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, it->ssid);    if (esp_err != ESP_OK) {        messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Deleting network entry %s error (%s). Error %s", key, ap_list_nsv_namespace, esp_err_to_name(esp_err));    }    ESP_LOGD(TAG, "Removing network %s from the known AP list", key);    network_wifi_remove_ap_entry(it->ssid);    return esp_err;}esp_err_t network_wifi_erase_legacy() {    esp_err_t err = erase_nvs_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace);    if (err == ESP_OK) {        ESP_LOGW(TAG, "Erased wifi configuration. Disconnecting from network");        if ((err = esp_wifi_disconnect()) != ESP_OK) {            ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));        }    }    return err;}esp_err_t network_wifi_erase_known_ap() {    network_wifi_empty_known_list();    esp_err_t err = erase_nvs_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace);    return err;}esp_err_t network_wifi_write_ap(const char* key, const char* value, size_t size) {    size_t size_override = size > 0 ? size : strlen(value) + 1;    esp_err_t esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_BLOB, key, value, size_override);    if (esp_err != ESP_OK) {        messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "%s (%s). Error %s", key, network_wifi_nvs_namespace, esp_err_to_name(esp_err));    }    return esp_err;}esp_err_t network_wifi_write_nvs(const char* key, const char* value, size_t size) {    size_t size_override = size > 0 ? size : strlen(value) + 1;    esp_err_t esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace, NVS_TYPE_BLOB, key, value, size_override);    if (esp_err != ESP_OK) {        messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "%s (%s). Error %s", key, network_wifi_nvs_namespace, esp_err_to_name(esp_err));    }    return esp_err;}esp_err_t network_wifi_store_ap_json(known_access_point_t* item) {    esp_err_t err = ESP_OK;    size_t size = 0;    char* json_string = NULL;    const wifi_sta_config_t* sta = network_wifi_get_active_config();    if ((err = network_wifi_alloc_ap_json(item, &json_string)) == ESP_OK) {        // get any existing entry from the nvs and compare        char* existing = get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_BLOB, item->ssid, &size);        if (!existing || strncmp(existing, json_string, strlen(json_string)) != 0) {            ESP_LOGI(TAG, "SSID %s was changed or is new. Committing to flash", item->ssid);            err = network_wifi_write_ap(item->ssid, json_string, 0);            if (sta && strlen(ssid_string(sta)) > 0 && strcmp(ssid_string(sta), item->ssid) == 0) {                ESP_LOGI(TAG, "Committing active access point");                err = network_wifi_write_nvs("ssid", ssid_string(sta), 0);                if (err == ESP_OK) {                    err = network_wifi_write_nvs("password", STR_OR_BLANK(password_string(sta)), 0);                }                if (err != ESP_OK) {                    ESP_LOGE(TAG, "Error committing active access point : %s", esp_err_to_name(err));                }            }        }        FREE_AND_NULL(existing);        FREE_AND_NULL(json_string);    }    return err;}esp_netif_t* network_wifi_get_interface() {    return wifi_netif;}esp_netif_t* network_wifi_get_ap_interface() {    return wifi_ap_netif;}esp_err_t network_wifi_set_sta_mode() {    if (!wifi_netif) {        ESP_LOGE(TAG, "Wifi not initialized. Cannot set sta mode");        return ESP_ERR_INVALID_STATE;    }    ESP_LOGD(TAG, "Set Mode to STA");    esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA);    if (err != ESP_OK) {        ESP_LOGE(TAG, "Error setting mode to STA: %s", esp_err_to_name(err));    } else {        ESP_LOGI(TAG, "Starting wifi");        err = esp_wifi_start();        if (err != ESP_OK) {            ESP_LOGE(TAG, "Error starting wifi: %s", esp_err_to_name(err));        }    }    return err;}esp_netif_t* network_wifi_start() {    MEMTRACE_PRINT_DELTA_MESSAGE( "Starting wifi interface as STA mode");    accessp_cjson = network_manager_clear_ap_list_json(&accessp_cjson);    if (!wifi_netif) {        MEMTRACE_PRINT_DELTA_MESSAGE("Init STA mode - creating default interface. ");        wifi_netif = esp_netif_create_default_wifi_sta();        MEMTRACE_PRINT_DELTA_MESSAGE("Initializing Wifi. ");        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();        ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_init(&cfg));        MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi Handlers");        //network_wifi_register_handlers();        ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_instance_register(WIFI_EVENT,                                                                          ESP_EVENT_ANY_ID,                                                                          &network_wifi_event_handler,                                                                          NULL,                                                                          NULL));        MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi Storage");        ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_set_storage(WIFI_STORAGE_RAM));    }    MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi mode as STA");    network_wifi_set_sta_mode();    MEMTRACE_PRINT_DELTA_MESSAGE("Setting hostname");    network_set_hostname(wifi_netif);    MEMTRACE_PRINT_DELTA_MESSAGE("Done starting wifi interface");    return wifi_netif;}void destroy_network_wifi() {    cJSON_Delete(accessp_cjson);    accessp_cjson = NULL;}bool network_wifi_sta_config_changed() {    bool changed = true;    const wifi_sta_config_t* sta = network_wifi_get_active_config();    if (!sta || strlen(ssid_string(sta)) == 0)        return false;    known_access_point_t* known = network_wifi_get_ap_entry(ssid_string(sta));    if (known && strcmp(known->ssid, ssid_string(sta)) == 0 &&        strcmp((char*)known->password, password_string(sta)) == 0) {        changed = false;    } else {        ESP_LOGI(TAG, "New network configuration found");    }    return changed;}esp_err_t network_wifi_save_sta_config() {    esp_err_t esp_err = ESP_OK;    known_access_point_t* item = NULL;    MEMTRACE_PRINT_DELTA_MESSAGE("Config Save");    const wifi_sta_config_t* sta = network_wifi_get_active_config();    if (sta && strlen(ssid_string(sta)) > 0) {        MEMTRACE_PRINT_DELTA_MESSAGE("Checking if current SSID is known");        item = network_wifi_get_ap_entry(ssid_string(sta));        if (!item) {            ESP_LOGD(TAG,"New SSID %s found", ssid_string(sta));            // this is a new access point. First add it to the end of the AP list            esp_err = network_wifi_add_ap_from_sta_copy(sta);        }    }    // now traverse the list and commit    MEMTRACE_PRINT_DELTA_MESSAGE("Saving all known ap as json strings");    known_access_point_t* it;    SLIST_FOREACH(it, &s_ap_list, next) {        if ((esp_err = network_wifi_store_ap_json(it)) != ESP_OK) {            ESP_LOGW(TAG, "Error saving wifi ap entry %s : %s", it->ssid, esp_err_to_name(esp_err));            break;        }    }    return esp_err;}void network_wifi_load_known_access_points() {    esp_err_t esp_err;    size_t size = 0;    if (network_wifi_get_known_count() > 0) {        ESP_LOGW(TAG, "Access points already loaded");        return;    }    nvs_iterator_t it = nvs_entry_find(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_ANY);    if (it == NULL) {        ESP_LOGW(TAG, "No known access point found");        return;    }    do {        nvs_entry_info_t info;        nvs_entry_info(it, &info);        if (strstr(info.namespace_name, ap_list_nsv_namespace)) {            void* value = get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, info.type, info.key, &size);            if (value == NULL) {                ESP_LOGE(TAG, "nvs read failed for %s.", info.key);            } else if ((esp_err = network_wifi_add_json_entry(value)) != ESP_OK) {                ESP_LOGE(TAG, "Invalid entry or error for %s.", (char*)value);            }            FREE_AND_NULL(value);        }        it = nvs_entry_next(it);    } while (it != NULL);    return;}esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key) {    esp_err_t esp_err = ESP_OK;    size_t found_size = 0;    if (!target) {        ESP_LOGE(TAG, "%s invalid target pointer", __FUNCTION__);        return ESP_ERR_INVALID_ARG;    }    memset(target, 0x00, size);    char* value = (char*)get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace, NVS_TYPE_BLOB, key, &found_size);    if (!value) {        ESP_LOGD(TAG,"nvs key %s not found.", key);        esp_err = ESP_FAIL;    } else {        memcpy((char*)target, value, size > found_size ? found_size : size);        FREE_AND_NULL(value);        ESP_LOGD(TAG,"Successfully loaded key %s", key);    }    return esp_err;}const wifi_sta_config_t* network_wifi_load_active_config() {    static wifi_sta_config_t config;    esp_err_t esp_err = ESP_OK;    memset(&config, 0x00, sizeof(config));    config.scan_method = WIFI_ALL_CHANNEL_SCAN;    MEMTRACE_PRINT_DELTA_MESSAGE("Fetching wifi sta config - ssid.");    esp_err = network_wifi_get_blob(&config.ssid, sizeof(config.ssid), "ssid");    if (esp_err == ESP_OK && strlen((char*)config.ssid) > 0) {        ESP_LOGD(TAG,"network_wifi_load_active_config: ssid:%s. Fetching password (if any) ", ssid_string(&config));        if (network_wifi_get_blob(&config.password, sizeof(config.password), "password") != ESP_OK) {            ESP_LOGW(TAG, "No wifi password found in nvs");        }    } else {        if(network_wifi_get_known_count() > 0) {            ESP_LOGW(TAG, "No wifi ssid found in nvs, but known access points found. Using first known access point.");            known_access_point_t* ap = SLIST_FIRST(&s_ap_list);            if (ap) {                strncpy((char*)&config.ssid, ap->ssid, sizeof(config.ssid));                strncpy((char*)&config.password, ap->password, sizeof(config.password));            }            esp_err = ESP_OK;        } else {            ESP_LOGW(TAG, "network manager has no previous configuration. %s", esp_err_to_name(esp_err));            return NULL;        }    }    return &config;}bool network_wifi_load_wifi_sta_config() {    network_wifi_load_known_access_points();    const wifi_sta_config_t* config = network_wifi_load_active_config();    if (config) {        known_access_point_t* item = network_wifi_get_ap_entry(ssid_string(config));        if (!item) {            ESP_LOGI(TAG, "Adding legacy/active wifi connection to the known list");            network_wifi_add_ap_from_sta_copy(config);        }    }    return config && config->ssid[0] != '\0';}bool network_wifi_get_config_for_ssid(wifi_config_t* config, const char* ssid) {    known_access_point_t* item = network_wifi_get_ap_entry(ssid);    if (!item) {        ESP_LOGE(TAG, "Unknown ssid %s", ssid);        return false;    }    memset(&config->ap, 0x00, sizeof(config->ap));    strncpy((char*)config->ap.ssid, item->ssid, sizeof(config->ap.ssid));    strncpy((char*)config->ap.password, item->password, sizeof(config->ap.ssid));    config->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;    return true;}static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {    if (event_base != WIFI_EVENT)        return;    switch (event_id) {        case WIFI_EVENT_WIFI_READY:            ESP_LOGD(TAG, "WIFI_EVENT_WIFI_READY");            break;        case WIFI_EVENT_SCAN_DONE:            ESP_LOGD(TAG, "WIFI_EVENT_SCAN_DONE");            network_async_scan_done();            break;        case WIFI_EVENT_STA_AUTHMODE_CHANGE:            ESP_LOGD(TAG, "WIFI_EVENT_STA_AUTHMODE_CHANGE");            break;        case WIFI_EVENT_AP_START:            ESP_LOGD(TAG, "WIFI_EVENT_AP_START");            break;        case WIFI_EVENT_AP_STOP:            ESP_LOGD(TAG, "WIFI_EVENT_AP_STOP");            break;        case WIFI_EVENT_AP_PROBEREQRECVED: {            wifi_event_ap_probe_req_rx_t* s = (wifi_event_ap_probe_req_rx_t*)event_data;            char* mac = network_manager_alloc_get_mac_string(s->mac);            if (mac) {                ESP_LOGD(TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s", s->rssi, STR_OR_BLANK(mac));            }            FREE_AND_NULL(mac);        } break;        case WIFI_EVENT_STA_WPS_ER_SUCCESS:            ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");            break;        case WIFI_EVENT_STA_WPS_ER_FAILED:            ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");            break;        case WIFI_EVENT_STA_WPS_ER_TIMEOUT:            ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT");            break;        case WIFI_EVENT_STA_WPS_ER_PIN:            ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN");            break;        case WIFI_EVENT_AP_STACONNECTED: {            wifi_event_ap_staconnected_t* stac = (wifi_event_ap_staconnected_t*)event_data;            char* mac = network_manager_alloc_get_mac_string(stac->mac);            if (mac) {                ESP_LOGD(TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s", stac->aid, STR_OR_BLANK(mac));            }            FREE_AND_NULL(mac);        } break;        case WIFI_EVENT_AP_STADISCONNECTED:            ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED");            break;        case WIFI_EVENT_STA_START:            ESP_LOGD(TAG, "WIFI_EVENT_STA_START");            break;        case WIFI_EVENT_STA_STOP:            ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP");            break;        case WIFI_EVENT_STA_CONNECTED: {            ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. ");            wifi_event_sta_connected_t* s = (wifi_event_sta_connected_t*)event_data;            char* bssid = network_manager_alloc_get_mac_string(s->bssid);            char* ssid = strdup_psram((char*)s->ssid);            network_wifi_set_connect_state(NETWORK_WIFI_STATE_CONNECTED);            if (bssid && ssid) {                ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. Channel: %d, Access point: %s, BSSID: %s ", s->channel, STR_OR_BLANK(ssid), (bssid));            }            FREE_AND_NULL(bssid);            FREE_AND_NULL(ssid);            network_async(EN_CONNECTED);        } break;        case WIFI_EVENT_STA_DISCONNECTED: {            //		    		structwifi_event_sta_disconnected_t            //		    		Argument structure for WIFI_EVENT_STA_DISCONNECTED event            //            //		    		Public Members            //            //		    		uint8_t ssid[32]            //		    		SSID of disconnected AP            //            //		    		uint8_t ssid_len            //		    		SSID length of disconnected AP            //            //		    		uint8_t bssid[6]            //		    		BSSID of disconnected AP            //            //		    		uint8_t reason            //		    		reason of disconnection            wifi_event_sta_disconnected_t* s = (wifi_event_sta_disconnected_t*)event_data;            char* bssid = network_manager_alloc_get_mac_string(s->bssid);            ESP_LOGW(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)", STR_OR_BLANK(bssid), s->reason, get_disconnect_code_desc(s->reason));            FREE_AND_NULL(bssid);            if (s->reason == WIFI_REASON_ROAMING) {                ESP_LOGI(TAG, "WiFi Roaming to new access point");            } else {                network_async_lost_connection((wifi_event_sta_disconnected_t*)event_data);                network_wifi_set_connect_state(NETWORK_WIFI_STATE_FAILED);            }        } break;        default:            break;    }}cJSON* network_wifi_get_new_array_json(cJSON** old) {    ESP_LOGV(TAG, "network_wifi_get_new_array_json called");    cJSON* root = *old;    if (root != NULL) {        cJSON_Delete(root);        *old = NULL;    }    ESP_LOGV(TAG, "network_wifi_get_new_array_json done");    return cJSON_CreateArray();}void network_wifi_global_init() {    network_wifi_get_new_array_json(&accessp_cjson);    ESP_LOGD(TAG, "Loading existing wifi configuration (if any)");    network_wifi_load_wifi_sta_config();}void network_wifi_add_access_point_json(cJSON* ap_list, wifi_ap_record_t* ap_rec) {    cJSON* ap = cJSON_CreateObject();    if (ap == NULL) {        ESP_LOGE(TAG, "Unable to allocate memory for access point %s", ap_rec->ssid);        return;    }    cJSON* radio = cJSON_CreateObject();    if (radio == NULL) {        ESP_LOGE(TAG, "Unable to allocate memory for access point %s", ap_rec->ssid);        cJSON_Delete(ap);        return;    }    cJSON_AddItemToObject(ap, "ssid", cJSON_CreateString(ap_ssid_string(ap_rec)));    cJSON_AddBoolToObject(ap, "known", network_wifi_is_known_ap(ap_ssid_string(ap_rec)));    if (ap_rec->rssi != 0) {        // only add the rest of the details when record doesn't come from        // "known" access points that aren't in range        cJSON_AddNumberToObject(ap, "chan", ap_rec->primary);        cJSON_AddNumberToObject(ap, "rssi", ap_rec->rssi);        cJSON_AddNumberToObject(ap, "auth", ap_rec->authmode);        char* bssid = network_manager_alloc_get_mac_string(ap_rec->bssid);        if (bssid) {            cJSON_AddItemToObject(ap, "bssid", cJSON_CreateString(STR_OR_BLANK(bssid)));        }        FREE_AND_NULL(bssid);        cJSON_AddNumberToObject(radio, "b", ap_rec->phy_11b ? 1 : 0);        cJSON_AddNumberToObject(radio, "g", ap_rec->phy_11g ? 1 : 0);        cJSON_AddNumberToObject(radio, "n", ap_rec->phy_11n ? 1 : 0);        cJSON_AddNumberToObject(radio, "low_rate", ap_rec->phy_lr ? 1 : 0);        cJSON_AddItemToObject(ap, "radio", radio);    }    cJSON_AddItemToArray(ap_list, ap);    char* ap_json = cJSON_PrintUnformatted(ap);    if (ap_json != NULL) {        ESP_LOGD(TAG, "New access point found: %s", ap_json);        free(ap_json);    }}void network_wifi_generate_access_points_json(cJSON** ap_list) {    *ap_list = network_wifi_get_new_array_json(ap_list);    wifi_ap_record_t known_ap;    known_access_point_t* it;    if (*ap_list == NULL)        return;    improv_wifi_list_allocate(ap_num);    for (int i = 0; i < ap_num; i++) {        network_wifi_add_access_point_json(*ap_list, &accessp_records[i]);        improv_wifi_list_add(ap_ssid_string(&accessp_records[i]),accessp_records[i].rssi, accessp_records[i].authmode!=WIFI_AUTH_OPEN);    }    SLIST_FOREACH(it, &s_ap_list, next) {        if (!network_wifi_was_ssid_seen(it->ssid)) {            memset(&known_ap, 0x00, sizeof(known_ap));            strlcpy((char*)known_ap.ssid, it->ssid, sizeof(known_ap.ssid));            ESP_LOGD(TAG, "Adding known access point that is not in range: %s", it->ssid);            network_wifi_add_access_point_json(*ap_list, &known_ap);        }    }    char* ap_list_json = cJSON_PrintUnformatted(*ap_list);    if (ap_list_json != NULL) {        ESP_LOGV(TAG, "Full access point list: %s", ap_list_json);        free(ap_list_json);    }}void network_wifi_set_ipv4val(const char* key, char* default_value, ip4_addr_t* target) {    char* value = config_alloc_get_default(NVS_TYPE_STR, key, default_value, 0);    if (value != NULL) {        ESP_LOGD(TAG, "%s: %s", key, value);        inet_pton(AF_INET, value, target); /* access point is on a static IP */    }    FREE_AND_NULL(value);}esp_netif_t* network_wifi_config_ap() {    esp_netif_ip_info_t info;    esp_err_t err = ESP_OK;    char* value = NULL;    wifi_config_t ap_config = {        .ap = {            .ssid_len = 0,        },    };    ESP_LOGI(TAG, "Configuring Access Point.");    if (!wifi_ap_netif) {        wifi_ap_netif = esp_netif_create_default_wifi_ap();    }    network_wifi_set_ipv4val("ap_ip_address", DEFAULT_AP_IP, (ip4_addr_t*)&info.ip);    network_wifi_set_ipv4val("ap_ip_gateway", CONFIG_DEFAULT_AP_GATEWAY, (ip4_addr_t*)&info.gw);    network_wifi_set_ipv4val("ap_ip_netmask", CONFIG_DEFAULT_AP_NETMASK, (ip4_addr_t*)&info.netmask);    /* In order to change the IP info structure, we have to first stop      * the DHCP server on the new interface     */    network_start_stop_dhcps(wifi_ap_netif, false);    ESP_LOGD(TAG, "Setting tcp_ip info for access point");    if ((err = esp_netif_set_ip_info(wifi_ap_netif, &info)) != ESP_OK) {        ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s", esp_err_to_name(err));        return wifi_ap_netif;    }    network_start_stop_dhcps(wifi_ap_netif, true);    /*		 * Set Access Point configuration		 */    value = config_alloc_get_default(NVS_TYPE_STR, "ap_ssid", CONFIG_DEFAULT_AP_SSID, 0);    if (value != NULL) {        strlcpy((char*)ap_config.ap.ssid, value, sizeof(ap_config.ap.ssid));        ESP_LOGI(TAG, "AP SSID: %s", (char*)ap_config.ap.ssid);    }    FREE_AND_NULL(value);    value = config_alloc_get_default(NVS_TYPE_STR, "ap_pwd", DEFAULT_AP_PASSWORD, 0);    if (value != NULL) {        strlcpy((char*)ap_config.ap.password, value, sizeof(ap_config.ap.password));        ESP_LOGI(TAG, "AP Password: %s", (char*)ap_config.ap.password);    }    FREE_AND_NULL(value);    value = config_alloc_get_default(NVS_TYPE_STR, "ap_channel", STR(CONFIG_DEFAULT_AP_CHANNEL), 0);    if (value != NULL) {        ESP_LOGD(TAG, "Channel: %s", value);        ap_config.ap.channel = atoi(value);    }    FREE_AND_NULL(value);    ap_config.ap.authmode = AP_AUTHMODE;    ap_config.ap.ssid_hidden = DEFAULT_AP_SSID_HIDDEN;    ap_config.ap.max_connection = DEFAULT_AP_MAX_CONNECTIONS;    ap_config.ap.beacon_interval = DEFAULT_AP_BEACON_INTERVAL;    ESP_LOGD(TAG, "Auth Mode: %d", ap_config.ap.authmode);    ESP_LOGD(TAG, "SSID Hidden: %d", ap_config.ap.ssid_hidden);    ESP_LOGD(TAG, "Max Connections: %d", ap_config.ap.max_connection);    ESP_LOGD(TAG, "Beacon interval: %d", ap_config.ap.beacon_interval);    const char* msg = "Setting wifi mode as WIFI_MODE_APSTA";    ESP_LOGD(TAG, "%s", msg);    if ((err = esp_wifi_set_mode(WIFI_MODE_APSTA)) != ESP_OK) {        ESP_LOGE(TAG, "%s. Error %s", msg, esp_err_to_name(err));        return wifi_ap_netif;    }    msg = "Setting wifi AP configuration for WIFI_IF_AP";    ESP_LOGD(TAG, "%s", msg);    if ((err = esp_wifi_set_config(WIFI_IF_AP, &ap_config)) != ESP_OK) /* stop AP DHCP server */    {        ESP_LOGE(TAG, "%s . Error %s", msg, esp_err_to_name(err));        return wifi_ap_netif;    }    msg = "Setting wifi bandwidth";    ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_AP_BANDWIDTH);    if ((err = esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH)) != ESP_OK) /* stop AP DHCP server */    {        ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));        return wifi_ap_netif;    }    msg = "Setting wifi power save";    ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_STA_POWER_SAVE);    if ((err = esp_wifi_set_ps(DEFAULT_STA_POWER_SAVE)) != ESP_OK) /* stop AP DHCP server */    {        ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));        return wifi_ap_netif;    }    ESP_LOGD(TAG, "Done configuring Soft Access Point");    return wifi_ap_netif;}void network_wifi_filter_unique(wifi_ap_record_t* aplist, uint16_t* aps) {    int total_unique;    wifi_ap_record_t* first_free;    total_unique = *aps;    first_free = NULL;    for (int i = 0; i < *aps - 1; i++) {        wifi_ap_record_t* ap = &aplist[i];        /* skip the previously removed APs */        if (ap->ssid[0] == 0)            continue;        /* remove the identical SSID+authmodes */        for (int j = i + 1; j < *aps; j++) {            wifi_ap_record_t* ap1 = &aplist[j];            if ((strcmp((const char*)ap->ssid, (const char*)ap1->ssid) == 0) &&                (ap->authmode == ap1->authmode)) { /* same SSID, different auth mode is skipped */                /* save the rssi for the display */                if ((ap1->rssi) > (ap->rssi))                    ap->rssi = ap1->rssi;                /* clearing the record */                memset(ap1, 0, sizeof(wifi_ap_record_t));            }        }    }    /* reorder the list so APs follow each other in the list */    for (int i = 0; i < *aps; i++) {        wifi_ap_record_t* ap = &aplist[i];        /* skipping all that has no name */        if (ap->ssid[0] == 0) {            /* mark the first free slot */            if (first_free == NULL)                first_free = ap;            total_unique--;            continue;        }        if (first_free != NULL) {            memcpy(first_free, ap, sizeof(wifi_ap_record_t));            memset(ap, 0, sizeof(wifi_ap_record_t));            /* find the next free slot */            for (int j = 0; j < *aps; j++) {                if (aplist[j].ssid[0] == 0) {                    first_free = &aplist[j];                    break;                }            }        }    }    /* update the length of the list */    *aps = total_unique;}char* network_status_alloc_get_ap_list_json() {    return cJSON_PrintUnformatted(accessp_cjson);}cJSON* network_manager_clear_ap_list_json(cJSON** old) {    ESP_LOGV(TAG, "network_manager_clear_ap_list_json called");    cJSON* root = network_wifi_get_new_array_json(old);    ESP_LOGV(TAG, "network_manager_clear_ap_list_json done");    return root;}esp_err_t network_wifi_built_known_ap_list() {    if (network_status_lock_json_buffer(pdMS_TO_TICKS(1000))) {        ESP_LOGD(TAG,"Building known AP list");        accessp_cjson = network_manager_clear_ap_list_json(&accessp_cjson);        network_wifi_generate_access_points_json(&accessp_cjson);        network_status_unlock_json_buffer();        ESP_LOGD(TAG, "Done building ap JSON list");    } else {        ESP_LOGE(TAG, "Failed to lock json buffer");        return ESP_FAIL;    }    return ESP_OK;}esp_err_t wifi_scan_done() {    esp_err_t err = ESP_OK;    /* As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns.				 * As a consequence, ap_num MUST be reset to MAX_AP_NUM at every scan */    ESP_LOGD(TAG, "Getting AP list records");    ap_num = MAX_AP_NUM;    if ((err = esp_wifi_scan_get_ap_num(&ap_num)) != ESP_OK) {        ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s", esp_err_to_name(err));        return err;    }    FREE_AND_NULL(accessp_records);    if (ap_num > 0) {        accessp_records = (wifi_ap_record_t*)malloc_init_external(sizeof(wifi_ap_record_t) * ap_num);        if ((err = esp_wifi_scan_get_ap_records(&ap_num, accessp_records)) != ESP_OK) {            ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s", esp_err_to_name(err));            return err;        }        /* make sure the http server isn't trying to access the list while it gets refreshed */        ESP_LOGD(TAG, "Preparing to build ap JSON list");        if (network_status_lock_json_buffer(pdMS_TO_TICKS(1000))) {            /* Will remove the duplicate SSIDs from the list and update ap_num */            network_wifi_filter_unique(accessp_records, &ap_num);            network_wifi_set_found_ap();            network_wifi_generate_access_points_json(&accessp_cjson);            network_status_unlock_json_buffer();            ESP_LOGD(TAG, "Done building ap JSON list");        } else {            ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan");            err = ESP_FAIL;        }    } else {        //        ESP_LOGD(TAG, "No AP Found.  Emptying the list.");        accessp_cjson = network_wifi_get_new_array_json(&accessp_cjson);    }    return err;}bool is_wifi_up() {    return wifi_netif != NULL;}esp_err_t network_wifi_start_scan() {    wifi_scan_config_t scan_config = {        .ssid = 0,        .bssid = 0,        .channel = 0,        .scan_type = WIFI_SCAN_TYPE_ACTIVE,        .show_hidden = true};    esp_err_t err = ESP_OK;    ESP_LOGI(TAG, "Initiating wifi network scan");    if (!is_wifi_up()) {        messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot scan");        return ESP_FAIL;    }    /* if a scan is already in progress this message is simply ignored thanks to the WIFI_MANAGER_SCAN_BIT uxBit */    if ((err = esp_wifi_scan_start(&scan_config, false)) != ESP_OK) {        ESP_LOGW(TAG, "Unable to start scan; %s ", esp_err_to_name(err));        //						set_status_message(WARNING, "Wifi Connecting. Cannot start scan.");        messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Scanning failed: %s", esp_err_to_name(err));    }    return err;}bool network_wifi_is_ap_mode() {    wifi_mode_t mode;    /* update config to latest and attempt connection */    return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_AP;}bool network_wifi_is_sta_mode() {    wifi_mode_t mode;    /* update config to latest and attempt connection */    return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_STA;}bool network_wifi_is_ap_sta_mode() {    wifi_mode_t mode;    /* update config to latest and attempt connection */    return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_APSTA;}esp_err_t network_wifi_connect(const char* ssid, const char* password) {    esp_err_t err = ESP_OK;    wifi_config_t config;    memset(&config, 0x00, sizeof(config));    ESP_LOGD(TAG, "network_wifi_connect");    if (!is_wifi_up()) {        messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot connect");        network_wifi_set_connect_state(NETWORK_WIFI_STATE_DOWN);        return ESP_FAIL;    }    if (!ssid || !password || strlen(ssid) == 0) {        ESP_LOGE(TAG, "Cannot connect wifi. wifi config is null!");        network_wifi_set_connect_state(NETWORK_WIFI_STATE_INVALID_CONFIG);        return ESP_ERR_INVALID_ARG;    }    wifi_mode_t wifi_mode;    err = esp_wifi_get_mode(&wifi_mode);    if (err == ESP_ERR_WIFI_NOT_INIT) {        ESP_LOGW(TAG, "Wifi not initialized. Attempting to start sta mode");        network_wifi_start();    } else if (err != ESP_OK) {        ESP_LOGE(TAG, "Could not retrieve wifi mode : %s", esp_err_to_name(err));    } else if (wifi_mode != WIFI_MODE_STA && wifi_mode != WIFI_MODE_APSTA) {        ESP_LOGD(TAG, "Changing wifi mode to STA");        err = network_wifi_set_sta_mode();        if (err != ESP_OK) {            ESP_LOGE(TAG, "Could not set mode to STA.  Cannot connect to SSID %s", ssid);            return err;        }    }    // copy configuration and connect    strlcpy((char*)config.sta.ssid, ssid, sizeof(config.sta.ssid));    if (password) {        strlcpy((char*)config.sta.password, password, sizeof(config.sta.password));    }    // First Disconnect    esp_wifi_disconnect();    config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;    if ((err = esp_wifi_set_config(WIFI_IF_STA, &config)) != ESP_OK) {        network_wifi_set_connect_state(NETWORK_WIFI_STATE_FAILED);        ESP_LOGE(TAG, "Failed to set STA configuration. Error %s", esp_err_to_name(err));    }    if (err == ESP_OK) {        ESP_LOGI(TAG, "Wifi Connecting to %s...", ssid);        if ((err = esp_wifi_connect()) != ESP_OK) {            ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s", esp_err_to_name(err));            network_wifi_set_connect_state(NETWORK_WIFI_STATE_FAILED);        }        else{            network_wifi_set_connect_state(NETWORK_WIFI_STATE_CONNECTING);        }    }    return err;}esp_err_t network_wifi_connect_next_in_range(){    const char * ssid = network_wifi_get_next_ap_in_range();    if(ssid){        return network_wifi_connect_ssid(ssid);    }    return ESP_FAIL;}esp_err_t network_wifi_connect_ssid(const char* ssid) {    known_access_point_t* item = network_wifi_get_ap_entry(ssid);    if (item) {        item->last_try = (esp_timer_get_time() / 1000);        return network_wifi_connect(item->ssid, item->password);    }    return ESP_FAIL;}esp_err_t network_wifi_connect_active_ssid() {    const wifi_sta_config_t* config = network_wifi_load_active_config();    if (config) {        return network_wifi_connect(ssid_string(config), password_string(config));    }    return ESP_FAIL;}void network_wifi_clear_config() {    /* erase configuration */    const wifi_sta_config_t* sta = network_wifi_get_active_config();    network_wifi_delete_ap(ssid_string(sta));    esp_err_t err = ESP_OK;    if ((err = esp_wifi_disconnect()) != ESP_OK) {        ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));    }}char* get_disconnect_code_desc(uint8_t reason) {    switch (reason) {        ENUM_TO_STRING(WIFI_REASON_UNSPECIFIED);        ENUM_TO_STRING(WIFI_REASON_AUTH_EXPIRE);        ENUM_TO_STRING(WIFI_REASON_AUTH_LEAVE);        ENUM_TO_STRING(WIFI_REASON_ASSOC_EXPIRE);        ENUM_TO_STRING(WIFI_REASON_ASSOC_TOOMANY);        ENUM_TO_STRING(WIFI_REASON_NOT_AUTHED);        ENUM_TO_STRING(WIFI_REASON_NOT_ASSOCED);        ENUM_TO_STRING(WIFI_REASON_ASSOC_LEAVE);        ENUM_TO_STRING(WIFI_REASON_ASSOC_NOT_AUTHED);        ENUM_TO_STRING(WIFI_REASON_DISASSOC_PWRCAP_BAD);        ENUM_TO_STRING(WIFI_REASON_DISASSOC_SUPCHAN_BAD);        ENUM_TO_STRING(WIFI_REASON_IE_INVALID);        ENUM_TO_STRING(WIFI_REASON_MIC_FAILURE);        ENUM_TO_STRING(WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT);        ENUM_TO_STRING(WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT);        ENUM_TO_STRING(WIFI_REASON_IE_IN_4WAY_DIFFERS);        ENUM_TO_STRING(WIFI_REASON_GROUP_CIPHER_INVALID);        ENUM_TO_STRING(WIFI_REASON_PAIRWISE_CIPHER_INVALID);        ENUM_TO_STRING(WIFI_REASON_AKMP_INVALID);        ENUM_TO_STRING(WIFI_REASON_UNSUPP_RSN_IE_VERSION);        ENUM_TO_STRING(WIFI_REASON_INVALID_RSN_IE_CAP);        ENUM_TO_STRING(WIFI_REASON_802_1X_AUTH_FAILED);        ENUM_TO_STRING(WIFI_REASON_CIPHER_SUITE_REJECTED);        ENUM_TO_STRING(WIFI_REASON_INVALID_PMKID);        ENUM_TO_STRING(WIFI_REASON_BEACON_TIMEOUT);        ENUM_TO_STRING(WIFI_REASON_NO_AP_FOUND);        ENUM_TO_STRING(WIFI_REASON_AUTH_FAIL);        ENUM_TO_STRING(WIFI_REASON_ASSOC_FAIL);        ENUM_TO_STRING(WIFI_REASON_HANDSHAKE_TIMEOUT);        ENUM_TO_STRING(WIFI_REASON_CONNECTION_FAIL);        ENUM_TO_STRING(WIFI_REASON_AP_TSF_RESET);        ENUM_TO_STRING(WIFI_REASON_ROAMING);    }    return "";}
 |