Network manager implemented and relatively stable

This commit is contained in:
Sebastien L
2021-12-10 13:07:27 -05:00
parent 81756a7649
commit 63fbc2f645
66 changed files with 4528 additions and 2679 deletions

View File

@@ -2,6 +2,17 @@ cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite ) set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite )
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_definitions(-DMODEL_NAME=SqueezeESP32) add_definitions(-DMODEL_NAME=SqueezeESP32)
# Uncomment line below to get memory usage trace details
#add_definitions(-DENABLE_MEMTRACE=1)
#uncomment line below to get network ethernet debug logs
#add_definitions(-DNETWORK_ETHERNET_LOG_LEVEL=ESP_LOG_DEBUG)
#uncomment line below to get network status debug logs
#add_definitions(-DNETWORK_STATUS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_HANDLERS_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_WIFI_LOG_LEVEL=ESP_LOG_DEBUG)
#add_definitions(-DNETWORK_MANAGER_LOG_LEVEL=ESP_LOG_DEBUG)
if(NOT DEFINED DEPTH) if(NOT DEFINED DEPTH)
set(DEPTH "16") set(DEPTH "16")
endif() endif()
@@ -11,10 +22,16 @@ set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery )
include(squeezelite.cmake) include(squeezelite.cmake)
set(PROJECT_VER $ENV{PROJECT_VER}) set(PROJECT_VER $ENV{PROJECT_VER})
#target_compile_definitions(__idf_wifi-manager PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
target_compile_definitions(__idf_esp_wifi PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
target_compile_definitions(__idf_app_recovery PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
#target_compile_definitions(__idf_services PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_driver PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_wifi-manager PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
#target_compile_definitions(__idf_esp_wifi PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_platform_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
#target_compile_definitions(__idf_app_recovery PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) # target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_event PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) # target_compile_definitions(__idf_esp_event PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO)
# target_compile_definitions(__idf_esp_netif PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_esp_netif PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
@@ -84,13 +101,12 @@ target_compile_definitions(__idf_app_recovery PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_
# target_compile_definitions(__idf_openssl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_openssl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_perfmon PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_perfmon PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_platform_config PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_platform_config PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_platform_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_protobuf-c PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_protobuf-c PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_protocomm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_protocomm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_pthread PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_pthread PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_raop PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_raop PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_sdmmc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_sdmmc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_services PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_soc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_soc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_spiffs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_spiffs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)
# target_compile_definitions(__idf_spi_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) # target_compile_definitions(__idf_spi_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)

Submodule components/cpp-stateless deleted from 9e7138f8fe

View File

@@ -17,6 +17,7 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "globdefs.h"
static const char * TAG = "btappcore"; static const char * TAG = "btappcore";
@@ -41,8 +42,7 @@ bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, i
if (param_len == 0) { if (param_len == 0) {
return bt_app_send_msg(&msg); return bt_app_send_msg(&msg);
} else if (p_params && param_len > 0) { } else if (p_params && param_len > 0) {
if ((msg.param = malloc(param_len)) != NULL) { if ((msg.param = clone_obj_psram(p_params, param_len)) != NULL) {
memcpy(msg.param, p_params, param_len);
/* check if caller has provided a copy callback to do the deep copy */ /* check if caller has provided a copy callback to do the deep copy */
if (p_copy_cback) { if (p_copy_cback) {
p_copy_cback(&msg, msg.param, p_params); p_copy_cback(&msg, msg.param, p_params);

View File

@@ -20,6 +20,7 @@
#include "trace.h" #include "trace.h"
#include "messaging.h" #include "messaging.h"
#include "cJSON.h" #include "cJSON.h"
#include "globdefs.h"
static const char * TAG = "bt_app_source"; static const char * TAG = "bt_app_source";
static const char * BT_RC_CT_TAG="RCCT"; static const char * BT_RC_CT_TAG="RCCT";
@@ -226,8 +227,8 @@ void hal_bluetooth_init(const char * options)
squeezelite_args.end = arg_end(2); squeezelite_args.end = arg_end(2);
ESP_LOGD(TAG,"Copying parameters"); ESP_LOGD(TAG,"Copying parameters");
char * opts = strdup(options); char * opts = strdup_psram(options);
char **argv = malloc(sizeof(char**)*15); char **argv = malloc_init_external(sizeof(char**)*15);
size_t argv_size=15; size_t argv_size=15;
@@ -254,7 +255,7 @@ void hal_bluetooth_init(const char * options)
ESP_LOGW(TAG,"Unable to retrieve the a2dp sink name from nvs."); ESP_LOGW(TAG,"Unable to retrieve the a2dp sink name from nvs.");
} }
} else { } else {
squeezelite_conf.sink_name=strdup(squeezelite_args.sink_name->sval[0]); squeezelite_conf.sink_name=strdup_psram(squeezelite_args.sink_name->sval[0]);
// sync with NVS // sync with NVS
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
if((err= config_set_value(NVS_TYPE_STR, "a2dp_sink_name", squeezelite_args.sink_name->sval[0]))!=ESP_OK){ if((err= config_set_value(NVS_TYPE_STR, "a2dp_sink_name", squeezelite_args.sink_name->sval[0]))!=ESP_OK){

View File

@@ -1,6 +1,6 @@
idf_component_register( SRC_DIRS . idf_component_register( SRC_DIRS .
INCLUDE_DIRS . INCLUDE_DIRS .
PRIV_REQUIRES tools newlib console esp_common freertos PRIV_REQUIRES tools newlib console esp_common freertos services
REQUIRES nvs_flash json REQUIRES nvs_flash json
) )

View File

@@ -1,4 +1,3 @@
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "nvs_utilities.h" #include "nvs_utilities.h"
#include <stdio.h> #include <stdio.h>
@@ -15,6 +14,7 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "nvs_utilities.h" #include "nvs_utilities.h"
#include "platform_config.h" #include "platform_config.h"
#include "globdefs.h"
const char current_namespace[] = "config"; const char current_namespace[] = "config";
const char settings_partition[] = "settings"; const char settings_partition[] = "settings";
@@ -69,6 +69,11 @@ const char *type_to_str(nvs_type_t type)
return "Unknown"; return "Unknown";
} }
void erase_settings_partition(){
ESP_LOGW(TAG, "Erasing nvs on partition %s",settings_partition);
ESP_ERROR_CHECK(nvs_flash_erase_partition(settings_partition));
nvs_flash_init_partition(settings_partition);
}
void initialize_nvs() { void initialize_nvs() {
ESP_LOGI(TAG, "Initializing flash nvs "); ESP_LOGI(TAG, "Initializing flash nvs ");
esp_err_t err = nvs_flash_init(); esp_err_t err = nvs_flash_init();
@@ -95,62 +100,89 @@ void initialize_nvs() {
ESP_LOGD(TAG, "nvs init completed"); ESP_LOGD(TAG, "nvs init completed");
} }
esp_err_t nvs_load_config(){ esp_err_t nvs_load_config() {
nvs_entry_info_t info; nvs_entry_info_t info;
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
size_t malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); size_t malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); size_t malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, NVS_TYPE_ANY); nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, NVS_TYPE_ANY);
if(it == NULL) { if (it == NULL) {
ESP_LOGW(TAG, "empty nvs partition %s, namespace %s",settings_partition,current_namespace ); ESP_LOGW(TAG, "empty nvs partition %s, namespace %s", settings_partition, current_namespace);
} }
while (it != NULL) { while (it != NULL) {
nvs_entry_info(it, &info); nvs_entry_info(it, &info);
if(strstr(info.namespace_name, current_namespace)) { if (strstr(info.namespace_name, current_namespace)) {
void * value = get_nvs_value_alloc(info.type,info.key); if (strlen(info.key) == 0) {
if(value==NULL) ESP_LOGW(TAG, "empty key name in namespace %s. Removing it.", current_namespace);
{ nvs_handle_t nvs_handle;
ESP_LOGE(TAG, "nvs read failed."); err = nvs_open(settings_partition, NVS_READWRITE, &nvs_handle);
return ESP_FAIL; if (err != ESP_OK) {
ESP_LOGE(TAG, "nvs_open failed. %s", esp_err_to_name(err));
} else {
if ((err = nvs_erase_key(nvs_handle, info.key)) != ESP_OK) {
ESP_LOGE(TAG, "nvs_erase_key failed. %s", esp_err_to_name(err));
} else {
nvs_commit(nvs_handle);
}
nvs_close(nvs_handle);
if (err == ESP_OK) {
ESP_LOGW(TAG, "nvs_erase_key completed on empty key. Restarting system to apply changes.");
esp_restart();
}
}
if (err != ESP_OK) {
ESP_LOGW(TAG, "nvs_erase_key failed on empty key. Configuration partition should be erased. %s", esp_err_to_name(err));
err = ESP_OK;
}
}
else {
void* value = get_nvs_value_alloc(info.type, info.key);
if (value == NULL) {
ESP_LOGE(TAG, "nvs read failed.");
return ESP_FAIL;
}
config_set_value(info.type, info.key, value);
free(value);
} }
config_set_value(info.type, info.key, value); }
free(value ); it = nvs_entry_next(it);
} }
it = nvs_entry_next(it); char* json_string = config_alloc_get_json(false);
} if (json_string != NULL) {
char * json_string= config_alloc_get_json(false); ESP_LOGD(TAG, "config json : %s\n", json_string);
if(json_string!=NULL) { free(json_string);
ESP_LOGD(TAG, "config json : %s\n", json_string); }
free(json_string);
}
ESP_LOGD(TAG,"Config memory usage. Heap internal:%zu (min:%zu) (used:%zu) external:%zu (min:%zu) (used:%zd)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
malloc_int-heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
malloc_spiram -heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
return err;
}
ESP_LOGW(TAG, "Configuration memory usage. Heap internal:%zu (min:%zu) (used:%zu) external:%zu (min:%zu) (used:%zd)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
malloc_int - heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
malloc_spiram - heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
return err;
}
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data) { esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data) {
if (type == NVS_TYPE_BLOB) if (type == NVS_TYPE_BLOB)
return ESP_ERR_NVS_TYPE_MISMATCH; return ESP_ERR_NVS_TYPE_MISMATCH;
return store_nvs_value_len(type, key, data,0); return store_nvs_value_len(type, key, data,0);
} }
esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, const void * data,size_t data_len) {
size_t data_len) {
esp_err_t err; esp_err_t err;
nvs_handle nvs; nvs_handle nvs;
if(!key || key[0]=='\0'){
ESP_LOGE(TAG, "Cannot store value to nvs: key is empty");
return ESP_ERR_INVALID_ARG;
}
if (type == NVS_TYPE_ANY) { if (type == NVS_TYPE_ANY) {
return ESP_ERR_NVS_TYPE_MISMATCH; return ESP_ERR_NVS_TYPE_MISMATCH;
} }
err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READWRITE, &nvs); err = nvs_open_from_partition(partition, namespace, NVS_READWRITE, &nvs);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@@ -185,53 +217,65 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
nvs_close(nvs); nvs_close(nvs);
return err; return err;
} }
void * get_nvs_value_alloc(nvs_type_t type, const char *key) { esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
size_t data_len) {
return store_nvs_value_len_for_partition(settings_partition,current_namespace,type,key,data,data_len);
}
void * get_nvs_value_alloc_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, size_t * size){
nvs_handle nvs; nvs_handle nvs;
esp_err_t err; esp_err_t err;
void * value=NULL; void * value=NULL;
if(size){
err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READONLY, &nvs); *size=0;
}
err = nvs_open_from_partition(partition, namespace, NVS_READONLY, &nvs);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not open the nvs storage."); ESP_LOGE(TAG, "Could not open the nvs storage.");
return NULL; return NULL;
} }
if (type == NVS_TYPE_I8) { if (type == NVS_TYPE_I8) {
value=malloc(sizeof(int8_t)); value=malloc_init_external(sizeof(int8_t));
err = nvs_get_i8(nvs, key, (int8_t *) value); err = nvs_get_i8(nvs, key, (int8_t *) value);
} else if (type == NVS_TYPE_U8) { } else if (type == NVS_TYPE_U8) {
value=malloc(sizeof(uint8_t)); value=malloc_init_external(sizeof(uint8_t));
err = nvs_get_u8(nvs, key, (uint8_t *) value); err = nvs_get_u8(nvs, key, (uint8_t *) value);
} else if (type == NVS_TYPE_I16) { } else if (type == NVS_TYPE_I16) {
value=malloc(sizeof(int16_t)); value=malloc_init_external(sizeof(int16_t));
err = nvs_get_i16(nvs, key, (int16_t *) value); err = nvs_get_i16(nvs, key, (int16_t *) value);
} else if (type == NVS_TYPE_U16) { } else if (type == NVS_TYPE_U16) {
value=malloc(sizeof(uint16_t)); value=malloc_init_external(sizeof(uint16_t));
err = nvs_get_u16(nvs, key, (uint16_t *) value); err = nvs_get_u16(nvs, key, (uint16_t *) value);
} else if (type == NVS_TYPE_I32) { } else if (type == NVS_TYPE_I32) {
value=malloc(sizeof(int32_t)); value=malloc_init_external(sizeof(int32_t));
err = nvs_get_i32(nvs, key, (int32_t *) value); err = nvs_get_i32(nvs, key, (int32_t *) value);
} else if (type == NVS_TYPE_U32) { } else if (type == NVS_TYPE_U32) {
value=malloc(sizeof(uint32_t)); value=malloc_init_external(sizeof(uint32_t));
err = nvs_get_u32(nvs, key, (uint32_t *) value); err = nvs_get_u32(nvs, key, (uint32_t *) value);
} else if (type == NVS_TYPE_I64) { } else if (type == NVS_TYPE_I64) {
value=malloc(sizeof(int64_t)); value=malloc_init_external(sizeof(int64_t));
err = nvs_get_i64(nvs, key, (int64_t *) value); err = nvs_get_i64(nvs, key, (int64_t *) value);
} else if (type == NVS_TYPE_U64) { } else if (type == NVS_TYPE_U64) {
value=malloc(sizeof(uint64_t)); value=malloc_init_external(sizeof(uint64_t));
err = nvs_get_u64(nvs, key, (uint64_t *) value); err = nvs_get_u64(nvs, key, (uint64_t *) value);
} else if (type == NVS_TYPE_STR) { } else if (type == NVS_TYPE_STR) {
size_t len=0; size_t len=0;
err = nvs_get_str(nvs, key, NULL, &len); err = nvs_get_str(nvs, key, NULL, &len);
if (err == ESP_OK) { if (err == ESP_OK) {
value=malloc(len); value=malloc_init_external(len+1);
err = nvs_get_str(nvs, key, value, &len); err = nvs_get_str(nvs, key, value, &len);
} if(size){
*size=len;
}
}
} else if (type == NVS_TYPE_BLOB) { } else if (type == NVS_TYPE_BLOB) {
size_t len; size_t len;
err = nvs_get_blob(nvs, key, NULL, &len); err = nvs_get_blob(nvs, key, NULL, &len);
if (err == ESP_OK) { if (err == ESP_OK) {
value=malloc(len+1); value=malloc_init_external(len+1);
if(size){
*size=len;
}
err = nvs_get_blob(nvs, key, value, &len); err = nvs_get_blob(nvs, key, value, &len);
} }
} }
@@ -244,6 +288,9 @@ void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
nvs_close(nvs); nvs_close(nvs);
return value; return value;
} }
void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
return get_nvs_value_alloc_for_partition(settings_partition, current_namespace,type,key,NULL);
}
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size) { esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size) {
nvs_handle nvs; nvs_handle nvs;
esp_err_t err; esp_err_t err;
@@ -296,11 +343,10 @@ esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint
nvs_close(nvs); nvs_close(nvs);
return err; return err;
} }
esp_err_t erase_nvs(const char *key) esp_err_t erase_nvs_for_partition(const char * partition, const char * namespace,const char *key)
{ {
nvs_handle nvs; nvs_handle nvs;
esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
if (err == ESP_OK) { if (err == ESP_OK) {
err = nvs_erase_key(nvs, key); err = nvs_erase_key(nvs, key);
if (err == ESP_OK) { if (err == ESP_OK) {
@@ -311,7 +357,35 @@ esp_err_t erase_nvs(const char *key)
} }
nvs_close(nvs); nvs_close(nvs);
} }
else {
ESP_LOGE(TAG,"Could not erase key %s from partition %s namespace %s : %s", key,partition,namespace, esp_err_to_name(err));
}
return err; return err;
} }
esp_err_t erase_nvs(const char *key)
{
return erase_nvs_for_partition(NVS_DEFAULT_PART_NAME, current_namespace,key);
}
esp_err_t erase_nvs_partition(const char * partition, const char * namespace){
nvs_handle nvs;
const char * step = "Opening";
ESP_LOGD(TAG,"%s partition %s, namespace %s ",step,partition,namespace);
esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
if (err == ESP_OK) {
step = "Erasing";
ESP_LOGD(TAG,"%s namespace %s ",step,partition);
err = nvs_erase_all(nvs);
if (err == ESP_OK) {
step = "Committing";
ESP_LOGD(TAG,"%s",step);
err = nvs_commit(nvs);
}
}
if(err !=ESP_OK){
ESP_LOGE(TAG,"%s partition %s, name space %s : %s",step,partition,namespace,esp_err_to_name(err));
}
ESP_LOGD(TAG,"Closing %s ",namespace);
nvs_close(nvs);
return err;
}

View File

@@ -13,10 +13,15 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, siz
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data); esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data);
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size); esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size);
void * get_nvs_value_alloc(nvs_type_t type, const char *key); void * get_nvs_value_alloc(nvs_type_t type, const char *key);
void * get_nvs_value_alloc_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, size_t * size);
esp_err_t erase_nvs_for_partition(const char * partition, const char * namespace,const char *key);
esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, const void * data,size_t data_len);
esp_err_t erase_nvs(const char *key); esp_err_t erase_nvs(const char *key);
void print_blob(const char *blob, size_t len); void print_blob(const char *blob, size_t len);
const char *type_to_str(nvs_type_t type); const char *type_to_str(nvs_type_t type);
nvs_type_t str_to_type(const char *type); nvs_type_t str_to_type(const char *type);
esp_err_t erase_nvs_partition(const char * partition, const char * namespace);
void erase_settings_partition();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "platform_config.h" #include "platform_config.h"
#include "nvs_utilities.h" #include "nvs_utilities.h"
#include "platform_esp32.h" #include "platform_esp32.h"
@@ -39,18 +38,18 @@
#include "cJSON.h" #include "cJSON.h"
#include "freertos/timers.h" #include "freertos/timers.h"
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "globdefs.h"
#define CONFIG_COMMIT_DELAY 1000 #define CONFIG_COMMIT_DELAY 1000
#define LOCK_MAX_WAIT 20*CONFIG_COMMIT_DELAY #define LOCK_MAX_WAIT 20*CONFIG_COMMIT_DELAY
static const char * TAG = "config"; static const char * TAG = "config";
static cJSON * nvs_json=NULL; EXT_RAM_ATTR static cJSON * nvs_json=NULL;
static TimerHandle_t timer; EXT_RAM_ATTR static TimerHandle_t timer;
static SemaphoreHandle_t config_mutex = NULL; EXT_RAM_ATTR static SemaphoreHandle_t config_mutex = NULL;
static EventGroupHandle_t config_group; EXT_RAM_ATTR static EventGroupHandle_t config_group;
/* @brief indicate that the ESP32 is currently connected. */ /* @brief indicate that the ESP32 is currently connected. */
static const int CONFIG_NO_COMMIT_PENDING = BIT0; EXT_RAM_ATTR static const int CONFIG_NO_COMMIT_PENDING = BIT0;
static const int CONFIG_LOAD_BIT = BIT1; EXT_RAM_ATTR static const int CONFIG_LOAD_BIT = BIT1;
bool config_lock(TickType_t xTicksToWait); bool config_lock(TickType_t xTicksToWait);
void config_unlock(); void config_unlock();
@@ -62,7 +61,7 @@ cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key,const void *
static void vCallbackFunction( TimerHandle_t xTimer ); static void vCallbackFunction( TimerHandle_t xTimer );
void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag); void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
#define IMPLEMENT_SET_DEFAULT(t,nt) void config_set_default_## t (const char *key, t value){\ #define IMPLEMENT_SET_DEFAULT(t,nt) void config_set_default_## t (const char *key, t value){\
void * pval = malloc(sizeof(value));\ void * pval = malloc_init_external(sizeof(value));\
*((t *) pval) = value;\ *((t *) pval) = value;\
config_set_default(nt, key,pval,0);\ config_set_default(nt, key,pval,0);\
free(pval); } free(pval); }
@@ -72,7 +71,7 @@ void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
return ESP_FAIL;} return ESP_FAIL;}
static void * malloc_fn(size_t sz){ static void * malloc_fn(size_t sz){
void * ptr = is_recovery_running?malloc(sz):heap_caps_malloc(sz, MALLOC_CAP_SPIRAM); void * ptr = is_recovery_running?malloc(sz):heap_caps_malloc(sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if(ptr==NULL){ if(ptr==NULL){
ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!"); ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!");
} }
@@ -85,20 +84,28 @@ void init_cJSON(){
} }
void config_init(){ void config_init(){
ESP_LOGD(TAG, "Creating mutex for Config"); ESP_LOGD(TAG, "Creating mutex for Config");
MEMTRACE_PRINT_DELTA();
config_mutex = xSemaphoreCreateMutex(); config_mutex = xSemaphoreCreateMutex();
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG, "Creating event group"); ESP_LOGD(TAG, "Creating event group");
MEMTRACE_PRINT_DELTA();
config_group = xEventGroupCreate(); config_group = xEventGroupCreate();
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG, "Loading config from nvs"); ESP_LOGD(TAG, "Loading config from nvs");
init_cJSON(); init_cJSON();
MEMTRACE_PRINT_DELTA();
if(nvs_json !=NULL){ if(nvs_json !=NULL){
cJSON_Delete(nvs_json); cJSON_Delete(nvs_json);
} }
nvs_json = cJSON_CreateObject(); nvs_json = cJSON_CreateObject();
config_set_group_bit(CONFIG_LOAD_BIT,true); config_set_group_bit(CONFIG_LOAD_BIT,true);
MEMTRACE_PRINT_DELTA();
nvs_load_config(); nvs_load_config();
MEMTRACE_PRINT_DELTA();
config_set_group_bit(CONFIG_LOAD_BIT,false); config_set_group_bit(CONFIG_LOAD_BIT,false);
MEMTRACE_PRINT_DELTA();
config_start_timer(); config_start_timer();
} }
@@ -318,28 +325,28 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
return NULL; return NULL;
} }
if (nvs_type == NVS_TYPE_I8) { if (nvs_type == NVS_TYPE_I8) {
value=malloc(sizeof(int8_t)); value=malloc_init_external(sizeof(int8_t));
*(int8_t *)value = (int8_t)entry_value->valuedouble; *(int8_t *)value = (int8_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U8) { } else if (nvs_type == NVS_TYPE_U8) {
value=malloc(sizeof(uint8_t)); value=malloc_init_external(sizeof(uint8_t));
*(uint8_t *)value = (uint8_t)entry_value->valuedouble; *(uint8_t *)value = (uint8_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I16) { } else if (nvs_type == NVS_TYPE_I16) {
value=malloc(sizeof(int16_t)); value=malloc_init_external(sizeof(int16_t));
*(int16_t *)value = (int16_t)entry_value->valuedouble; *(int16_t *)value = (int16_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U16) { } else if (nvs_type == NVS_TYPE_U16) {
value=malloc(sizeof(uint16_t)); value=malloc_init_external(sizeof(uint16_t));
*(uint16_t *)value = (uint16_t)entry_value->valuedouble; *(uint16_t *)value = (uint16_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I32) { } else if (nvs_type == NVS_TYPE_I32) {
value=malloc(sizeof(int32_t)); value=malloc_init_external(sizeof(int32_t));
*(int32_t *)value = (int32_t)entry_value->valuedouble; *(int32_t *)value = (int32_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U32) { } else if (nvs_type == NVS_TYPE_U32) {
value=malloc(sizeof(uint32_t)); value=malloc_init_external(sizeof(uint32_t));
*(uint32_t *)value = (uint32_t)entry_value->valuedouble; *(uint32_t *)value = (uint32_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_I64) { } else if (nvs_type == NVS_TYPE_I64) {
value=malloc(sizeof(int64_t)); value=malloc_init_external(sizeof(int64_t));
*(int64_t *)value = (int64_t)entry_value->valuedouble; *(int64_t *)value = (int64_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_U64) { } else if (nvs_type == NVS_TYPE_U64) {
value=malloc(sizeof(uint64_t)); value=malloc_init_external(sizeof(uint64_t));
*(uint64_t *)value = (uint64_t)entry_value->valuedouble; *(uint64_t *)value = (uint64_t)entry_value->valuedouble;
} else if (nvs_type == NVS_TYPE_STR) { } else if (nvs_type == NVS_TYPE_STR) {
if(!cJSON_IsString(entry_value)){ if(!cJSON_IsString(entry_value)){
@@ -361,8 +368,7 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
} }
else { else {
size_t len=strlen(cJSON_GetStringValue(entry_value)); size_t len=strlen(cJSON_GetStringValue(entry_value));
value=(void *)heap_caps_malloc(len+1, MALLOC_CAP_DMA); value=(void *)malloc_init_external(len+1);
memset(value,0x00,len+1);
memcpy(value,cJSON_GetStringValue(entry_value),len); memcpy(value,cJSON_GetStringValue(entry_value),len);
if(value==NULL){ if(value==NULL){
char * entry_str = cJSON_PrintUnformatted(entry); char * entry_str = cJSON_PrintUnformatted(entry);
@@ -406,12 +412,11 @@ void config_commit_to_nvs(){
void * value = config_safe_alloc_get_entry_value(type, entry); void * value = config_safe_alloc_get_entry_value(type, entry);
if(value!=NULL){ if(value!=NULL){
size_t len=strlen(entry->string); size_t len=strlen(entry->string);
char * key=(void *)heap_caps_malloc(len+1, MALLOC_CAP_DMA); char * key=(void *)malloc_init_external(len+1);
memset(key,0x00,len+1);
memcpy(key,entry->string,len); memcpy(key,entry->string,len);
esp_err_t err = store_nvs_value(type,key,value); esp_err_t err = store_nvs_value(type,key,value);
free(key); FREE_AND_NULL(key);
free(value); FREE_AND_NULL(value);
if(err!=ESP_OK){ if(err!=ESP_OK){
char * entry_str = cJSON_PrintUnformatted(entry); char * entry_str = cJSON_PrintUnformatted(entry);
@@ -617,11 +622,11 @@ void * config_alloc_get(nvs_type_t nvs_type, const char *key) {
} }
void * config_alloc_get_str(const char *key, char *lead, char *fallback) { void * config_alloc_get_str(const char *key, char *lead, char *fallback) {
if (lead && *lead) return strdup(lead); if (lead && *lead) return strdup_psram(lead);
char *value = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0); char *value = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0);
if ((!value || !*value) && fallback) { if ((!value || !*value) && fallback) {
if (value) free(value); if (value) free(value);
value = strdup(fallback); value = strdup_psram(fallback);
} }
return value; return value;
} }
@@ -673,7 +678,7 @@ char * config_alloc_get_json(bool bFormatted){
char * json_buffer = NULL; char * json_buffer = NULL;
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT); ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
return strdup("{\"error\":\"Unable to lock configuration object.\"}"); return strdup_psram("{\"error\":\"Unable to lock configuration object.\"}");
} }
if(bFormatted){ if(bFormatted){
json_buffer= cJSON_Print(nvs_json); json_buffer= cJSON_Print(nvs_json);
@@ -686,6 +691,10 @@ char * config_alloc_get_json(bool bFormatted){
} }
esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value){ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value){
esp_err_t result = ESP_OK; esp_err_t result = ESP_OK;
if(!key ||!key[0]){
ESP_LOGW(TAG,"Empty key passed. Ignoring entry!");
return ESP_ERR_INVALID_ARG;
}
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT); ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
result = ESP_FAIL; result = ESP_FAIL;

View File

@@ -8,6 +8,6 @@ idf_component_register( SRCS
cmd_config.c cmd_config.c
INCLUDE_DIRS . INCLUDE_DIRS .
REQUIRES nvs_flash REQUIRES nvs_flash
PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite) PRIV_REQUIRES console app_update tools services spi_flash platform_config vfs pthread wifi-manager platform_config newlib telnet display squeezelite services)
target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=GDS_DrawPixelFast") target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=GDS_DrawPixelFast")
target_link_libraries(${COMPONENT_LIB} ${build_dir}/esp-idf/$<TARGET_PROPERTY:RECOVERY_PREFIX>/lib$<TARGET_PROPERTY:RECOVERY_PREFIX>.a ) target_link_libraries(${COMPONENT_LIB} ${build_dir}/esp-idf/$<TARGET_PROPERTY:RECOVERY_PREFIX>/lib$<TARGET_PROPERTY:RECOVERY_PREFIX>.a )

View File

@@ -1,7 +1,7 @@
idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(idf_path IDF_PATH)
idf_component_register( SRCS cmd_squeezelite.c idf_component_register( SRCS cmd_squeezelite.c
INCLUDE_DIRS . INCLUDE_DIRS .
PRIV_REQUIRES spi_flash bootloader_support partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display ) PRIV_REQUIRES spi_flash bootloader_support partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display services)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=feof") target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=feof")

View File

@@ -12,6 +12,8 @@
#include "platform_esp32.h" #include "platform_esp32.h"
#include "platform_config.h" #include "platform_config.h"
#include "esp_app_format.h" #include "esp_app_format.h"
#include "globdefs.h"
extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length); extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
static const char * TAG = "squeezelite_cmd"; static const char * TAG = "squeezelite_cmd";
#define SQUEEZELITE_THREAD_STACK_SIZE (4*1024) #define SQUEEZELITE_THREAD_STACK_SIZE (4*1024)
@@ -112,8 +114,7 @@ static int launchsqueezelite(int argc, char **argv)
ESP_LOGV(TAG,"Saving args in thread structure"); ESP_LOGV(TAG,"Saving args in thread structure");
thread_parms.argc=0; thread_parms.argc=0;
thread_parms.argv = malloc(sizeof(char**)*(argc+ADDITIONAL_SQUEEZELITE_ARGS)); thread_parms.argv = malloc_init_external(sizeof(char**)*(argc+ADDITIONAL_SQUEEZELITE_ARGS));
memset(thread_parms.argv,'\0',sizeof(char**)*(argc+ADDITIONAL_SQUEEZELITE_ARGS));
for(int i=0;i<argc;i++){ for(int i=0;i<argc;i++){
ESP_LOGD(TAG ,"assigning parm %u : %s",i,argv[i]); ESP_LOGD(TAG ,"assigning parm %u : %s",i,argv[i]);

View File

@@ -6,7 +6,6 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. CONDITIONS OF ANY KIND, either express or implied.
*/ */
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include <stdio.h> #include <stdio.h>
#include "cmd_config.h" #include "cmd_config.h"
#include "argtable3/argtable3.h" #include "argtable3/argtable3.h"
@@ -18,14 +17,19 @@
#include "trace.h" #include "trace.h"
#include "messaging.h" #include "messaging.h"
#include "accessors.h" #include "accessors.h"
#include "adac.h"
#include "globdefs.h"
#include "cJSON.h"
const char * desc_squeezelite ="Squeezelite Options"; const char * desc_squeezelite ="Squeezelite Options";
const char * desc_dac= "DAC Options"; const char * desc_dac= "DAC Options";
const char * desc_preset= "Preset Options";
const char * desc_spdif= "SPDIF Options"; const char * desc_spdif= "SPDIF Options";
const char * desc_audio= "General Audio Options"; const char * desc_audio= "General Audio Options";
const char * desc_bt_source= "Bluetooth Audio Output Options"; const char * desc_bt_source= "Bluetooth Audio Output Options";
const char * desc_rotary= "Rotary Control"; const char * desc_rotary= "Rotary Control";
extern const struct adac_s *dac_set[];
#define CODECS_BASE "flac|pcm|mp3|ogg" #define CODECS_BASE "flac|pcm|mp3|ogg"
#if NO_FAAD #if NO_FAAD
@@ -44,6 +48,11 @@ const char * desc_rotary= "Rotary Control";
#define CODECS_DSD "" #define CODECS_DSD ""
#endif #endif
#define CODECS_MP3 "|mad|mpg" #define CODECS_MP3 "|mad|mpg"
#ifdef CONFIG_SQUEEZEAMP
static const char * known_configs = "";
#else
static const char * known_configs_string = "[{\"name\":\"ESP32A1S Old Model config 1 (AC101)\",\"config\":[{\"dac_config\":\"AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32\"},{\"dac_controlset\":\"\"},{\"set_GPIO\":\"\"},{\"spdif_config\":\"21=amp,22=green:0,39=jack:0\"}]},{\"name\":\"ESP32A1S Old Model config 2 (AC101)\",\"config\":[{\"dac_config\":\"AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32\"},{\"dac_controlset\":\"\"},{\"set_GPIO\":\"\"},{\"spdif_config\":\"21=amp,22=green:0,5=jack:0\"}]},{\"name\":\"ESP32A1S V2.2+ variant 1 (ES8388)\",\"config\":[{\"dac_config\":\"model=ES8388,bck=27,ws=25,do=26,sda=33,scl=32,di=35,i2c=16\"},{\"dac_controlset\":\"\"},{\"set_GPIO\":\"21=amp,22=green:0,39=jack:0\"},{\"spdif_config\":\"\"}]},{\"name\":\"ESP32A1S V2.2+ variant 2 (ES8388)\",\"config\":[{\"dac_config\":\"model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16\"},{\"dac_controlset\":\"\"},{\"set_GPIO\":\"21=amp,22=green:0,39=jack:0\"},{\"spdif_config\":\"\"}]}]";
#endif
#if !defined(MODEL_NAME) #if !defined(MODEL_NAME)
@@ -58,6 +67,7 @@ const char * desc_rotary= "Rotary Control";
#define MODEL_NAME_STRING STR(MODEL_NAME) #define MODEL_NAME_STRING STR(MODEL_NAME)
#endif #endif
#define CODECS CODECS_BASE CODECS_AAC CODECS_FF CODECS_DSD CODECS_MP3 #define CODECS CODECS_BASE CODECS_AAC CODECS_FF CODECS_DSD CODECS_MP3
#define NOT_OUTPUT "has input capabilities only" #define NOT_OUTPUT "has input capabilities only"
#define NOT_GPIO "is not a GPIO" #define NOT_GPIO "is not a GPIO"
@@ -85,7 +95,10 @@ static struct {
struct arg_lit *clear; struct arg_lit *clear;
struct arg_end *end; struct arg_end *end;
} i2s_args; } i2s_args;
static struct {
struct arg_str *model_name;
struct arg_end *end;
} known_model_args;
static struct { static struct {
struct arg_rem * rem; struct arg_rem * rem;
struct arg_int * A; struct arg_int * A;
@@ -189,9 +202,8 @@ int check_missing_parm(struct arg_int * int_parm, FILE * f){
} }
char * strip_bt_name(char * opt_str) char * strip_bt_name(char * opt_str)
{ {
char *result = malloc(strlen(opt_str)+1); char *result = malloc_init_external(strlen(opt_str)+1);
memset(result, 0x00, strlen(opt_str)+1); char *str = strdup_psram(opt_str);
char *str = strdup(opt_str);
const char * output_marker=" -o"; const char * output_marker=" -o";
if(!result ){ if(!result ){
@@ -555,7 +567,18 @@ static int do_rotary_cmd(int argc, char **argv){
FREE_AND_NULL(buf); FREE_AND_NULL(buf);
return (nerrors==0 && err==ESP_OK)?0:1; return (nerrors==0 && err==ESP_OK)?0:1;
} }
static int is_valid_gpio_number(int gpio, const char * name, FILE *f, bool mandatory, struct arg_int * target, bool output){
bool invalid = (!GPIO_IS_VALID_GPIO(gpio) ||(output && !GPIO_IS_VALID_OUTPUT_GPIO(gpio))) ;
if(invalid && mandatory && gpio!=-1){
fprintf(f,"Error: Invalid mandatory gpio %d for %s\n",gpio,name);
return 1;
}
if(target && !invalid){
target->count=1;
target->ival[0]=gpio;
}
return 0;
}
static int do_i2s_cmd(int argc, char **argv) static int do_i2s_cmd(int argc, char **argv)
{ {
i2s_platform_config_t i2s_dac_pin = { i2s_platform_config_t i2s_dac_pin = {
@@ -570,6 +593,7 @@ static int do_i2s_cmd(int argc, char **argv)
return 1; return 1;
} }
strcpy(i2s_dac_pin.model, "I2S"); strcpy(i2s_dac_pin.model, "I2S");
ESP_LOGD(TAG,"Processing i2s command %s with %d parameters",argv[0],argc);
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
int nerrors = arg_parse(argc, argv,(void **)&i2s_args); int nerrors = arg_parse(argc, argv,(void **)&i2s_args);
@@ -583,39 +607,39 @@ static int do_i2s_cmd(int argc, char **argv)
size_t buf_size = 0; size_t buf_size = 0;
FILE *f = open_memstream(&buf, &buf_size); FILE *f = open_memstream(&buf, &buf_size);
if (f == NULL) { if (f == NULL) {
ESP_LOGE(TAG, "do_i2s_cmd: Failed to open memstream");
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n"); cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1; return 1;
} }
if(nerrors >0){ if(nerrors >0){
ESP_LOGE(TAG,"do_i2s_cmd: %d errors parsing arguments",nerrors);
arg_print_errors(f,i2s_args.end,desc_dac); arg_print_errors(f,i2s_args.end,desc_dac);
fclose(f);
return 1;
} }
nerrors+=is_output_gpio(i2s_args.clock, f, &i2s_dac_pin.pin.bck_io_num, true); else {
nerrors+=is_output_gpio(i2s_args.wordselect, f, &i2s_dac_pin.pin.ws_io_num, true);
nerrors+=is_output_gpio(i2s_args.data, f, &i2s_dac_pin.pin.data_out_num, true);
nerrors+=is_output_gpio(i2s_args.mute_gpio, f, &i2s_dac_pin.mute_gpio, false);
if(i2s_dac_pin.mute_gpio>0){
i2s_dac_pin.mute_level = i2s_args.mute_level->count>0?1:0;
}
if(i2s_args.dac_sda->count>0 && i2s_args.dac_sda->ival[0]>=0){
// if SDA specified, then SDA and SCL are both mandatory
nerrors+=is_output_gpio(i2s_args.dac_sda, f, &i2s_dac_pin.sda, false);
nerrors+=is_output_gpio(i2s_args.dac_scl, f, &i2s_dac_pin.scl, false);
}
if(i2s_args.dac_sda->count==0&& i2s_args.dac_i2c->count>0){
fprintf(f,"warning: ignoring i2c address, since dac i2c gpios config is incomplete\n");
}
else if(i2s_args.dac_i2c->count>0){
i2s_dac_pin.i2c_addr = i2s_args.dac_i2c->ival[0];
}
if(i2s_args.model_name->count>0 && strlen(i2s_args.model_name->sval[0])>0){
strncpy(i2s_dac_pin.model,i2s_args.model_name->sval[0],sizeof(i2s_dac_pin.model)); strncpy(i2s_dac_pin.model,i2s_args.model_name->sval[0],sizeof(i2s_dac_pin.model));
i2s_dac_pin.model[sizeof(i2s_dac_pin.model) - 1] = '\0'; i2s_dac_pin.model[sizeof(i2s_dac_pin.model) - 1] = '\0';
} nerrors += is_output_gpio(i2s_args.clock, f, &i2s_dac_pin.pin.bck_io_num, true);
if(!nerrors ){ nerrors += is_output_gpio(i2s_args.wordselect, f, &i2s_dac_pin.pin.ws_io_num, true);
fprintf(f,"Storing i2s parameters.\n"); nerrors += is_output_gpio(i2s_args.data, f, &i2s_dac_pin.pin.data_out_num, true);
nerrors+=(config_i2s_set(&i2s_dac_pin, "dac_config")!=ESP_OK); nerrors += is_output_gpio(i2s_args.mute_gpio, f, &i2s_dac_pin.mute_gpio, false);
if (i2s_dac_pin.mute_gpio >= 0) {
i2s_dac_pin.mute_level = i2s_args.mute_level->count > 0 ? 1 : 0;
}
if (i2s_args.dac_sda->count > 0 && i2s_args.dac_sda->ival[0] >= 0) {
// if SDA specified, then SDA and SCL are both mandatory
nerrors += is_output_gpio(i2s_args.dac_sda, f, &i2s_dac_pin.sda, false);
nerrors += is_output_gpio(i2s_args.dac_scl, f, &i2s_dac_pin.scl, false);
}
if (i2s_args.dac_sda->count == 0 && i2s_args.dac_i2c->count > 0) {
fprintf(f, "warning: ignoring i2c address, since dac i2c gpios config is incomplete\n");
} else if (i2s_args.dac_i2c->count > 0) {
i2s_dac_pin.i2c_addr = i2s_args.dac_i2c->ival[0];
}
if (!nerrors) {
fprintf(f, "Storing i2s parameters.\n");
nerrors += (config_i2s_set(&i2s_dac_pin, "dac_config") != ESP_OK);
}
} }
if(!nerrors ){ if(!nerrors ){
fprintf(f,"Done.\n"); fprintf(f,"Done.\n");
@@ -647,40 +671,58 @@ cJSON * example_cb(){
return values; return values;
} }
//const i2s_pin_config_t * config_get_spdif_pin_struct( ); cJSON * known_model_cb(){
const char * key="board_model";
cJSON * values = cJSON_CreateObject();
if(!values){
ESP_LOGE(TAG,"known_model_cb: Failed to create JSON object");
return NULL;
}
char * name = config_alloc_get_default(NVS_TYPE_STR,key,"",0);
if(!name){
ESP_LOGE(TAG,"Failed to get board model from nvs key %s ",key);
}
else {
cJSON_AddStringToObject(values,known_model_args.model_name->hdr.longopts,name);
}
return values;
}
cJSON * i2s_cb(){ cJSON * i2s_cb(){
cJSON * values = cJSON_CreateObject(); cJSON * values = cJSON_CreateObject();
const i2s_platform_config_t * i2s_conf= config_dac_get( ); const i2s_platform_config_t * i2s_conf= config_dac_get( );
if(i2s_conf->pin.bck_io_num>0 ) { if(i2s_conf->pin.bck_io_num>0 ) {
cJSON_AddNumberToObject(values,"clock",i2s_conf->pin.bck_io_num); cJSON_AddNumberToObject(values,i2s_args.clock->hdr.longopts,i2s_conf->pin.bck_io_num);
} }
if(i2s_conf->pin.ws_io_num>=0 ) { if(i2s_conf->pin.ws_io_num>=0 ) {
cJSON_AddNumberToObject(values,"wordselect",i2s_conf->pin.ws_io_num); cJSON_AddNumberToObject(values,i2s_args.wordselect->hdr.longopts,i2s_conf->pin.ws_io_num);
} }
if(i2s_conf->pin.data_out_num>=0 ) { if(i2s_conf->pin.data_out_num>=0 ) {
cJSON_AddNumberToObject(values,"data",i2s_conf->pin.data_out_num); cJSON_AddNumberToObject(values,i2s_args.data->hdr.longopts,i2s_conf->pin.data_out_num);
} }
if(i2s_conf->sda>=0 ) { if(i2s_conf->sda>=0 ) {
cJSON_AddNumberToObject(values,"dac_sda",i2s_conf->sda); cJSON_AddNumberToObject(values,i2s_args.dac_sda->hdr.longopts,i2s_conf->sda);
} }
if(i2s_conf->scl>=0 ) { if(i2s_conf->scl>=0 ) {
cJSON_AddNumberToObject(values,"dac_scl",i2s_conf->scl); cJSON_AddNumberToObject(values,i2s_args.dac_scl->hdr.longopts,i2s_conf->scl);
} }
if(i2s_conf->i2c_addr>=0 ) { if(i2s_conf->i2c_addr>=0 ) {
cJSON_AddNumberToObject(values,"dac_i2c",i2s_conf->i2c_addr); cJSON_AddNumberToObject(values,i2s_args.dac_i2c->hdr.longopts,i2s_conf->i2c_addr);
} }
if(i2s_conf->mute_gpio>=0 ) { if(i2s_conf->mute_gpio>=0 ) {
cJSON_AddNumberToObject(values,"mute_gpio",i2s_conf->mute_gpio); cJSON_AddNumberToObject(values,i2s_args.mute_gpio->hdr.longopts,i2s_conf->mute_gpio);
} }
if(i2s_conf->mute_level>=0 ) { if(i2s_conf->mute_level>=0 ) {
cJSON_AddBoolToObject(values,"mute_level",i2s_conf->mute_level>0); cJSON_AddBoolToObject(values,i2s_args.mute_level->hdr.longopts,i2s_conf->mute_level>0);
} }
if(strlen(i2s_conf->model)>0){ if(strlen(i2s_conf->model)>0){
cJSON_AddStringToObject(values,"model_name",i2s_conf->model); cJSON_AddStringToObject(values,i2s_args.model_name->hdr.longopts,i2s_conf->model);
} }
else { else {
cJSON_AddStringToObject(values,"model_name","I2S"); cJSON_AddStringToObject(values,i2s_args.model_name->hdr.longopts,"I2S");
} }
return values; return values;
@@ -862,17 +904,288 @@ static char * get_log_level_options(const char * longname){
char * options = NULL; char * options = NULL;
int len = snprintf(NULL,0,template,longname,longname,longname); int len = snprintf(NULL,0,template,longname,longname,longname);
if(len>0){ if(len>0){
options = malloc(len+1); options = malloc_init_external(len+1);
snprintf(options,len,template,longname,longname,longname); snprintf(options,len,template,longname,longname,longname);
} }
return options; return options;
} }
// loop through dac_set and concatenate model name separated with |
static char * get_dac_list(){
const char * ES8388_MODEL_NAME = "ES8388|";
char * dac_list=NULL;
size_t total_len=0;
for(int i=0;dac_set[i];i++){
if(dac_set[i]->model && strlen(dac_set[i]->model)>0){
total_len+=strlen(dac_set[i]->model)+1;
}
else {
break;
}
}
total_len+=strlen(ES8388_MODEL_NAME);
dac_list = malloc_init_external(total_len+1);
if(dac_list){
for(int i=0;dac_set[i];i++){
if(dac_set[i]->model && strlen(dac_set[i]->model)>0){
strcat(dac_list,dac_set[i]->model);
strcat(dac_list,"|");
}
else {
break;
}
}
strcat(dac_list,ES8388_MODEL_NAME);
}
return dac_list;
}
void replace_char_in_string(char * str, char find, char replace){
for(int i=0;str[i];i++){
if(str[i]==find){
str[i]=replace;
}
}
}
static cJSON * get_known_configurations(FILE * f){
#define err1_msg "Failed to parse known_configs json. %s\nError at:\n%s"
#define err2_msg "Known configs should be an array and it is not: \n%s"
if(!known_configs_string || strlen(known_configs_string)==0){
return NULL;
}
cJSON * known_configs_json = cJSON_Parse(known_configs_string);
if(!known_configs_json){
if(f){
fprintf(f,err1_msg,known_configs_string,STR_OR_BLANK(cJSON_GetErrorPtr()));
}
else {
ESP_LOGE(TAG,err1_msg,known_configs_string,STR_OR_BLANK(cJSON_GetErrorPtr()));
}
return NULL;
}
else {
if(!cJSON_IsArray(known_configs_json)){
if(f){
fprintf(f,err2_msg,STR_OR_BLANK(cJSON_GetErrorPtr()));
}
else {
ESP_LOGE(TAG,err2_msg,STR_OR_BLANK(cJSON_GetErrorPtr()));
}
cJSON_Delete(known_configs_json);
return NULL;
}
}
return known_configs_json;
}
static cJSON * find_known_model_name(cJSON * root,const char * name, FILE * f, bool * found){
if(found){
*found = false;
}
if(!root){
return NULL;
}
cJSON * item;
cJSON_ArrayForEach(item, root){
if(cJSON_IsObject(item)){
cJSON * model = cJSON_GetObjectItem(item,"name");
if(model && cJSON_IsString(model) && strcmp(cJSON_GetStringValue(model),name)==0){
if(found){
*found = true;
}
return item;
}
}
}
return NULL;
}
static esp_err_t is_known_model_name(const char * name, FILE * f, bool * found){
esp_err_t err = ESP_OK;
if(found){
*found = false;
}
if(!known_configs_string || strlen(known_configs_string)==0){
return err;
}
cJSON * known_configs_json = get_known_configurations(f);
if(known_configs_json){
cJSON * known_item = find_known_model_name(known_configs_json,name,f,found);
if(known_item && found){
*found = true;
}
cJSON_Delete(known_configs_json);
}
return err;
}
static esp_err_t save_known_config(const char * name, FILE * f){
esp_err_t err = ESP_OK;
char * json_string=NULL;
if(!known_configs_string || strlen(known_configs_string)==0){
return err;
}
cJSON * known_configs_json = get_known_configurations(f);
if(known_configs_json){
bool found = false;
cJSON * known_item = find_known_model_name(known_configs_json,name,f,&found);
if(known_item && found){
json_string = cJSON_Print(known_item);
ESP_LOGD(TAG,"known_item_string: %s",STR_OR_BLANK(json_string));
FREE_AND_NULL(json_string);
cJSON * kvp=NULL;
cJSON * config_array = cJSON_GetObjectItem(known_item,"config");
if(config_array && cJSON_IsArray(config_array)){
json_string = cJSON_Print(config_array);
ESP_LOGD(TAG,"config_array: %s",STR_OR_BLANK(json_string));
FREE_AND_NULL(json_string);
cJSON_ArrayForEach(kvp, config_array){
cJSON * kvp_value=kvp->child;
if(!kvp_value){
ESP_LOGE(TAG,"config entry is not an object!");
err=ESP_FAIL;
continue;
}
char * key = kvp_value->string;
char * value = kvp_value->valuestring;
if(!key || !value || strlen(key)==0){
ESP_LOGE(TAG,"Invalid config entry %s:%s",STR_OR_BLANK(key),STR_OR_BLANK(value));
err=ESP_FAIL;
continue;
}
fprintf(f,"Storing %s=%s\n",key,value);
err = config_set_value(NVS_TYPE_STR,key,value);
if(err){
fprintf(f,"Failed: %s\n",esp_err_to_name(err));
break;
}
}
}
else {
json_string = cJSON_Print(config_array);
char * known_item_string = cJSON_Print(known_item);
fprintf(f,"Failed to parse config array. %s\n%s\nKnown item found: %s\n",config_array?cJSON_IsArray(config_array)?"":"NOT AN ARRAY":"config entry not found",STR_OR_BLANK(json_string),STR_OR_BLANK(known_item_string));
FREE_AND_NULL(json_string);
FREE_AND_NULL(known_item_string);
err = ESP_FAIL;
}
}
if(err==ESP_OK){
err = config_set_value(NVS_TYPE_STR,"board_model",name);
if(err!=ESP_OK){
fprintf(f,"Failed to save board model %s\n",name);
}
}
cJSON_Delete(known_configs_json);
}
return err;
}
char * config_dac_alloc_print_known_config(){
cJSON * item=NULL;
char * dac_list=NULL;
size_t total_len=0;
cJSON * object = get_known_configurations(NULL);
if(!object){
return strdup_psram("");
}
// loop through all items, and concatenate model name separated with |
cJSON_ArrayForEach(item, object){
if(cJSON_IsObject(item)){
cJSON * model = cJSON_GetObjectItem(item,"name");
if(model && cJSON_IsString(model)){
total_len+=strlen(model->valuestring)+1;
}
}
}
if(total_len==0){
ESP_LOGI(TAG,"No known configs found");
cJSON_Delete(object);
return NULL;
}
dac_list = malloc_init_external(total_len+1);
if(dac_list){
cJSON_ArrayForEach(item, object){
if(cJSON_IsObject(item)){
cJSON * model = cJSON_GetObjectItem(item,"name");
if(model && cJSON_IsString(model)){
strcat(dac_list,model->valuestring);
strcat(dac_list,"|");
}
}
}
}
dac_list[strlen(dac_list)-1]='\0';
cJSON_Delete(object);
return dac_list;
}
static int do_register_known_templates_config(int argc, char **argv){
esp_err_t err=ESP_OK;
int nerrors = arg_parse(argc, argv,(void **)&known_model_args);
char *buf = NULL;
size_t buf_size = 0;
FILE *f = open_memstream(&buf, &buf_size);
if (f == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
return 1;
}
if(nerrors >0){
arg_print_errors(f,known_model_args.end,desc_preset);
}
else {
bool found=false;
if(nerrors +=(is_known_model_name(known_model_args.model_name->sval[0],f,&found)!=ESP_OK)){
fprintf(f,"Error registering known config %s. The model was not found.\n",known_model_args.model_name->sval[0]);
}
if(nerrors==0 && found){
fprintf(f,"Appling template configuration for %s\n",known_model_args.model_name->sval[0]);
nerrors+=((err=save_known_config(known_model_args.model_name->sval[0],f))!=ESP_OK);
}
if(err!=ESP_OK){
nerrors++;
fprintf(f,"Error registering known config %s.\n",known_model_args.model_name->sval[0]);
}
else {
fprintf(f,"Registered known config %s.\n",known_model_args.model_name->sval[0]);
}
}
if(!nerrors ){
fprintf(f,"Done.\n");
}
fflush (f);
cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
fclose(f);
FREE_AND_NULL(buf);
return (nerrors==0 && err==ESP_OK)?0:1;
}
static void register_known_templates_config(){
char * known_models = config_dac_alloc_print_known_config();
known_model_args.model_name = arg_str1(NULL,"model_name",known_models,"Known Board Name.\nFor known boards, several systems parameters will be updated");
known_model_args.end = arg_end(1);
const esp_console_cmd_t cmd = {
.command = CFG_TYPE_HW("preset"),
.help = desc_preset,
.hint = NULL,
.func = &do_register_known_templates_config,
.argtable = &known_model_args
};
cmd_to_json_with_cb(&cmd,&known_model_cb);
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
FREE_AND_NULL(known_models);
}
static void register_i2s_config(void){ static void register_i2s_config(void){
i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|WM8978|I2S","DAC Model Name"); i2s_args.model_name = arg_str1(NULL,"model_name",STR_OR_BLANK(get_dac_list()),"DAC Model Name");
i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
i2s_args.clock = arg_int1(NULL,"clock","<n>","Clock GPIO. e.g. 33"); i2s_args.clock = arg_int0(NULL,"clock","<n>","Clock GPIO. e.g. 33");
i2s_args.wordselect = arg_int1(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25"); i2s_args.wordselect = arg_int0(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25");
i2s_args.data = arg_int1(NULL,"data","<n>","Data GPIO. e.g. 32"); i2s_args.data = arg_int0(NULL,"data","<n>","Data GPIO. e.g. 32");
i2s_args.mute_gpio = arg_int0(NULL,"mute_gpio", "<n>", "Mute GPIO. e.g. 14"); i2s_args.mute_gpio = arg_int0(NULL,"mute_gpio", "<n>", "Mute GPIO. e.g. 14");
i2s_args.mute_level = arg_lit0(NULL,"mute_level","Mute GPIO level. Checked=HIGH, Unchecked=LOW"); i2s_args.mute_level = arg_lit0(NULL,"mute_level","Mute GPIO level. Checked=HIGH, Unchecked=LOW");
i2s_args.dac_sda = arg_int0(NULL,"dac_sda", "<n>", "SDA GPIO. e.g. 27"); i2s_args.dac_sda = arg_int0(NULL,"dac_sda", "<n>", "SDA GPIO. e.g. 27");
@@ -1005,6 +1318,9 @@ static void register_squeezelite_config(void){
} }
void register_config_cmd(void){ void register_config_cmd(void){
if(!is_dac_config_locked()){
register_known_templates_config();
}
register_audio_config(); register_audio_config();
// register_squeezelite_config(); // register_squeezelite_config();
register_bt_source_config(); register_bt_source_config();

View File

@@ -6,7 +6,6 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. CONDITIONS OF ANY KIND, either express or implied.
*/ */
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include <stdio.h> #include <stdio.h>
#include "cmd_i2ctools.h" #include "cmd_i2ctools.h"
#include "argtable3/argtable3.h" #include "argtable3/argtable3.h"
@@ -21,6 +20,7 @@
#include "messaging.h" #include "messaging.h"
#include "display.h" #include "display.h"
#include "config.h" #include "config.h"
#include "globdefs.h"
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
@@ -754,7 +754,7 @@ static int do_i2cget_cmd(int argc, char **argv)
} }
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
uint8_t *data = malloc(len); uint8_t *data = malloc_init_external(len);
if (data_addr != -1) { if (data_addr != -1) {
i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN); i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN);

View File

@@ -6,7 +6,6 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. CONDITIONS OF ANY KIND, either express or implied.
*/ */
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -27,41 +26,50 @@ extern "C" {
#include "nvs_utilities.h" #include "nvs_utilities.h"
#include "platform_console.h" #include "platform_console.h"
#include "messaging.h" #include "messaging.h"
#include "globdefs.h"
#include "trace.h"
extern esp_err_t network_wifi_erase_legacy();
extern esp_err_t network_wifi_erase_known_ap();
static const char *ARG_TYPE_STR = "type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob"; static const char *ARG_TYPE_STR = "type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob";
static const char * TAG = "cmd_nvs"; static const char * TAG = "cmd_nvs";
static struct { EXT_RAM_ATTR static struct {
struct arg_str *key; struct arg_str *key;
struct arg_str *type; struct arg_str *type;
struct arg_str *value; struct arg_str *value;
struct arg_end *end; struct arg_end *end;
} set_args; } set_args;
static struct { EXT_RAM_ATTR static struct {
struct arg_str *key; struct arg_str *key;
struct arg_str *type; struct arg_str *type;
struct arg_end *end; struct arg_end *end;
} get_args; } get_args;
static struct { EXT_RAM_ATTR static struct {
struct arg_str *key; struct arg_str *key;
struct arg_end *end; struct arg_end *end;
} erase_args; } erase_args;
static struct { EXT_RAM_ATTR static struct {
struct arg_str *namespace; struct arg_str *namespace;
struct arg_end *end; struct arg_end *end;
} erase_all_args; } erase_all_args;
static struct { EXT_RAM_ATTR static struct {
struct arg_str *partition; struct arg_str *partition;
struct arg_str *namespace; struct arg_str *namespace;
struct arg_str *type; struct arg_str *type;
struct arg_end *end; struct arg_end *end;
} list_args; } list_args;
EXT_RAM_ATTR static struct {
struct arg_lit *legacy;
struct arg_lit *ap_list;
struct arg_end *end;
} wifi_erase_args;
static esp_err_t store_blob(nvs_handle nvs, const char *key, const char *str_values) static esp_err_t store_blob(nvs_handle nvs, const char *key, const char *str_values)
@@ -75,7 +83,7 @@ static esp_err_t store_blob(nvs_handle nvs, const char *key, const char *str_val
return ESP_ERR_NVS_TYPE_MISMATCH; return ESP_ERR_NVS_TYPE_MISMATCH;
} }
char *blob = (char *)malloc(blob_len); char *blob = (char *)malloc_init_external(blob_len);
if (blob == NULL) { if (blob == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
@@ -261,7 +269,7 @@ static esp_err_t get_value_from_nvs(const char *key, const char *str_type)
} else if (type == NVS_TYPE_STR) { } else if (type == NVS_TYPE_STR) {
size_t len=0; size_t len=0;
if ( (err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) { if ( (err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
char *str = (char *)malloc(len); char *str = (char *)malloc_init_external(len);
if ( (err = nvs_get_str(nvs, key, str, &len)) == ESP_OK) { if ( (err = nvs_get_str(nvs, key, str, &len)) == ESP_OK) {
log_send_messaging(MESSAGING_INFO,"String associated with key '%s' is %s \n", key, str); log_send_messaging(MESSAGING_INFO,"String associated with key '%s' is %s \n", key, str);
} }
@@ -270,7 +278,7 @@ static esp_err_t get_value_from_nvs(const char *key, const char *str_type)
} else if (type == NVS_TYPE_BLOB) { } else if (type == NVS_TYPE_BLOB) {
size_t len; size_t len;
if ( (err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) { if ( (err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
char *blob = (char *)malloc(len); char *blob = (char *)malloc_init_external(len);
if ( (err = nvs_get_blob(nvs, key, blob, &len)) == ESP_OK) { if ( (err = nvs_get_blob(nvs, key, blob, &len)) == ESP_OK) {
log_send_messaging(MESSAGING_INFO,"Blob associated with key '%s' is %d bytes long: \n", key, len); log_send_messaging(MESSAGING_INFO,"Blob associated with key '%s' is %d bytes long: \n", key, len);
print_blob(blob, len); print_blob(blob, len);
@@ -399,7 +407,7 @@ static int erase_namespace(int argc, char **argv)
return 0; return 0;
} }
static int erase_wifi_manager(int argc, char **argv) static int erase_network_manager(int argc, char **argv)
{ {
nvs_handle nvs; nvs_handle nvs;
esp_err_t err = nvs_open("config", NVS_READWRITE, &nvs); esp_err_t err = nvs_open("config", NVS_READWRITE, &nvs);
@@ -411,15 +419,49 @@ static int erase_wifi_manager(int argc, char **argv)
} }
nvs_close(nvs); nvs_close(nvs);
if (err != ESP_OK) { if (err != ESP_OK) {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "wifi manager configuration was not erase. %s", esp_err_to_name(err)); cmd_send_messaging(argv[0],MESSAGING_ERROR, "System configuration was not erased. %s", esp_err_to_name(err));
return 1; return 1;
} }
else { else {
cmd_send_messaging(argv[0],MESSAGING_WARNING, "Wifi manager configuration was erased"); cmd_send_messaging(argv[0],MESSAGING_WARNING, "system configuration was erased. Please reboot.");
} }
return 0; return 0;
} }
static int wifi_erase_config(int argc, char **argv)
{
esp_err_t err=ESP_OK;
esp_err_t err_ap_list=ESP_OK;
bool done = false;
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&wifi_erase_args);
if (nerrors != 0) {
return 1;
}
if(wifi_erase_args.ap_list->count>0){
err_ap_list = network_wifi_erase_known_ap();
if (err_ap_list != ESP_OK) {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Could not erase legacy wifi configuration: %s", esp_err_to_name(err));
}
else {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Legacy wifi configuration was erased");
}
done = true;
}
if(wifi_erase_args.legacy->count>0){
err = network_wifi_erase_legacy();
if (err != ESP_OK) {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Could not erase known ap list : %s", esp_err_to_name(err));
}
else {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "Known access point list was erased");
}
done = true;
}
if(!done){
cmd_send_messaging(argv[0],MESSAGING_WARNING, "Please specify at least one configuration type to erase.", esp_err_to_name(err));
}
return (err_ap_list==ESP_OK && err==ESP_OK)?0:1;
}
static int list(const char *part, const char *name, const char *str_type) static int list(const char *part, const char *name, const char *str_type)
{ {
@@ -476,6 +518,10 @@ void register_nvs()
erase_all_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace to be erased"); erase_all_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace to be erased");
erase_all_args.end = arg_end(2); erase_all_args.end = arg_end(2);
wifi_erase_args.ap_list = arg_lit0("a","ap_list","Erases Known access points list");
wifi_erase_args.legacy = arg_lit0("l","legacy","Erases legacy access point storage");
wifi_erase_args.end = arg_end(1);
list_args.partition = arg_str1(NULL, NULL, "<partition>", "partition name"); list_args.partition = arg_str1(NULL, NULL, "<partition>", "partition name");
list_args.namespace = arg_str0("n", "namespace", "<namespace>", "namespace name"); list_args.namespace = arg_str0("n", "namespace", "<namespace>", "namespace name");
list_args.type = arg_str0("t", "type", "<type>", ARG_TYPE_STR); list_args.type = arg_str0("t", "type", "<type>", ARG_TYPE_STR);
@@ -516,11 +562,19 @@ void register_nvs()
.func = &erase_namespace, .func = &erase_namespace,
.argtable = &erase_all_args .argtable = &erase_all_args
}; };
const esp_console_cmd_t erase_wifimanager_cmd = { const esp_console_cmd_t erase_config_cmd = {
.command = "nvs_erase_wifi_manager", .command = "wifi_erase_config",
.help = "Erases wifi_manager's config", .help = "Erases all stored access points from flash",
.hint = NULL, .hint = NULL,
.func = &erase_wifi_manager, .func = &wifi_erase_config,
.argtable = &wifi_erase_args
};
const esp_console_cmd_t erase_networkmanager_cmd = {
.command = "nvs_erase_configuration",
.help = "Erases system's configuration",
.hint = NULL,
.func = &erase_network_manager,
.argtable = NULL .argtable = NULL
}; };
@@ -535,12 +589,21 @@ void register_nvs()
.func = &list_entries, .func = &list_entries,
.argtable = &list_args .argtable = &list_args
}; };
MEMTRACE_PRINT_DELTA_MESSAGE("registering list_entries_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering set_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&set_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&set_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering get_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&get_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&get_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering erase_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&erase_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&erase_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering erase_namespace_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&erase_namespace_cmd)); ESP_ERROR_CHECK(esp_console_cmd_register(&erase_namespace_cmd));
ESP_ERROR_CHECK(esp_console_cmd_register(&erase_wifimanager_cmd)); MEMTRACE_PRINT_DELTA_MESSAGE("registering erase_config_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&erase_networkmanager_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("registering erase_config_cmd");
ESP_ERROR_CHECK(esp_console_cmd_register(&erase_config_cmd));
MEMTRACE_PRINT_DELTA_MESSAGE("Done");
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -32,21 +32,23 @@
#include "messaging.h" #include "messaging.h"
#include "platform_console.h" #include "platform_console.h"
#include "trace.h" #include "trace.h"
#include "globdefs.h"
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
#pragma message("Runtime stats enabled") #pragma message("Runtime stats enabled")
#define WITH_TASKS_INFO 1 #define WITH_TASKS_INFO 1
#else #else
#pragma message("Runtime stats disabled") #pragma message("Runtime stats disabled")
#endif #endif
static struct { EXT_RAM_ATTR static struct {
struct arg_str *scanmode; struct arg_str *scanmode;
struct arg_end *end; struct arg_end *end;
} wifi_parms_arg; } wifi_parms_arg;
static struct { EXT_RAM_ATTR static struct {
struct arg_str *name; struct arg_str *name;
struct arg_end *end; struct arg_end *end;
} name_args; } name_args;
static struct { EXT_RAM_ATTR static struct {
struct arg_lit *btspeaker; struct arg_lit *btspeaker;
struct arg_lit *airplay; struct arg_lit *airplay;
struct arg_str *telnet; struct arg_str *telnet;
@@ -61,6 +63,7 @@ static const char * TAG = "cmd_system";
static void register_free(); static void register_free();
static void register_setdevicename(); static void register_setdevicename();
static void register_heap(); static void register_heap();
static void register_dump_heap();
static void register_version(); static void register_version();
static void register_restart(); static void register_restart();
static void register_deep_sleep(); static void register_deep_sleep();
@@ -73,7 +76,7 @@ static void register_set_wifi_parms();
#if WITH_TASKS_INFO #if WITH_TASKS_INFO
static void register_tasks(); static void register_tasks();
#endif #endif
extern BaseType_t wifi_manager_task; extern BaseType_t network_manager_task;
void register_system() void register_system()
{ {
register_set_wifi_parms(); register_set_wifi_parms();
@@ -81,6 +84,7 @@ void register_system()
register_free(); register_free();
register_set_services(); register_set_services();
register_heap(); register_heap();
register_dump_heap();
register_setdevicename(); register_setdevicename();
register_version(); register_version();
register_restart(); register_restart();
@@ -297,12 +301,35 @@ static void register_free()
cmd_to_json(&cmd); cmd_to_json(&cmd);
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
} }
static int dump_heap(int argc, char **argv)
{
ESP_LOGD(TAG, "Dumping heap");
heap_caps_dump_all();
return 0;
}
/* 'heap' command prints minumum heap size */ /* 'heap' command prints minumum heap size */
static int heap_size(int argc, char **argv) static int heap_size(int argc, char **argv)
{ {
uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT); ESP_LOGI(TAG,"Heap internal:%zu (min:%zu) (largest block:%zu)\nexternal:%zu (min:%zu) (largest block:%zd)\ndma :%zu (min:%zu) (largest block:%zd)",
cmd_send_messaging(argv[0],MESSAGING_INFO, "min heap size: %u", heap_size); heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA),
heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
cmd_send_messaging(argv[0],MESSAGING_INFO,"Heap internal:%zu (min:%zu) (largest block:%zu)\nexternal:%zu (min:%zu) (largest block:%zd)\ndma :%zu (min:%zu) (largest block:%zd)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA),
heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
return 0; return 0;
} }
cJSON * setdevicename_cb(){ cJSON * setdevicename_cb(){
@@ -341,10 +368,9 @@ int set_squeezelite_player_name(FILE * f,const char * name){
if(nvs_config && strlen(nvs_config)>0){ if(nvs_config && strlen(nvs_config)>0){
// allocate enough memory to hold the new command line // allocate enough memory to hold the new command line
size_t cmdLength = strlen(nvs_config) + strlen(cleaned_name) + strlen(parm) +1 ; size_t cmdLength = strlen(nvs_config) + strlen(cleaned_name) + strlen(parm) +1 ;
newCommandLine = malloc(cmdLength); newCommandLine = malloc_init_external(cmdLength);
memset(newCommandLine,0x00, cmdLength); ESP_LOGD(TAG,"Parsing command %s",nvs_config);
ESP_LOGD(TAG,"Parsing command %s",nvs_config); argv = (char **) malloc_init_external(22* sizeof(char *));
argv = (char **) calloc(22, sizeof(char *));
if (argv == NULL) { if (argv == NULL) {
FREE_AND_NULL(nvs_config); FREE_AND_NULL(nvs_config);
return 1; return 1;
@@ -400,7 +426,7 @@ static int setdevicename(int argc, char **argv)
/* Check "--name" option */ /* Check "--name" option */
if (name_args.name->count) { if (name_args.name->count) {
name=strdup(name_args.name->sval[0]); name=strdup_psram(name_args.name->sval[0]);
} }
else { else {
cmd_send_messaging(argv[0],MESSAGING_ERROR,"Name must be specified."); cmd_send_messaging(argv[0],MESSAGING_ERROR,"Name must be specified.");
@@ -448,6 +474,17 @@ static void register_heap()
} }
static void register_dump_heap()
{
const esp_console_cmd_t heap_cmd = {
.command = "dump_heap",
.help = "Dumps the content of the heap to serial output",
.hint = NULL,
.func = &dump_heap,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
}
static void register_setdevicename() static void register_setdevicename()
{ {
@@ -470,7 +507,7 @@ static void register_setdevicename()
static int tasks_info(int argc, char **argv) static int tasks_info(int argc, char **argv)
{ {
const size_t bytes_per_task = 40; /* see vTaskList description */ const size_t bytes_per_task = 40; /* see vTaskList description */
char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task); char *task_list_buffer = malloc_init_external(uxTaskGetNumberOfTasks() * bytes_per_task);
if (task_list_buffer == NULL) { if (task_list_buffer == NULL) {
cmd_send_messaging(argv[0],MESSAGING_ERROR, "failed to allocate buffer for vTaskList output"); cmd_send_messaging(argv[0],MESSAGING_ERROR, "failed to allocate buffer for vTaskList output");
return 1; return 1;

View File

@@ -32,12 +32,12 @@
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_event.h" #include "esp_event.h"
#include "led.h" #include "led.h"
extern bool bypass_wifi_manager; extern bool bypass_network_manager;
#define JOIN_TIMEOUT_MS (10000) #define JOIN_TIMEOUT_MS (10000)
#include "platform_console.h" #include "platform_console.h"
extern EventGroupHandle_t wifi_event_group; extern EventGroupHandle_t network_event_group;
extern const int CONNECTED_BIT; extern const int CONNECTED_BIT;
//static const char * TAG = "cmd_wifi"; //static const char * TAG = "cmd_wifi";
/** Arguments used by 'join' function */ /** Arguments used by 'join' function */
@@ -65,10 +65,10 @@ static void event_handler(void* arg, esp_event_base_t event_base,
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
led_blink_pushed(LED_GREEN, 250, 250); led_blink_pushed(LED_GREEN, 250, 250);
esp_wifi_connect(); esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); xEventGroupClearBits(network_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
led_unpush(LED_GREEN); led_unpush(LED_GREEN);
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); xEventGroupSetBits(network_event_group, CONNECTED_BIT);
} }
} }
//bool wait_for_wifi(){ //bool wait_for_wifi(){
@@ -127,7 +127,7 @@ static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_connect() ); ESP_ERROR_CHECK( esp_wifi_connect() );
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, int bits = xEventGroupWaitBits(network_event_group, CONNECTED_BIT,
pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS); pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
return (bits & CONNECTED_BIT) != 0; return (bits & CONNECTED_BIT) != 0;
} }
@@ -202,7 +202,7 @@ void register_wifi_join()
void register_wifi() void register_wifi()
{ {
register_wifi_join(); register_wifi_join();
if(bypass_wifi_manager){ if(bypass_network_manager){
initialise_wifi(); initialise_wifi();
} }
} }

View File

@@ -34,7 +34,7 @@ pthread_t thread_console;
static void * console_thread(); static void * console_thread();
void console_start(); void console_start();
static const char * TAG = "console"; static const char * TAG = "console";
extern bool bypass_wifi_manager; extern bool bypass_network_manager;
extern void register_squeezelite(); extern void register_squeezelite();
/* Prompt to be printed before each line. /* Prompt to be printed before each line.
@@ -188,8 +188,8 @@ void process_autoexec(){
uint8_t autoexec_flag=0; uint8_t autoexec_flag=0;
char * str_flag = config_alloc_get(NVS_TYPE_STR, "autoexec"); char * str_flag = config_alloc_get(NVS_TYPE_STR, "autoexec");
if(!bypass_wifi_manager){ if(!bypass_network_manager){
ESP_LOGW(TAG, "Processing autoexec commands while wifi_manager active. Wifi related commands will be ignored."); ESP_LOGW(TAG, "Processing autoexec commands while network manager active. Wifi related commands will be ignored.");
} }
if(is_recovery_running){ if(is_recovery_running){
ESP_LOGD(TAG, "Processing autoexec commands in recovery mode. Squeezelite commands will be ignored."); ESP_LOGD(TAG, "Processing autoexec commands in recovery mode. Squeezelite commands will be ignored.");
@@ -203,7 +203,7 @@ void process_autoexec(){
ESP_LOGD(TAG,"Getting command name %s", autoexec_name); ESP_LOGD(TAG,"Getting command name %s", autoexec_name);
autoexec_value= config_alloc_get(NVS_TYPE_STR, autoexec_name); autoexec_value= config_alloc_get(NVS_TYPE_STR, autoexec_name);
if(autoexec_value!=NULL ){ if(autoexec_value!=NULL ){
if(!bypass_wifi_manager && strstr(autoexec_value, "join ")!=NULL ){ if(!bypass_network_manager && strstr(autoexec_value, "join ")!=NULL ){
ESP_LOGW(TAG,"Ignoring wifi join command."); ESP_LOGW(TAG,"Ignoring wifi join command.");
} }
else if(is_recovery_running && !strstr(autoexec_value, "squeezelite " ) ){ else if(is_recovery_running && !strstr(autoexec_value, "squeezelite " ) ){
@@ -298,18 +298,26 @@ void console_start() {
ESP_ERROR_CHECK(esp_console_init(&console_config)); ESP_ERROR_CHECK(esp_console_init(&console_config));
} }
/* Register commands */ /* Register commands */
MEMTRACE_PRINT_DELTA_MESSAGE("Registering help command");
esp_console_register_help_command(); esp_console_register_help_command();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering system commands");
register_system(); register_system();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering config commands");
register_config_cmd(); register_config_cmd();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering nvs commands");
register_nvs(); register_nvs();
MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi commands");
register_wifi(); register_wifi();
if(!is_recovery_running){ if(!is_recovery_running){
MEMTRACE_PRINT_DELTA_MESSAGE("Registering squeezelite commands");
register_squeezelite(); register_squeezelite();
} }
else { else {
MEMTRACE_PRINT_DELTA_MESSAGE("Registering recovery commands");
register_ota_cmd(); register_ota_cmd();
} }
MEMTRACE_PRINT_DELTA_MESSAGE("Registering i2c commands");
register_i2ctools(); register_i2ctools();
if(!is_serial_suppressed()){ if(!is_serial_suppressed()){
@@ -358,14 +366,16 @@ void console_start() {
prompt = recovery_prompt; prompt = recovery_prompt;
cfg.stack_size = 4096 ; cfg.stack_size = 4096 ;
} }
MEMTRACE_PRINT_DELTA_MESSAGE("Creating console thread with stack size of 4096 bytes");
esp_pthread_set_cfg(&cfg); esp_pthread_set_cfg(&cfg);
pthread_attr_t attr; pthread_attr_t attr;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_create(&thread_console, &attr, console_thread, NULL); pthread_create(&thread_console, &attr, console_thread, NULL);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
MEMTRACE_PRINT_DELTA_MESSAGE("Console thread created");
} }
else if(!is_recovery_running){ else if(!is_recovery_running){
MEMTRACE_PRINT_DELTA_MESSAGE("Running autoexec");
process_autoexec(); process_autoexec();
} }
@@ -392,7 +402,9 @@ esp_err_t run_command(char * line){
} }
static void * console_thread() { static void * console_thread() {
if(!is_recovery_running){ if(!is_recovery_running){
MEMTRACE_PRINT_DELTA_MESSAGE("Running autoexec");
process_autoexec(); process_autoexec();
MEMTRACE_PRINT_DELTA_MESSAGE("Autoexec done");
} }
/* Main loop */ /* Main loop */
while (1) { while (1) {

View File

@@ -164,6 +164,8 @@ static bool raop_sink_start(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
tcpip_adapter_if_t ifs[] = { TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_IF_AP }; tcpip_adapter_if_t ifs[] = { TCPIP_ADAPTER_IF_ETH, TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_IF_AP };
// get various IP info // get various IP info
// it is possible to get the currently active interface with the following call:
// network_get_active_interface()
for (int i = 0; i < sizeof(ifs) / sizeof(tcpip_adapter_if_t); i++) for (int i = 0; i < sizeof(ifs) / sizeof(tcpip_adapter_if_t); i++)
if (tcpip_adapter_get_ip_info(ifs[i], &ipInfo) == ESP_OK && ipInfo.ip.addr != IPADDR_ANY) { if (tcpip_adapter_get_ip_info(ifs[i], &ipInfo) == ESP_OK && ipInfo.ip.addr != IPADDR_ANY) {
tcpip_adapter_get_hostname(ifs[i], &hostname); tcpip_adapter_get_hostname(ifs[i], &hostname);

View File

@@ -1,6 +1,6 @@
idf_component_register(SRC_DIRS . idf_component_register(SRC_DIRS .
INCLUDE_DIRS . ${IDF_PATH}/components/driver INCLUDE_DIRS . ${IDF_PATH}/components/driver
REQUIRES json tools platform_config display REQUIRES json tools platform_config display wifi-manager
PRIV_REQUIRES soc esp32 squeezelite PRIV_REQUIRES soc esp32 squeezelite
) )

View File

@@ -32,6 +32,7 @@
#include "trace.h" #include "trace.h"
#include "monitor.h" #include "monitor.h"
#include "messaging.h" #include "messaging.h"
#include "network_ethernet.h"
static const char *TAG = "services"; static const char *TAG = "services";
@@ -62,6 +63,7 @@ static char * config_spdif_get_string(){
",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO)); ",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO));
} }
/**************************************************************************************** /****************************************************************************************
* *
*/ */
@@ -122,7 +124,6 @@ const i2s_platform_config_t * config_get_i2s_from_str(char * dac_config ){
set_i2s_pin(dac_config, &i2s_dac_pin.pin); set_i2s_pin(dac_config, &i2s_dac_pin.pin);
strcpy(i2s_dac_pin.model, "i2s"); strcpy(i2s_dac_pin.model, "i2s");
char * p=NULL; char * p=NULL;
if ((p = strcasestr(dac_config, "i2c")) != NULL) i2s_dac_pin.i2c_addr = atoi(strchr(p, '=') + 1); if ((p = strcasestr(dac_config, "i2c")) != NULL) i2s_dac_pin.i2c_addr = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(dac_config, "sda")) != NULL) i2s_dac_pin.sda = atoi(strchr(p, '=') + 1); if ((p = strcasestr(dac_config, "sda")) != NULL) i2s_dac_pin.sda = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(dac_config, "scl")) != NULL) i2s_dac_pin.scl = atoi(strchr(p, '=') + 1); if ((p = strcasestr(dac_config, "scl")) != NULL) i2s_dac_pin.scl = atoi(strchr(p, '=') + 1);
@@ -143,9 +144,8 @@ const eth_config_t * config_get_eth_from_str(char * eth_config ){
char * p=NULL; char * p=NULL;
static EXT_RAM_ATTR eth_config_t eth_pin; static EXT_RAM_ATTR eth_config_t eth_pin;
memset(&eth_pin, 0xFF, sizeof(eth_pin)); memset(&eth_pin, 0xFF, sizeof(eth_pin));
memset(&eth_pin.model, 0xFF, sizeof(eth_pin.model)); memset(&eth_pin.model, 0x00, sizeof(eth_pin.model));
eth_pin.spi = false; eth_pin.valid = true;
eth_pin.rmii = false;
if ((p = strcasestr(eth_config, "model")) != NULL) sscanf(p, "%*[^=]=%15[^,]", eth_pin.model); if ((p = strcasestr(eth_config, "model")) != NULL) sscanf(p, "%*[^=]=%15[^,]", eth_pin.model);
if ((p = strcasestr(eth_config, "mdc")) != NULL) eth_pin.mdc = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "mdc")) != NULL) eth_pin.mdc = atoi(strchr(p, '=') + 1);
@@ -158,15 +158,32 @@ const eth_config_t * config_get_eth_from_str(char * eth_config ){
if ((p = strcasestr(eth_config, "speed")) != NULL) eth_pin.speed = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "speed")) != NULL) eth_pin.speed = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(eth_config, "clk")) != NULL) eth_pin.clk = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "clk")) != NULL) eth_pin.clk = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(eth_config, "host")) != NULL) eth_pin.host = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "host")) != NULL) eth_pin.host = atoi(strchr(p, '=') + 1);
eth_pin.valid = eth_pin.model && strlen(eth_pin.model)>0 && GPIO_IS_VALID_GPIO(eth_pin.mdio) && GPIO_IS_VALID_GPIO(eth_pin.mdc);
if(!eth_pin.model || strlen(eth_pin.model)==0){
if(strcasestr(eth_pin.model, "LAN8720")){ eth_pin.valid = false;
eth_pin.rmii = true; return &eth_pin;
} }
else { network_ethernet_driver_t* network_driver = network_ethernet_driver_autodetect(eth_pin.model);
eth_pin.spi = true; if(!network_driver || !network_driver->valid){
/* here we must also check that we have at least a CS gpio */ messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Ethernet config invalid: model %s %s",eth_pin.model,network_driver?"was not compiled in":"was not found");
eth_pin.valid = eth_pin.valid && GPIO_IS_VALID_GPIO(eth_pin.cs); eth_pin.valid = false;
}
if(network_driver){
eth_pin.rmii = network_driver->rmii;
eth_pin.spi = network_driver->spi;
if(network_driver->rmii){
if(!GPIO_IS_VALID_GPIO(eth_pin.mdio) || !GPIO_IS_VALID_GPIO(eth_pin.mdc)){
messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Ethernet config invalid: %s %s",!GPIO_IS_VALID_GPIO(eth_pin.mdc)?"Invalid MDC":"",!GPIO_IS_VALID_GPIO(eth_pin.mdio)?"Invalid mdio":"");
eth_pin.valid = false;
}
}
else if(network_driver->spi){
if(!GPIO_IS_VALID_GPIO(eth_pin.cs)){
messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Ethernet config invalid: invalid CS pin");
return false;
}
}
} }
return &eth_pin; return &eth_pin;
} }
@@ -216,10 +233,12 @@ const eth_config_t * config_eth_get( ){
#endif #endif
#endif #endif
",mdc=" STR(CONFIG_ETH_MDC_IO) ",mdio=" STR(CONFIG_ETH_MDIO_IO)) ; ",mdc=" STR(CONFIG_ETH_MDC_IO) ",mdio=" STR(CONFIG_ETH_MDIO_IO)) ;
if(config && strlen(config)>0){
ESP_LOGD(TAG,"Parsing ethernet configuration %s", config);
}
static EXT_RAM_ATTR eth_config_t eth_config; static EXT_RAM_ATTR eth_config_t eth_config;
ESP_LOGD(TAG, "Ethernet config string %s", config);
memcpy(&eth_config, config_get_eth_from_str(config), sizeof(eth_config)); memcpy(&eth_config, config_get_eth_from_str(config), sizeof(eth_config));
free(config); FREE_AND_NULL(config);
return &eth_config; return &eth_config;
} }
/**************************************************************************************** /****************************************************************************************
@@ -236,7 +255,7 @@ void config_eth_init( eth_config_t * target ){
esp_err_t config_i2c_set(const i2c_config_t * config, int port){ esp_err_t config_i2c_set(const i2c_config_t * config, int port){
int buffer_size=255; int buffer_size=255;
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
if(config_buffer) { if(config_buffer) {
snprintf(config_buffer,buffer_size,"scl=%u,sda=%u,speed=%u,port=%u",config->scl_io_num,config->sda_io_num,config->master.clk_speed,port); snprintf(config_buffer,buffer_size,"scl=%u,sda=%u,speed=%u,port=%u",config->scl_io_num,config->sda_io_num,config->master.clk_speed,port);
log_send_messaging(MESSAGING_INFO,"Updating I2C configuration to %s",config_buffer); log_send_messaging(MESSAGING_INFO,"Updating I2C configuration to %s",config_buffer);
@@ -255,8 +274,8 @@ esp_err_t config_i2c_set(const i2c_config_t * config, int port){
esp_err_t config_rotary_set(rotary_struct_t * config){ esp_err_t config_rotary_set(rotary_struct_t * config){
int buffer_size=512; int buffer_size=512;
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
char * config_buffer2=calloc(buffer_size,1); char * config_buffer2=malloc_init_external(buffer_size);
if(config_buffer && config_buffer2) { if(config_buffer && config_buffer2) {
snprintf(config_buffer,buffer_size,"A=%i,B=%i",config->A, config->B); snprintf(config_buffer,buffer_size,"A=%i,B=%i",config->A, config->B);
if(config->SW >=0 ){ if(config->SW >=0 ){
@@ -296,8 +315,8 @@ esp_err_t config_rotary_set(rotary_struct_t * config){
esp_err_t config_display_set(const display_config_t * config){ esp_err_t config_display_set(const display_config_t * config){
int buffer_size=512; int buffer_size=512;
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
char * config_buffer2=calloc(buffer_size,1); char * config_buffer2=malloc_init_external(buffer_size);
if(config_buffer && config_buffer2) { if(config_buffer && config_buffer2) {
snprintf(config_buffer,buffer_size,"%s,width=%i,height=%i",config->type,config->width,config->height); snprintf(config_buffer,buffer_size,"%s,width=%i,height=%i",config->type,config->width,config->height);
if(strcasecmp("I2C",config->type)==0){ if(strcasecmp("I2C",config->type)==0){
@@ -348,8 +367,8 @@ esp_err_t config_display_set(const display_config_t * config){
esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_name){ esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_name){
int buffer_size=255; int buffer_size=255;
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
char * config_buffer2=calloc(buffer_size,1); char * config_buffer2=malloc_init_external(buffer_size);
if(config_buffer && config_buffer2) { if(config_buffer && config_buffer2) {
snprintf(config_buffer,buffer_size,"model=%s,bck=%u,ws=%u,do=%u",config->model,config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num); snprintf(config_buffer,buffer_size,"model=%s,bck=%u,ws=%u,do=%u",config->model,config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num);
if(config->mute_gpio>=0){ if(config->mute_gpio>=0){
@@ -384,7 +403,7 @@ esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_
esp_err_t config_spdif_set(const i2s_platform_config_t * config){ esp_err_t config_spdif_set(const i2s_platform_config_t * config){
int buffer_size=255; int buffer_size=255;
esp_err_t err=ESP_OK; esp_err_t err=ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
if(config_buffer ) { if(config_buffer ) {
snprintf(config_buffer,buffer_size,"bck=%u,ws=%u,do=%u",config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num); snprintf(config_buffer,buffer_size,"bck=%u,ws=%u,do=%u",config->pin.bck_io_num,config->pin.ws_io_num,config->pin.data_out_num);
log_send_messaging(MESSAGING_INFO,"Updating SPDIF configuration to %s",config_buffer); log_send_messaging(MESSAGING_INFO,"Updating SPDIF configuration to %s",config_buffer);
@@ -406,7 +425,7 @@ esp_err_t config_spdif_set(const i2s_platform_config_t * config){
esp_err_t config_spi_set(const spi_bus_config_t * config, int host, int dc){ esp_err_t config_spi_set(const spi_bus_config_t * config, int host, int dc){
int buffer_size=255; int buffer_size=255;
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
char * config_buffer=calloc(buffer_size,1); char * config_buffer=malloc_init_external(buffer_size);
if(config_buffer) { if(config_buffer) {
snprintf(config_buffer,buffer_size,"data=%u,clk=%u,dc=%u,host=%u,miso=%d",config->mosi_io_num,config->sclk_io_num,dc,host,config->miso_io_num); snprintf(config_buffer,buffer_size,"data=%u,clk=%u,dc=%u,host=%u,miso=%d",config->mosi_io_num,config->sclk_io_num,dc,host,config->miso_io_num);
log_send_messaging(MESSAGING_INFO,"Updating SPI configuration to %s",config_buffer); log_send_messaging(MESSAGING_INFO,"Updating SPI configuration to %s",config_buffer);
@@ -855,7 +874,7 @@ cJSON * get_Rotary_GPIO(cJSON * list){
*/ */
esp_err_t get_gpio_structure(cJSON * gpio_entry, gpio_entry_t ** gpio){ esp_err_t get_gpio_structure(cJSON * gpio_entry, gpio_entry_t ** gpio){
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
*gpio = malloc(sizeof(gpio_entry_t)); *gpio = malloc_init_external(sizeof(gpio_entry_t));
cJSON * val = cJSON_GetObjectItem(gpio_entry,"gpio"); cJSON * val = cJSON_GetObjectItem(gpio_entry,"gpio");
if(val){ if(val){
(*gpio)->gpio= (int)val->valuedouble; (*gpio)->gpio= (int)val->valuedouble;
@@ -865,14 +884,14 @@ esp_err_t get_gpio_structure(cJSON * gpio_entry, gpio_entry_t ** gpio){
} }
val = cJSON_GetObjectItem(gpio_entry,"name"); val = cJSON_GetObjectItem(gpio_entry,"name");
if(val){ if(val){
(*gpio)->name= strdup(cJSON_GetStringValue(val)); (*gpio)->name= strdup_psram(cJSON_GetStringValue(val));
} else { } else {
ESP_LOGE(TAG,"gpio name value not found"); ESP_LOGE(TAG,"gpio name value not found");
err=ESP_FAIL; err=ESP_FAIL;
} }
val = cJSON_GetObjectItem(gpio_entry,"group"); val = cJSON_GetObjectItem(gpio_entry,"group");
if(val){ if(val){
(*gpio)->group= strdup(cJSON_GetStringValue(val)); (*gpio)->group= strdup_psram(cJSON_GetStringValue(val));
} else { } else {
ESP_LOGE(TAG,"gpio group value not found"); ESP_LOGE(TAG,"gpio group value not found");
err=ESP_FAIL; err=ESP_FAIL;

View File

@@ -12,6 +12,8 @@
#include "driver/i2c.h" #include "driver/i2c.h"
#include "driver/i2s.h" #include "driver/i2s.h"
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "freertos/queue.h"
extern const char *i2c_name_type; extern const char *i2c_name_type;
extern const char *spi_name_type; extern const char *spi_name_type;
typedef struct { typedef struct {
@@ -30,7 +32,7 @@ typedef struct {
bool rotate; bool rotate;
} display_config_t; } display_config_t;
typedef struct { typedef struct eth_config_struct {
char model[16]; char model[16];
bool valid; bool valid;
bool rmii; bool rmii;
@@ -98,6 +100,7 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host);
void parse_set_GPIO(void (*cb)(int gpio, char *value)); void parse_set_GPIO(void (*cb)(int gpio, char *value));
const i2s_platform_config_t * config_dac_get(); const i2s_platform_config_t * config_dac_get();
const i2s_platform_config_t * config_spdif_get( ); const i2s_platform_config_t * config_spdif_get( );
const i2s_platform_config_t * config_get_i2s_from_str(char * dac_config );
esp_err_t config_spdif_set(const i2s_platform_config_t * config); esp_err_t config_spdif_set(const i2s_platform_config_t * config);
bool is_spdif_config_locked(); bool is_spdif_config_locked();
esp_err_t free_gpio_entry( gpio_entry_t ** gpio); esp_err_t free_gpio_entry( gpio_entry_t ** gpio);

View File

@@ -21,7 +21,6 @@ typedef struct {
int timer, base_channel, max; int timer, base_channel, max;
} pwm_system_t; } pwm_system_t;
extern pwm_system_t pwm_system; extern pwm_system_t pwm_system;
#ifdef CONFIG_SQUEEZEAMP #ifdef CONFIG_SQUEEZEAMP
#define ADAC dac_tas57xx #define ADAC dac_tas57xx
#elif defined(CONFIG_A1S) #elif defined(CONFIG_A1S)
@@ -29,3 +28,6 @@ extern pwm_system_t pwm_system;
#else #else
#define ADAC dac_external #define ADAC dac_external
#endif #endif
void * malloc_init_external(size_t sz);
void * clone_obj_psram(void * source, size_t source_sz);
char * strdup_psram(const char * source);

View File

@@ -15,6 +15,7 @@
#include "platform_esp32.h" #include "platform_esp32.h"
#include "messaging.h" #include "messaging.h"
#include "trace.h" #include "trace.h"
#include "globdefs.h"
/************************************ /************************************
* Globals * Globals
*/ */
@@ -38,7 +39,7 @@ messaging_handle_t get_handle_ptr(messaging_list_t * handle){
RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){ RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){
RingbufHandle_t buf_handle = NULL; RingbufHandle_t buf_handle = NULL;
StaticRingbuffer_t *buffer_struct = malloc(sizeof(StaticRingbuffer_t)); StaticRingbuffer_t *buffer_struct = malloc_init_external(sizeof(StaticRingbuffer_t));
if (buffer_struct != NULL) { if (buffer_struct != NULL) {
size_t buf_size = (size_t )(sizeof(single_message_t)+8+MSG_LENGTH_AVG)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes size_t buf_size = (size_t )(sizeof(single_message_t)+8+MSG_LENGTH_AVG)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes
buf_size = buf_size - (buf_size % 4); buf_size = buf_size - (buf_size % 4);
@@ -76,7 +77,7 @@ messaging_handle_t messaging_register_subscriber(uint8_t max_count, char * name)
while(cur->next){ while(cur->next){
cur = get_struct_ptr(cur->next); cur = get_struct_ptr(cur->next);
} }
cur->next=heap_caps_malloc(sizeof(messaging_list_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); cur->next=malloc_init_external(sizeof(messaging_list_t));
if(!cur->next){ if(!cur->next){
ESP_LOGE(tag,"subscriber alloc failed"); ESP_LOGE(tag,"subscriber alloc failed");
return NULL; return NULL;
@@ -84,7 +85,7 @@ messaging_handle_t messaging_register_subscriber(uint8_t max_count, char * name)
memset(cur->next,0x00,sizeof(messaging_list_t)); memset(cur->next,0x00,sizeof(messaging_list_t));
cur = get_struct_ptr(cur->next); cur = get_struct_ptr(cur->next);
cur->max_count=max_count; cur->max_count=max_count;
cur->subscriber_name=strdup(name); cur->subscriber_name=strdup_psram(name);
cur->buf_handle = messaging_create_ring_buffer(max_count); cur->buf_handle = messaging_create_ring_buffer(max_count);
if(cur->buf_handle){ if(cur->buf_handle){
messaging_fill_messages(cur); messaging_fill_messages(cur);
@@ -99,7 +100,7 @@ void messaging_service_init(){
} }
else { else {
top.max_count = max_count; top.max_count = max_count;
top.subscriber_name = strdup("messaging"); top.subscriber_name = strdup_psram("messaging");
} }
return; return;
} }
@@ -161,10 +162,7 @@ single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle){
vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting);
if(uxItemsWaiting>0){ if(uxItemsWaiting>0){
message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50)); message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50));
message_copy = heap_caps_malloc(item_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); message_copy = clone_obj_psram(message,item_size);
if(message_copy){
memcpy(message_copy,message,item_size);
}
vRingbufferReturnItem(buf_handle, (void *)message); vRingbufferReturnItem(buf_handle, (void *)message);
} }
return message_copy; return message_copy;
@@ -231,7 +229,7 @@ void messaging_post_message(messaging_types type,messaging_classes msg_class, co
va_start(va, fmt); va_start(va, fmt);
ln = vsnprintf(NULL, 0, fmt, va)+1; ln = vsnprintf(NULL, 0, fmt, va)+1;
msg_size = sizeof(single_message_t)+ln; msg_size = sizeof(single_message_t)+ln;
message = (single_message_t *)heap_caps_malloc(msg_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); message = (single_message_t *)malloc_init_external(msg_size);
vsprintf(message->message, fmt, va); vsprintf(message->message, fmt, va);
va_end(va); va_end(va);
message->msg_size = msg_size; message->msg_size = msg_size;
@@ -256,11 +254,25 @@ void messaging_post_message(messaging_types type,messaging_classes msg_class, co
return; return;
} }
char * messaging_alloc_format_string(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
char * message_txt = malloc_init_external(ln);
if(message_txt){
vsprintf(message_txt, fmt, va);
va_end(va);
}
else{
ESP_LOGE(tag, "Memory allocation failed while sending message");
}
return message_txt;
}
void log_send_messaging(messaging_types msgtype,const char *fmt, ...) { void log_send_messaging(messaging_types msgtype,const char *fmt, ...) {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
size_t ln = vsnprintf(NULL, 0, fmt, va)+1; size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
char * message_txt = malloc(ln); char * message_txt = malloc_init_external(ln);
if(message_txt){ if(message_txt){
vsprintf(message_txt, fmt, va); vsprintf(message_txt, fmt, va);
va_end(va); va_end(va);
@@ -272,12 +284,13 @@ void log_send_messaging(messaging_types msgtype,const char *fmt, ...) {
ESP_LOGE(tag, "Memory allocation failed while sending message"); ESP_LOGE(tag, "Memory allocation failed while sending message");
} }
} }
void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...){ void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...){
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
size_t cmd_len = strlen(cmdname)+1; size_t cmd_len = strlen(cmdname)+1;
size_t ln = vsnprintf(NULL, 0, fmt, va)+1; size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
char * message_txt = malloc(ln+cmd_len); char * message_txt = malloc_init_external(ln+cmd_len);
if(message_txt){ if(message_txt){
strcpy(message_txt,cmdname); strcpy(message_txt,cmdname);
strcat(message_txt,"\n"); strcat(message_txt,"\n");

View File

@@ -39,6 +39,7 @@ single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle);
void log_send_messaging(messaging_types msgtype,const char *fmt, ...); void log_send_messaging(messaging_types msgtype,const char *fmt, ...);
void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...); void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...);
esp_err_t messaging_type_to_err_type(messaging_types type); esp_err_t messaging_type_to_err_type(messaging_types type);
char * messaging_alloc_format_string(const char *fmt, ...) ;
void messaging_service_init(); void messaging_service_init();
#define REALLOC_CAT(e,n) e=realloc(e,strlen(n)); e=strcat(e,n) #define REALLOC_CAT(e,n) e=realloc(e,strlen(n)); e=strcat(e,n)

View File

@@ -54,7 +54,7 @@ static void task_stats( cJSON* top ) {
} current, previous; } current, previous;
cJSON * tlist=cJSON_CreateArray(); cJSON * tlist=cJSON_CreateArray();
current.n = uxTaskGetNumberOfTasks(); current.n = uxTaskGetNumberOfTasks();
current.tasks = malloc( current.n * sizeof( TaskStatus_t ) ); current.tasks = malloc_init_external( current.n * sizeof( TaskStatus_t ) );
current.n = uxTaskGetSystemState( current.tasks, current.n, &current.total ); current.n = uxTaskGetSystemState( current.tasks, current.n, &current.total );
cJSON_AddNumberToObject(top,"ntasks",current.n); cJSON_AddNumberToObject(top,"ntasks",current.n);
@@ -126,11 +126,13 @@ static void monitor_callback(TimerHandle_t xTimer) {
cJSON_AddNumberToObject(top,"free_spiram",heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); cJSON_AddNumberToObject(top,"free_spiram",heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
cJSON_AddNumberToObject(top,"min_free_spiram",heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); cJSON_AddNumberToObject(top,"min_free_spiram",heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu)", ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
task_stats(top); task_stats(top);
char * top_a= cJSON_PrintUnformatted(top); char * top_a= cJSON_PrintUnformatted(top);
@@ -248,11 +250,13 @@ void monitor_svc_init(void) {
} }
FREE_AND_NULL(p); FREE_AND_NULL(p);
ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu)", ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
} }
/**************************************************************************************** /****************************************************************************************

View File

@@ -18,6 +18,9 @@
#include "globdefs.h" #include "globdefs.h"
#include "accessors.h" #include "accessors.h"
#include "messaging.h" #include "messaging.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
extern void battery_svc_init(void); extern void battery_svc_init(void);
extern void monitor_svc_init(void); extern void monitor_svc_init(void);
@@ -35,6 +38,43 @@ pwm_system_t pwm_system = {
static const char *TAG = "services"; static const char *TAG = "services";
void * malloc_init_external(size_t sz){
void * ptr=NULL;
ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if(ptr==NULL){
ESP_LOGE(TAG,"malloc_init_external: unable to allocate %d bytes of PSRAM!",sz);
}
else {
memset(ptr,0x00,sz);
}
return ptr;
}
void * clone_obj_psram(void * source, size_t source_sz){
void * ptr=NULL;
ptr = heap_caps_malloc(source_sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if(ptr==NULL){
ESP_LOGE(TAG,"clone_obj_psram: unable to allocate %d bytes of PSRAM!",source_sz);
}
else {
memcpy(ptr,source,source_sz);
}
return ptr;
}
char * strdup_psram(const char * source){
void * ptr=NULL;
size_t source_sz = strlen(source)+1;
ptr = heap_caps_malloc(source_sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if(ptr==NULL){
ESP_LOGE(TAG,"strdup_psram: unable to allocate %d bytes of PSRAM! Cannot clone string %s",source_sz,source);
}
else {
memset(ptr,0x00,source_sz);
strcpy(ptr,source);
}
return ptr;
}
/**************************************************************************************** /****************************************************************************************
* *
*/ */

View File

@@ -38,7 +38,7 @@
#include "gds_draw.h" #include "gds_draw.h"
#include "platform_esp32.h" #include "platform_esp32.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
#include "globdefs.h"
extern const char * get_certificate(); extern const char * get_certificate();
#define IF_DISPLAY(x) if(display) { x; } #define IF_DISPLAY(x) if(display) { x; }
@@ -95,11 +95,13 @@ static esp_http_client_config_t http_client_config;
void _printMemStats(){ void _printMemStats(){
ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)", ESP_LOGD(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
} }
uint8_t ota_get_pct_complete(){ uint8_t ota_get_pct_complete(){
return ota_status->total_image_len==0?0: return ota_status->total_image_len==0?0:
@@ -183,7 +185,7 @@ void sendMessaging(messaging_types type,const char * fmt, ...){
va_start(args, fmt); va_start(args, fmt);
str_len = vsnprintf(NULL,0,fmt,args)+1; str_len = vsnprintf(NULL,0,fmt,args)+1;
if(str_len>0){ if(str_len>0){
msg_str = malloc(str_len); msg_str = malloc_init_external(str_len);
vsnprintf(msg_str,str_len,fmt,args); vsnprintf(msg_str,str_len,fmt,args);
if(type == MESSAGING_WARNING){ if(type == MESSAGING_WARNING){
ESP_LOGW(TAG,"%s",msg_str); ESP_LOGW(TAG,"%s",msg_str);
@@ -237,7 +239,7 @@ esp_err_t handle_http_on_data(esp_http_client_event_t *evt){
ota_status->total_image_len=esp_http_client_get_content_length(evt->client); ota_status->total_image_len=esp_http_client_get_content_length(evt->client);
ota_status->downloaded_image_len = 0; ota_status->downloaded_image_len = 0;
ota_status->newdownloadpct = 0; ota_status->newdownloadpct = 0;
ota_status->bin_data= malloc(ota_status->total_image_len); ota_status->bin_data= malloc_init_external(ota_status->total_image_len);
if(ota_status->bin_data==NULL){ if(ota_status->bin_data==NULL){
sendMessaging(MESSAGING_ERROR,"Error: buffer alloc error"); sendMessaging(MESSAGING_ERROR,"Error: buffer alloc error");
return ESP_FAIL; return ESP_FAIL;
@@ -351,7 +353,7 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){
http_client_config.event_handler = _http_event_handler; http_client_config.event_handler = _http_event_handler;
http_client_config.disable_auto_redirect=false; http_client_config.disable_auto_redirect=false;
http_client_config.skip_cert_common_name_check = false; http_client_config.skip_cert_common_name_check = false;
http_client_config.url = strdup(p_ota_thread_parms->url); http_client_config.url = strdup_psram(p_ota_thread_parms->url);
http_client_config.max_redirection_count = 4; http_client_config.max_redirection_count = 4;
// buffer size below is for http read chunks // buffer size below is for http read chunks
http_client_config.buffer_size = 8192; //1024 ; http_client_config.buffer_size = 8192; //1024 ;
@@ -680,12 +682,11 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t
ESP_LOGE(TAG,"OTA Already started. "); ESP_LOGE(TAG,"OTA Already started. ");
return ESP_FAIL; return ESP_FAIL;
} }
ota_status = heap_caps_malloc(sizeof(ota_status_t) , (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); ota_status = malloc_init_external(sizeof(ota_status_t));
memset(ota_status, 0x00, sizeof(ota_status_t));
ota_status->bOTAThreadStarted=true; ota_status->bOTAThreadStarted=true;
if(bin_url){ if(bin_url){
ota_thread_parms.url =strdup(bin_url); ota_thread_parms.url =strdup_psram(bin_url);
ESP_LOGD(TAG, "Starting ota on core %u for : %s", OTA_CORE,ota_thread_parms.url); ESP_LOGD(TAG, "Starting ota on core %u for : %s", OTA_CORE,ota_thread_parms.url);
} }
else { else {
@@ -751,7 +752,7 @@ in_addr_t discover_ota_server(int max) {
do { do {
ESP_LOGI(TAG,"sending LMS discovery"); ESP_LOGI(TAG,"sending LMS discovery for OTA Update");
memset(&s, 0, sizeof(s)); memset(&s, 0, sizeof(s));
if (sendto(disc_sock, buf, len, 0, (struct sockaddr *)&d, sizeof(d)) < 0) { if (sendto(disc_sock, buf, len, 0, (struct sockaddr *)&d, sizeof(d)) < 0) {

View File

@@ -58,7 +58,7 @@ static size_t log_buf_size=2000; //32-bit aligned size
static bool bIsEnabled=false; static bool bIsEnabled=false;
static int partnerSocket=0; static int partnerSocket=0;
static telnet_t *tnHandle; static telnet_t *tnHandle;
extern bool bypass_wifi_manager; extern bool bypass_network_manager;
/************************************ /************************************
* Forward declarations * Forward declarations
@@ -92,7 +92,7 @@ void init_telnet(){
// if wifi manager is bypassed, there will possibly be no wifi available // if wifi manager is bypassed, there will possibly be no wifi available
// //
bMirrorToUART = (strcasestr("D",val)!=NULL); bMirrorToUART = (strcasestr("D",val)!=NULL);
if(!bMirrorToUART && bypass_wifi_manager){ if(!bMirrorToUART && bypass_network_manager){
// This isn't supposed to happen, as telnet won't start if wifi manager isn't // This isn't supposed to happen, as telnet won't start if wifi manager isn't
// started. So this is a safeguard only. // started. So this is a safeguard only.
ESP_LOGW(TAG,"Wifi manager is not active. Forcing console on Serial output."); ESP_LOGW(TAG,"Wifi manager is not active. Forcing console on Serial output.");

View File

@@ -1,6 +1,7 @@
idf_component_register(SRCS operator.cpp utf8.c idf_component_register(SRCS operator.cpp utf8.c trace.c
REQUIRES esp_common pthread REQUIRES esp_common pthread
INCLUDE_DIRS . INCLUDE_DIRS .
PRIV_REQUIRES services freertos pthread esp_common
) )
#doing our own implementation of new operator for some pre-compiled binaries #doing our own implementation of new operator for some pre-compiled binaries

120
components/tools/trace.c Normal file
View File

@@ -0,0 +1,120 @@
#include <stdint.h>
#include "esp_system.h"
#include <string.h>
#include <stdbool.h>
#include "esp_log.h"
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "globdefs.h"
#include "esp_event.h"
#include "trace.h"
static const char TAG[] = "TRACE";
// typedef struct mem_usage_trace_for_thread {
// TaskHandle_t task;
// size_t malloc_int_last;
// size_t malloc_spiram_last;
// size_t malloc_dma_last;
// const char *name;
// SLIST_ENTRY(mem_usage_trace_for_thread) next;
// } mem_usage_trace_for_thread_t;
// static EXT_RAM_ATTR SLIST_HEAD(memtrace, mem_usage_trace_for_thread) s_memtrace;
// mem_usage_trace_for_thread_t* memtrace_get_thread_entry(TaskHandle_t task) {
// if(!task) {
// ESP_LOGE(TAG, "memtrace_get_thread_entry: task is NULL");
// return NULL;
// }
// ESP_LOGD(TAG,"Looking for task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
// mem_usage_trace_for_thread_t* it;
// SLIST_FOREACH(it, &s_memtrace, next) {
// if ( it->task == task ) {
// ESP_LOGD(TAG,"Found task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
// return it;
// }
// }
// return NULL;
// }
// void memtrace_add_thread_entry(TaskHandle_t task) {
// if(!task) {
// ESP_LOGE(TAG, "memtrace_get_thread_entry: task is NULL");
// return ;
// }
// mem_usage_trace_for_thread_t* it = memtrace_get_thread_entry(task);
// if (it) {
// ESP_LOGW(TAG, "memtrace_add_thread_entry: thread already in list");
// return;
// }
// it = (mem_usage_trace_for_thread_t*)malloc_init_external(sizeof(mem_usage_trace_for_thread_t));
// if (!it) {
// ESP_LOGE(TAG, "memtrace_add_thread_entry: malloc failed");
// return;
// }
// it->task = task;
// it->malloc_int_last = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
// it->malloc_spiram_last = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
// it->malloc_dma_last = heap_caps_get_free_size(MALLOC_CAP_DMA);
// it->name = pcTaskGetName(task);
// SLIST_INSERT_HEAD(&s_memtrace, it, next);
// return;
// }
// void memtrace_print_delta(){
// TaskHandle_t task = xTaskGetCurrentTaskHandle();
// mem_usage_trace_for_thread_t* it = memtrace_get_thread_entry(task);
// if (!it) {
// memtrace_add_thread_entry(task);
// ESP_LOGW(TAG, "memtrace_print_delta: added new entry for task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
// return;
// }
// size_t malloc_int_delta = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) - it->malloc_int_last;
// size_t malloc_spiram_delta = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) - it->malloc_spiram_last;
// size_t malloc_dma_delta = heap_caps_get_free_size(MALLOC_CAP_DMA) - it->malloc_dma_last;
// ESP_LOG(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
// heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
// heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
// heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
// heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
// heap_caps_get_free_size(MALLOC_CAP_DMA),
// heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
// ESP_LOGW(TAG, "memtrace_print_delta: %s: malloc_int_delta=%d, malloc_spiram_delta=%d, malloc_dma_delta=%d",
// STR_OR_ALT(it->name, "unknown"),
// malloc_int_delta,
// malloc_spiram_delta,
// malloc_dma_delta);
// it->malloc_int_last = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
// it->malloc_spiram_last = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
// it->malloc_dma_last = heap_caps_get_free_size(MALLOC_CAP_DMA);
// }
size_t malloc_int = 0;
size_t malloc_spiram =0;
size_t malloc_dma = 0;
void memtrace_print_delta(const char * msg, const char * tag, const char * function){
size_t malloc_int_delta = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) - malloc_int;
size_t malloc_spiram_delta = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) - malloc_spiram;
size_t malloc_dma_delta = heap_caps_get_free_size(MALLOC_CAP_DMA) - malloc_dma;
ESP_LOGW(TAG, "Heap internal:%zu (min:%zu)(chg:%d)/external:%zu (min:%zu)(chg:%d)/dma:%zu (min:%zu)(chg:%d) : %s%s%s%s%s",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
malloc_int_delta,
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
malloc_spiram_delta,
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA),
malloc_dma_delta,
STR_OR_BLANK(tag),
tag?" ":"",
STR_OR_BLANK(function),
function?" ":"",
STR_OR_BLANK(msg)
);
malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
malloc_dma = heap_caps_get_free_size(MALLOC_CAP_DMA);
}

View File

@@ -21,6 +21,9 @@
#ifndef STR_OR_ALT #ifndef STR_OR_ALT
#define STR_OR_ALT(str,alt) (str?str:alt) #define STR_OR_ALT(str,alt) (str?str:alt)
#endif #endif
#ifndef STR_OR_BLANK
#define STR_OR_BLANK(p) p == NULL ? "" : p
#endif
#define ENUM_TO_STRING(g) \ #define ENUM_TO_STRING(g) \
case g: \ case g: \
return STR(g); \ return STR(g); \
@@ -28,6 +31,14 @@
extern const char unknown_string_placeholder[]; extern const char unknown_string_placeholder[];
extern const char * str_or_unknown(const char * str); extern const char * str_or_unknown(const char * str);
extern const char * str_or_null(const char * str); extern const char * str_or_null(const char * str);
void memtrace_print_delta(const char * msg, const char * TAG, const char * function);
#ifdef ENABLE_MEMTRACE
#define MEMTRACE_PRINT_DELTA() memtrace_print_delta(NULL,TAG,__FUNCTION__);
#define MEMTRACE_PRINT_DELTA_MESSAGE(x) memtrace_print_delta(x,TAG,__FUNCTION__);
#else
#define MEMTRACE_PRINT_DELTA()
#define MEMTRACE_PRINT_DELTA_MESSAGE(x) ESP_LOGD(TAG,"%s",x);
#endif
#ifndef FREE_AND_NULL #ifndef FREE_AND_NULL
#define FREE_AND_NULL(x) if(x) { free(x); x=NULL; } #define FREE_AND_NULL(x) if(x) { free(x); x=NULL; }

View File

@@ -1,9 +1,9 @@
set( WEBPACK_DIR webapp/webpack/dist ) set( WEBPACK_DIR webapp/webpack/dist )
idf_component_register( SRC_DIRS . webapp idf_component_register( SRC_DIRS . webapp UML-State-Machine-in-C/src
INCLUDE_DIRS . webapp ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/ INCLUDE_DIRS . webapp UML-State-Machine-in-C/src ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/
REQUIRES squeezelite-ota json mdns REQUIRES squeezelite-ota json mdns
PRIV_REQUIRES tools cpp-stateless services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt PRIV_REQUIRES tools services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt
) )

View File

@@ -1,41 +0,0 @@
# What is esp32-wifi-manager?
*esp32-wifi-manager* is an esp32 program that enables easy management of wifi networks through a web application.
*esp32-wifi-manager* is **lightweight** (8KB of task stack in total) and barely uses any CPU power through a completely event driven architecture. It's an all in one wifi scanner, http server & dns daemon living in the least amount of RAM possible.
For real time constrained applications, *esp32-wifi-manager* can live entirely on PRO CPU, leaving the entire APP CPU untouched for your own needs.
*esp32-wifi-manager* will automatically attempt to re-connect to a previously saved network on boot, and it will start its own wifi access point through which you can manage wifi networks if a saved network cannot be found and/or if the connection is lost.
*esp32-wifi-manager* is an esp-idf project that compiles successfully with the esp-idf 3.2 release. You can simply copy the project and start adding your own code to it.
# Demo
[![esp32-wifi-manager demo](http://img.youtube.com/vi/hxlZi15bym4/0.jpg)](http://www.youtube.com/watch?v=hxlZi15bym4)
# Look and Feel
![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-password.png "esp32-wifi-manager") ![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-connected-to.png "esp32-wifi-manager")
# Adding esp32-wifi-manager to your code
Ther are effectively three different ways you can embed esp32-wifi-manager with your code:
* Just forget about it and poll in your code for wifi connectivity status
* Use event callbacks
* Modify esp32-wifi-manager code directly to fit your needs
**Event callbacks** are the cleanest way to use the wifi manager and that's the recommended way to do it. A typical use-case would be to get notified when wifi manager finally gets a connection an access point. In order to do this you can simply define a callback function:
```c
void cb_connection_ok(void *pvParameter){
ESP_LOGI(TAG, "I have a connection!");
}
```
Then just register it by calling:
```c
wifi_manager_set_callback(EVENT_STA_GOT_IP, &cb_connection_ok);
```
That's it! Now everytime the event is triggered it will call this function.
# License
*esp32-wifi-manager* is MIT licensed. As such, it can be included in any project, commercial or not, as long as you retain original copyright. Please make sure to read the license file.

Submodule components/wifi-manager/UML-State-Machine-in-C added at 96264241ad

View File

@@ -24,6 +24,7 @@
#include <_esp_http_server.h> #include <_esp_http_server.h>
#include "esp_httpd_priv.h" #include "esp_httpd_priv.h"
#include "ctrl_sock.h" #include "ctrl_sock.h"
#include "globdefs.h"
static const char *TAG = "_httpd"; static const char *TAG = "_httpd";
@@ -269,18 +270,18 @@ static void _httpd_thread(void *arg)
static struct httpd_data *__httpd_create(const httpd_config_t *config) static struct httpd_data *__httpd_create(const httpd_config_t *config)
{ {
/* Allocate memory for httpd instance data */ /* Allocate memory for httpd instance data */
struct httpd_data *hd = calloc(1, sizeof(struct httpd_data)); struct httpd_data *hd = malloc_init_external(sizeof(struct httpd_data));
if (!hd) { if (!hd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance")); ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
return NULL; return NULL;
} }
hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *)); hd->hd_calls = malloc_init_external(config->max_uri_handlers* sizeof(httpd_uri_t *));
if (!hd->hd_calls) { if (!hd->hd_calls) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers")); ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
free(hd); free(hd);
return NULL; return NULL;
} }
hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db)); hd->hd_sd = malloc_init_external(config->max_open_sockets* sizeof(struct sock_db));
if (!hd->hd_sd) { if (!hd->hd_sd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data")); ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
free(hd->hd_calls); free(hd->hd_calls);
@@ -288,7 +289,7 @@ static struct httpd_data *__httpd_create(const httpd_config_t *config)
return NULL; return NULL;
} }
struct httpd_req_aux *ra = &hd->hd_req_aux; struct httpd_req_aux *ra = &hd->hd_req_aux;
ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr)); ra->resp_hdrs = malloc_init_external(config->max_resp_headers* sizeof(struct resp_hdr));
if (!ra->resp_hdrs) { if (!ra->resp_hdrs) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers")); ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
free(hd->hd_sd); free(hd->hd_sd);
@@ -296,7 +297,7 @@ static struct httpd_data *__httpd_create(const httpd_config_t *config)
free(hd); free(hd);
return NULL; return NULL;
} }
hd->err_handler_fns = calloc(HTTPD_ERR_CODE_MAX, sizeof(httpd_err_handler_func_t)); hd->err_handler_fns = malloc_init_external(HTTPD_ERR_CODE_MAX* sizeof(httpd_err_handler_func_t));
if (!hd->err_handler_fns) { if (!hd->err_handler_fns) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers")); ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
free(ra->resp_hdrs); free(ra->resp_hdrs);

View File

@@ -59,8 +59,8 @@ static const char TAG[] = "dns_server";
static TaskHandle_t task_dns_server = NULL; static TaskHandle_t task_dns_server = NULL;
int socket_fd; int socket_fd;
void dns_server_start() { void dns_server_start(esp_netif_t * netif) {
xTaskCreate(&dns_server, "dns_server", 3072, NULL, WIFI_MANAGER_TASK_PRIORITY-1, &task_dns_server); xTaskCreate(&dns_server, "dns_server", 3072, (void *)netif, WIFI_MANAGER_TASK_PRIORITY-1, &task_dns_server);
} }
void dns_server_stop(){ void dns_server_stop(){
@@ -75,7 +75,8 @@ void dns_server_stop(){
void dns_server(void *pvParameters) { void dns_server(void *pvParameters) {
struct sockaddr_in sa, ra; struct sockaddr_in sa, ra;
esp_err_t esp_err = ESP_OK;
esp_netif_t * netif = (esp_netif_t * )pvParameters;
/* Set redirection DNS hijack to the access point IP */ /* Set redirection DNS hijack to the access point IP */
ip4_addr_t ip_resolved; ip4_addr_t ip_resolved;
inet_pton(AF_INET, DEFAULT_AP_IP, &ip_resolved); inet_pton(AF_INET, DEFAULT_AP_IP, &ip_resolved);
@@ -90,10 +91,14 @@ void dns_server(void *pvParameters) {
memset(&sa, 0, sizeof(struct sockaddr_in)); memset(&sa, 0, sizeof(struct sockaddr_in));
/* Bind to port 53 (typical DNS Server port) */ /* Bind to port 53 (typical DNS Server port) */
tcpip_adapter_ip_info_t ip; esp_netif_ip_info_t ip_info;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip); esp_err = esp_netif_get_ip_info(netif,&ip_info);
if(esp_err!=ESP_OK) {
ESP_LOGE(TAG, "Failed to get adapter info for udp: %s", esp_err_to_name(esp_err));
exit(1);
}
ra.sin_family = AF_INET; ra.sin_family = AF_INET;
ra.sin_addr.s_addr = ip.ip.addr; ra.sin_addr.s_addr = ip_info.ip.addr;
ra.sin_port = htons(53); ra.sin_port = htons(53);
if (bind(socket_fd, (struct sockaddr *)&ra, sizeof(struct sockaddr_in)) == -1) { if (bind(socket_fd, (struct sockaddr *)&ra, sizeof(struct sockaddr_in)) == -1) {
ESP_LOGE(TAG, "Failed to bind to 53/udp"); ESP_LOGE(TAG, "Failed to bind to 53/udp");
@@ -149,7 +154,7 @@ void dns_server(void *pvParameters) {
for(char* c=domain; *c != '\0'; c++){ for(char* c=domain; *c != '\0'; c++){
if(*c < ' ' || *c > 'z') *c = '.'; /* technically we should test if the first two bits are 00 (e.g. if( (*c & 0xC0) == 0x00) *c = '.') but this makes the code a lot more readable */ if(*c < ' ' || *c > 'z') *c = '.'; /* technically we should test if the first two bits are 00 (e.g. if( (*c & 0xC0) == 0x00) *c = '.') but this makes the code a lot more readable */
} }
ESP_LOGI(TAG, "Replying to DNS request for %s from %s", domain, ip_address); ESP_LOGD(TAG, "Replying to DNS request for %s from %s", domain, ip_address);
/* create DNS answer at the end of the query*/ /* create DNS answer at the end of the query*/

View File

@@ -35,6 +35,7 @@ Contains the freeRTOS task for the DNS server that processes the requests.
#include <esp_system.h> #include <esp_system.h>
#include <stdbool.h> #include <stdbool.h>
#include "squeezelite-ota.h" #include "squeezelite-ota.h"
#include "esp_netif.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -128,7 +129,7 @@ typedef struct __attribute__((__packed__)) dns_answer_t{
}dns_answer_t; }dns_answer_t;
void dns_server(void *pvParameters); void dns_server(void *pvParameters);
void dns_server_start(); void dns_server_start(esp_netif_t * netif);
void dns_server_stop(); void dns_server_stop();

View File

@@ -1,34 +1,5 @@
/* /*
Copyright (c) 2017-2019 Tony Pottier Copyright (c) 2017-2021 Sebastien L
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file http_server.c
@author Tony Pottier
@brief Defines all functions necessary for the HTTP server to run.
Contains the freeRTOS task for the HTTP listener and all necessary support
function to process requests, decode URLs, serve files, etc. etc.
@note http_server task cannot run without the wifi_manager task!
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
*/ */
#include "http_server_handlers.h" #include "http_server_handlers.h"
@@ -57,7 +28,8 @@ function to process requests, decode URLs, serve files, etc. etc.
#include "webapp/webpack.h" #include "webapp/webpack.h"
#include "network_wifi.h" #include "network_wifi.h"
#include "network_status.h" #include "network_status.h"
#include "globdefs.h"
#define HTTP_STACK_SIZE (5*1024) #define HTTP_STACK_SIZE (5*1024)
const char str_na[]="N/A"; const char str_na[]="N/A";
#define STR_OR_NA(s) s?s:str_na #define STR_OR_NA(s) s?s:str_na
@@ -104,7 +76,7 @@ char * alloc_get_http_header(httpd_req_t * req, const char * key){
* extra byte for null termination */ * extra byte for null termination */
buf_len = httpd_req_get_hdr_value_len(req, key) + 1; buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
if (buf_len > 1) { if (buf_len > 1) {
buf = malloc(buf_len); buf = malloc_init_external(buf_len);
/* Copy null terminated value string into buffer */ /* Copy null terminated value string into buffer */
if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) { if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
ESP_LOGD_LOC(TAG, "Found header => %s: %s",key, buf); ESP_LOGD_LOC(TAG, "Found header => %s: %s",key, buf);
@@ -120,16 +92,14 @@ char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * p
union sockaddr_aligned addr; union sockaddr_aligned addr;
len = sizeof(addr); len = sizeof(addr);
ip_addr_t * ip_addr=NULL; ip_addr_t * ip_addr=NULL;
char * ipstr = malloc(INET6_ADDRSTRLEN); char * ipstr = malloc_init_external(INET6_ADDRSTRLEN);
memset(ipstr,0x0,INET6_ADDRSTRLEN);
typedef int (*getaddrname_fn_t)(int s, struct sockaddr *name, socklen_t *namelen); typedef int (*getaddrname_fn_t)(int s, struct sockaddr *name, socklen_t *namelen);
getaddrname_fn_t get_addr = NULL; getaddrname_fn_t get_addr = NULL;
int s = httpd_req_to_sockfd(req); int s = httpd_req_to_sockfd(req);
if(s == -1) { if(s == -1) {
free(ipstr); free(ipstr);
return strdup("httpd_req_to_sockfd error"); return strdup_psram("httpd_req_to_sockfd error");
} }
ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s); ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s);
@@ -192,7 +162,7 @@ bool is_captive_portal_host_name(httpd_req_t *req){
ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name);
} }
ap_ip_address = malloc(IP4ADDR_STRLEN_MAX); ap_ip_address = malloc_init_external(IP4ADDR_STRLEN_MAX);
memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX); memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX);
if(ap_ip_address){ if(ap_ip_address){
ESP_LOGD_LOC(TAG, "Converting soft ip address to string"); ESP_LOGD_LOC(TAG, "Converting soft ip address to string");
@@ -233,8 +203,7 @@ session_context_t* get_session_context(httpd_req_t *req){
bool newConnection=false; bool newConnection=false;
if (! req->sess_ctx) { if (! req->sess_ctx) {
ESP_LOGD(TAG,"New connection context. Allocating session buffer"); ESP_LOGD(TAG,"New connection context. Allocating session buffer");
req->sess_ctx = malloc(sizeof(session_context_t)); req->sess_ctx = malloc_init_external(sizeof(session_context_t));
memset(req->sess_ctx,0x00,sizeof(session_context_t));
req->free_ctx = free_ctx_func; req->free_ctx = free_ctx_func;
newConnection = true; newConnection = true;
// get the remote IP address only once per session // get the remote IP address only once per session
@@ -256,11 +225,13 @@ bool is_user_authenticated(httpd_req_t *req){
return true; return true;
} }
ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)", ESP_LOGD(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
// todo: ask for user to authenticate // todo: ask for user to authenticate
return false; return false;
@@ -439,7 +410,7 @@ esp_err_t ap_scan_handler(httpd_req_t *req){
// todo: redirect to login page // todo: redirect to login page
// return ESP_OK; // return ESP_OK;
} }
network_manager_async_scan(); network_async_scan();
esp_err_t err = set_content_type_from_req(req); esp_err_t err = set_content_type_from_req(req);
if(err == ESP_OK){ if(err == ESP_OK){
httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN); httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN);
@@ -529,9 +500,9 @@ esp_err_t ap_get_handler(httpd_req_t *req){
} }
/* if we can get the mutex, write the last version of the AP list */ /* if we can get the mutex, write the last version of the AP list */
esp_err_t err = set_content_type_from_req(req); esp_err_t err = set_content_type_from_req(req);
if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){ if( err == ESP_OK && network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){
char *buff = wifi_manager_alloc_get_ap_list_json(); char *buff = network_status_alloc_get_ap_list_json();
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
if(buff!=NULL){ if(buff!=NULL){
httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN); httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN);
free(buff); free(buff);
@@ -683,7 +654,7 @@ esp_err_t config_post_handler(httpd_req_t *req){
else { else {
// we're getting a request to do an OTA from that URL // we're getting a request to do an OTA from that URL
ESP_LOGW_LOC(TAG, "Found OTA request!"); ESP_LOGW_LOC(TAG, "Found OTA request!");
otaURL=strdup(val); otaURL=strdup_psram(val);
bOTA=true; bOTA=true;
} }
} }
@@ -730,7 +701,7 @@ esp_err_t config_post_handler(httpd_req_t *req){
ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL); ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL);
} }
network_manager_reboot_ota(otaURL); network_reboot_ota(otaURL);
free(otaURL); free(otaURL);
} }
return err; return err;
@@ -766,15 +737,15 @@ esp_err_t connect_post_handler(httpd_req_t *req){
cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid"); cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid");
if(ssid_object !=NULL){ if(ssid_object !=NULL){
ssid = strdup(ssid_object->valuestring); ssid = strdup_psram(ssid_object->valuestring);
} }
cJSON * password_object = cJSON_GetObjectItem(root, "pwd"); cJSON * password_object = cJSON_GetObjectItem(root, "pwd");
if(password_object !=NULL){ if(password_object !=NULL){
password = strdup(password_object->valuestring); password = strdup_psram(password_object->valuestring);
} }
cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name"); cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name");
if(host_name_object !=NULL){ if(host_name_object !=NULL){
host_name = strdup(host_name_object->valuestring); host_name = strdup_psram(host_name_object->valuestring);
} }
cJSON_Delete(root); cJSON_Delete(root);
@@ -785,14 +756,7 @@ esp_err_t connect_post_handler(httpd_req_t *req){
} }
if(ssid !=NULL && strlen(ssid) <= MAX_SSID_SIZE && strlen(password) <= MAX_PASSWORD_SIZE ){ if(ssid !=NULL && strlen(ssid) <= MAX_SSID_SIZE && strlen(password) <= MAX_PASSWORD_SIZE ){
wifi_config_t* config = wifi_manager_get_wifi_sta_config(); network_async_connect(ssid, password);
memset(config, 0x00, sizeof(wifi_config_t));
strlcpy((char *)config->sta.ssid, ssid, sizeof(config->sta.ssid)+1);
if(password){
strlcpy((char *)config->sta.password, password, sizeof(config->sta.password)+1);
}
ESP_LOGD_LOC(TAG, "http_server_netconn_serve: network_manager_async_scan() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password);
network_manager_async_scan();
httpd_resp_send(req, (const char *)success, strlen(success)); httpd_resp_send(req, (const char *)success, strlen(success));
} }
else { else {
@@ -816,7 +780,7 @@ esp_err_t connect_delete_handler(httpd_req_t *req){
return err; return err;
} }
httpd_resp_send(req, (const char *)success, strlen(success)); httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_disconnect(); network_async_delete();
return ESP_OK; return ESP_OK;
} }
@@ -833,7 +797,7 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){
} }
httpd_resp_send(req, (const char *)success, strlen(success)); httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(OTA); network_async_reboot(OTA);
return ESP_OK; return ESP_OK;
} }
esp_err_t reboot_post_handler(httpd_req_t *req){ esp_err_t reboot_post_handler(httpd_req_t *req){
@@ -848,7 +812,7 @@ esp_err_t reboot_post_handler(httpd_req_t *req){
return err; return err;
} }
httpd_resp_send(req, (const char *)success, strlen(success)); httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(RESTART); network_async_reboot(RESTART);
return ESP_OK; return ESP_OK;
} }
esp_err_t recovery_post_handler(httpd_req_t *req){ esp_err_t recovery_post_handler(httpd_req_t *req){
@@ -863,7 +827,7 @@ esp_err_t recovery_post_handler(httpd_req_t *req){
return err; return err;
} }
httpd_resp_send(req, (const char *)success, strlen(success)); httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(RECOVERY); network_async_reboot(RECOVERY);
return ESP_OK; return ESP_OK;
} }
@@ -881,7 +845,7 @@ esp_err_t flash_post_handler(httpd_req_t *req){
if(err != ESP_OK){ if(err != ESP_OK){
return err; return err;
} }
char * binary_buffer = malloc(req->content_len); char * binary_buffer = malloc_init_external(req->content_len);
if(binary_buffer == NULL){ if(binary_buffer == NULL){
ESP_LOGE(TAG, "File too large : %d bytes", req->content_len); ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
/* Respond with 400 Bad Request */ /* Respond with 400 Bad Request */
@@ -981,11 +945,11 @@ esp_err_t process_redirect(httpd_req_t *req, const char * status){
remote_ip = http_alloc_get_socket_address(req,0, &port); remote_ip = http_alloc_get_socket_address(req,0, &port);
size_t buf_size = strlen(redirect_payload1) +strlen(redirect_payload2) + strlen(redirect_payload3) +2*(strlen(location_prefix)+strlen(ap_ip_address))+1; size_t buf_size = strlen(redirect_payload1) +strlen(redirect_payload2) + strlen(redirect_payload3) +2*(strlen(location_prefix)+strlen(ap_ip_address))+1;
char * redirect=malloc(buf_size); char * redirect=malloc_init_external(buf_size);
if(strcasestr(status,"302")){ if(strcasestr(status,"302")){
size_t url_buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1; size_t url_buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1;
redirect_url = malloc(url_buf_size); redirect_url = malloc_init_external(url_buf_size);
memset(redirect_url,0x00,url_buf_size); memset(redirect_url,0x00,url_buf_size);
snprintf(redirect_url, buf_size,"%s%s/",location_prefix, ap_ip_address); snprintf(redirect_url, buf_size,"%s%s/",location_prefix, ap_ip_address);
ESP_LOGW_LOC(TAG, "Redirecting host [%s] to %s (from uri %s)",remote_ip, redirect_url,req->uri); ESP_LOGW_LOC(TAG, "Redirecting host [%s] to %s (from uri %s)",remote_ip, redirect_url,req->uri);
@@ -1034,9 +998,9 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){
remote_ip = http_alloc_get_socket_address(req,0, &port); remote_ip = http_alloc_get_socket_address(req,0, &port);
ESP_LOGW_LOC(TAG, "%s requested invalid URL: [%s]",remote_ip, req->uri); ESP_LOGW_LOC(TAG, "%s requested invalid URL: [%s]",remote_ip, req->uri);
if(wifi_manager_lock_sta_ip_string(portMAX_DELAY)){ if(network_status_lock_sta_ip_string(portMAX_DELAY)){
sta_ip_address = strdup(wifi_manager_get_sta_ip_string()); sta_ip_address = strdup_psram(network_status_get_sta_ip_string());
wifi_manager_unlock_sta_ip_string(); network_status_unlock_sta_ip_string();
} }
else { else {
ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager."); ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager.");
@@ -1149,9 +1113,9 @@ esp_err_t status_get_handler(httpd_req_t *req){
return err; return err;
} }
if(wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) { if(network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) {
char *buff = wifi_manager_alloc_get_ip_info_json(); char *buff = network_status_alloc_get_ip_info_json();
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
if(buff) { if(buff) {
httpd_resp_send(req, (const char *)buff, strlen(buff)); httpd_resp_send(req, (const char *)buff, strlen(buff));
free(buff); free(buff);
@@ -1164,7 +1128,7 @@ esp_err_t status_get_handler(httpd_req_t *req){
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object"); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object");
} }
// update status for next status call // update status for next status call
network_manager_async_update_status(); network_async_update_status();
return ESP_OK; return ESP_OK;
} }

View File

@@ -1,34 +1,5 @@
/* /*
Copyright (c) 2017-2019 Tony Pottier Copyright (c) 2017-2021 Sebastien L
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file http_server.h
@author Tony Pottier
@brief Defines all functions necessary for the HTTP server to run.
Contains the freeRTOS task for the HTTP listener and all necessary support
function to process requests, decode URLs, serve files, etc. etc.
@note http_server task cannot run without the wifi_manager task!
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
*/ */
#ifndef HTTP_SERVER_H_INCLUDED #ifndef HTTP_SERVER_H_INCLUDED

View File

@@ -1,38 +1,40 @@
#include "esp_eth.h" #include "esp_eth.h"
#include "network_ethernet.h" #include "network_ethernet.h"
static EXT_RAM_ATTR network_ethernet_driver_t DM9051;
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051 #ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_dm9051_config_t eth_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); eth_dm9051_config_t eth_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
// we assume that isr has been installed already // we assume that isr has been installed already
eth_config.int_gpio_num = ethernet_config->intr; eth_config.int_gpio_num = ethernet_config->intr;
return esp_eth_mac_new_dm9051(&eth_config, &mac_config); phy_config.phy_addr = -1;
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
phy_config.reset_gpio_num = ethernet_config->rst; phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_dm9051(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_dm9051(&eth_config, &mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_dm9051(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &DM9051.handle);
#else #else
return NULL; return ESP_ERR_NOT_SUPPORTED;
#endif #endif
} }
static void init_config(eth_config_t* ethernet_config) {
}
static network_ethernet_driver_t DM9051 = { static void init_config(eth_config_t* ethernet_config) {
.mac_new = mac_new, DM9051.start = start;
.phy_new = phy_new, DM9051.rmii = true;
.init_config = init_config, DM9051.spi = false;
.valid = true, DM9051.valid = true;
}; }
network_ethernet_driver_t* DM9051_Detect(char* Driver) { network_ethernet_driver_t* DM9051_Detect(char* Driver) {
if (!strcasestr(Driver, "DM9051")) if (!strcasestr(Driver, "DM9051"))
return NULL; return NULL;
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
DM9051.valid = true;
#else
DM9051.valid = false;
#endif
DM9051.init_config = init_config;
return &DM9051; return &DM9051;
} }

View File

@@ -1,47 +1,40 @@
#include "esp_eth.h" #include "esp_eth.h"
#include "network_ethernet.h" #include "network_ethernet.h"
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { static EXT_RAM_ATTR network_ethernet_driver_t LAN8720;
static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII #ifdef CONFIG_ETH_PHY_INTERFACE_RMII
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.smi_mdc_gpio_num = ethernet_config->mdc; mac_config.smi_mdc_gpio_num = ethernet_config->mdc;
mac_config.smi_mdio_gpio_num = ethernet_config->mdio; mac_config.smi_mdio_gpio_num = ethernet_config->mdio;
mac_config.sw_reset_timeout_ms = 400;
return esp_eth_mac_new_esp32(&mac_config);
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1; phy_config.phy_addr = 1;
phy_config.reset_gpio_num = ethernet_config->rst; phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_lan8720(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_esp32(&mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_lan8720(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &LAN8720.handle);
#else #else
return NULL; return ESP_ERR_NOT_SUPPORTED;
#endif #endif
} }
static void init_config(eth_config_t* ethernet_config) { static void init_config(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII LAN8720.start = start;
#else LAN8720.rmii = true;
return NULL; LAN8720.spi = false;
#endif
} }
static network_ethernet_driver_t LAN8720 = {
.mac_new = mac_new,
.phy_new = phy_new,
.init_config = init_config,
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
.valid = true,
#else
.valid = false,
#endif
};
network_ethernet_driver_t* LAN8720_Detect(char* Driver) { network_ethernet_driver_t* LAN8720_Detect(char* Driver) {
if (!strcasestr(Driver, "LAN8720")) if (!strcasestr(Driver, "LAN8720"))
return NULL; return NULL;
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
LAN8720.valid = true;
#else
LAN8720.valid = false;
#endif
LAN8720.init_config = init_config;
return &LAN8720; return &LAN8720;
} }

View File

@@ -1,43 +1,55 @@
#include "esp_eth.h" #include "esp_eth.h"
#include "globdefs.h"
#include "network_ethernet.h" #include "network_ethernet.h"
static EXT_RAM_ATTR network_ethernet_driver_t W5500;
static EXT_RAM_ATTR spi_device_interface_config_t devcfg;
static EXT_RAM_ATTR esp_netif_config_t cfg_spi;
static EXT_RAM_ATTR esp_netif_inherent_config_t esp_netif_config;
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500 #ifdef CONFIG_ETH_SPI_ETHERNET_W5500
eth_w5500_config_t eth_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); eth_w5500_config_t eth_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
// we assume that isr has been installed already
eth_config.int_gpio_num = ethernet_config->intr;
return esp_eth_mac_new_w5500(&eth_config, &mac_config);
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
eth_config.int_gpio_num = ethernet_config->intr;
phy_config.phy_addr = -1; // let the system automatically find out the phy address
phy_config.reset_gpio_num = ethernet_config->rst; phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_w5500(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_w5500(&eth_config, &mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_w5500(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &W5500.handle);
#else #else
return NULL; return ESP_ERR_NOT_SUPPORTED;
#endif #endif
} }
static void init_config(eth_config_t* ethernet_config) { static void init_config(eth_config_t* ethernet_config) {
} esp_netif_inherent_config_t loc_esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
devcfg.command_bits = 16; // Actually it's the address phase in W5500 SPI frame
devcfg.address_bits = 8; // Actually it's the control phase in W5500 SPI frame
devcfg.mode = 0;
devcfg.clock_speed_hz = ethernet_config->speed > 0 ? ethernet_config->speed : SPI_MASTER_FREQ_20M; // default speed
devcfg.queue_size = 20;
devcfg.spics_io_num = ethernet_config->cs;
memcpy(&esp_netif_config, &loc_esp_netif_config, sizeof(loc_esp_netif_config));
cfg_spi.base = &esp_netif_config,
cfg_spi.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH;
W5500.cfg_netif = &cfg_spi;
W5500.devcfg = &devcfg;
W5500.start = start;
W5500.spi = true;
W5500.rmii = false;
static network_ethernet_driver_t W5500 = { }
.mac_new = mac_new,
.phy_new = phy_new,
.init_config = init_config,
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
.valid = true,
#else
.valid = false,
#endif
};
network_ethernet_driver_t* W5500_Detect(char* Driver, network_ethernet_driver_t* Device) { network_ethernet_driver_t* W5500_Detect(char* Driver, network_ethernet_driver_t* Device) {
if (!strcasestr(Driver, "W5500")) if (!strcasestr(Driver, "W5500"))
return NULL; return NULL;
W5500.init_config = init_config;
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
W5500.valid = true;
#else
W5500.valid = false;
#endif
return &W5500; return &W5500;
} }

View File

@@ -1,3 +1,6 @@
#ifdef NETWORK_ETHERNET_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_ETHERNET_LOG_LEVEL
#endif
#include "network_ethernet.h" #include "network_ethernet.h"
#include "freertos/timers.h" #include "freertos/timers.h"
#include "globdefs.h" #include "globdefs.h"
@@ -5,14 +8,13 @@
#include "network_status.h" #include "network_status.h"
#include "platform_config.h" #include "platform_config.h"
#include "trace.h" #include "trace.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include "accessors.h"
#include "esp_log.h" #include "esp_log.h"
//#include "dnserver.h" //#include "dnserver.h"
static char TAG[] = "network_ethernet"; static char TAG[] = "network_ethernet";
TimerHandle_t ETH_timer; TimerHandle_t ETH_timer;
esp_eth_handle_t eth_handle = NULL;
esp_netif_t* eth_netif = NULL; esp_netif_t* eth_netif = NULL;
EventGroupHandle_t ethernet_event_group; EventGroupHandle_t ethernet_event_group;
const int LINK_UP_BIT = BIT0; const int LINK_UP_BIT = BIT0;
@@ -22,7 +24,6 @@ static network_ethernet_driver_t* network_driver = NULL;
extern network_ethernet_detect_func_t DM9051_Detect, W5500_Detect, LAN8720_Detect; extern network_ethernet_detect_func_t DM9051_Detect, W5500_Detect, LAN8720_Detect;
static network_ethernet_detect_func_t* drivers[] = {DM9051_Detect, W5500_Detect, LAN8720_Detect, NULL}; static network_ethernet_detect_func_t* drivers[] = {DM9051_Detect, W5500_Detect, LAN8720_Detect, NULL};
#define ETH_TIMEOUT_MS (30 * 1000) #define ETH_TIMEOUT_MS (30 * 1000)
static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
/**************************************************************************************** /****************************************************************************************
* *
@@ -67,7 +68,7 @@ bool network_ethernet_is_up() {
return (xEventGroupGetBits(ethernet_event_group) & LINK_UP_BIT)!=0; return (xEventGroupGetBits(ethernet_event_group) & LINK_UP_BIT)!=0;
} }
bool network_ethernet_enabled() { bool network_ethernet_enabled() {
return eth_handle != NULL; return network_driver !=NULL && network_driver->handle != NULL;
} }
bool network_ethernet_wait_for_link(uint16_t max_wait_ms){ bool network_ethernet_wait_for_link(uint16_t max_wait_ms){
if(!network_ethernet_enabled()) return false; if(!network_ethernet_enabled()) return false;
@@ -89,75 +90,33 @@ bool network_ethernet_wait_for_link(uint16_t max_wait_ms){
static void ETH_Timeout(void* timer_id); static void ETH_Timeout(void* timer_id);
void destroy_network_ethernet() { void destroy_network_ethernet() {
} }
static void set_host_name() {
ESP_LOGE(TAG, "TODO: Find a way to set the host name here!");
// esp_err_t err;
// ESP_LOGD(TAG, "Retrieving host name from nvs");
// char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name");
// if (host_name == NULL) {
// ESP_LOGE(TAG, "Could not retrieve host name from nvs");
// } else {
// if (!network_ethernet_enabled()) {
// ESP_LOGE(TAG, "Cannot set name on a disabled interface");
// } else {
// ESP_LOGD(TAG, "Setting host name to : %s", host_name);
// if ((err = esp_netif_set_hostname(eth_handle, host_name)) != ESP_OK) {
// ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err));
// }
// ESP_LOGD(TAG, "Done setting host name to : %s", host_name);
// }
// FREE_AND_NULL(host_name);
// }
}
static void network_ethernet_print_config(const eth_config_t* eth_config) { static void network_ethernet_print_config(const eth_config_t* eth_config) {
// #if defined(CONFIG_ETH_PHY_INTERFACE_RMII) ESP_LOGI(TAG,"Ethernet config: \n model: %s, valid: %s, type: %s, mdc:%d, mdio:%d, rst:%d, mosi:%d, miso:%d, intr:%d, cs:%d, speed:%d, clk:%d, host:%s(%d)",
// if(eth_config->) eth_config->model, eth_config->valid?"YES":"NO",eth_config->spi?"SPI":"RMII", eth_config->mdc, eth_config->mdio, eth_config->rst, eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->cs, eth_config->speed, eth_config->clk, eth_config->host==0?"SPI1":eth_config->host==1?"SPI2":eth_config->host==2?"SPI3":"",eth_config->host);
// ESP_LOGI(TAG,
// "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d, tx_en=%d, tx0=%d, tx1=%d, rx0=%d, rx1=%d, crs_dv=%d",
// eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs,
// eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed,
// eth_config->tx_en, eth_config->tx0, eth_config->tx1, eth_config->rx0, eth_config->rx1, eth_config->crs_dv);
// #else
// ESP_LOGI(TAG, "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d ",
// eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs,
// eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed);
// :
// #endif
} }
void init_network_ethernet() { void init_network_ethernet() {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
esp_eth_mac_t* mac;
esp_eth_phy_t* phy;
eth_config_t eth; eth_config_t eth;
ESP_LOGI(TAG, "Attempting to initialize Ethernet");
config_eth_init(&eth); config_eth_init(&eth);
ESP_LOGD(TAG, "Attempting to initialize Ethernet"); if(!eth.valid){
// quick check if we have a valid ethernet configuration ESP_LOGI(TAG,"No Ethernet configuration, or configuration invalid");
if (!eth.valid) {
ESP_LOGI(TAG, "No ethernet");
return;
}
network_driver = network_ethernet_driver_autodetect(eth.model);
if (!network_driver) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Invalid ethernet Ethernet chip %s", eth.model);
return;
}
if (!network_driver->valid) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Code not compiled for Ethernet chip %s", eth.model);
return; return;
} }
network_driver->init_config(&eth); network_driver->init_config(&eth);
network_ethernet_print_config(&eth); network_ethernet_print_config(&eth);
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
eth_netif = esp_netif_new(&cfg); eth_netif = esp_netif_new(network_driver->cfg_netif);
esp_eth_set_default_handlers(eth_netif); esp_eth_set_default_handlers(eth_netif);
esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL); esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL);
esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL);
ethernet_event_group = xEventGroupCreate(); ethernet_event_group = xEventGroupCreate();
xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT); xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT);
spi_device_handle_t spi_handle = NULL; spi_device_handle_t spi_handle = NULL;
if (network_driver->eth_config.spi) { if (network_driver->spi) {
spi_host_device_t host = SPI3_HOST; spi_host_device_t host = SPI3_HOST;
if (eth.host != -1) { if (eth.host != -1) {
@@ -169,12 +128,18 @@ void init_network_ethernet() {
.quadwp_io_num = -1, .quadwp_io_num = -1,
.quadhd_io_num = -1, .quadhd_io_num = -1,
}; };
// can't use SPI0 // can't use SPI0
if (eth.host == 1) if (eth.host == 0)
{
ESP_LOGW(TAG,"Cannot use SPI1 host. Defaulting to SPI2");
host = SPI2_HOST; host = SPI2_HOST;
ESP_LOGI(TAG, "Initializing SPI bus on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso); }
err = spi_bus_initialize(host, &buscfg, 1); else {
host = eth.host;
}
ESP_LOGI(TAG, "Initializing SPI bus on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI bus init failed : %s", esp_err_to_name(err)); ESP_LOGE(TAG, "SPI bus init failed : %s", esp_err_to_name(err));
} }
@@ -184,38 +149,39 @@ void init_network_ethernet() {
host = spi_system_host; host = spi_system_host;
} }
if (err == ESP_OK) { if (err == ESP_OK) {
spi_device_interface_config_t devcfg = { ESP_LOGI(TAG, "Adding ethernet SPI on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
.command_bits = 1, err = spi_bus_add_device(host, network_driver->devcfg, &spi_handle);
.address_bits = 7,
.mode = 0,
.clock_speed_hz = eth.speed,
.spics_io_num = eth.cs,
.queue_size = 20};
ESP_LOGI(TAG, "Adding ethernet SPI on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso);
err = spi_bus_add_device(host, &devcfg, &spi_handle);
} }
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI host failed : %s", esp_err_to_name(err)); ESP_LOGE(TAG, "SPI host failed : %s", esp_err_to_name(err));
} }
} }
if (err == ESP_OK) { if (err == ESP_OK) {
ESP_LOGD(TAG, "Setting up ethernet driver"); err = network_driver->start(spi_handle,&eth);
mac = network_driver->mac_new(spi_handle, &eth);
phy = network_driver->phy_new(&eth);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
err = esp_eth_driver_install(&config, &eth_handle);
} }
if(err == ESP_OK){
uint8_t mac_address[6];
esp_read_mac(mac_address,ESP_MAC_ETH);
char * mac_string=network_manager_alloc_get_mac_string(mac_address);
ESP_LOGD(TAG,"Assigning mac address %s to ethernet interface", STR_OR_BLANK(mac_string));
FREE_AND_NULL(mac_string);
esp_eth_ioctl(network_driver->handle, ETH_CMD_S_MAC_ADDR, mac_address);
}
if (err == ESP_OK) { if (err == ESP_OK) {
ESP_LOGD(TAG, "Attaching ethernet to network interface"); ESP_LOGD(TAG, "Attaching ethernet to network interface");
err = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); err = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(network_driver->handle));
} }
if (err == ESP_OK) { if (err == ESP_OK) {
ESP_LOGI(TAG, "Starting ethernet network"); ESP_LOGI(TAG, "Starting ethernet network");
err = esp_eth_start(eth_handle); err = esp_eth_start(network_driver->handle);
} }
if (err != ESP_OK) { if (err != ESP_OK) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Configuring Ethernet failed: %s", esp_err_to_name(err)); messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Configuring Ethernet failed: %s", esp_err_to_name(err));
eth_handle = NULL; if(spi_handle) {
spi_bus_remove_device(spi_handle);
}
network_driver->handle = NULL;
} }
} }
@@ -235,18 +201,17 @@ static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t ev
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, ""); ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "Ethernet Link Up, HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); ESP_LOGI(TAG, "Ethernet Link Up, HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
ESP_LOGD(TAG, "Sending EVENT_ETH_LINK_UP message to network manager"); network_async_link_up();
network_manager_async_link_up();
break; break;
case ETHERNET_EVENT_DISCONNECTED: case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down"); ESP_LOGI(TAG, "Ethernet Link Down");
xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT); xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT);
ESP_LOGD(TAG, "Sending EVENT_ETH_LINK_DOWN message to network manager"); network_async_link_down();
network_manager_async_link_down();
break; break;
case ETHERNET_EVENT_START: case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started. Setting host name"); ESP_LOGI(TAG, "Ethernet Started. Setting host name");
set_host_name(); network_set_hostname(eth_netif);
network_async_success();
break; break;
case ETHERNET_EVENT_STOP: case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped"); ESP_LOGI(TAG, "Ethernet Stopped");
@@ -254,30 +219,10 @@ static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t ev
default: default:
break; break;
} }
} else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) { }
network_manager_ethernet_ip_event_handler(arg, event_base, event_id, event_data);
}
} }
static void ETH_Timeout(void* timer_id) { static void ETH_Timeout(void* timer_id) {
network_manager_async_fail(); network_async_fail();
} }
static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base != IP_EVENT)
return;
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ip_event_got_ip_t* s = event_data;
tcpip_adapter_if_t index = s->if_index;
esp_netif_ip_info_t* ip_info = &s->ip_info;
ESP_LOGI(TAG, "Got an IP address from Ethernet interface #%i. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s",
index,
IP2STR(&ip_info->ip),
IP2STR(&ip_info->gw),
IP2STR(&ip_info->netmask),
s->ip_changed ? "Address was changed" : "Address unchanged");
ip_event_got_ip_t* parm = malloc(sizeof(ip_event_got_ip_t));
memcpy(parm, event_data, sizeof(ip_event_got_ip_t));
network_manager_async_got_ip(parm);
}

View File

@@ -3,19 +3,26 @@
#include "network_manager.h" #include "network_manager.h"
#include "accessors.h" #include "accessors.h"
#include <string.h> #include <string.h>
#include "esp_netif_defaults.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct { typedef struct {
bool valid; bool valid;
eth_config_t eth_config; bool rmii;
esp_eth_mac_t* (*mac_new)(spi_device_handle_t spi_handle, eth_config_t * eth_config); bool spi;
esp_eth_phy_t *(*phy_new)( eth_config_t* eth_config); esp_eth_handle_t handle;
esp_netif_config_t * cfg_netif;
spi_device_interface_config_t * devcfg;
// esp_eth_mac_t* (*mac_new)(spi_device_handle_t spi_handle, eth_config_t * eth_config);
// esp_eth_phy_t *(*phy_new)( eth_config_t* eth_config);
esp_err_t (*start)(spi_device_handle_t spi_handle,eth_config_t *ethernet_config);
void (*init_config)(eth_config_t * eth_config); void (*init_config)(eth_config_t * eth_config);
} network_ethernet_driver_t; } network_ethernet_driver_t;
typedef network_ethernet_driver_t* network_ethernet_detect_func_t(const char* Driver); typedef network_ethernet_driver_t* network_ethernet_detect_func_t(const char* Driver);
network_ethernet_driver_t* network_ethernet_driver_autodetect(const char* Driver);
void destroy_network_ethernet(); void destroy_network_ethernet();
void init_network_ethernet(); void init_network_ethernet();
bool network_ethernet_wait_for_link(uint16_t max_wait_ms); bool network_ethernet_wait_for_link(uint16_t max_wait_ms);

View File

@@ -1,34 +1,10 @@
/* /*
Copyright (c) 2017-2019 Tony Pottier Copyright (c) 2017-2021 Sebastien L
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file wifi_manager.c
@author Tony Pottier
@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis
Contains the freeRTOS task and all necessary support
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
*/ */
#ifdef NETWORK_MANAGER_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_MANAGER_LOG_LEVEL
#endif
#include "network_manager.h" #include "network_manager.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@@ -37,16 +13,15 @@ Contains the freeRTOS task and all necessary support
#include "network_ethernet.h" #include "network_ethernet.h"
#include "network_status.h" #include "network_status.h"
#include "network_wifi.h" #include "network_wifi.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "dns_server.h"
#include "esp_log.h" #include "esp_log.h"
#include "platform_esp32.h"
#include "esp_system.h" #include "esp_system.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "platform_esp32.h"
#include "freertos/task.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "freertos/task.h"
#include "cJSON.h" #include "cJSON.h"
#include "cmd_system.h" #include "cmd_system.h"
@@ -62,59 +37,696 @@ Contains the freeRTOS task and all necessary support
#include "lwip/netdb.h" #include "lwip/netdb.h"
#include "mdns.h" #include "mdns.h"
#include "messaging.h" #include "messaging.h"
#include "state_machine.h"
#include "platform_config.h" #include "platform_config.h"
#include "trace.h" #include "trace.h"
#include "accessors.h" #include "accessors.h"
#include "esp_err.h"
#include "globdefs.h" #include "globdefs.h"
#include "http_server_handlers.h" #include "http_server_handlers.h"
#include "network_manager.h"
QueueHandle_t network_queue;
BaseType_t network_task_handle;
static const char TAG[] = "network";
static TaskHandle_t task_network_manager = NULL;
RTC_NOINIT_ATTR static bool s_wifi_prioritized = false;
extern esp_reset_reason_t xReason;
typedef struct network_callback {
network_status_reached_cb cb;
nm_state_t state;
int sub_state;
const char* from;
SLIST_ENTRY(network_callback)
next; //!< next callback
} network_callback_t;
/** linked list of command structures */
static SLIST_HEAD(cb_list, network_callback) s_cb_list;
network_t NM;
//! Create and initialize the array of state machines.
state_machine_t* const SM[] = {(state_machine_t*)&NM};
static void network_timer_cb(void* timer_id);
int get_root_id(const state_t * state);
const state_t* get_root( const state_t* const state);
static void network_task(void* pvParameters);
void network_start_stop_dhcp(esp_netif_t* netif, bool start) {
tcpip_adapter_dhcp_status_t status;
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "Checking if DHCP client for STA interface is running");
if (!netif) {
ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp. ");
return;
}
if((err=esp_netif_dhcpc_get_status(netif, &status))!=ESP_OK){
ESP_LOGE(TAG,"Error retrieving dhcp status : %s", esp_err_to_name(err));
return;
}
switch (status)
{
case ESP_NETIF_DHCP_STARTED:
if(start){
ESP_LOGD(TAG, "DHCP client already started");
}
else {
ESP_LOGI(TAG, "Stopping DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_stop(netif));
}
break;
case ESP_NETIF_DHCP_STOPPED:
if(start){
ESP_LOGI(TAG, "Starting DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_start(netif));
}
else {
ESP_LOGI(TAG, "DHCP client already started");
}
break;
case ESP_NETIF_DHCP_INIT:
if(start){
ESP_LOGI(TAG, "Starting DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_start(netif));
}
else {
ESP_LOGI(TAG, "Stopping DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_stop(netif));
}
break;
default:
ESP_LOGW(TAG,"Unknown DHCP status");
break;
}
}
void network_start_stop_dhcps(esp_netif_t* netif, bool start) {
tcpip_adapter_dhcp_status_t status;
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "Checking if DHCP server is running");
if (!netif) {
ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp server. ");
return;
}
if((err=esp_netif_dhcps_get_status(netif, &status))!=ESP_OK){
ESP_LOGE(TAG,"Error retrieving dhcp server status : %s", esp_err_to_name(err));
return;
}
switch (status)
{
case ESP_NETIF_DHCP_STARTED:
if(start){
ESP_LOGD(TAG, "DHCP server already started");
}
else {
ESP_LOGI(TAG, "Stopping DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
}
break;
case ESP_NETIF_DHCP_STOPPED:
if(start){
ESP_LOGI(TAG, "Starting DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
}
else {
ESP_LOGI(TAG, "DHCP server already stopped");
}
break;
case ESP_NETIF_DHCP_INIT:
if(start){
ESP_LOGI(TAG, "Starting DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
}
else {
ESP_LOGI(TAG, "Stopping DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
}
break;
default:
ESP_LOGW(TAG,"Unknown DHCP status");
break;
}
}
/*********************************************************************************************
* String conversion routines
*/
#ifndef STR_OR_BLANK #define ADD_ROOT(name,...) CASE_TO_STR(name);
#define STR_OR_BLANK(p) p == NULL ? "" : p #define ADD_ROOT_LEAF(name,...) CASE_TO_STR(name);
#endif #define ADD_LEAF(name,...) CASE_TO_STR(name);
#define ADD_EVENT(name) CASE_TO_STR(name);
#define ADD_FIRST_EVENT(name) CASE_TO_STR(name);
static const char* state_to_string(const state_t * state) {
if(!state) {
return "";
}
switch (state->Parent?state->Parent->Id:state->Id) {
ALL_NM_STATE
default:
break;
}
return "Unknown";
}
static const char* wifi_state_to_string(mn_wifi_active_state_t state) {
switch (state) {
ALL_WIFI_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* eth_state_to_string(mn_eth_active_state_t state) {
switch (state) {
ALL_ETH_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* wifi_configuring_state_to_string(mn_wifi_configuring_state_t state) {
switch (state) {
ALL_WIFI_CONFIGURING_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* sub_state_to_string(const state_t * state) {
if(!state) {
return "N/A";
}
int root_id = get_root_id(state);
switch (root_id)
{
case NETWORK_ETH_ACTIVE_STATE:
return eth_state_to_string(state->Id);
break;
case NETWORK_WIFI_ACTIVE_STATE:
return wifi_state_to_string(state->Id);
case NETWORK_WIFI_CONFIGURING_ACTIVE_STATE:
return wifi_configuring_state_to_string(state->Id);
default:
break;
}
return "*";
}
//EventGroupHandle_t wifi_manager_event_group; static const char* event_to_string(network_event_t state) {
void (**cb_ptr_arr)(void*) = NULL; switch (state) {
ALL_NM_EVENTS
/* @brief tag used for ESP serial console messages */ default:
//static const char TAG[] = "network_manager"; break;
}
return "Unknown";
}
/* @brief indicate that the ESP32 is currently connected. */ #undef ADD_EVENT
const int WIFI_MANAGER_WIFI_CONNECTED_BIT = BIT0; #undef ADD_FIRST_EVENT
const int WIFI_MANAGER_AP_STA_CONNECTED_BIT = BIT1; #undef ADD_ROOT
/* @brief Set automatically once the SoftAP is started */ #undef ADD_ROOT_LEAF
const int WIFI_MANAGER_AP_STARTED_BIT = BIT2; #undef ADD_LEAF
/* @brief When set, means a client requested to connect to an access point.*/
const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT = BIT3;
/* @brief This bit is set automatically as soon as a connection was lost */
const int WIFI_MANAGER_STA_DISCONNECT_BIT = BIT4;
/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */
const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT = BIT5;
/* @brief When set, means a client requested to disconnect from currently connected AP. */
const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT = BIT6;
/* @brief When set, means a scan is in progress */
const int WIFI_MANAGER_SCAN_BIT = BIT7;
/* @brief When set, means user requested for a disconnect */
const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT = BIT8;
/* @brief When set, means user requested connecting to a new network and it failed */
const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT = BIT9;
/* @brief task handle for the main wifi_manager task */ typedef struct {
int parent_state;
int sub_state_last ;
} max_sub_states_t;
static const max_sub_states_t state_max[] = {
{ .parent_state = NETWORK_INSTANTIATED_STATE, .sub_state_last = 0 },
{.parent_state = NETWORK_ETH_ACTIVE_STATE, .sub_state_last = TOTAL_ETH_ACTIVE_STATE-1 },
{.parent_state = NETWORK_WIFI_ACTIVE_STATE, .sub_state_last = TOTAL_WIFI_ACTIVE_STATE-1 },
{.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE-1 },
{.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE-1 },
{.parent_state =-1}
};
void network_start() {
if(xReason == ESP_RST_POWERON ){
ESP_LOGD(TAG, "Power on reset, initializing wifi priotitized to false");
s_wifi_prioritized = false;
}
ESP_LOGD(TAG, " Creating message queue");
network_queue = xQueueCreate(3, sizeof(queue_message));
ESP_LOGD(TAG, " Creating network manager task");
network_task_handle = xTaskCreate(&network_task, "network", 4096, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_network_manager);
}
static void event_logger(uint32_t state_machine, uint32_t state, uint32_t event) {
ESP_LOGI(TAG, "Handling network manager event state Id %d->[%s]", state, event_to_string(event));
}
static const char * get_state_machine_result_string(state_machine_result_t result) {
switch(result) {
case EVENT_HANDLED:
return "EVENT_HANDLED";
case EVENT_UN_HANDLED:
return "EVENT_UN_HANDLED";
case TRIGGERED_TO_SELF:
return "TRIGGERED_TO_SELF";
}
return "Unknown";
}
static void result_logger(uint32_t state, state_machine_result_t result) {
ESP_LOGD(TAG, "Network Manager Result: %s, New State id: %d", get_state_machine_result_string(result) , state);
}
static void network_task(void* pvParameters) {
queue_message msg;
BaseType_t xStatus;
initialize_network_handlers((state_machine_t*)&NM);
network_async(EN_START);
/* main processing loop */
for (;;) {
xStatus = xQueueReceive(network_queue, &msg, portMAX_DELAY);
if (xStatus == pdPASS) {
// pass the event to the sync processor
NM.event_parameters = &msg;
NM.Machine.Event = msg.trigger;
if (dispatch_event(SM, 1, event_logger, result_logger) == EVENT_UN_HANDLED) {
network_manager_format_from_to_states(ESP_LOG_ERROR,"Unhandled Event",NULL,NM.Machine.State,msg.trigger,false,"network manager");
}
} /* end of if status=pdPASS */
} /* end of for loop */
vTaskDelete(NULL);
}
int get_max_substate(nm_state_t state){
for(int i=0;state_max[i].parent_state!=-1;i++){
if(state_max[i].parent_state == state){
return state_max[i].sub_state_last;
}
}
return -1;
}
esp_err_t network_register_state_callback(nm_state_t state,int sub_state, const char* from, network_status_reached_cb cb) {
network_callback_t* item = NULL;
if (!cb) {
return ESP_ERR_INVALID_ARG;
}
item = calloc(1, sizeof(*item));
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
if(sub_state != -1 && sub_state>get_max_substate(state)){
// sub state has to be valid
return ESP_ERR_INVALID_ARG;
}
item->state = state;
item->cb = cb;
item->from = from;
item->sub_state=sub_state;
network_callback_t* last = SLIST_FIRST(&s_cb_list);
if (last == NULL) {
SLIST_INSERT_HEAD(&s_cb_list, item, next);
} else {
network_callback_t* it;
while ((it = SLIST_NEXT(last, next)) != NULL) {
last = it;
}
SLIST_INSERT_AFTER(last, item, next);
}
return ESP_OK;
}
const state_t* get_root( const state_t* const state){
if(!state) return NULL;
return state->Parent==NULL?state: get_root(state->Parent);
}
int get_root_id(const state_t * state){
if(!state) return -1;
return state->Parent==NULL?state->Id: get_root_id(state->Parent);
}
void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*)) { static bool is_root_state(const state_t * state){
if (cb_ptr_arr && message_code < MESSAGE_CODE_COUNT) { return state->Parent==NULL;
cb_ptr_arr[message_code] = func_ptr; }
static bool is_current_state(const state_t* state, nm_state_t state_id, int sub_state_id){
return get_root(state)->Id == state_id && (sub_state_id==-1 || (!is_root_state(state) && state->Id == sub_state_id) );
}
void network_execute_cb(state_machine_t* const state_machine, const char * caller) {
network_callback_t* it;
SLIST_FOREACH(it, &s_cb_list, next) {
if (is_current_state(state_machine->State,it->state, it->sub_state)) {
char * cb_prefix= messaging_alloc_format_string("BEGIN Executing Callback %s", it->from) ;
NETWORK_DEBUG_STATE_MACHINE(true,STR_OR_BLANK(cb_prefix),state_machine,false, STR_OR_BLANK(caller));
FREE_AND_NULL(cb_prefix);
it->cb((nm_state_t)get_root(state_machine->State)->Id, is_root_state(state_machine->State)?-1:state_machine->State->Id);
cb_prefix= messaging_alloc_format_string("END Executing Callback %s", it->from) ;
NETWORK_DEBUG_STATE_MACHINE(false,STR_OR_BLANK(cb_prefix),state_machine,false, STR_OR_BLANK(caller));
FREE_AND_NULL(cb_prefix);
}
} }
} }
bool network_is_wifi_prioritized() {
eth_config_t eth_config;
config_eth_init(&eth_config);
// char* prioritize = (char*)config_alloc_get_default(NVS_TYPE_STR, "prio_wifi", "N", 0);
// bool result = strcasecmp("N", prioritize);
bool result = s_wifi_prioritized;
if(result){
result = network_wifi_get_known_count()>0 || !eth_config.valid;
ESP_LOGD(TAG,"Wifi is prioritized with %d known access points.%s %s",network_wifi_get_known_count(),eth_config.valid?" And a valid ethernet adapter":"",result?"Wifi prioritized":"Ethernet prioritized");
}
return result;
}
void network_prioritize_wifi(bool activate) {
if(s_wifi_prioritized == activate) return;
s_wifi_prioritized = activate;
ESP_LOGI(TAG,"Wifi is %s prioritized",activate?"":"not");
// if (network_is_wifi_prioritized() != activate) {
// ESP_LOGW(TAG, "Wifi will %s be prioritized on next boot", activate ? "" : "NOT");
// config_set_value(NVS_TYPE_STR, "prio_wifi", activate ? "Y" : "N");
// }
}
void network_manager_format_state_machine(esp_log_level_t level, const char* prefix, state_machine_t* state_machine, bool show_source, const char * caller) {
state_t const* source_state = NULL;
state_t const* current_state = NULL;
network_event_t event = -1;
MEMTRACE_PRINT_DELTA();
if (state_machine) {
source_state = ((network_t *)state_machine)->source_state;
current_state = state_machine->State;
event = state_machine->Event;
network_manager_format_from_to_states(level, prefix, source_state, current_state, event, show_source,caller);
}
else {
ESP_LOG_LEVEL(level, TAG, "%s - %s -> [%s]",
STR_OR_BLANK(caller),
prefix,
event_to_string(event));
}
}
void network_manager_format_from_to_states(esp_log_level_t level, const char* prefix, const state_t * from_state,const state_t * current_state, network_event_t event,bool show_source, const char * caller) {
const char* source_state = "";
const char* source_sub_state = "";
const char* state = "N/A";
const char* sub_state = "N/A";
if (current_state) {
state = state_to_string(current_state);
sub_state = sub_state_to_string(current_state);
}
if (!from_state) {
source_state = "N/A";
} else {
source_state = state_to_string(from_state);
source_sub_state = sub_state_to_string(from_state);
}
if (show_source) {
ESP_LOG_LEVEL(level, TAG, "%s %s %s(%s)->%s(%s) [%s]",
STR_OR_BLANK(caller),
prefix,
source_state,
source_sub_state,
state,
sub_state,
event_to_string(event));
} else {
ESP_LOG_LEVEL(level, TAG, "%s %s %s(%s) [%s]",
STR_OR_BLANK(caller),
prefix,
state,
sub_state,
event_to_string(event));
}
}
void network_async(network_event_t trigger) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = trigger;
ESP_LOGD(TAG, "Posting event %s directly", event_to_string(trigger));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_async_fail() {
network_async(EN_FAIL);
}
void network_async_success() {
network_async(EN_SUCCESS);
}
void network_async_connected(){
network_async(EN_CONNECTED);
}
void network_async_link_up() {
network_async(EN_LINK_UP);
}
void network_async_link_down() {
network_async(EN_LINK_DOWN);
}
void network_async_configure() {
network_async(EN_CONFIGURE);
}
void network_async_got_ip() {
network_async(EN_GOT_IP);
}
void network_async_eth_got_ip() {
network_async(EN_ETH_GOT_IP);
}
void network_async_timer() {
network_async(EN_TIMER);
}
void network_async_start() {
network_async(EN_START);
}
void network_async_scan() {
network_async(EN_SCAN);
}
void network_async_update_status() {
network_async(EN_UPDATE_STATUS);
}
void network_async_delete() {
network_async(EN_DELETE);
}
void network_async_scan_done() {
network_async(EN_SCAN_DONE);
}
void network_async_connect(const char * ssid, const char * password) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_CONNECT_NEW;
msg.ssid = strdup_psram(ssid);
if(password && strlen(password) >0){
msg.password = strdup_psram(password);
}
ESP_LOGD(TAG, "Posting event %s", event_to_string(msg.trigger));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_LOST_CONNECTION;
ESP_LOGD(TAG, "Posting event %s", event_to_string(msg.trigger));
msg.disconnected_event = malloc_init_external(sizeof(wifi_event_sta_disconnected_t));
if(msg.disconnected_event){
memcpy(msg.disconnected_event, disconnected_event,sizeof(wifi_event_sta_disconnected_t));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
else {
ESP_LOGE(TAG,"Unable to post lost connection event.");
}
}
void network_async_reboot(reboot_type_t rtype) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_REBOOT;
msg.rtype = rtype;
ESP_LOGD(TAG, "Posting event %s - type %d", event_to_string(msg.trigger),rtype);
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_reboot_ota(char* url) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
if (url == NULL) {
msg.trigger = EN_REBOOT;
msg.rtype = OTA;
ESP_LOGD(TAG, "Posting event %s - type %d", event_to_string(msg.trigger),msg.rtype);
} else {
msg.trigger = EN_REBOOT_URL;
ESP_LOGD(TAG, "Posting event %s - type reboot URL", event_to_string(msg.trigger));
msg.strval = strdup_psram(url);
}
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
network_t* network_get_state_machine() {
return &NM;
}
static void network_timer_cb(void* timer_id) {
network_async_timer();
}
esp_netif_t* network_get_active_interface() {
if (NM.wifi_ap_netif && (network_wifi_is_ap_mode() || network_wifi_is_ap_sta_mode())) {
return NM.wifi_ap_netif;
} else if (NM.wifi_netif && network_wifi_is_sta_mode()) {
return NM.wifi_netif;
}
return NM.eth_netif;
}
bool network_is_interface_connected(esp_netif_t* interface) {
esp_err_t err = ESP_OK;
tcpip_adapter_ip_info_t ipInfo;
if(!interface){
return false;
}
err = network_get_ip_info_for_netif(interface, &ipInfo);
if(err != ESP_OK){
ESP_LOGD(TAG,"network_get_ip_info_for_netif returned %s", esp_err_to_name(err));
}
return ((err == ESP_OK) && (ipInfo.ip.addr != IPADDR_ANY));
}
static esp_netif_t* get_connected_interface() {
esp_netif_t* interface = NULL;
for (int i = 0; i < 4; i++) {
switch (i) {
case 0:
// try the active interface
interface = network_get_active_interface();
break;
case 1:
interface = NM.wifi_ap_netif;
break;
case 2:
interface = NM.wifi_netif;
break;
case 3:
interface = NM.eth_netif;
break;
default:
break;
}
if (interface && network_is_interface_connected(interface)) {
ESP_LOGD(TAG,"Found connected interface in iteration #%d",i);
return interface;
}
}
ESP_LOGD(TAG,"No connected interface found");
return NULL;
}
esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo) {
esp_netif_ip_info_t loc_ip_info;
if (!ipInfo ) {
ESP_LOGE(TAG, "Invalid pointer for ipInfo");
return ESP_ERR_INVALID_ARG;
}
if (!netif) {
ESP_LOGE(TAG, "Invalid pointer for netif");
return ESP_ERR_INVALID_ARG;
}
memset(ipInfo,0x00,sizeof(tcpip_adapter_ip_info_t));
esp_err_t err= esp_netif_get_ip_info(netif, &loc_ip_info);
if(err==ESP_OK){
ip4_addr_set(&(ipInfo->ip),&loc_ip_info.ip);
ip4_addr_set(&(ipInfo->gw),&loc_ip_info.gw);
ip4_addr_set(&(ipInfo->netmask),&loc_ip_info.netmask);
}
return err;
}
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo) {
esp_netif_t* netif= get_connected_interface();
if(netif){
return network_get_ip_info_for_netif(netif,ipInfo);
}
return ESP_FAIL;
}
esp_err_t network_get_hostname(const char** hostname) {
return esp_netif_get_hostname(get_connected_interface(), hostname);
}
void network_set_timer(uint16_t duration) {
if (duration > 0) {
if (!NM.state_timer) {
ESP_LOGD(TAG, "Starting new pulse check timer with period of %u ms.", duration);
NM.state_timer = xTimerCreate("background STA", pdMS_TO_TICKS(duration), pdFALSE, NULL, network_timer_cb);
} else {
ESP_LOGD(TAG, "Changing the pulse timer period to %u ms.", duration);
xTimerChangePeriod(NM.state_timer, pdMS_TO_TICKS(duration), portMAX_DELAY);
}
xTimerStart(NM.state_timer, portMAX_DELAY);
} else if (NM.state_timer) {
ESP_LOGD(TAG, "Stopping timer");
xTimerStop(NM.state_timer, portMAX_DELAY);
}
}
void network_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
ip_event_got_ip_t* s = NULL;
esp_netif_ip_info_t* ip_info = NULL;
if (event_base != IP_EVENT)
return;
switch (event_id) {
case IP_EVENT_ETH_GOT_IP:
case IP_EVENT_STA_GOT_IP:
s = (ip_event_got_ip_t*)event_data;
ip_info = &s->ip_info;
ESP_LOGI(TAG, "Got an IP address from interface %s. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s",
event_id == IP_EVENT_ETH_GOT_IP ? "Eth" : event_id == IP_EVENT_STA_GOT_IP ? "Wifi"
: "Unknown",
IP2STR(&ip_info->ip),
IP2STR(&ip_info->gw),
IP2STR(&ip_info->netmask),
s->ip_changed ? "Address was changed" : "Address unchanged");
network_async(event_id == IP_EVENT_ETH_GOT_IP ? EN_ETH_GOT_IP : EN_GOT_IP);
break;
case IP_EVENT_STA_LOST_IP:
ESP_LOGD(TAG, "IP_EVENT_STA_LOST_IP");
break;
case IP_EVENT_AP_STAIPASSIGNED:
ESP_LOGD(TAG, "IP_EVENT_AP_STAIPASSIGNED");
break;
case IP_EVENT_GOT_IP6:
ESP_LOGD(TAG, "IP_EVENT_GOT_IP6");
break;
default:
break;
}
}
void network_set_hostname(esp_netif_t* interface) {
esp_err_t err;
ESP_LOGD(TAG, "Retrieving host name from nvs");
char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name");
if (host_name == NULL) {
ESP_LOGE(TAG, "Could not retrieve host name from nvs");
} else {
ESP_LOGD(TAG, "Setting host name to : %s", host_name);
if ((err = esp_netif_set_hostname(interface, host_name)) != ESP_OK) {
ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err));
}
free(host_name);
}
}
#define LOCAL_MAC_SIZE 20
char* network_manager_alloc_get_mac_string(uint8_t mac[6]) {
char* macStr = malloc_init_external(LOCAL_MAC_SIZE);
if(macStr){
snprintf(macStr, LOCAL_MAC_SIZE, MACSTR, MAC2STR(mac));
}
return macStr;
}

View File

@@ -1,41 +1,5 @@
/* #pragma once
Copyright (c) 2017-2019 Tony Pottier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file network_manager.h
@author Tony Pottier
@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis
Contains the freeRTOS task and all necessary support
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
*/
#ifndef WIFI_MANAGER_H_INCLUDED
#define WIFI_MANAGER_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_wifi_types.h" #include "esp_wifi_types.h"
@@ -43,8 +7,192 @@ extern "C" {
#include "cJSON.h" #include "cJSON.h"
#include "esp_eth.h" #include "esp_eth.h"
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "state_machine.h" #include "hsm.h"
#include "state_machine.h" #include "esp_log.h"
#ifdef __cplusplus
extern "C" {
#endif
#define STA_POLLING_MIN (15 * 1000)
#define STA_POLLING_MAX (10 * 60 * 1000)
#define ETH_LINK_DOWN_REBOOT (2 * 1000)
#define ETH_DHCP_FAIL (6 * 1000)
#define WIFI_DHCP_FAIL (6 * 1000)
/*
* --------------------- ENUMERATION ---------------------
*/
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_LEAF(NAME, HANDLER, ENTRY, EXIT, PARENT, LEVEL)
#define ALL_NM_STATE \
ADD_ROOT_LEAF(NETWORK_INSTANTIATED_STATE)\
ADD_ROOT_LEAF(NETWORK_INITIALIZING_STATE)\
ADD_ROOT(NETWORK_ETH_ACTIVE_STATE, Eth_Active_State)\
ADD_ROOT(NETWORK_WIFI_ACTIVE_STATE, Wifi_Active_State)\
ADD_ROOT(NETWORK_WIFI_CONFIGURING_ACTIVE_STATE, Wifi_Configuring_State)
#define ALL_ETH_STATE(PARENT, LEVEL)\
ADD_LEAF(ETH_STARTING_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKUP_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKDOWN_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_CONNECTING_NEW_STATE,PARENT,LEVEL)
#define ALL_WIFI_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_INITIALIZING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_FAILED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_USER_DISCONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_LOST_CONNECTION_STATE,PARENT,LEVEL)
#define ALL_WIFI_CONFIGURING_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_GOTOSTA_STATE,PARENT,LEVEL)
#define ADD_ROOT(name, ...) name,
#define ADD_ROOT_LEAF(name, ...) name,
#define ADD_LEAF(name, ...) name,
typedef enum {
ALL_NM_STATE
TOTAL_NM_STATE
} nm_state_t;
typedef enum {
ALL_WIFI_STATE(,)
TOTAL_WIFI_ACTIVE_STATE
} mn_wifi_active_state_t;
typedef enum {
ALL_ETH_STATE(,)
TOTAL_ETH_ACTIVE_STATE
} mn_eth_active_state_t;
typedef enum {
ALL_WIFI_CONFIGURING_STATE(,)
TOTAL_WIFI_CONFIGURING_STATE
} mn_wifi_configuring_state_t;
#undef ADD_STATE
#undef ADD_ROOT
#undef ADD_ROOT_LEAF
#undef ADD_LEAF
typedef void (*network_status_reached_cb)(nm_state_t state_id, int sub_state );
//! List of oven events
#define ALL_NM_EVENTS \
ADD_FIRST_EVENT(EN_LINK_UP) \
ADD_EVENT(EN_LINK_DOWN)\
ADD_EVENT(EN_CONFIGURE)\
ADD_EVENT(EN_GOT_IP)\
ADD_EVENT(EN_ETH_GOT_IP)\
ADD_EVENT(EN_DELETE)\
ADD_EVENT(EN_TIMER)\
ADD_EVENT(EN_START)\
ADD_EVENT(EN_SCAN)\
ADD_EVENT(EN_FAIL)\
ADD_EVENT(EN_SUCCESS)\
ADD_EVENT(EN_SCAN_DONE)\
ADD_EVENT(EN_CONNECT)\
ADD_EVENT(EN_CONNECT_NEW)\
ADD_EVENT(EN_REBOOT)\
ADD_EVENT(EN_REBOOT_URL)\
ADD_EVENT(EN_LOST_CONNECTION)\
ADD_EVENT(EN_ETHERNET_FALLBACK)\
ADD_EVENT(EN_UPDATE_STATUS)\
ADD_EVENT(EN_CONNECTED)
#define ADD_EVENT(name) name,
#define ADD_FIRST_EVENT(name) name=1,
typedef enum {
ALL_NM_EVENTS
} network_event_t;
#undef ADD_EVENT
#undef ADD_FIRST_EVENT
typedef enum {
OTA,
RECOVERY,
RESTART,
} reboot_type_t;
typedef struct {
network_event_t trigger;
char * ssid;
char * password;
reboot_type_t rtype;
char* strval;
wifi_event_sta_disconnected_t* disconnected_event;
esp_netif_t *netif;
} queue_message;
typedef struct
{
state_machine_t Machine; //!< Abstract state machine
const state_t* source_state;
bool ethernet_connected;
TimerHandle_t state_timer;
uint32_t STA_duration;
int32_t total_connected_time;
int64_t last_connected;
uint16_t num_disconnect;
uint16_t retries;
bool wifi_connected;
esp_netif_t *wifi_netif;
esp_netif_t *eth_netif;
esp_netif_t *wifi_ap_netif;
queue_message * event_parameters;
} network_t;
/*
* --------------------- External function prototype ---------------------
*/
void network_start();
network_t * network_get_state_machine();
void network_event_simple(network_event_t trigger);
void network_event(network_event_t trigger, void* param);
void network_async_event(network_event_t trigger, void* param);
void network_async(network_event_t trigger);
void network_async_fail();
void network_async_success();
void network_async_link_up();
void network_async_link_down();
void network_async_configure();
void network_async_got_ip();
void network_async_timer();
void network_async_start();
void network_async_scan();
void network_async_scan_done();
void network_async_connect(const char * ssid, const char * password);
void network_async_lost_connection(wifi_event_sta_disconnected_t * disconnected_event);
void network_async_reboot(reboot_type_t rtype);
void network_reboot_ota(char* url);
void network_async_delete();
void network_async_update_status();
void network_async_eth_got_ip();
void network_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
bool network_is_interface_connected(esp_netif_t * interface);
/*
* --------------------- Inline functions ---------------------
*/
/** /**
* @brief Defines the maximum size of a SSID name. 32 is IEEE standard. * @brief Defines the maximum size of a SSID name. 32 is IEEE standard.
* @warning limit is also hard coded in wifi_config_t. Never extend this value. * @warning limit is also hard coded in wifi_config_t. Never extend this value.
@@ -149,96 +297,23 @@ extern "C" {
*/ */
#define DEFAULT_STA_POWER_SAVE WIFI_PS_MIN_MODEM #define DEFAULT_STA_POWER_SAVE WIFI_PS_MIN_MODEM
/**
* @brief Defines the maximum length in bytes of a JSON representation of an access point.
*
* maximum ap string length with full 32 char ssid: 75 + \\n + \0 = 77\n
* example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","chan":12,"rssi":-100,"auth":4},\n
* BUT: we need to escape JSON. Imagine a ssid full of \" ? so it's 32 more bytes hence 77 + 32 = 99.\n
* this is an edge case but I don't think we should crash in a catastrophic manner just because
* someone decided to have a funny wifi name.
*/
#define JSON_ONE_APP_SIZE 99
/** void network_reboot_ota(char * url);
* @brief Defines the complete list of all messages that the wifi_manager can process.
*
* Some of these message are events ("EVENT"), and some of them are action ("ORDER")
* Each of these messages can trigger a callback function and each callback function is stored
* in a function pointer array for convenience. Because of this behavior, it is extremely important
* to maintain a strict sequence and the top level special element 'MESSAGE_CODE_COUNT'
*
* @see wifi_manager_set_callback
*/
typedef enum message_code_t {
NONE = 0,
ORDER_START_HTTP_SERVER = 1,
ORDER_STOP_HTTP_SERVER = 2,
ORDER_START_DNS_SERVICE = 3,
ORDER_STOP_DNS_SERVICE = 4,
ORDER_START_WIFI_SCAN = 5,
ORDER_LOAD_AND_RESTORE_STA = 6,
ORDER_CONNECT_STA = 7,
ORDER_DISCONNECT_STA = 8,
ORDER_START_AP = 9,
ORDER_START_HTTP = 10,
ORDER_START_DNS_HIJACK = 11,
EVENT_STA_DISCONNECTED = 12,
EVENT_SCAN_DONE = 13,
EVENT_GOT_IP = 14,
ORDER_RESTART_OTA = 15,
ORDER_RESTART_RECOVERY = 16,
ORDER_RESTART_OTA_URL = 17,
ORDER_RESTART = 18,
ORDER_UPDATE_STATUS = 19,
EVENT_ETH_GOT_IP = 20,
EVENT_ETH_TIMEOUT = 21,
EVENT_ETH_LINK_UP = 22,
EVENT_ETH_LINK_DOWN = 23,
MESSAGE_CODE_COUNT = 24 /* important for the callback array */
}message_code_t;
/* @brief indicate that the ESP32 is currently connected. */
extern const int WIFI_MANAGER_WIFI_CONNECTED_BIT;
extern const int WIFI_MANAGER_AP_STA_CONNECTED_BIT;
/* @brief Set automatically once the SoftAP is started */
extern const int WIFI_MANAGER_AP_STARTED_BIT;
/* @brief When set, means a client requested to connect to an access point.*/
extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT;
/* @brief This bit is set automatically as soon as a connection was lost */
extern const int WIFI_MANAGER_STA_DISCONNECT_BIT ;
/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */
extern const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT ;
/* @brief When set, means a client requested to disconnect from currently connected AP. */
extern const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT ;
/* @brief When set, means a scan is in progress */
extern const int WIFI_MANAGER_SCAN_BIT ;
/* @brief When set, means user requested for a disconnect */
extern const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT ;
/* @brief When set, means user requested connecting to a new network and it failed */
extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT ;
void network_manager_reboot_ota(char * url);
/** /**
* @brief simplified reason codes for a lost connection. * @brief simplified reason codes for a lost connection.
* *
* esp-idf maintains a big list of reason codes which in practice are useless for most typical application. * esp-idf maintains a big list of reason codes which in practice are useless for most typical application.
* UPDATE_CONNECTION_OK - Web UI expects this when attempting to connect to a new access point succeeds
* UPDATE_FAILED_ATTEMPT - Web UI expects this when attempting to connect to a new access point fails
* UPDATE_USER_DISCONNECT = 2,
* UPDATE_LOST_CONNECTION = 3,
* UPDATE_FAILED_ATTEMPT_AND_RESTORE - Web UI expects this when attempting to connect to a new access point fails and previous connection is restored
* UPDATE_ETHERNET_CONNECTED = 5
*/ */
typedef enum update_reason_code_t { typedef enum update_reason_code_t {
UPDATE_CONNECTION_OK = 0, UPDATE_CONNECTION_OK = 0, // expected when
UPDATE_FAILED_ATTEMPT = 1, UPDATE_FAILED_ATTEMPT = 1,
UPDATE_USER_DISCONNECT = 2, UPDATE_USER_DISCONNECT = 2,
UPDATE_LOST_CONNECTION = 3, UPDATE_LOST_CONNECTION = 3,
@@ -247,33 +322,6 @@ typedef enum update_reason_code_t {
}update_reason_code_t; }update_reason_code_t;
typedef enum connection_request_made_by_code_t{
CONNECTION_REQUEST_NONE = 0,
CONNECTION_REQUEST_USER = 1,
CONNECTION_REQUEST_AUTO_RECONNECT = 2,
CONNECTION_REQUEST_RESTORE_CONNECTION = 3,
CONNECTION_REQUEST_MAX_FAILED = 4,
CONNECTION_REQUEST_MAX = 0x7fffffff /*force the creation of this enum as a 32 bit int */
}connection_request_made_by_code_t;
/**
* The wifi manager settings in use
*/
//struct wifi_settings_t{
// bool sta_only;
// bool sta_static_ip;
// wifi_ps_type_t sta_power_save;
// tcpip_adapter_ip_info_t sta_static_ip_config;
//};
//extern struct wifi_settings_t wifi_settings;
// /**
// * @brief Structure used to store one message in the queue.
// */
// typedef struct{
// message_code_t code;
// void *param;
// } queue_message;
@@ -284,59 +332,95 @@ typedef enum connection_request_made_by_code_t{
/** /**
* Frees up all memory allocated by the wifi_manager and kill the task. * Frees up all memory allocated by the wifi_manager and kill the task.
*/ */
void network_manager_destroy(); void network_destroy();
/** /**
* Filters the AP scan list to unique SSIDs * Filters the AP scan list to unique SSIDs
*/ */
void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num); void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num);
/**
* Main task for the wifi_manager
*/
void network_manager( void * pvParameters );
char* network_status_alloc_get_ap_list_json();
char* wifi_manager_alloc_get_ap_list_json(); cJSON * network_manager_clear_ap_list_json(cJSON **old);
cJSON * wifi_manager_clear_ap_list_json(cJSON **old);
/** /**
* @brief A standard wifi event handler as recommended by Espressif * @brief A standard wifi event handler as recommended by Espressif
*/ */
esp_err_t wifi_manager_event_handler(void *ctx, system_event_t *event); esp_err_t network_manager_event_handler(void *ctx, system_event_t *event);
/** /**
* @brief Clears the connection status json. * @brief Clears the connection status json.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. * @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/ */
cJSON * wifi_manager_clear_ip_info_json(cJSON **old); cJSON * network_status_clear_ip_info_json(cJSON **old);
cJSON * wifi_manager_get_new_json(cJSON **old); cJSON * network_status_get_new_json(cJSON **old);
/** /**
* @brief Start the mDNS service * @brief Start the mDNS service
*/ */
void wifi_manager_initialise_mdns(); void network_manager_initialise_mdns();
/** /**
* @brief Register a callback to a custom function when specific event message_code happens. * @brief Register a callback to a custom function when specific network manager states are reached.
*/ */
void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) ); esp_err_t network_register_state_callback(nm_state_t state, int sub_state, const char* from, network_status_reached_cb cb);
bool network_is_wifi_prioritized();
esp_netif_t * network_get_active_interface();
esp_err_t network_get_hostname( const char **hostname);
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo);
void network_set_timer(uint16_t duration);
void network_set_hostname(esp_netif_t * netif);
esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo);
void network_start_stop_dhcp(esp_netif_t* netif, bool start);
void network_start_stop_dhcps(esp_netif_t* netif, bool start);
void network_prioritize_wifi(bool activate);
#define ADD_ROOT_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_ROOT_LEAF_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_LEAF_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_STATE_FORWARD_DECLARATION_(name) \
static state_machine_result_t name##_handler(state_machine_t* const State_Machine); \
static state_machine_result_t name##_entry_handler(state_machine_t* const State_Machine); \
static state_machine_result_t name##_exit_handler(state_machine_t* const State_Machine);
void initialize_network_handlers(state_machine_t* state_machine);
void network_manager_format_from_to_states(esp_log_level_t level, const char* prefix, state_t const * from_state, state_t const* current_state, network_event_t event,bool show_source, const char * caller );
void network_manager_format_state_machine(esp_log_level_t level, const char* prefix, state_machine_t * state_machine, bool show_source, const char * caller) ;
char* network_manager_alloc_get_mac_string(uint8_t mac[6]);
bool network_manager_is_flag_set(EventBits_t bit); #if defined(LOG_LOCAL_LEVEL) && LOG_LOCAL_LEVEL >=ESP_LOG_VERBOSE
void network_manager_set_flag(EventBits_t bit); #define NETWORK_PRINT_TRANSITION(begin, prefix, source,target, event, print_source,caller ) network_manager_format_from_to_states(ESP_LOG_VERBOSE, prefix, source,target, event, print_source,caller )
void network_manager_clear_flag(EventBits_t bit); #define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller) network_manager_format_state_machine(ESP_LOG_DEBUG,cb_prefix,state_machine,print_from,caller)
#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,__FUNCTION__);
#define network_handler_entry_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"ENTRY START":"ENTRY END",State_Machine,false,__FUNCTION__)
#define network_exit_handler_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"EXIT START":"END END",State_Machine,false,__FUNCTION__)
#define network_handler_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"HANDLER START":"HANDLER END",State_Machine,false,__FUNCTION__)
#elif defined(LOG_LOCAL_LEVEL) && LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG
#define network_handler_entry_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"BEGIN ENTRY":"END ENTRY",State_Machine,false,__FUNCTION__)
#define network_exit_handler_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"BEGIN EXIT":"END EXIT",State_Machine,false,__FUNCTION__)
#define network_handler_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"HANDLER START":"HANDLER END",State_Machine,false,__FUNCTION__)
#define NETWORK_PRINT_TRANSITION(begin, prefix, source,target, event, print_source,caller ) if(begin) network_manager_format_from_to_states(ESP_LOG_DEBUG, prefix, source,target, event, print_source,caller )#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,__FUNCTION__);
#define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,cb_prefix,state_machine,print_from,caller)
#else
#define network_exit_handler_print(nm, begin)
#define network_handler_entry_print(State_Machine, begin)
#define network_handler_print(State_Machine, begin)
#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,NULL)
#define NETWORK_PRINT_TRANSITION(prefix, source,target, event, print_source,caller )
#define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller)
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* WIFI_MANAGER_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
#ifdef NETWORK_STATUS_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_STATUS_LOG_LEVEL
#endif
#include "network_status.h" #include "network_status.h"
#include <string.h> #include <string.h>
#include "bt_app_core.h" #include "bt_app_core.h"
@@ -16,10 +20,12 @@
#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases" #define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#endif #endif
static const char TAG[] = "network_status"; static const char TAG[] = "network_status";
SemaphoreHandle_t wifi_manager_json_mutex = NULL; SemaphoreHandle_t network_status_json_mutex = NULL;
SemaphoreHandle_t wifi_manager_sta_ip_mutex = NULL; static TaskHandle_t network_json_locked_task = NULL;
SemaphoreHandle_t network_status_ip_address_mutex = NULL;
static TaskHandle_t network_status_ip_address_locked_task = NULL;
char* release_url = NULL; char* release_url = NULL;
char* wifi_manager_sta_ip = NULL; char* network_status_ip_address = NULL;
char* ip_info_json = NULL; char* ip_info_json = NULL;
cJSON* ip_info_cjson = NULL; cJSON* ip_info_cjson = NULL;
static char lms_server_ip[IP4ADDR_STRLEN_MAX] = {0}; static char lms_server_ip[IP4ADDR_STRLEN_MAX] = {0};
@@ -33,11 +39,11 @@ void init_network_status() {
chained_notify = server_notify; chained_notify = server_notify;
server_notify = connect_notify; server_notify = connect_notify;
ESP_LOGD(TAG, "init_network_status. Creating mutexes"); ESP_LOGD(TAG, "init_network_status. Creating mutexes");
wifi_manager_json_mutex = xSemaphoreCreateMutex(); network_status_json_mutex = xSemaphoreCreateMutex();
wifi_manager_sta_ip_mutex = xSemaphoreCreateMutex(); network_status_ip_address_mutex = xSemaphoreCreateMutex();
ip_info_json = NULL; ip_info_json = NULL;
ESP_LOGD(TAG, "init_network_status. Creating status json structure"); ESP_LOGD(TAG, "init_network_status. Creating status json structure");
ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson); ip_info_cjson = network_status_clear_ip_info_json(&ip_info_cjson);
ESP_LOGD(TAG, "Getting release url "); ESP_LOGD(TAG, "Getting release url ");
char* release_url = (char*)config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0); char* release_url = (char*)config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0);
if (release_url == NULL) { if (release_url == NULL) {
@@ -46,57 +52,73 @@ void init_network_status() {
ESP_LOGD(TAG, "Found release url %s", release_url); ESP_LOGD(TAG, "Found release url %s", release_url);
} }
ESP_LOGD(TAG, "About to set the STA IP String to 0.0.0.0"); ESP_LOGD(TAG, "About to set the STA IP String to 0.0.0.0");
wifi_manager_sta_ip = (char*)malloc(STA_IP_LEN); network_status_ip_address = (char*)malloc_init_external(STA_IP_LEN);
wifi_manager_safe_update_sta_ip_string(NULL); network_status_safe_update_sta_ip_string(NULL);
} }
void destroy_network_status() { void destroy_network_status() {
FREE_AND_NULL(release_url); FREE_AND_NULL(release_url);
FREE_AND_NULL(ip_info_json); FREE_AND_NULL(ip_info_json);
FREE_AND_NULL(wifi_manager_sta_ip); FREE_AND_NULL(network_status_ip_address);
cJSON_Delete(ip_info_cjson); cJSON_Delete(ip_info_cjson);
vSemaphoreDelete(wifi_manager_json_mutex); vSemaphoreDelete(network_status_json_mutex);
wifi_manager_json_mutex = NULL; network_status_json_mutex = NULL;
vSemaphoreDelete(wifi_manager_sta_ip_mutex); vSemaphoreDelete(network_status_ip_address_mutex);
wifi_manager_sta_ip_mutex = NULL; network_status_ip_address_mutex = NULL;
ip_info_cjson = NULL; ip_info_cjson = NULL;
} }
cJSON* wifi_manager_get_new_json(cJSON** old) { cJSON* network_status_get_new_json(cJSON** old) {
ESP_LOGV(TAG, "wifi_manager_get_new_json called"); ESP_LOGV(TAG, "network_status_get_new_json called");
cJSON* root = *old; cJSON* root = *old;
if (root != NULL) { if (root != NULL) {
cJSON_Delete(root); cJSON_Delete(root);
*old = NULL; *old = NULL;
} }
ESP_LOGV(TAG, "wifi_manager_get_new_json done"); ESP_LOGV(TAG, "network_status_get_new_json done");
return cJSON_CreateObject(); return cJSON_CreateObject();
} }
cJSON* wifi_manager_clear_ip_info_json(cJSON** old) { cJSON* network_status_clear_ip_info_json(cJSON** old) {
ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json called"); ESP_LOGV(TAG, "network_status_clear_ip_info_json called");
cJSON* root = wifi_manager_get_basic_info(old); cJSON* root = network_status_get_basic_info(old);
ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json done"); cJSON_DeleteItemFromObjectCaseSensitive(root, "ip");
cJSON_DeleteItemFromObjectCaseSensitive(root, "netmask");
cJSON_DeleteItemFromObjectCaseSensitive(root, "gw");
cJSON_DeleteItemFromObjectCaseSensitive(root, "rssi");
cJSON_DeleteItemFromObjectCaseSensitive(root, "ssid");
cJSON_DeleteItemFromObjectCaseSensitive(root, "eth");
ESP_LOGV(TAG, "network_status_clear_ip_info_json done");
return root; return root;
} }
void network_status_clear_ip() { void network_status_clear_ip() {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { if (network_status_lock_json_buffer(portMAX_DELAY)) {
ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson); ip_info_cjson = network_status_clear_ip_info_json(&ip_info_cjson);
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
} }
} }
char* wifi_manager_alloc_get_ip_info_json() { char* network_status_alloc_get_ip_info_json() {
return cJSON_PrintUnformatted(ip_info_cjson); return cJSON_PrintUnformatted(ip_info_cjson);
} }
void wifi_manager_unlock_json_buffer() { void network_status_unlock_json_buffer() {
ESP_LOGV(TAG, "Unlocking json buffer!"); ESP_LOGV(TAG, "Unlocking json buffer!");
xSemaphoreGive(wifi_manager_json_mutex); network_json_locked_task = NULL;
xSemaphoreGive(network_status_json_mutex);
} }
bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait) { bool network_status_lock_json_buffer(TickType_t xTicksToWait) {
ESP_LOGV(TAG, "Locking json buffer"); ESP_LOGV(TAG, "Locking json buffer");
if (wifi_manager_json_mutex) {
if (xSemaphoreTake(wifi_manager_json_mutex, xTicksToWait) == pdTRUE) { TaskHandle_t calling_task = xTaskGetCurrentTaskHandle();
if (calling_task == network_json_locked_task) {
ESP_LOGV(TAG, "json buffer already locked to current task");
return true;
}
if (network_status_json_mutex) {
if (xSemaphoreTake(network_status_json_mutex, xTicksToWait) == pdTRUE) {
ESP_LOGV(TAG, "Json buffer locked!"); ESP_LOGV(TAG, "Json buffer locked!");
network_json_locked_task = calling_task;
return true; return true;
} else { } else {
ESP_LOGE(TAG, "Semaphore take failed. Unable to lock json buffer mutex"); ESP_LOGE(TAG, "Semaphore take failed. Unable to lock json buffer mutex");
@@ -108,9 +130,15 @@ bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait) {
} }
} }
bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait) { bool network_status_lock_sta_ip_string(TickType_t xTicksToWait) {
if (wifi_manager_sta_ip_mutex) { TaskHandle_t calling_task = xTaskGetCurrentTaskHandle();
if (xSemaphoreTake(wifi_manager_sta_ip_mutex, xTicksToWait) == pdTRUE) { if (calling_task == network_status_ip_address_locked_task) {
ESP_LOGD(TAG, "json buffer already locked to current task ");
return true;
}
if (network_status_ip_address_mutex) {
if (xSemaphoreTake(network_status_ip_address_mutex, xTicksToWait) == pdTRUE) {
network_status_ip_address_locked_task = calling_task;
return true; return true;
} else { } else {
return false; return false;
@@ -120,26 +148,27 @@ bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait) {
} }
} }
void wifi_manager_unlock_sta_ip_string() { void network_status_unlock_sta_ip_string() {
xSemaphoreGive(wifi_manager_sta_ip_mutex); network_status_ip_address_locked_task = NULL;
xSemaphoreGive(network_status_ip_address_mutex);
} }
void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t* ip4) { void network_status_safe_update_sta_ip_string(esp_ip4_addr_t* ip4) {
if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) { if (network_status_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(wifi_manager_sta_ip, ip4 != NULL ? ip4addr_ntoa(ip4) : "0.0.0.0"); strcpy(network_status_ip_address, ip4 != NULL ? ip4addr_ntoa((ip4_addr_t*)ip4) : "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip); ESP_LOGD(TAG, "Set STA IP String to: %s", network_status_ip_address);
wifi_manager_unlock_sta_ip_string(); network_status_unlock_sta_ip_string();
} }
} }
void wifi_manager_safe_reset_sta_ip_string() { void network_status_safe_reset_sta_ip_string() {
if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) { if (network_status_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(wifi_manager_sta_ip, "0.0.0.0"); strcpy(network_status_ip_address, "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip); ESP_LOGD(TAG, "Set STA IP String to: %s", network_status_ip_address);
wifi_manager_unlock_sta_ip_string(); network_status_unlock_sta_ip_string();
} }
} }
char* wifi_manager_get_sta_ip_string() { char* network_status_get_sta_ip_string() {
return wifi_manager_sta_ip; return network_status_ip_address;
} }
void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport) { void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport) {
strncpy(lms_server_ip, inet_ntoa(ip), sizeof(lms_server_ip)); strncpy(lms_server_ip, inet_ntoa(ip), sizeof(lms_server_ip));
@@ -152,98 +181,47 @@ static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) {
set_lms_server_details(ip, hport, cport); set_lms_server_details(ip, hport, cport);
if (chained_notify) if (chained_notify)
(*chained_notify)(ip, hport, cport); (*chained_notify)(ip, hport, cport);
network_manager_async_update_status(); network_async_update_status();
} }
void wifi_manager_update_basic_info() {
int32_t total_connected_time = 0;
int64_t last_connected = 0;
uint16_t num_disconnect = 0;
network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect);
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
monitor_gpio_t* mgpio = get_jack_insertion_gpio();
cJSON* voltage = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Voltage"); void network_status_update_basic_info() {
if (voltage) { // locking happens below this level
cJSON_SetNumberValue(voltage, battery_value_svc()); network_status_get_basic_info(&ip_info_cjson);
}
cJSON* bt_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_status");
if (bt_status) {
cJSON_SetNumberValue(bt_status, bt_app_source_get_a2d_state());
}
cJSON* bt_sub_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_sub_status");
if (bt_sub_status) {
cJSON_SetNumberValue(bt_sub_status, bt_app_source_get_media_state());
}
cJSON* jack = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Jack");
if (jack) {
jack->type = mgpio->gpio >= 0 && jack_inserted_svc() ? cJSON_True : cJSON_False;
}
cJSON* disconnect_count = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "disconnect_count");
if (disconnect_count) {
cJSON_SetNumberValue(disconnect_count, num_disconnect);
}
cJSON* avg_conn_time = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "avg_conn_time");
if (avg_conn_time) {
cJSON_SetNumberValue(avg_conn_time, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0);
}
if (lms_server_cport > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport");
if (value) {
cJSON_SetNumberValue(value, lms_server_cport);
} else {
cJSON_AddNumberToObject(ip_info_cjson, "lms_cport", lms_server_cport);
}
}
if (lms_server_port > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port");
if (value) {
cJSON_SetNumberValue(value, lms_server_port);
} else {
cJSON_AddNumberToObject(ip_info_cjson, "lms_port", lms_server_port);
}
}
if (strlen(lms_server_ip) > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip");
if (!value) {
// only create if it does not exist. Since we're creating a reference
// to a char buffer, updates to cJSON aren't needed
cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip));
}
}
if (network_ethernet_enabled()) {
cJSON* eth = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "eth_up");
if (eth) {
eth->type = network_ethernet_is_up() ? cJSON_True : cJSON_False;
}
}
wifi_manager_unlock_json_buffer();
}
} }
cJSON* network_status_update_string(cJSON** root, const char* key, const char* value) { cJSON* network_status_update_string(cJSON** root, const char* key, const char* value) {
if (*root == NULL) { if (network_status_lock_json_buffer(portMAX_DELAY)) {
*root = cJSON_CreateObject(); if (*root == NULL) {
} *root = cJSON_CreateObject();
if (*root == NULL) {
ESP_LOGE(TAG, "Error creating cJSON object!");
}
}
if (!key || !value || strlen(key) == 0) if (!key || !value || strlen(key) == 0) {
return *root; ESP_LOGE(TAG, "network_status_update_string. Invalid key or value passed! key: %s, value: %s", STR_OR_ALT(key, ""), STR_OR_ALT(value, ""));
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); network_status_unlock_json_buffer();
if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) { return *root;
ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value); }
cJSON_SetValuestring(cjsonvalue, value); cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) {
ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value);
cJSON_SetValuestring(cjsonvalue, value);
} else {
cJSON_AddItemToObject(*root, key, cJSON_CreateString(value));
}
network_status_unlock_json_buffer();
} else { } else {
cJSON_AddItemToObject(*root, key, cJSON_CreateString(value)); ESP_LOGW(TAG, "Unable to lock status json buffer. ");
} }
return *root; return *root;
} }
cJSON* network_status_update_number(cJSON** root, const char* key, int value) { cJSON* network_status_update_number(cJSON** root, const char* key, int value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) { if (*root == NULL) {
*root = cJSON_CreateObject(); *root = cJSON_CreateObject();
} }
if (key && value && strlen(key) != 0) { if (key && strlen(key) != 0) {
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue) { if (cjsonvalue) {
cJSON_SetNumberValue(cjsonvalue, value); cJSON_SetNumberValue(cjsonvalue, value);
@@ -251,14 +229,14 @@ cJSON* network_status_update_number(cJSON** root, const char* key, int value) {
cJSON_AddNumberToObject(*root, key, value); cJSON_AddNumberToObject(*root, key, value);
} }
} }
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
} else { } else {
ESP_LOGW(TAG, "Unable to lock status json buffer. "); ESP_LOGW(TAG, "Unable to lock status json buffer. ");
} }
return *root; return *root;
} }
cJSON* network_status_update_float(cJSON** root, const char* key, float value) { cJSON* network_status_update_float(cJSON** root, const char* key, float value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) { if (*root == NULL) {
*root = cJSON_CreateObject(); *root = cJSON_CreateObject();
} }
@@ -271,14 +249,14 @@ cJSON* network_status_update_float(cJSON** root, const char* key, float value) {
cJSON_AddNumberToObject(*root, key, value); cJSON_AddNumberToObject(*root, key, value);
} }
} }
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
} else { } else {
ESP_LOGW(TAG, "Unable to lock status json buffer. "); ESP_LOGW(TAG, "Unable to lock status json buffer. ");
} }
return *root; return *root;
} }
cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) { cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) { if (*root == NULL) {
*root = cJSON_CreateObject(); *root = cJSON_CreateObject();
} }
@@ -291,91 +269,110 @@ cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) {
cJSON_AddBoolToObject(*root, key, value); cJSON_AddBoolToObject(*root, key, value);
} }
} }
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
} else { } else {
ESP_LOGW(TAG, "Unable to lock status json buffer. "); ESP_LOGW(TAG, "Unable to lock status json buffer. ");
} }
return *root; return *root;
} }
cJSON* wifi_manager_get_basic_info(cJSON** old) { cJSON* network_status_get_basic_info(cJSON** old) {
int32_t total_connected_time = 0; if (network_status_lock_json_buffer(portMAX_DELAY)) {
int64_t last_connected = 0; network_t* nm = network_get_state_machine();
uint16_t num_disconnect = 0; monitor_gpio_t* mgpio = get_jack_insertion_gpio();
network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect); const esp_app_desc_t* desc = esp_ota_get_app_description();
monitor_gpio_t* mgpio = get_jack_insertion_gpio(); *old = network_status_update_string(old, "project_name", desc->project_name);
const esp_app_desc_t* desc = esp_ota_get_app_description();
ESP_LOGV(TAG, "wifi_manager_get_basic_info called");
cJSON* root = network_status_update_string(&root, "project_name", desc->project_name);
#ifdef CONFIG_FW_PLATFORM_NAME #ifdef CONFIG_FW_PLATFORM_NAME
root = network_status_update_string(&root, "platform_name", CONFIG_FW_PLATFORM_NAME); *old = network_status_update_string(old, "platform_name", CONFIG_FW_PLATFORM_NAME);
#endif #endif
root = network_status_update_string(&root, "version", desc->version); *old = network_status_update_string(old, "version", desc->version);
if (release_url != NULL) if (release_url != NULL)
root = network_status_update_string(&root, "release_url", release_url); *old = network_status_update_string(old, "release_url", release_url);
root = network_status_update_number(&root, "recovery", is_recovery_running ? 1 : 0); *old = network_status_update_number(old, "recovery", is_recovery_running ? 1 : 0);
root = network_status_update_bool(&root, "Jack", mgpio->gpio >= 0 && jack_inserted_svc()); *old = network_status_update_bool(old, "Jack", mgpio->gpio >= 0 && jack_inserted_svc());
root = network_status_update_float(&root, "Voltage", battery_value_svc()); *old = network_status_update_float(old, "Voltage", battery_value_svc());
root = network_status_update_number(&root, "disconnect_count", num_disconnect); *old = network_status_update_number(old, "disconnect_count", nm->num_disconnect);
root = network_status_update_float(&root, "avg_conn_time", num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0); *old = network_status_update_float(old, "avg_conn_time", nm->num_disconnect > 0 ? (nm->total_connected_time / nm->num_disconnect) : 0);
root = network_status_update_number(&root, "bt_status", bt_app_source_get_a2d_state()); *old = network_status_update_number(old, "bt_status", bt_app_source_get_a2d_state());
root = network_status_update_number(&root, "bt_sub_status", bt_app_source_get_media_state()); *old = network_status_update_number(old, "bt_sub_status", bt_app_source_get_media_state());
#if CONFIG_I2C_LOCKED #if CONFIG_I2C_LOCKED
root = network_status_update_bool(&root, "is_i2c_locked", true); *old = network_status_update_bool(old, "is_i2c_locked", true);
#else #else
root = network_status_update_bool(&root, "is_i2c_locked", false); *old = network_status_update_bool(old, "is_i2c_locked", false);
#endif #endif
if (network_ethernet_enabled()) { if (network_ethernet_enabled()) {
root = network_status_update_bool(&root, "eth_up", network_ethernet_is_up()); *old = network_status_update_bool(old, "eth_up", network_ethernet_is_up());
} }
ESP_LOGV(TAG, "wifi_manager_get_basic_info done"); if (lms_server_cport > 0) {
return root; *old = network_status_update_number(old, "lms_cport", lms_server_cport);
} }
void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code) { if (lms_server_port > 0) {
ESP_LOGD(TAG, "wifi_manager_generate_ip_info_json called"); *old = network_status_update_number(old, "lms_port", lms_server_port);
}
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { if (strlen(lms_server_ip) > 0) {
/* generate the connection info with success */ *old = network_status_update_string(old, "lms_ip", lms_server_ip);
}
ip_info_cjson = wifi_manager_get_basic_info(&ip_info_cjson); ESP_LOGV(TAG, "network_status_get_basic_info done");
wifi_manager_unlock_json_buffer(); network_status_unlock_json_buffer();
} else { } else {
ESP_LOGW(TAG, "Unable to lock status json buffer. "); ESP_LOGW(TAG, "Unable to lock status json buffer. ");
} }
ip_info_cjson = network_status_update_number(&ip_info_cjson, "urc", update_reason_code); return *old;
if (update_reason_code == UPDATE_CONNECTION_OK || update_reason_code == UPDATE_ETHERNET_CONNECTED) { }
/* rest of the information is copied after the ssid */ void network_status_update_address(cJSON* root, esp_netif_ip_info_t* ip_info) {
tcpip_adapter_ip_info_t ip_info; if (!root || !ip_info) {
esp_netif_get_ip_info(network_wifi_get_interface(), &ip_info); ESP_LOGE(TAG, "Cannor update IP address. JSON structure or ip_info is null");
return;
network_status_update_string(&ip_info_cjson, "ip", ip4addr_ntoa((ip4_addr_t*)&ip_info.ip)); }
network_status_update_string(&ip_info_cjson, "netmask", ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask)); network_status_update_string(&root, "ip", ip4addr_ntoa((ip4_addr_t*)&ip_info->ip));
network_status_update_string(&ip_info_cjson, "gw", ip4addr_ntoa((ip4_addr_t*)&ip_info.gw)); network_status_update_string(&root, "netmask", ip4addr_ntoa((ip4_addr_t*)&ip_info->netmask));
wifi_mode_t mode; network_status_update_string(&root, "gw", ip4addr_ntoa((ip4_addr_t*)&ip_info->gw));
if (esp_wifi_get_mode(&mode) == ESP_OK && (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA)) { }
/* wifi is active, and associated to an AP */ void network_status_update_ip_info(update_reason_code_t update_reason_code) {
wifi_ap_record_t ap; ESP_LOGV(TAG, "network_status_update_ip_info called");
esp_wifi_sta_get_ap_info(&ap); esp_netif_ip_info_t ip_info;
network_status_update_string(&ip_info_cjson, "ssid", ((char*)ap.ssid)); if (network_status_lock_json_buffer(portMAX_DELAY)) {
network_status_update_number(&ip_info_cjson, "rssi", ap.rssi); /* generate the connection info with success */
}
if (network_ethernet_is_up()) { ip_info_cjson = network_status_get_basic_info(&ip_info_cjson);
esp_netif_get_ip_info(network_ethernet_get_interface(), &ip_info); ip_info_cjson = network_status_update_number(&ip_info_cjson, "urc", update_reason_code);
cJSON* ethernet_ip = cJSON_CreateObject(); ESP_LOGD(TAG,"Updating ip info with reason code %d. Checking if Wifi interface is connected",update_reason_code);
cJSON_AddItemToObject(ethernet_ip, "ip", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.ip))); if (network_is_interface_connected(network_wifi_get_interface())) {
cJSON_AddItemToObject(ethernet_ip, "netmask", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask)));
cJSON_AddItemToObject(ethernet_ip, "gw", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.gw))); esp_netif_get_ip_info(network_wifi_get_interface(), &ip_info);
cJSON_AddItemToObject(ip_info_cjson, "eth", ethernet_ip); network_status_update_address(ip_info_cjson, &ip_info);
} if (!network_wifi_is_ap_mode()) {
} else { /* wifi is active, and associated to an AP */
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ip"); wifi_ap_record_t ap;
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "netmask"); esp_wifi_sta_get_ap_info(&ap);
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "gw"); network_status_update_string(&ip_info_cjson, "ssid", ((char*)ap.ssid));
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "rssi"); network_status_update_number(&ip_info_cjson, "rssi", ap.rssi);
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ssid"); }
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "eth");
} } else {
ESP_LOGV(TAG, "wifi_manager_generate_ip_info_json done"); cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ip");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "netmask");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "gw");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "rssi");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ssid");
}
ESP_LOGD(TAG,"Checking if ethernet interface is connected");
if (network_is_interface_connected(network_ethernet_get_interface())) {
cJSON* ethernet_ip = cJSON_GetObjectItem(ip_info_cjson, "eth");
if (!ethernet_ip) {
ethernet_ip = cJSON_CreateObject();
cJSON_AddItemToObject(ip_info_cjson, "eth", ethernet_ip);
}
esp_netif_get_ip_info(network_ethernet_get_interface(), &ip_info);
network_status_update_address(ethernet_ip, &ip_info);
} else {
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "eth");
}
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
ESP_LOGV(TAG, "wifi_status_generate_ip_info_json done");
} }

View File

@@ -5,7 +5,7 @@
extern "C" { extern "C" {
#endif #endif
char* wifi_manager_alloc_get_ip_info_json(); char* network_status_alloc_get_ip_info_json();
/** /**
* @brief Tries to get access to json buffer mutex. * @brief Tries to get access to json buffer mutex.
* *
@@ -21,39 +21,39 @@ char* wifi_manager_alloc_get_ip_info_json();
* @param xTicksToWait The time in ticks to wait for the semaphore to become available. * @param xTicksToWait The time in ticks to wait for the semaphore to become available.
* @return true in success, false otherwise. * @return true in success, false otherwise.
*/ */
bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait); bool network_status_lock_json_buffer(TickType_t xTicksToWait);
/** /**
* @brief Releases the json buffer mutex. * @brief Releases the json buffer mutex.
*/ */
void wifi_manager_unlock_json_buffer(); void network_status_unlock_json_buffer();
bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait); bool network_status_lock_sta_ip_string(TickType_t xTicksToWait);
void wifi_manager_unlock_sta_ip_string(); void network_status_unlock_sta_ip_string();
/** /**
* @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69" * @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69"
*/ */
char* wifi_manager_get_sta_ip_string(); char* network_status_get_sta_ip_string();
/** /**
* @brief thread safe char representation of the STA IP update * @brief thread safe char representation of the STA IP update
*/ */
void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t * ip4); void network_status_safe_update_sta_ip_string(esp_ip4_addr_t * ip4);
/** /**
* @brief Generates the connection status json: ssid and IP addresses. * @brief Generates the connection status json: ssid and IP addresses.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. * @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/ */
void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code); void network_status_update_ip_info(update_reason_code_t update_reason_code);
void init_network_status(); void init_network_status();
void destroy_network_status(); void destroy_network_status();
cJSON* wifi_manager_get_basic_info(cJSON** old); cJSON* network_status_get_basic_info(cJSON** old);
void wifi_manager_update_basic_info(); void network_status_update_basic_info();
void network_status_clear_ip(); void network_status_clear_ip();
void wifi_manager_safe_reset_sta_ip_string(); void network_status_safe_reset_sta_ip_string();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
extern "C" { extern "C" {
#endif #endif
void init_network_wifi(); esp_netif_t * network_wifi_start();
void destroy_network_wifi(); void destroy_network_wifi();
/** /**
* @brief saves the current STA wifi config to flash ram storage. * @brief saves the current STA wifi config to flash ram storage.
@@ -16,46 +16,59 @@ esp_err_t network_wifi_save_sta_config();
* @brief fetch a previously STA wifi config in the flash ram storage. * @brief fetch a previously STA wifi config in the flash ram storage.
* @return true if a previously saved config was found, false otherwise. * @return true if a previously saved config was found, false otherwise.
*/ */
bool wifi_manager_fetch_wifi_sta_config(); bool network_wifi_load_wifi_sta_config();
wifi_config_t* wifi_manager_get_wifi_sta_config();
/** /**
* @brief Registers handler for wifi and ip events * @brief Registers handler for wifi and ip events
*/ */
void wifi_manager_register_handlers(); void network_wifi_register_handlers();
/** /**
* @brief Generates the list of access points after a wifi scan. * @brief Generates the list of access points after a wifi scan.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. * @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/ */
void wifi_manager_generate_access_points_json(cJSON ** ap_list); void network_wifi_generate_access_points_json(cJSON ** ap_list);
/** /**
* @brief Clear the list of access points. * @brief Clear the list of access points.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. * @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/ */
void wifi_manager_clear_access_points_json(); void network_wifi_clear_access_points_json();
void wifi_manager_config_ap(); esp_netif_t * network_wifi_config_ap();
void wifi_manager_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps); void network_wifi_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps);
esp_err_t wifi_scan_done(queue_message *msg); esp_err_t wifi_scan_done();
esp_err_t network_wifi_start_scan(queue_message *msg); esp_err_t network_wifi_start_scan();
esp_err_t network_wifi_load_restore(queue_message *msg); esp_err_t network_wifi_load_restore(queue_message *msg);
esp_err_t network_wifi_order_connect(queue_message *msg); esp_err_t network_wifi_order_connect(queue_message *msg);
esp_err_t network_wifi_disconnected(queue_message *msg); esp_err_t network_wifi_disconnected(queue_message *msg);
esp_err_t network_wifi_start_ap(queue_message *msg); esp_err_t network_wifi_start_ap(queue_message *msg);
bool wifi_manager_load_wifi_sta_config(wifi_config_t* config ); bool network_wifi_get_config_for_ssid(wifi_config_t* config, const char * ssid);
esp_err_t network_wifi_handle_event(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); esp_err_t network_wifi_handle_event(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
esp_err_t network_wifi_connect(wifi_config_t * cfg);
bool is_wifi_up(); bool is_wifi_up();
wifi_config_t* network_wifi_set_wifi_sta_config(const char * ssid, const char * password) ;
void network_wifi_clear_config(); void network_wifi_clear_config();
esp_netif_t *network_wifi_get_interface(); esp_netif_t *network_wifi_get_interface();
esp_netif_t *network_wifi_get_ap_interface();
bool network_wifi_is_ap_sta_mode();
bool network_wifi_is_sta_mode();
bool network_wifi_is_ap_mode();
bool network_wifi_sta_config_changed(); bool network_wifi_sta_config_changed();
void network_wifi_get_stats( int32_t * ret_total_connected_time, int64_t * ret_last_connected, uint16_t * ret_num_disconnect); void network_wifi_global_init();
bool network_wifi_is_known_ap(const char * ssid);
esp_err_t network_wifi_connect(const char * ssid, const char * password);
esp_err_t network_wifi_erase_legacy();
esp_err_t network_wifi_connect_ssid(const char * ssid);
esp_err_t network_wifi_connect_active_ssid();
esp_err_t network_wifi_erase_known_ap();
esp_err_t network_wifi_set_sta_mode();
size_t network_wifi_get_known_count();
esp_err_t network_wifi_built_known_ap_list();
const wifi_sta_config_t* network_wifi_load_active_config();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 B

View File

@@ -1,793 +0,0 @@
#include <state_machine.hpp>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "cmd_system.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
#include "esp_wifi_types.h"
#include "http_server_handlers.h"
#include "messaging.h"
#include "network_ethernet.h"
#include "network_status.h"
#include "network_wifi.h"
#include "state_machine.h"
#include "trace.h"
#include "dns_server.h"
BaseType_t network_manager_task;
/* objects used to manipulate the main queue of events */
QueueHandle_t network_manager_queue;
using namespace stateless;
using namespace std::placeholders;
static const char TAG[] = "network_manager";
static TaskHandle_t task_network_manager = NULL;
TimerHandle_t STA_timer = NULL;
uint32_t STA_duration;
static int32_t total_connected_time = 0;
static int64_t last_connected = 0;
static uint16_t num_disconnect = 0;
void network_wifi_get_stats(int32_t* ret_total_connected_time, int64_t* ret_last_connected, uint16_t* ret_num_disconnect) {
*ret_total_connected_time = total_connected_time;
*ret_last_connected = last_connected;
*ret_num_disconnect = num_disconnect;
}
namespace {
std::ostream& operator<<(std::ostream& os, const state_t s) {
//static const char* name[] = { "idle", "stopped", "started", "running" };
static const char* name[] = {
"initializing",
"global",
"eth_starting",
"eth_active",
"eth_active_linkup",
"eth_active_connected",
"eth_active_linkdown",
"wifi_up",
"wifi_initializing",
"network_manager_async",
"wifi_connecting_scanning",
"wifi_connecting",
"wifi_connected",
"wifi_disconnecting",
"wifi_user_disconnected",
"wifi_connected_waiting_for_ip",
"wifi_connected_scanning",
"wifi_lost_connection",
"wifi_ap_mode",
"wifi_ap_mode_scanning",
"wifi_ap_mode_scan_done",
"wifi_ap_mode_connecting",
"wifi_ap_mode_connected",
"system_rebooting"};
os << name[(int)s];
return os;
}
const char* trigger_to_string(trig_t trigger) {
switch (trigger) {
ENUM_TO_STRING(t_link_up);
ENUM_TO_STRING(t_link_down);
ENUM_TO_STRING(t_configure);
ENUM_TO_STRING(t_got_ip);
ENUM_TO_STRING(t_next);
ENUM_TO_STRING(t_start);
ENUM_TO_STRING(t_scan);
ENUM_TO_STRING(t_fail);
ENUM_TO_STRING(t_success);
ENUM_TO_STRING(t_scan_done);
ENUM_TO_STRING(t_connect);
ENUM_TO_STRING(t_reboot);
ENUM_TO_STRING(t_reboot_url);
ENUM_TO_STRING(t_lost_connection);
ENUM_TO_STRING(t_update_status);
ENUM_TO_STRING(t_disconnect);
default:
break;
}
return "Unknown trigger";
}
std::ostream& operator<<(std::ostream& os, const trig_t & t) {
//static const char* name[] = { "start", "stop", "set_speed", "halt" };
os << trigger_to_string(t);
return os;
}
} // namespace
// namespace stateless
// {
// template<> void print_state<state>(std::ostream& os, const state& s)
// { os << s; }
// template<> void print_trigger<trigger_t_t(std::ostream& os, const trigger& t)
// { os << t; }
// }
// namespace
// {
// class network_manager
// {
// public:
// network_manager()
// : sm_(state_t::initializing)
// ,
// {
//}
// sm_.configure(state_t::idle)
// .permit(trig_t::t_start, state_t::started);
// sm_.configure(state_t::stopped)
// .on_entry([=](const TTransition&) { speed_ = 0; })
// .permit(trig_t::t_halt, state_t::idle);
// sm_.configure(state_t::started)
// .permit(trig_t::t_set_speed, state_t::running)
// .permit(trig_t::t_stop, state_t::stopped);
// sm_.configure(state_t::running)
// .on_entry_from(
// set_speed_trigger_,
// [=](const TTransition& t, int speed) { speed_ = speed; })
// .permit(trig_t::t_stop, state_t::stopped)
// .permit_reentry(trig_t::t_set_speed);
// void start(int speed)
// {
// sm_.fire(trig_t::t_start);
// set_speed(speed);
// }
// void stop()
// {
// sm_.fire(trig_t::t_stop);
// sm_.fire(trig_t::t_halt);
// }
// void set_speed(int speed)
// {
// sm_.fire(set_speed_trigger_, speed);
// }
// std::string print() const
// {
// std::ostringstream oss;
// print(oss);
// return oss.str();
// }
// void print(std::ostream& os) const
// {
// os << "Motor " << sm_ << " speed = " << speed_;
// }
// private:
// //typedef std::shared_ptr<stateless::trigger_with_parameters<trigger_t, int>> TSetSpeedTrigger;
// wifi_config_t * wifi_config;
// TStateMachine sm_;
// ;
// ;
// };
// std::ostream& operator<<(std::ostream& os, const motor& m)
// {
// m.print(os);
// return os;
// }
//}
namespace {
typedef state_machine<state_t, trig_t> TStateMachine;
typedef TStateMachine::TTransition TTransition;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, wifi_config_t*>> TConnectTrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, reboot_type_t>> TRebootTrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, char*>> TRebootOTATrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, wifi_event_sta_disconnected_t*>> TDisconnectTrigger;
}; // namespace
class NetworkManager {
public:
NetworkManager()
: sm_(state_t::instantiated),
connect_trigger_(sm_.set_trigger_parameters<wifi_config_t*>(trig_t::t_connect)),
reboot_trigger_(sm_.set_trigger_parameters<reboot_type_t>(trig_t::t_reboot)),
reboot_ota_(sm_.set_trigger_parameters<char*>(trig_t::t_reboot)),
disconnected_(sm_.set_trigger_parameters<wifi_event_sta_disconnected_t*>(trig_t::t_lost_connection)) {
sm_.configure(state_t::instantiated)
.permit(trig_t::t_start, state_t::initializing);
sm_.configure(state_t::global)
.permit(trig_t::t_reboot, state_t::system_rebooting)
.permit(trig_t::t_reboot_url, state_t::system_rebooting)
.permit_reentry(trig_t::t_update_status)
.on_entry_from(trig_t::t_update_status,
[=](const TTransition& t) {
wifi_manager_update_basic_info();
});
sm_.configure(state_t::system_rebooting)
.on_entry_from(reboot_ota_, [=](const TTransition& t, char* url) {
if (url) {
start_ota(url, NULL, 0);
free(url);
}
})
.on_entry_from(reboot_trigger_, [=](const TTransition& t, reboot_type_t reboot_type) {
switch (reboot_type) {
case reboot_type_t::OTA:
ESP_LOGD(TAG, "Calling guided_restart_ota.");
guided_restart_ota();
break;
case reboot_type_t::RECOVERY:
ESP_LOGD(TAG, "Calling guided_factory.");
guided_factory();
break;
case reboot_type_t::RESTART:
ESP_LOGD(TAG, "Calling simple_restart.");
simple_restart();
break;
default:
break;
}
});
sm_.configure(state_t::initializing)
.on_entry([=](const TTransition& t) {
/* memory allocation */
ESP_LOGD(TAG, "network_manager_start. Creating message queue");
network_manager_queue = xQueueCreate(3, sizeof(queue_message));
ESP_LOGD(TAG, "network_manager_start. Allocating memory for callback functions registration");
// todo: allow registration of event callbacks
ESP_LOGD(TAG, "Initializing tcp_ip adapter");
esp_netif_init();
ESP_LOGD(TAG, "Creating the default event loop");
ESP_ERROR_CHECK(esp_event_loop_create_default());
init_network_status();
ESP_LOGD(TAG, "Initializing network. done");
/* start wifi manager task */
ESP_LOGD(TAG, "Creating network manager task");
network_manager_task = xTaskCreate(&network_manager, "network_manager", 4096, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_network_manager);
// send a message to start the connections
})
.permit(trig_t::t_start, state_t::eth_starting);
sm_.configure(state_t::eth_starting)
.on_entry([=](const TTransition& t) {
/* start http server */
http_server_start();
ESP_LOGD(TAG, "network_manager task started. Configuring Network Interface");
init_network_ethernet();
})
.permit(trig_t::t_fail, state_t::wifi_initializing)
.permit(trig_t::t_success, state_t::eth_active);
sm_.configure(state_t::eth_active)
.permit(trig_t::t_link_up, state_t::eth_active_linkup)
.permit(trig_t::t_got_ip, state_t::eth_active_connected)
.permit(trig_t::t_link_down, state_t::eth_active_linkdown)
.permit(trig_t::t_fail, state_t::wifi_initializing);
sm_.configure(state_t::eth_active_linkup)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
// Anything we need to do on link becoming active?
});
sm_.configure(state_t::eth_active_linkdown)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
// If not connected after a certain time, start
// wifi
});
sm_.configure(state_t::eth_active_connected)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
})
.on_exit([=](const TTransition& t) {
});
sm_.configure(state_t::wifi_up)
.on_entry([=](const TTransition& t) {
})
.on_exit([=](const TTransition& t) {
});
sm_.configure(state_t::wifi_initializing)
.sub_state_of(state_t::wifi_up)
.on_entry([=](const TTransition& t) {
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "network_wifi_load_restore");
if (!is_wifi_up()) {
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Load Configuration");
return ESP_FAIL;
}
if (wifi_manager_fetch_wifi_sta_config()) {
ESP_LOGI(TAG, "Saved wifi found on startup. Will attempt to connect.");
network_manager_async_connect(wifi_manager_get_wifi_sta_config());
} else {
/* no wifi saved: start soft AP! This is what should happen during a first run */
ESP_LOGD(TAG, "No saved wifi. Starting AP.");
network_manager_async_configure();
}
return err;
})
.permit(trig_t::t_configure, state_t::wifi_ap_mode)
.permit(trig_t::t_connect, state_t::wifi_connecting_scanning);
sm_.configure(state_t::wifi_connecting_scanning)
.sub_state_of(state_t::wifi_up)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
if (network_wifi_connect(wifi_config) == ESP_OK) {
network_manager_async_connect(wifi_config);
} else {
network_manager_async_fail();
}
// STA_duration = STA_POLLING_MIN;
// /* create timer for background STA connection */
// if (!STA_timer) {
// STA_timer = xTimerCreate("background STA", pdMS_TO_TICKS(STA_duration), pdFALSE, NULL, polling_STA);
// }
// setup a timeout here. On timeout,
// check reconnect_attempts and
// fire trig_t::t_scan if we have more attempts to try
// fire trig_t::t_fail otherwise
})
.permit_reentry_if(trig_t::t_scan, [&]() {
return ++reconnect_attempt < 3;
})
.permit(trig_t::t_connect, state_t::wifi_connecting)
.permit(trig_t::t_fail, state_t::wifi_lost_connection);
sm_.configure(state_t::wifi_connecting)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
// setup a timeout here. On timeout,
// check reconnect_attempts and
// fire trig_t::t_wifi_connecting_existing if we have more attempts to try
// fire trig_t::t_fail otherwise
})
.permit(trig_t::t_success, state_t::wifi_connected_waiting_for_ip)
.permit(trig_t::t_got_ip, state_t::wifi_connected)
.permit(trig_t::t_lost_connection, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_connected_waiting_for_ip)
.permit(trig_t::t_got_ip, state_t::wifi_connected);
sm_.configure(state_t::wifi_ap_mode)
.on_entry([=](const TTransition& t) {
wifi_manager_config_ap();
ESP_LOGD(TAG, "AP Starting, requesting wifi scan.");
network_manager_async_scan();
})
.on_entry_from(disconnected_, [=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
if(disconnected_event){
free(disconnected_event);
}
})
.permit(trig_t::t_scan, state_t::wifi_ap_mode_scanning);
sm_.configure(state_t::wifi_ap_mode_scanning)
.on_entry([=](const TTransition& t) {
// build a list of found AP
})
.permit(trig_t::t_scan_done, state_t::wifi_ap_mode_scan_done);
sm_.configure(state_t::wifi_ap_mode_scan_done)
.permit(trig_t::t_connect, state_t::wifi_ap_mode_connecting);
sm_.configure(state_t::wifi_ap_mode_connecting)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
})
.permit(trig_t::t_got_ip, state_t::wifi_ap_mode_connected)
.permit(trig_t::t_fail, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_ap_mode_connected)
.on_entry([=](const TTransition& t) {
})
.permit(trig_t::t_success, state_t::wifi_connected);
sm_.configure(state_t::wifi_connected)
.on_entry([&](const TTransition& t) {
last_connected = esp_timer_get_time();
/* bring down DNS hijack */
ESP_LOGD(TAG, "Stopping DNS.");
dns_server_stop();
if (network_wifi_sta_config_changed()) {
network_wifi_save_sta_config();
}
/* stop AP mode */
esp_wifi_set_mode(WIFI_MODE_STA);
})
.permit_reentry(trig_t::t_scan_done)
.permit(trig_t::t_lost_connection, state_t::wifi_lost_connection)
.permit(trig_t::t_scan, state_t::wifi_connected_scanning)
.permit(trig_t::t_disconnect, state_t::wifi_disconnecting)
.permit(trig_t::t_connect, state_t::wifi_connecting);
sm_.configure(state_t::wifi_disconnecting)
.permit(trig_t::t_lost_connection, state_t::wifi_user_disconnected);
sm_.configure(state_t::wifi_user_disconnected)
.on_entry_from(disconnected_,
[=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
ESP_LOGD(TAG, "WiFi disconnected by user");
network_wifi_clear_config();
wifi_manager_generate_ip_info_json(UPDATE_USER_DISCONNECT);
network_manager_async_configure();
if (disconnected_event) {
free(disconnected_event);
}
})
.permit(trig_t::t_configure, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_lost_connection)
.on_entry_from(disconnected_,
[=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
ESP_LOGE(TAG, "WiFi Connection lost.");
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "WiFi Connection lost");
wifi_manager_generate_ip_info_json(UPDATE_LOST_CONNECTION);
if (last_connected > 0)
total_connected_time += ((esp_timer_get_time() - last_connected) / (1000 * 1000));
last_connected = 0;
num_disconnect++;
ESP_LOGW(TAG, "Wifi disconnected. Number of disconnects: %d, Average time connected: %d", num_disconnect, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0);
//network_manager_async_connect(wifi_manager_get_wifi_sta_config());
if (retries < WIFI_MANAGER_MAX_RETRY) {
ESP_LOGD(TAG, "Issuing ORDER_CONNECT_STA to retry connection.");
retries++;
network_manager_async_connect(wifi_manager_get_wifi_sta_config());
free(disconnected_event);
} else {
/* In this scenario the connection was lost beyond repair: kick start the AP! */
retries = 0;
wifi_mode_t mode;
ESP_LOGW(TAG, "All connect retry attempts failed.");
/* put us in softAP mode first */
esp_wifi_get_mode(&mode);
if (WIFI_MODE_APSTA != mode) {
STA_duration = STA_POLLING_MIN;
network_manager_async_lost_connection(disconnected_event);
} else if (STA_duration < STA_POLLING_MAX) {
STA_duration *= 1.25;
free(disconnected_event);
}
/* keep polling for existing connection */
xTimerChangePeriod(STA_timer, pdMS_TO_TICKS(STA_duration), portMAX_DELAY);
xTimerStart(STA_timer, portMAX_DELAY);
ESP_LOGD(TAG, "STA search slow polling of %d", STA_duration);
}
})
.on_entry([=](const TTransition& t) {
wifi_manager_safe_reset_sta_ip_string();
})
.permit(trig_t::t_connect, state_t::wifi_connecting)
.permit(trig_t::t_lost_connection, state_t::wifi_ap_mode);
// Register a callback for state transitions (the default does nothing).
sm_.on_transition([](const TTransition& t) {
std::cout << "transition from [" << t.source() << "] to ["
<< t.destination() << "] via trigger [" << t.trigger() << "]"
<< std::endl;
});
// Override the default behaviour of throwing when a trigger is unhandled.
sm_.on_unhandled_trigger([](const state_t s, const trig_t t) {
std::cerr << "ignore unhandled trigger [" << t << "] in state [" << s
<< "]" << std::endl;
});
}
public:
bool
Allowed(trig_t trigger) {
if (!sm_.can_fire(trigger)) {
ESP_LOGW(TAG, "Network manager might not be able to process trigger %s", trigger_to_string(trigger));
return false;
}
return true;
}
bool Fire(trig_t trigger) {
try {
sm_.fire(trigger);
return true;
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
return false;
}
bool Event(queue_message& msg) {
trig_t trigger = msg.trigger;
try {
if (trigger == trig_t::t_connect) {
sm_.fire(connect_trigger_, msg.wifi_config);
} else if (trigger == trig_t::t_reboot) {
sm_.fire(reboot_trigger_, msg.rtype);
} else if (trigger == trig_t::t_reboot_url) {
sm_.fire(reboot_ota_, msg.strval);
} else if (trigger == trig_t::t_lost_connection) {
sm_.fire(disconnected_, msg.disconnected_event);
} else {
sm_.fire(trigger);
}
return true;
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
return false;
}
}
private:
uint8_t reconnect_attempt = 0;
bool existing_connection = false;
uint8_t retries = 0;
TStateMachine sm_;
TConnectTrigger connect_trigger_;
TRebootTrigger reboot_trigger_;
TRebootOTATrigger reboot_ota_;
TDisconnectTrigger disconnected_;
};
NetworkManager nm;
void network_manager_start() {
nm.Fire(trig_t::t_start);
}
bool network_manager_async(trig_t trigger) {
queue_message msg;
msg.trigger = trigger;
if (nm.Allowed(trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_fail() {
return network_manager_async(trig_t::t_fail);
}
bool network_manager_async_success() {
return network_manager_async(trig_t::t_success);
}
bool network_manager_async_link_up() {
return network_manager_async(trig_t::t_link_up);
}
bool network_manager_async_link_down() {
return network_manager_async(trig_t::t_link_down);
}
bool network_manager_async_configure() {
return network_manager_async(trig_t::t_configure);
}
bool network_manager_async_got_ip() {
return network_manager_async(trig_t::t_got_ip);
}
bool network_manager_async_next() {
return network_manager_async(trig_t::t_next);
}
bool network_manager_async_start() {
return network_manager_async(trig_t::t_start);
}
bool network_manager_async_scan() {
return network_manager_async(trig_t::t_scan);
}
bool network_manager_async_update_status() {
return network_manager_async(trig_t::t_update_status);
}
bool network_manager_async_disconnect() {
return network_manager_async(trig_t::t_disconnect);
}
bool network_manager_async_scan_done() {
return network_manager_async(trig_t::t_scan_done);
}
bool network_manager_async_connect(wifi_config_t* wifi_config) {
queue_message msg;
msg.trigger = trig_t::t_connect;
msg.wifi_config = wifi_config;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) {
queue_message msg;
msg.trigger = trig_t::t_lost_connection;
msg.disconnected_event = disconnected_event;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_reboot(reboot_type_t rtype) {
queue_message msg;
msg.trigger = trig_t::t_reboot;
msg.rtype = rtype;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
void network_manager_reboot_ota(char* url) {
queue_message msg;
if (url == NULL) {
msg.trigger = trig_t::t_reboot;
msg.rtype = reboot_type_t::OTA;
} else {
msg.trigger = trig_t::t_reboot_url;
msg.strval = strdup(url);
}
if (nm.Allowed(msg.trigger)) {
xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return;
}
// switch (msg.code) {
// case EVENT_SCAN_DONE:
// err = wifi_scan_done(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code]) {
// ESP_LOGD(TAG, "Invoking SCAN DONE callback");
// (*cb_ptr_arr[msg.code])(NULL);
// ESP_LOGD(TAG, "Done Invoking SCAN DONE callback");
// }
// break;
// case ORDER_START_WIFI_SCAN:
// err = network_wifi_start_scan(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_LOAD_AND_RESTORE_STA:
// err = network_wifi_load_restore(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_CONNECT_STA:
// err = network_wifi_order_connect(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_STA_DISCONNECTED:
// err = network_wifi_disconnected(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_START_AP:
// err = network_wifi_start_ap(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_GOT_IP:
// ESP_LOGD(TAG, "MESSAGE: EVENT_GOT_IP");
// /* save IP as a string for the HTTP server host */
// //s->ip_info.ip.addr
// ip_event_got_ip_t* event = (ip_event_got_ip_t*)msg.param;
// wifi_manager_safe_update_sta_ip_string(&(event->ip_info.ip));
// wifi_manager_generate_ip_info_json(network_manager_is_flag_set(WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT)? UPDATE_FAILED_ATTEMPT_AND_RESTORE : UPDATE_CONNECTION_OK, event->esp_netif, event->ip_changed);
// free(msg.param);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case UPDATE_CONNECTION_OK:
// messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "UPDATE_CONNECTION_OK not implemented");
// break;
// case ORDER_DISCONNECT_STA:
// ESP_LOGD(TAG, "MESSAGE: ORDER_DISCONNECT_STA. Calling esp_wifi_disconnect()");
// /* precise this is coming from a user request */
// xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT);
// /* order wifi discconect */
// ESP_ERROR_CHECK(esp_wifi_disconnect());
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_RESTART_OTA_URL:
// ESP_LOGD(TAG, "Calling start_ota.");
// start_ota(msg.param, NULL, 0);
// free(msg.param);
// break;
// case ORDER_RESTART_RECOVERY:
// break;
// case ORDER_RESTART:
// ESP_LOGD(TAG, "Calling simple_restart.");
// simple_restart();
// break;
// case ORDER_UPDATE_STATUS:
// ;
// break;
// case EVENT_ETH_TIMEOUT:
// ESP_LOGW(TAG, "Ethernet connection timeout. Rebooting with WiFi Active");
// network_manager_reboot(RESTART);
// break;
// case EVENT_ETH_LINK_UP:
// /* callback */
// ESP_LOGD(TAG,"EVENT_ETH_LINK_UP message received");
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_ETH_LINK_DOWN:
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// default:
// break;
// } /* end of switch/case */
// if (!network_ethernet_wait_for_link(500)) {
// if(network_ethernet_enabled()){
// ESP_LOGW(TAG, "Ethernet not connected. Starting Wifi");
// }
// init_network_wifi();
// wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL);
// }
void network_manager(void* pvParameters) {
queue_message msg;
esp_err_t err = ESP_OK;
BaseType_t xStatus;
network_manager_async(trig_t::t_start);
/* main processing loop */
for (;;) {
xStatus = xQueueReceive(network_manager_queue, &msg, portMAX_DELAY);
if (xStatus == pdPASS) {
// pass the event to the sync processor
nm.Event(msg);
} /* end of if status=pdPASS */
} /* end of for loop */
vTaskDelete(NULL);
}
void network_manager_destroy() {
vTaskDelete(task_network_manager);
task_network_manager = NULL;
/* heap buffers */
destroy_network_status();
destroy_network_wifi();
destroy_network_status();
/* RTOS objects */
vQueueDelete(network_manager_queue);
network_manager_queue = NULL;
}

View File

@@ -1,108 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#define STA_POLLING_MIN (15 * 1000)
#define STA_POLLING_MAX (10 * 60 * 1000)
//enum class state { idle, stopped, started, running };
//enum class trigger { start, stop, set_speed, halt };
typedef enum {
t_link_up,
t_link_down,
t_configure,
t_got_ip,
t_disconnect,
t_next,
t_start,
t_scan,
t_fail,
t_success,
t_scan_done,
t_connect,
t_reboot,
t_reboot_url,
t_lost_connection,
t_update_status
} trig_t;
typedef enum {
instantiated,
initializing,
global,
eth_starting,
eth_active,
eth_active_linkup,
eth_active_connected,
eth_active_linkdown,
wifi_up,
wifi_initializing,
wifi_connecting_scanning,
wifi_connecting,
wifi_connected,
wifi_disconnecting,
wifi_user_disconnected,
wifi_connected_waiting_for_ip,
wifi_connected_scanning,
wifi_lost_connection,
wifi_ap_mode,
wifi_ap_mode_scanning,
wifi_ap_mode_scan_done,
wifi_ap_mode_connecting,
wifi_ap_mode_connected,
system_rebooting
} state_t;
typedef enum {
OTA,
RECOVERY,
RESTART,
} reboot_type_t;
typedef struct {
trig_t trigger;
union
{
wifi_config_t* wifi_config;
reboot_type_t rtype;
char * strval;
wifi_event_sta_disconnected_t * disconnected_event;
} ;
} queue_message;
bool network_manager_event_simple(trig_t trigger);
bool network_manager_event(trig_t trigger, void* param);
bool network_t_connect_event(wifi_config_t* wifi_config);
bool network_t_link_event(bool link_up);
bool network_manager_async_event(trig_t trigger, void* param);
bool network_manager_async(trig_t trigger);
bool network_manager_async_fail();
bool network_manager_async_success();
bool network_manager_async_link_up();
bool network_manager_async_link_down();
bool network_manager_async_configure();
bool network_manager_async_got_ip();
bool network_manager_async_next();
bool network_manager_async_start();
bool network_manager_async_scan();
bool network_manager_async_scan_done();
bool network_manager_async_connect(wifi_config_t* wifi_config);
bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t * disconnected_event);
bool network_manager_async_reboot(reboot_type_t rtype);
void network_manager_reboot_ota(char* url);
bool network_manager_async_disconnect();
bool network_manager_async_update_status();
/**
* Allocate heap memory for the wifi manager and start the wifi_manager RTOS task
*/
void network_manager_start();
#ifdef __cplusplus
}
#endif

View File

@@ -1,13 +1,13 @@
[ [
{"ssid":"Pantum-AP-A6D49F","chan":11,"rssi":-55,"auth":4}, {"ssid":"Pantum-AP-A6D49F","chan":11,"rssi":-55,"auth":4, "known":false},
{"ssid":"a0308","chan":1,"rssi":-56,"auth":3}, {"ssid":"a0308","chan":1,"rssi":-56,"auth":3, "known":false},
{"ssid":"dlink-D9D8","chan":11,"rssi":-82,"auth":4}, {"ssid":"dlink-D9D8","chan":11,"rssi":-82,"auth":4, "known":false},
{"ssid":"Linksys06730","chan":7,"rssi":-85,"auth":3}, {"ssid":"Linksys06730","chan":7,"rssi":-85,"auth":3, "known":false},
{"ssid":"SINGTEL-5171","chan":9,"rssi":-88,"auth":4}, {"ssid":"SINGTEL-5171","chan":9,"rssi":-88,"auth":4, "known":false},
{"ssid":"1126-1","chan":11,"rssi":-89,"auth":4}, {"ssid":"1126-1","chan":11,"rssi":-89,"auth":4, "known":false},
{"ssid":"The Shah 5GHz-2","chan":1,"rssi":-90,"auth":3}, {"ssid":"The Shah 5GHz-2","chan":1,"rssi":-90,"auth":3, "known":false},
{"ssid":"SINGTEL-1D28 (2G)","chan":11,"rssi":-91,"auth":3}, {"ssid":"SINGTEL-1D28 (2G)","chan":11,"rssi":-91,"auth":3, "known":false},
{"ssid":"dlink-F864","chan":1,"rssi":-92,"auth":4}, {"ssid":"dlink-F864","chan":1,"rssi":-92,"auth":4, "known":false},
{"ssid":"dlink-74F0","chan":1,"rssi":-93,"auth":4}, {"ssid":"dlink-74F0","chan":1,"rssi":-93,"auth":4, "known":false},
{"ssid":"MyTestSSID","chan":2,"rssi":-53,"auth":4} {"ssid":"MyTestSSID","chan":2,"rssi":-53,"auth":4, "known":true}
] ]

View File

@@ -54,7 +54,7 @@
"current_time": 147319 "current_time": 147319
}, },
{ {
"message": "Wifi connected", "message": "Network connected",
"type": "MESSAGING_INFO", "type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_SYSTEM", "class": "MESSAGING_CLASS_SYSTEM",
"sent_time": 141256, "sent_time": 141256,

View File

@@ -1098,7 +1098,7 @@ function rssiToIcon(rssi) {
} }
function refreshAP() { function refreshAP() {
$.getJSON('/scan.json', async function() { $.getJSON('/scan.json', async function() {
await sleep(2000); await sleep(2000);
$.getJSON('/ap.json', function(data) { $.getJSON('/ap.json', function(data) {
if (data.length > 0) { if (data.length > 0) {
@@ -1335,6 +1335,7 @@ function handleRecoveryMode(data) {
$('#boot-form').attr('action', '/recovery.json'); $('#boot-form').attr('action', '/recovery.json');
} }
} }
function hasConnectionChanged(data){ function hasConnectionChanged(data){
// gw: "192.168.10.1" // gw: "192.168.10.1"
// ip: "192.168.10.225" // ip: "192.168.10.225"
@@ -1366,10 +1367,10 @@ function handleWifiDialog(data){
$('.connecting-status').show(); $('.connecting-status').show();
} }
if(SystemConfig.ap_ssid){ if(SystemConfig.ap_ssid){
$('#apName').text(SystemConfig.ap_ssid); $('#apName').text(SystemConfig.ap_ssid.value);
} }
if(SystemConfig.ap_pwd){ if(SystemConfig.ap_pwd){
$('#apPass').text(SystemConfig.ap_pwd); $('#apPass').text(SystemConfig.ap_pwd.value);
} }
if(!data) if(!data)
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

View File

@@ -31,11 +31,13 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "messaging.h" #include "messaging.h"
#include "platform_esp32.h" #include "platform_esp32.h"
#include "globdefs.h"
#include "trace.h"
static const char TAG[] = "http_server"; static const char TAG[] = "http_server";
static httpd_handle_t _server = NULL; EXT_RAM_ATTR static httpd_handle_t _server = NULL;
rest_server_context_t *rest_context = NULL; EXT_RAM_ATTR rest_server_context_t *rest_context = NULL;
RingbufHandle_t messaging=NULL; EXT_RAM_ATTR RingbufHandle_t messaging=NULL;
void register_common_handlers(httpd_handle_t server){ void register_common_handlers(httpd_handle_t server){
httpd_uri_t css_get = { .uri = "/css/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; httpd_uri_t css_get = { .uri = "/css/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
@@ -46,7 +48,6 @@ void register_common_handlers(httpd_handle_t server){
httpd_register_uri_handler(server, &icon_get); httpd_register_uri_handler(server, &icon_get);
httpd_uri_t png_get = { .uri = "/favicon*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; httpd_uri_t png_get = { .uri = "/favicon*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &png_get); httpd_register_uri_handler(server, &png_get);
} }
void register_regular_handlers(httpd_handle_t server){ void register_regular_handlers(httpd_handle_t server){
httpd_uri_t root_get = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler, .user_ctx = rest_context }; httpd_uri_t root_get = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler, .user_ctx = rest_context };
@@ -124,13 +125,17 @@ void register_regular_handlers(httpd_handle_t server){
esp_err_t http_server_start() esp_err_t http_server_start()
{ {
ESP_LOGI(TAG, "Initializing HTTP Server"); ESP_LOGI(TAG, "Initializing HTTP Server");
MEMTRACE_PRINT_DELTA_MESSAGE("Registering messaging subscriber");
messaging = messaging_register_subscriber(10, "http_server"); messaging = messaging_register_subscriber(10, "http_server");
rest_context = calloc(1, sizeof(rest_server_context_t)); MEMTRACE_PRINT_DELTA_MESSAGE("Allocating RAM for server context");
rest_context = malloc_init_external( sizeof(rest_server_context_t));
if(rest_context==NULL){ if(rest_context==NULL){
ESP_LOGE(TAG,"No memory for http context"); ESP_LOGE(TAG,"No memory for http context");
return ESP_FAIL; return ESP_FAIL;
} }
strlcpy(rest_context->base_path, "/res/", sizeof(rest_context->base_path)); strlcpy(rest_context->base_path, "/res/", sizeof(rest_context->base_path));
httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_config_t config = HTTPD_DEFAULT_CONFIG();
@@ -141,15 +146,17 @@ esp_err_t http_server_start()
//todo: use the endpoint below to configure session token? //todo: use the endpoint below to configure session token?
// config.open_fn // config.open_fn
ESP_LOGD(TAG, "Starting HTTP Server"); MEMTRACE_PRINT_DELTA_MESSAGE( "Starting HTTP Server");
esp_err_t err= __httpd_start(&_server, &config); esp_err_t err= __httpd_start(&_server, &config);
if(err != ESP_OK){ if(err != ESP_OK){
ESP_LOGE_LOC(TAG,"Start server failed"); ESP_LOGE_LOC(TAG,"Start server failed");
} }
else { else {
MEMTRACE_PRINT_DELTA_MESSAGE( "HTTP Server started. Registering common handlers");
register_common_handlers(_server); register_common_handlers(_server);
MEMTRACE_PRINT_DELTA_MESSAGE("Registering regular handlers");
register_regular_handlers(_server); register_regular_handlers(_server);
MEMTRACE_PRINT_DELTA_MESSAGE("HTTP Server regular handlers registered");
} }
return err; return err;

View File

@@ -1,20 +1,20 @@
menu "Squeezelite-ESP32" menu "Squeezelite-ESP32"
menu "Logging" menu "Logging"
config LOGGING_SLIMPROTO config LOGGING_SLIMPROTO
string "logging level for slimproto" string "logging level for slimproto"
default "info" default "info"
help help
Set logging level info|debug|sdebug Set logging level info|debug|sdebug
config LOGGING_STREAM config LOGGING_STREAM
string "logging level for stream" string "logging level for stream"
default "info" default "info"
help help
Set logging level info|debug|sdebug Set logging level info|debug|sdebug
config LOGGING_DECODE config LOGGING_DECODE
string "logging level for decode" string "logging level for decode"
default "info" default "info"
help help
Set logging level info|debug|sdebug Set logging level info|debug|sdebug
config LOGGING_OUTPUT config LOGGING_OUTPUT
string "logging level for output" string "logging level for output"
default "info" default "info"
@@ -102,11 +102,22 @@ menu "Squeezelite-ESP32"
config DAC_CONTROLSET config DAC_CONTROLSET
string string
default '{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and" } ] }' if TWATCH2020 default '{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and" } ] }' if TWATCH2020
default "" default ""
# AGGREGATES - end # AGGREGATES - end
endmenu endmenu
menu "Audio settings" menu "Audio settings"
menu "Known Configurations"
visible if BASIC_I2C_BT
config DAC_KNOWN_CONFIGURATIONS
string "Known DAC configurations"
default "ESP32A1S Old (AC101)|ESP32A1S V2.2+ (ES8388)|Xiaomi Gateway" if BASIC_I2C_BT
default ""
config DAC_KNOWN_CONFIGURATIONS_GPIOS
string "GPIOs for known DAC configurations"
default "model=AC101,sda=33,scl=32,bck=27,ws=26,di=35,do=25|model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16|model=I2S,bck=12,ws=26,do=25,i2c=106,sda=18,scl=23" if BASIC_I2C_BT
default ""
endmenu
menu "DAC settings" menu "DAC settings"
visible if BASIC_I2C_BT visible if BASIC_I2C_BT
menu "I2S settings" menu "I2S settings"
@@ -198,7 +209,8 @@ menu "Squeezelite-ESP32"
int "Control loop delay." int "Control loop delay."
default 500 default 500
help help
Decreasing this will lead to a more responsive BT control, but might lead to noisy log files if debug is enabled. Decreasing this will lead to a more responsive BT control,
but might lead to noisy log files if debug is enabled.
config A2DP_CONNECT_TIMEOUT_MS config A2DP_CONNECT_TIMEOUT_MS
int "Time out duration when trying to connect to an A2DP audio sink" int "Time out duration when trying to connect to an A2DP audio sink"
default 1000 default 1000
@@ -351,5 +363,5 @@ menu "Squeezelite-ESP32"
string "Default command line to execute" string "Default command line to execute"
default "squeezelite -o I2S -b 500:2000 -d all=info -C 30" default "squeezelite -o I2S -b 500:2000 -d all=info -C 30"
help help
This is the command to run when starting the device This is the command to run when starting the device
endmenu endmenu

View File

@@ -45,14 +45,16 @@
#include "display.h" #include "display.h"
#include "accessors.h" #include "accessors.h"
#include "cmd_system.h" #include "cmd_system.h"
#include "globdefs.h"
static const char certs_namespace[] = "certificates"; static const char certs_namespace[] = "certificates";
static const char certs_key[] = "blob"; static const char certs_key[] = "blob";
static const char certs_version[] = "version"; static const char certs_version[] = "version";
const char unknown_string_placeholder[] = "unknown"; const char unknown_string_placeholder[] = "unknown";
const char null_string_placeholder[] = "null"; const char null_string_placeholder[] = "null";
EventGroupHandle_t wifi_event_group; EventGroupHandle_t network_event_group;
bool bypass_wifi_manager=false; bool bypass_network_manager=false;
const int CONNECTED_BIT = BIT0; const int CONNECTED_BIT = BIT0;
#define JOIN_TIMEOUT_MS (10000) #define JOIN_TIMEOUT_MS (10000)
#define LOCAL_MAC_SIZE 20 #define LOCAL_MAC_SIZE 20
@@ -61,7 +63,7 @@ static const char TAG[] = "esp_app_main";
char * fwurl = NULL; char * fwurl = NULL;
RTC_NOINIT_ATTR uint32_t RebootCounter ; RTC_NOINIT_ATTR uint32_t RebootCounter ;
static bool bWifiConnected=false; static bool bNetworkConnected=false;
extern const uint8_t server_cert_pem_start[] asm("_binary_github_pem_start"); extern const uint8_t server_cert_pem_start[] asm("_binary_github_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end"); extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end");
@@ -71,12 +73,11 @@ extern void display_init(char *welcome);
const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); } const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); }
const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); } const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); }
bool is_recovery_running; bool is_recovery_running;
/* brief this is an exemple of a callback that you can setup in your own app to get notified of wifi manager event */
void cb_connection_got_ip(void *pvParameter){ void cb_connection_got_ip(nm_state_t new_state, int sub_state){
static ip4_addr_t ip; static ip4_addr_t ip;
tcpip_adapter_ip_info_t ipInfo; tcpip_adapter_ip_info_t ipInfo;
network_get_ip_info(&ipInfo);
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo);
if (ip.addr && ipInfo.ip.addr != ip.addr) { if (ip.addr && ipInfo.ip.addr != ip.addr) {
ESP_LOGW(TAG, "IP change, need to reboot"); ESP_LOGW(TAG, "IP change, need to reboot");
if(!wait_for_commit()){ if(!wait_for_commit()){
@@ -85,10 +86,10 @@ void cb_connection_got_ip(void *pvParameter){
esp_restart(); esp_restart();
} }
ip.addr = ipInfo.ip.addr; ip.addr = ipInfo.ip.addr;
ESP_LOGI(TAG, "Wifi connected!"); ESP_LOGI(TAG, "Network connected!");
messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Wifi connected"); messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Network connected");
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); xEventGroupSetBits(network_event_group, CONNECTED_BIT);
bWifiConnected=true; bNetworkConnected=true;
led_unpush(LED_GREEN); led_unpush(LED_GREEN);
if(is_recovery_running){ if(is_recovery_running){
// when running in recovery, send a LMS discovery message // when running in recovery, send a LMS discovery message
@@ -98,24 +99,24 @@ void cb_connection_got_ip(void *pvParameter){
discover_ota_server(5); discover_ota_server(5);
} }
} }
void cb_connection_sta_disconnected(void *pvParameter){ void cb_connection_sta_disconnected(nm_state_t new_state, int sub_state){
led_blink_pushed(LED_GREEN, 250, 250); led_blink_pushed(LED_GREEN, 250, 250);
messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Wifi disconnected"); messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Wifi disconnected");
bWifiConnected=false; bNetworkConnected=false;
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); xEventGroupClearBits(network_event_group, CONNECTED_BIT);
} }
bool wait_for_wifi(){ bool wait_for_wifi(){
bool connected=(xEventGroupGetBits(wifi_event_group) & CONNECTED_BIT)!=0; bool connected=(xEventGroupGetBits(network_event_group) & CONNECTED_BIT)!=0;
if(!connected){ if(!connected){
ESP_LOGD(TAG,"Waiting for WiFi..."); ESP_LOGD(TAG,"Waiting for Network...");
connected = (xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, connected = (xEventGroupWaitBits(network_event_group, CONNECTED_BIT,
pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS)& CONNECTED_BIT)!=0; pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS)& CONNECTED_BIT)!=0;
if(!connected){ if(!connected){
ESP_LOGW(TAG,"wifi timeout."); ESP_LOGW(TAG,"Network timeout.");
} }
else else
{ {
ESP_LOGI(TAG,"WiFi Connected!"); ESP_LOGI(TAG,"Network Connected!");
} }
} }
return connected; return connected;
@@ -170,9 +171,8 @@ esp_err_t update_certificates(bool force){
char *str=NULL; char *str=NULL;
bool changed=false; bool changed=false;
if ( (esp_err= nvs_get_str(handle, certs_version, NULL, &len)) == ESP_OK) { if ( (esp_err= nvs_get_str(handle, certs_version, NULL, &len)) == ESP_OK) {
str=(char *)malloc(len+1); str=(char *)malloc_init_external(len+1);
if(str){ if(str){
memset(str,0x00,len+1);
if ( (esp_err = nvs_get_str(handle, certs_version, str, &len)) == ESP_OK) { if ( (esp_err = nvs_get_str(handle, certs_version, str, &len)) == ESP_OK) {
ESP_LOGI(TAG,"Certificate version: %s", str); ESP_LOGI(TAG,"Certificate version: %s", str);
} }
@@ -230,7 +230,8 @@ const char * get_certificate(){
size_t len; size_t len;
esp_err = nvs_get_blob(handle, certs_key, NULL, &len); esp_err = nvs_get_blob(handle, certs_key, NULL, &len);
if( esp_err == ESP_OK) { if( esp_err == ESP_OK) {
blob = (char *) heap_caps_malloc(len+1, (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); //blob = (char *) heap_caps_malloc(len+1, (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
blob = (char *) malloc_init_external(len+1);
if(!blob){ if(!blob){
log_send_messaging(MESSAGING_ERROR,"Unable to retrieve HTTPS certificates. %s","Memory allocation failed"); log_send_messaging(MESSAGING_ERROR,"Unable to retrieve HTTPS certificates. %s","Memory allocation failed");
return ""; return "";
@@ -275,7 +276,7 @@ void register_default_with_mac(const char* key, char* defval) {
char* fullvalue = NULL; char* fullvalue = NULL;
esp_read_mac((uint8_t*)&mac, ESP_MAC_WIFI_STA); esp_read_mac((uint8_t*)&mac, ESP_MAC_WIFI_STA);
snprintf(macStr, LOCAL_MAC_SIZE - 1, "-%x%x%x", mac[3], mac[4], mac[5]); snprintf(macStr, LOCAL_MAC_SIZE - 1, "-%x%x%x", mac[3], mac[4], mac[5]);
fullvalue = malloc(strlen(defval)+sizeof(macStr)+1); fullvalue = malloc_init_external(strlen(defval)+sizeof(macStr)+1);
if(fullvalue){ if(fullvalue){
strcpy(fullvalue, defval); strcpy(fullvalue, defval);
strcat(fullvalue, macStr); strcat(fullvalue, macStr);
@@ -287,6 +288,13 @@ void register_default_with_mac(const char* key, char* defval) {
} }
} }
#ifndef CONFIG_DAC_KNOWN_CONFIGURATIONS
#define CONFIG_DAC_KNOWN_CONFIGURATIONS ""
#endif
#ifndef CONFIG_DAC_KNOWN_CONFIGURATIONS_GPIOS
#define CONFIG_DAC_KNOWN_CONFIGURATIONS_GPIOS ""
#endif
void register_default_nvs(){ void register_default_nvs(){
@@ -341,24 +349,35 @@ void register_default_nvs(){
register_default_string_val( "stats", "n"); register_default_string_val( "stats", "n");
register_default_string_val( "rel_api", CONFIG_RELEASE_API); register_default_string_val( "rel_api", CONFIG_RELEASE_API);
register_default_string_val("wifi_smode", "A"); register_default_string_val("wifi_smode", "A");
register_default_string_val("kndac", CONFIG_DAC_KNOWN_CONFIGURATIONS);
register_default_string_val("kngpio", CONFIG_DAC_KNOWN_CONFIGURATIONS_GPIOS);
wait_for_commit(); wait_for_commit();
ESP_LOGD(TAG,"Done setting default values in nvs."); ESP_LOGD(TAG,"Done setting default values in nvs.");
} }
uint32_t halSTORAGE_RebootCounterRead(void) { return RebootCounter ; } uint32_t halSTORAGE_RebootCounterRead(void) { return RebootCounter ; }
uint32_t halSTORAGE_RebootCounterUpdate(int32_t xValue) { return (RebootCounter = (xValue != 0) ? (RebootCounter + xValue) : 0) ; } uint32_t halSTORAGE_RebootCounterUpdate(int32_t xValue) {
if(RebootCounter >100) {
RebootCounter = 0;
}
return (RebootCounter = (xValue != 0) ? (RebootCounter + xValue) : 0) ;
}
void handle_ap_connect(){ void handle_ap_connect(nm_state_t new_state, int sub_state){
start_telnet(NULL); start_telnet(NULL);
}
void handle_network_up(nm_state_t new_state, int sub_state){
halSTORAGE_RebootCounterUpdate(0); halSTORAGE_RebootCounterUpdate(0);
} }
esp_reset_reason_t xReason=ESP_RST_UNKNOWN;
void app_main() void app_main()
{ {
const esp_partition_t *running = esp_ota_get_running_partition(); const esp_partition_t *running = esp_ota_get_running_partition();
is_recovery_running = (running->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY); is_recovery_running = (running->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY);
esp_reset_reason_t xReason = esp_reset_reason(); xReason = esp_reset_reason();
ESP_LOGI(TAG,"Reset reason is: %u", xReason); ESP_LOGI(TAG,"Reset reason is: %u", xReason);
if(!is_recovery_running && xReason != ESP_RST_SW && xReason != ESP_RST_POWERON ) { if(!is_recovery_running ) {
/* unscheduled restart (HW, Watchdog or similar) thus increment dynamic /* unscheduled restart (HW, Watchdog or similar) thus increment dynamic
* counter then log current boot statistics as a warning */ * counter then log current boot statistics as a warning */
uint32_t Counter = halSTORAGE_RebootCounterUpdate(1) ; // increment counter uint32_t Counter = halSTORAGE_RebootCounterUpdate(1) ; // increment counter
@@ -369,30 +388,44 @@ void app_main()
guided_factory(); guided_factory();
} }
} }
else {
uint32_t Counter = halSTORAGE_RebootCounterUpdate(1) ; // increment counter
ESP_LOGI(TAG,"Recovery Reboot counter=%u\n", Counter) ;
if (Counter == 5) {
ESP_LOGW(TAG,"System rebooted too many times. This could be an indication that configuration is corrupted. Erasing config.");
halSTORAGE_RebootCounterUpdate(0);
erase_settings_partition();
// reboot one more time
guided_factory();
}
}
char * fwurl = NULL; char * fwurl = NULL;
MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Starting app_main"); ESP_LOGI(TAG,"Starting app_main");
initialize_nvs(); initialize_nvs();
MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Setting up telnet."); ESP_LOGI(TAG,"Setting up telnet.");
init_telnet(); // align on 32 bits boundaries init_telnet(); // align on 32 bits boundaries
MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Setting up config subsystem."); ESP_LOGI(TAG,"Setting up config subsystem.");
config_init(); config_init();
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG,"Creating event group for wifi"); ESP_LOGD(TAG,"Creating event group for wifi");
wifi_event_group = xEventGroupCreate(); network_event_group = xEventGroupCreate();
ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group"); ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group");
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); xEventGroupClearBits(network_event_group, CONNECTED_BIT);
ESP_LOGI(TAG,"Registering default values"); ESP_LOGI(TAG,"Registering default values");
register_default_nvs(); register_default_nvs();
MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Configuring services"); ESP_LOGI(TAG,"Configuring services");
services_init(); services_init();
MEMTRACE_PRINT_DELTA();
ESP_LOGI(TAG,"Initializing display"); ESP_LOGI(TAG,"Initializing display");
display_init("SqueezeESP32"); display_init("SqueezeESP32");
MEMTRACE_PRINT_DELTA();
if(is_recovery_running && display){ if(is_recovery_running && display){
GDS_ClearExt(display, true); GDS_ClearExt(display, true);
GDS_SetFont(display, &Font_droid_sans_fallback_15x17 ); GDS_SetFont(display, &Font_droid_sans_fallback_15x17 );
@@ -402,7 +435,7 @@ void app_main()
ESP_LOGI(TAG,"Checking if certificates need to be updated"); ESP_LOGI(TAG,"Checking if certificates need to be updated");
update_certificates(false); update_certificates(false);
MEMTRACE_PRINT_DELTA();
ESP_LOGD(TAG,"Getting firmware OTA URL (if any)"); ESP_LOGD(TAG,"Getting firmware OTA URL (if any)");
fwurl = process_ota_url(); fwurl = process_ota_url();
@@ -412,10 +445,10 @@ void app_main()
if(bypass_wm==NULL) if(bypass_wm==NULL)
{ {
ESP_LOGE(TAG, "Unable to retrieve the Wifi Manager bypass flag"); ESP_LOGE(TAG, "Unable to retrieve the Wifi Manager bypass flag");
bypass_wifi_manager = false; bypass_network_manager = false;
} }
else { else {
bypass_wifi_manager=(strcmp(bypass_wm,"1")==0 ||strcasecmp(bypass_wm,"y")==0); bypass_network_manager=(strcmp(bypass_wm,"1")==0 ||strcasecmp(bypass_wm,"y")==0);
} }
if(!is_recovery_running){ if(!is_recovery_running){
@@ -432,25 +465,32 @@ void app_main()
/* start the wifi manager */ /* start the wifi manager */
ESP_LOGD(TAG,"Blinking led"); ESP_LOGD(TAG,"Blinking led");
led_blink_pushed(LED_GREEN, 250, 250); led_blink_pushed(LED_GREEN, 250, 250);
MEMTRACE_PRINT_DELTA();
if(bypass_wifi_manager){ if(bypass_network_manager){
ESP_LOGW(TAG,"wifi manager is disabled. Use command line for wifi control."); ESP_LOGW(TAG,"Network manager is disabled. Use command line for wifi control.");
} }
else { else {
ESP_LOGI(TAG,"Starting Wifi Manager"); ESP_LOGI(TAG,"Starting Network Manager");
network_manager_start(); network_start();
//wifi_manager_set_callback(EVENT_STA_GOT_IP, &cb_connection_got_ip); MEMTRACE_PRINT_DELTA();
wifi_manager_set_callback(EVENT_ETH_GOT_IP, &cb_connection_got_ip); network_register_state_callback(NETWORK_WIFI_ACTIVE_STATE,WIFI_CONNECTED_STATE, "cb_connection_got_ip", &cb_connection_got_ip);
wifi_manager_set_callback(EVENT_STA_DISCONNECTED, &cb_connection_sta_disconnected); network_register_state_callback(NETWORK_ETH_ACTIVE_STATE,ETH_ACTIVE_CONNECTED_STATE, "cb_connection_got_ip",&cb_connection_got_ip);
network_register_state_callback(NETWORK_WIFI_ACTIVE_STATE,WIFI_LOST_CONNECTION_STATE, "cb_connection_sta_disconnected",&cb_connection_sta_disconnected);
/* Start the telnet service after we are certain that the network stack has been properly initialized. /* Start the telnet service after we are certain that the network stack has been properly initialized.
* This can be either after we're started the AP mode, or after we've started the STA mode */ * This can be either after we're started the AP mode, or after we've started the STA mode */
wifi_manager_set_callback(ORDER_START_AP, &handle_ap_connect); network_register_state_callback(NETWORK_INITIALIZING_STATE,-1, "handle_ap_connect", &handle_ap_connect);
wifi_manager_set_callback(ORDER_CONNECT_STA, &handle_ap_connect); network_register_state_callback(NETWORK_ETH_ACTIVE_STATE,ETH_ACTIVE_LINKDOWN_STATE, "handle_network_up", &handle_network_up);
network_register_state_callback(NETWORK_WIFI_ACTIVE_STATE,WIFI_INITIALIZING_STATE, "handle_network_up", &handle_network_up);
MEMTRACE_PRINT_DELTA();
} }
MEMTRACE_PRINT_DELTA_MESSAGE("Starting Console");
console_start(); console_start();
MEMTRACE_PRINT_DELTA_MESSAGE("Console started");
if(fwurl && strlen(fwurl)>0){ if(fwurl && strlen(fwurl)>0){
if(is_recovery_running){ if(is_recovery_running){
while(!bWifiConnected){ while(!bNetworkConnected){
wait_for_wifi(); wait_for_wifi();
taskYIELD(); taskYIELD();
} }

View File

@@ -202,6 +202,13 @@ CONFIG_DAC_CONTROLSET=""
# Audio settings # Audio settings
# #
#
# Known Configurations
#
CONFIG_DAC_KNOWN_CONFIGURATIONS="ESP-A1S-AC101(audio kit 2.2)-Fixed GPIOs|ESP-A1S-ES8388(audio kit 2.2+)-Fixed GPIOs"
CONFIG_DAC_KNOWN_CONFIGURATIONS_GPIOS="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32|model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16"
# end of Known Configurations
# #
# DAC settings # DAC settings
# #
@@ -313,7 +320,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
# CONFIG_COMPILER_CXX_EXCEPTIONS is not set # CONFIG_COMPILER_CXX_EXCEPTIONS is not set
CONFIG_COMPILER_CXX_RTTI=y # CONFIG_COMPILER_CXX_RTTI is not set
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
@@ -930,9 +937,9 @@ CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y # CONFIG_FREERTOS_ASSERT_FAIL_ABORT is not set
# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
# CONFIG_FREERTOS_ASSERT_DISABLE is not set CONFIG_FREERTOS_ASSERT_DISABLE=y
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_FREERTOS_ISR_STACKSIZE=2096 CONFIG_FREERTOS_ISR_STACKSIZE=2096
# CONFIG_FREERTOS_LEGACY_HOOKS is not set # CONFIG_FREERTOS_LEGACY_HOOKS is not set
@@ -980,12 +987,12 @@ CONFIG_HEAP_TRACING_OFF=y
# Log output # Log output
# #
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set CONFIG_LOG_DEFAULT_LEVEL_INFO=y
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
CONFIG_LOG_DEFAULT_LEVEL=1 CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_LOG_COLORS=y CONFIG_LOG_COLORS=y
CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set