SR: Import new SR to support IDF5.0

This commit is contained in:
marcus_xu
2022-11-21 17:40:35 +08:00
parent b477b995e4
commit 363c27cd33
18 changed files with 272 additions and 193 deletions
+21 -24
View File
@@ -19,34 +19,31 @@ before_script:
- git --version
- git submodule update --init --recursive --force
.build_examples_template: &build_examples_template
.build_all_examples_script: &build_all_examples_script
- for EXAMPLE in $EXAMPLES; do
- cd $CI_PROJECT_DIR/examples/$EXAMPLE
- echo Building $EXAMPLE
- idf.py fullclean
- idf.py build
- echo Build Complete for $EXAMPLE
- done
.build_template:
stage: build
image: espressif/idf:release-v4.4
tags:
- build
build_demo_cmake:
<<: *build_examples_template
variables:
EXAMPLES: "factory_demo image_display lv_demos mp3_demo watering_demo"
script:
- cd examples/factory_demo
- idf.py fullclean
- idf.py build
- cd ../
- cd image_display
- idf.py fullclean
- idf.py build
- cd ../
- cd lv_demos
- idf.py fullclean
- idf.py build
- cd ../
- cd mp3_demo
- idf.py fullclean
- idf.py build
- cd ../
- cd watering_demo
- idf.py fullclean
- idf.py build
- *build_all_examples_script
build_idf_v4.4:
extends: .build_template
image: espressif/idf:release-v4.4
build_idf_v5.0:
extends: .build_template
image: espressif/idf:release-v5.0
push_to_github:
stage: deploy
-1
View File
@@ -63,7 +63,6 @@ typedef struct {
bool LCD_MIRROR_X ;
bool LCD_MIRROR_Y ;
bool LCD_COLOR_INV ;
esp_lcd_color_space_t LCD_COLOR_SPACE;
int GPIO_LCD_BL ;
int GPIO_LCD_BL_ON ;
-1
View File
@@ -42,7 +42,6 @@ static const board_res_desc_t g_board_s3_box_res = {
.LCD_MIRROR_X = (true),
.LCD_MIRROR_Y = (true),
.LCD_COLOR_INV = (false),
.LCD_COLOR_SPACE = ESP_LCD_COLOR_SPACE_BGR,
.GPIO_LCD_BL = (GPIO_NUM_45),
.GPIO_LCD_BL_ON = (1),
@@ -38,7 +38,7 @@ static const board_res_desc_t g_board_s3_box_lite_res = {
.LCD_DISP_IC_ST = (1),
.LCD_WIDTH = (320),
.LCD_HEIGHT = (240),
.LCD_FREQ = (80 * 1000 * 1000),
.LCD_FREQ = (40 * 1000 * 1000),
.LCD_CMD_BITS = 8,
.LCD_PARAM_BITS = 8,
.LCD_HOST = (SPI2_HOST),
@@ -47,7 +47,6 @@ static const board_res_desc_t g_board_s3_box_lite_res = {
.LCD_MIRROR_X = (false),
.LCD_MIRROR_Y = (true),
.LCD_COLOR_INV = (true),
.LCD_COLOR_SPACE = ESP_LCD_COLOR_SPACE_RGB,
.GPIO_LCD_BL = (GPIO_NUM_45),
.GPIO_LCD_BL_ON = (0),
+18 -2
View File
@@ -119,10 +119,24 @@ esp_err_t bsp_lcd_init(void)
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = brd->GPIO_LCD_RST,
.color_space = brd->LCD_COLOR_SPACE,
.bits_per_pixel = 16,
};
if(brd->BSP_INDEV_IS_TP){
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
panel_config.rgb_endian = LCD_RGB_ENDIAN_BGR;
#else
panel_config.color_space = ESP_LCD_COLOR_SPACE_BGR;
#endif
}
else{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
panel_config.rgb_endian = LCD_RGB_ENDIAN_RGB;
#else
panel_config.color_space = ESP_LCD_COLOR_SPACE_RGB;
#endif
}
if (!brd->LCD_DISP_IC_ST) {
ESP_ERROR_CHECK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
} else {
@@ -140,7 +154,9 @@ esp_err_t bsp_lcd_init(void)
ret_val |= esp_lcd_panel_set_gap(panel_handle, 0, 0);
ret_val |= esp_lcd_panel_swap_xy(panel_handle, brd->LCD_SWAP_XY);
ret_val |= esp_lcd_panel_mirror(panel_handle, brd->LCD_MIRROR_X, brd->LCD_MIRROR_Y);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
ret_val |= esp_lcd_panel_disp_on_off(panel_handle, true);
#endif
/**
* @brief Configure LCD backlight IO.
*
+7 -4
View File
@@ -33,6 +33,9 @@
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#define LV_DISP_BUF_NUM 1
#define LV_DISP_BUF_HEIGHT 10
static lv_disp_drv_t disp_drv;
static const char *TAG = "lv_port";
static bool lv_port_use_fixed_buffer = false;
@@ -166,15 +169,15 @@ static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_
static void lv_port_disp_init(void)
{
static lv_disp_draw_buf_t draw_buf_dsc;
size_t disp_buf_height = 20;
size_t disp_buf_height = LV_DISP_BUF_HEIGHT;
const board_res_desc_t *brd = bsp_board_get_description();
/* Option 1 : Allocate memories from heap */
uint32_t buf_alloc_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT;
lv_color_t *p_disp_buf = heap_caps_malloc(brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * 2, buf_alloc_caps);
lv_color_t *p_disp_buf = heap_caps_malloc(brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * LV_DISP_BUF_NUM, buf_alloc_caps);
lv_color_t *p_disp_buf1 = p_disp_buf;
lv_color_t *p_disp_buf2 = p_disp_buf + brd->LCD_WIDTH * disp_buf_height;
ESP_LOGI(TAG, "Try allocate two %u * %u display buffer, size:%u Byte", brd->LCD_WIDTH, disp_buf_height, brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * 2);
lv_color_t *p_disp_buf2 = NULL;
ESP_LOGI(TAG, "Try allocate one %u * %u display buffer, size:%u Byte", brd->LCD_WIDTH, disp_buf_height, brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * LV_DISP_BUF_NUM);
if (NULL == p_disp_buf) {
ESP_LOGE(TAG, "No memory for LVGL display buffer");
esp_system_abort("Memory allocation failed");
+81 -77
View File
@@ -21,9 +21,17 @@
#include "app_sr.h"
#include "bsp_codec.h"
#include "bsp_i2s.h"
#include "esp_mn_speech_commands.h"
#include "esp_process_sdkconfig.h"
#include "esp_afe_sr_models.h"
#include "esp_mn_models.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "esp_afe_sr_iface.h"
#include "esp_mn_iface.h"
#include "app_sr_handler.h"
#include "model_path.h"
#include "bsp_board.h"
#include "bsp_btn.h"
#include "settings.h"
@@ -50,6 +58,9 @@ typedef struct {
bool b_record_en;
} sr_data_t;
static esp_afe_sr_iface_t *afe_handle = NULL;
static srmodel_list_t *models = NULL;
static sr_data_t *g_sr_data = NULL;
#define I2S_CHANNEL_NUM (2)
@@ -186,14 +197,14 @@ static const sr_cmd_t g_default_cmd_info[] = {
#endif
};
static void audio_feed_task(void *pvParam)
static void audio_feed_task(void *arg)
{
size_t bytes_read = 0;
const esp_afe_sr_iface_t *afe_handle = g_sr_data->afe_handle;
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) pvParam;
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) arg;
int audio_chunksize = afe_handle->get_feed_chunksize(afe_data);
int feed_channel = 3;
ESP_LOGI(TAG, "audio_chunksize=%d, feed_channel=%d", audio_chunksize, feed_channel);
/* Allocate audio buffer and check for result */
int16_t *audio_buffer = heap_caps_malloc(audio_chunksize * sizeof(int16_t) * feed_channel, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (NULL == audio_buffer) {
@@ -227,25 +238,17 @@ static void audio_feed_task(void *pvParam)
}
}
static void audio_detect_task(void *pvParam)
static void audio_detect_task(void *arg)
{
bool detect_flag = false;
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) pvParam;
esp_afe_sr_data_t *afe_data = arg;
int afe_chunksize = afe_handle->get_fetch_chunksize(afe_data);
//int nch = afe_handle->get_channel_num(afe_data);
/* Allocate buffer for detection */
size_t afe_chunk_size = g_sr_data->afe_handle->get_fetch_chunksize(afe_data);
g_sr_data->afe_out_buffer = heap_caps_malloc(afe_chunk_size * sizeof(int16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (NULL == g_sr_data->afe_out_buffer) {
ESP_LOGE(TAG, "Expect : %zu, avaliable : %zu",
afe_chunk_size * sizeof(int16_t),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
esp_system_abort("No mem for detect buffer");
}
/* Check for chunk size */
if (afe_chunk_size != g_sr_data->multinet->get_samp_chunksize(g_sr_data->model_data)) {
esp_system_abort("Invalid chunk size");
}
int mu_chunksize = g_sr_data->multinet->get_samp_chunksize(g_sr_data->model_data);
int chunk_num = g_sr_data->multinet->get_samp_chunknum(g_sr_data->model_data);
assert(mu_chunksize == afe_chunksize);
ESP_LOGI(TAG, "------------detect start------------\n");
while (true) {
if (NEED_DELETE && xEventGroupGetBits(g_sr_data->event_group)) {
@@ -254,33 +257,35 @@ static void audio_detect_task(void *pvParam)
vTaskDelete(NULL);
}
afe_fetch_mode_t ret_val = g_sr_data->afe_handle->fetch(afe_data, g_sr_data->afe_out_buffer);
afe_fetch_result_t* res = afe_handle->fetch(afe_data);
if (!res || res->ret_value == ESP_FAIL) {
continue;
}
if (AFE_FETCH_WWE_DETECTED == ret_val) {
if (res->wakeup_state == WAKENET_DETECTED) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "wakeword detected");
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_DETECTED,
.state = ESP_MN_STATE_DETECTING,
.command_id = 0,
};
xQueueSend(g_sr_data->result_que, &result, 0);
}
if (AFE_FETCH_CHANNEL_VERIFIED == ret_val) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Channel verified");
else if (res->wakeup_state == WAKENET_CHANNEL_VERIFIED) {
detect_flag = true;
g_sr_data->afe_handle->disable_wakenet(afe_data);
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "AFE_FETCH_CHANNEL_VERIFIED, channel index: %d\n", res->trigger_channel_id);
}
if (true == detect_flag) {
/* Save audio data to file if record enabled */
if (g_sr_data->b_record_en && (NULL != g_sr_data->fp)) {
fwrite(g_sr_data->afe_out_buffer, 1, afe_chunk_size * sizeof(int16_t), g_sr_data->fp);
fwrite(res->data, 1, afe_chunksize * sizeof(int16_t), g_sr_data->fp);
}
esp_mn_state_t mn_state = ESP_MN_STATE_DETECTING;
if (false == sr_echo_is_playing()) {
mn_state = g_sr_data->multinet->detect(g_sr_data->model_data, g_sr_data->afe_out_buffer);
mn_state = g_sr_data->multinet->detect(g_sr_data->model_data, res->data);
} else {
continue;
}
@@ -292,7 +297,7 @@ static void audio_detect_task(void *pvParam)
if (ESP_MN_STATE_TIMEOUT == mn_state) {
ESP_LOGW(TAG, "Time out");
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_NO_DETECT,
.state = mn_state,
.command_id = 0,
};
@@ -302,24 +307,24 @@ static void audio_detect_task(void *pvParam)
continue;
}
if (ESP_MN_STATE_DETECTED <= mn_state) {
if (ESP_MN_STATE_DETECTED == mn_state) {
esp_mn_results_t *mn_result = g_sr_data->multinet->get_results(g_sr_data->model_data);
for (int i = 0; i < mn_result->num; i++) {
ESP_LOGI(TAG, "TOP %d, command_id: %d, phrase_id: %d, prob: %f",
i + 1, mn_result->command_id[i], mn_result->phrase_id[i], mn_result->prob[i]);
printf("TOP %d, command_id: %d, phrase_id: %d, prob: %f\n",
i + 1, mn_result->command_id[i], mn_result->phrase_id[i], mn_result->prob[i]);
}
int sr_command_id = mn_result->command_id[0];
ESP_LOGI(TAG, "Deteted command : %d", sr_command_id);
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_NO_DETECT,
.state = mn_state,
.command_id = sr_command_id,
};
xQueueSend(g_sr_data->result_que, &result, 0);
#if !SR_CONTINUE_DET
g_sr_data->afe_handle->enable_wakenet(afe_data);
detect_flag = 0;
detect_flag = false;
#endif
if (g_sr_data->b_record_en && (NULL != g_sr_data->fp)) {
@@ -329,11 +334,9 @@ static void audio_detect_task(void *pvParam)
}
continue;
}
ESP_LOGE(TAG, "Exception unhandled");
}
}
/* Task never returns */
vTaskDelete(NULL);
}
@@ -353,35 +356,31 @@ esp_err_t app_sr_set_language(sr_language_t new_lang)
if (g_sr_data->model_data) {
g_sr_data->multinet->destroy(g_sr_data->model_data);
}
switch (g_sr_data->lang) {
case SR_LANG_EN:
g_sr_data->afe_handle->set_wakenet(g_sr_data->afe_data, FIRST_WAKE_WORD);
g_sr_data->multinet = &MULTINET_MODEL_EN;
g_sr_data->model_data = g_sr_data->multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF_EN, 5760);
break;
case SR_LANG_CN:
g_sr_data->afe_handle->set_wakenet(g_sr_data->afe_data, SECOND_WAKE_WORD);
g_sr_data->multinet = &MULTINET_MODEL_CN;
g_sr_data->model_data = g_sr_data->multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF_CN, 5760);
break;
default:
break;
}
// remove all command
sr_cmd_t *it;
while (!SLIST_EMPTY(&g_sr_data->cmd_list)) {
it = SLIST_FIRST(&g_sr_data->cmd_list);
SLIST_REMOVE_HEAD(&g_sr_data->cmd_list, next);
heap_caps_free(it);
}
app_sr_remove_all_cmd();
esp_mn_commands_free();
esp_mn_commands_alloc();
g_sr_data->cmd_num = 0;
char *wn_name = esp_srmodel_filter(models, ESP_WN_PREFIX, (SR_LANG_EN == g_sr_data->lang ? "hiesp" : "hilexin"));
g_sr_data->afe_handle->set_wakenet(g_sr_data->afe_data, wn_name);
ESP_LOGI(TAG, "load wakenet:%s", wn_name);
char *mn_name = esp_srmodel_filter(models, ESP_MN_PREFIX, ((SR_LANG_EN == g_sr_data->lang) ? ESP_MN_ENGLISH : ESP_MN_CHINESE));
esp_mn_iface_t *multinet = esp_mn_handle_from_name(mn_name);
model_iface_data_t *model_data = multinet->create(mn_name, 5760);
g_sr_data->multinet = multinet;
g_sr_data->model_data = model_data;
ESP_LOGI(TAG, "load multinet:%s,%d,%d", mn_name, sizeof(esp_mn_iface_t), sizeof(esp_mn_iface_t));
uint8_t cmd_number = 0;
// count command number
for (size_t i = 0; i < sizeof(g_default_cmd_info) / sizeof(sr_cmd_t); i++) {
if (g_default_cmd_info[i].lang == g_sr_data->lang) {
cmd_number++;
app_sr_add_cmd(&g_default_cmd_info[i]);
cmd_number++;
}
}
ESP_LOGI(TAG, "cmd_number=%d", cmd_number);
@@ -421,28 +420,34 @@ esp_err_t app_sr_start(bool record_en)
ESP_LOGI(TAG, "File created at %s", file_name);
}
esp_task_wdt_reset();
g_sr_data->afe_handle = &ESP_AFE_HANDLE;
BaseType_t ret_val;
models = esp_srmodel_init("model");
afe_handle = &ESP_AFE_SR_HANDLE;
afe_config_t afe_config = AFE_CONFIG_DEFAULT();
afe_config.wakenet_model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
afe_config.aec_init = false;
// afe_config.vad_init = false;
g_sr_data->afe_data = g_sr_data->afe_handle->create_from_config(&afe_config);
const sys_param_t *param = settings_get_parameter();
esp_afe_sr_data_t *afe_data = afe_handle->create_from_config(&afe_config);
g_sr_data->afe_handle = afe_handle;
g_sr_data->afe_data = afe_data;
sys_param_t *param = settings_get_parameter();
g_sr_data->lang = SR_LANG_MAX;
ret = app_sr_set_language(param->sr_lang);
ESP_GOTO_ON_FALSE(ESP_OK == ret, ESP_FAIL, err, TAG, "Failed to set language");
BaseType_t ret_val = xTaskCreatePinnedToCore(audio_feed_task, "Feed Task", 4 * 1024, g_sr_data->afe_data, 5, &g_sr_data->feed_task, 1);
ret_val = xTaskCreatePinnedToCore(&audio_feed_task, "Feed Task", 4 * 1024, (void*)afe_data, 5, &g_sr_data->feed_task, 0);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio feed task");
ret_val = xTaskCreatePinnedToCore(audio_detect_task, "Detect Task", 6 * 1024, g_sr_data->afe_data, 5, &g_sr_data->detect_task, 1);
ret_val = xTaskCreatePinnedToCore(&audio_detect_task, "Detect Task", 8 * 1024, (void*)afe_data, 5, &g_sr_data->detect_task, 1);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio detect task");
ret_val = xTaskCreatePinnedToCore(sr_handler_task, "SR Handler Task", 4 * 1024, NULL, configMAX_PRIORITIES - 3, &g_sr_data->handle_task, 0);
ret_val = xTaskCreatePinnedToCore(&sr_handler_task, "SR Handler Task", 6 * 1024, NULL, configMAX_PRIORITIES - 1, &g_sr_data->handle_task, 0);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio handler task");
return ESP_OK;
err:
app_sr_stop();
return ret;
@@ -515,7 +520,8 @@ esp_err_t app_sr_add_cmd(const sr_cmd_t *cmd)
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
ESP_RETURN_ON_FALSE(NULL != cmd, ESP_ERR_INVALID_ARG, TAG, "pointer of cmd is invaild");
ESP_RETURN_ON_FALSE(cmd->lang == g_sr_data->lang, ESP_ERR_INVALID_ARG, TAG, "cmd lang error");
ESP_RETURN_ON_FALSE(200 >= g_sr_data->cmd_num, ESP_ERR_INVALID_STATE, TAG, "cmd is full");
ESP_RETURN_ON_FALSE(ESP_MN_MAX_PHRASE_NUM >= g_sr_data->cmd_num, ESP_ERR_INVALID_STATE, TAG, "cmd is full");
sr_cmd_t *item = (sr_cmd_t *)heap_caps_calloc(1, sizeof(sr_cmd_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(NULL != item, ESP_ERR_NO_MEM, TAG, "memory for sr cmd is not enough");
memcpy(item, cmd, sizeof(sr_cmd_t));
@@ -534,6 +540,7 @@ esp_err_t app_sr_add_cmd(const sr_cmd_t *cmd)
#else // insert head
SLIST_INSERT_HEAD(&g_sr_data->cmd_list, it, next);
#endif
esp_mn_commands_add(g_sr_data->cmd_num, (char *)cmd->phoneme);
g_sr_data->cmd_num++;
return ESP_OK;
}
@@ -549,6 +556,7 @@ esp_err_t app_sr_modify_cmd(uint32_t id, const sr_cmd_t *cmd)
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (it->id == id) {
ESP_LOGI(TAG, "modify cmd [%d] from %s to %s", id, it->str, cmd->str);
esp_mn_commands_modify(it->phoneme, (char *)cmd->phoneme);
memcpy(it, cmd, sizeof(sr_cmd_t));
break;
}
@@ -592,24 +600,20 @@ esp_err_t app_sr_update_cmds(void)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
char *cmd_str = heap_caps_calloc(g_sr_data->cmd_num, SR_CMD_PHONEME_LEN_MAX, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(NULL != cmd_str, ESP_ERR_NO_MEM, TAG, "memory for sr cmd str is not enough");
uint32_t count = 0;
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
it->id = count++;
strcat(cmd_str, it->phoneme);
strcat(cmd_str, ";");
}
ESP_LOGI(TAG, "New %d command set to :[%s]", count, cmd_str);
esp_mn_phrase_err_id_t *err_id = g_sr_data->multinet->reset(g_sr_data->model_data, cmd_str, -1);
for (int i = 0; i < err_id->err_id_num; i++) {
ESP_LOGE(TAG, "err cmd id:%d", err_id->err_id[i]);
esp_mn_error_t *err_id = esp_mn_commands_update(g_sr_data->multinet, g_sr_data->model_data);
if(err_id){
for (int i = 0; i < err_id->num; i++) {
ESP_LOGE(TAG, "err cmd id:%d", err_id->phrase_idx[i]);
}
}
heap_caps_free(cmd_str);
esp_mn_commands_print();
return ESP_OK;
}
+1 -1
View File
@@ -31,7 +31,7 @@ extern "C" {
#define SR_CMD_PHONEME_LEN_MAX 64
typedef struct {
afe_fetch_mode_t fetch_mode;
wakenet_state_t wakenet_mode;
esp_mn_state_t state;
int command_id;
} sr_result_t;
+47 -28
View File
@@ -104,37 +104,61 @@ bool sr_echo_is_playing(void)
return b_audio_playing;
}
void sr_handler_task(void *pvParam)
sr_language_t sr_detect_language()
{
static sr_language_t sr_current_lang = SR_LANG_MAX;
esp_err_t ret;
FILE *fp;
const sys_param_t *param = settings_get_parameter();
const char *files[2][3] = {
{"/spiffs/echo_en_wake.wav", "/spiffs/echo_en_ok.wav", "/spiffs/echo_en_end.wav"},
{"/spiffs/echo_cn_wake.wav", "/spiffs/echo_cn_ok.wav", "/spiffs/echo_cn_end.wav"},
};
char audio_file[48] = {0};
for (size_t i = 0; i < AUDIO_MAX; i++) {
strncpy(audio_file, files[param->sr_lang][i], sizeof(audio_file));
fp = fopen(audio_file, "rb");
ESP_GOTO_ON_FALSE(NULL != fp, ESP_ERR_NOT_FOUND, err, TAG, "Open file %s failed", audio_file);
size_t file_size = fm_get_file_size(audio_file);
g_audio_data[i].len = file_size;
g_audio_data[i].audio_buffer = heap_caps_calloc(1, file_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
ESP_GOTO_ON_FALSE(NULL != g_audio_data[i].audio_buffer, ESP_ERR_NO_MEM, err, TAG, "No mem for sr echo buffer");
fread(g_audio_data[i].audio_buffer, 1, file_size, fp);
FILE *fp = NULL;
const sys_param_t * param = settings_get_parameter();
if(param->sr_lang^sr_current_lang){
sr_current_lang = param->sr_lang;
ESP_LOGI(TAG, "boardcast language change to = %s", (SR_LANG_EN == param->sr_lang ? "EN" : "CN"));
const char *files[2][3] = {
{"/spiffs/echo_en_wake.wav", "/spiffs/echo_en_ok.wav", "/spiffs/echo_en_end.wav"},
{"/spiffs/echo_cn_wake.wav", "/spiffs/echo_cn_ok.wav", "/spiffs/echo_cn_end.wav"},
};
char audio_file[48] = {0};
for (size_t i = 0; i < AUDIO_MAX; i++) {
strncpy(audio_file, files[param->sr_lang][i], sizeof(audio_file));
fp = fopen(audio_file, "rb");
ESP_GOTO_ON_FALSE(NULL != fp, ESP_ERR_NOT_FOUND, err, TAG, "Open file %s failed", audio_file);
size_t file_size = fm_get_file_size(audio_file);
if(g_audio_data[i].audio_buffer){
heap_caps_free(g_audio_data[i].audio_buffer);
g_audio_data[i].len = 0;
}
g_audio_data[i].len = file_size;
g_audio_data[i].audio_buffer = heap_caps_calloc(1, file_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
ESP_GOTO_ON_FALSE(NULL != g_audio_data[i].audio_buffer, ESP_ERR_NO_MEM, err, TAG, "No mem for sr echo buffer");
fread(g_audio_data[i].audio_buffer, 1, file_size, fp);
fclose(fp);
}
}
return sr_current_lang;
err:
if(fp){
fclose(fp);
}
(void)ret;
return sr_current_lang;
}
void sr_handler_task(void *pvParam)
{
sr_language_t sr_current_lang;
audio_player_state_t last_player_state = AUDIO_PLAYER_STATE_IDLE;
while (true) {
sr_result_t result;
app_sr_get_result(&result, portMAX_DELAY);
char audio_file[48] = {0};
sr_current_lang = sr_detect_language();
if (ESP_MN_STATE_TIMEOUT == result.state) {
if (SR_LANG_EN == param->sr_lang) {
if (SR_LANG_EN == sr_current_lang) {
sr_anim_set_text("Timeout");
} else {
sr_anim_set_text("超时");
@@ -149,12 +173,12 @@ void sr_handler_task(void *pvParam)
continue;
}
if (AFE_FETCH_WWE_DETECTED == result.fetch_mode) {
if (WAKENET_DETECTED == result.wakenet_mode) {
sr_anim_start();
last_player_state = audio_player_get_state();
audio_player_pause();
if (SR_LANG_EN == param->sr_lang) {
if (SR_LANG_EN == sr_current_lang) {
sr_anim_set_text("Say command");
} else {
sr_anim_set_text("请说");
@@ -214,7 +238,7 @@ void sr_handler_task(void *pvParam)
break;
}
#if !SR_RUN_TEST
if (SR_LANG_EN == param->sr_lang) {
if (SR_LANG_EN == sr_current_lang) {
strncpy(audio_file, "/spiffs/echo_en_ok.wav", sizeof(audio_file));
} else {
strncpy(audio_file, "/spiffs/echo_cn_ok.wav", sizeof(audio_file));
@@ -223,10 +247,5 @@ void sr_handler_task(void *pvParam)
#endif
}
}
err:
if (fp) {
fclose(fp);
}
vTaskDelete(NULL);
}
+1 -2
View File
@@ -104,7 +104,6 @@ void app_main(void)
ESP_ERROR_CHECK(bsp_board_init());
ESP_ERROR_CHECK(bsp_board_power_ctrl(POWER_MODULE_AUDIO, true));
ESP_ERROR_CHECK(lv_port_init());
ESP_ERROR_CHECK(bsp_spiffs_init("model", "/srmodel", 4));
ESP_ERROR_CHECK(bsp_spiffs_init("storage", "/spiffs", 2));
ESP_ERROR_CHECK(ui_main_start());
bsp_lcd_set_backlight(true); // Turn on the backlight after gui initialize
@@ -112,7 +111,7 @@ void app_main(void)
assert(file_iterator != NULL);
audio_player_config_t config = { .port = I2S_NUM_0,
.mute_fn = audio_mute_function,
.priority = 1 };
.priority = 5 };
ESP_ERROR_CHECK(audio_player_new(config));
const board_res_desc_t *brd = bsp_board_get_description();
+2 -2
View File
@@ -5,7 +5,7 @@ nvs, data, nvs, 0x10000, 0x6000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
fctry, data, nvs, , 0x6000,
ota_0, app, ota_0, , 3700K,
ota_0, app, ota_0, , 4200K,
# ota_1, app, ota_1, , 2700K,
storage, data, spiffs, , 2600K,
model, data, spiffs, , 8100K,
model, data, spiffs, , 7600K,
1 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
5 otadata, data, ota, , 0x2000,
6 phy_init, data, phy, , 0x1000,
7 fctry, data, nvs, , 0x6000,
8 ota_0, app, ota_0, , 3700K, ota_0, app, ota_0, , 4200K,
9 # ota_1, app, ota_1, , 2700K,
10 storage, data, spiffs, , 2600K,
11 model, data, spiffs, , 8100K, model, data, spiffs, , 7600K,
+24 -14
View File
@@ -7,16 +7,11 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
#
# ESP Speech Recognition
#
CONFIG_MODEL_IN_SPIFFS=y
CONFIG_USE_WAKENET=y
CONFIG_SR_WN_MODEL_WN8_QUANT=y
CONFIG_SR_WN_WN8_HIESP=y
CONFIG_USE_MULTINET=y
CONFIG_SR_MN_ENGLISH=y
CONFIG_SR_WN_LOAD_MULIT_WORD=y
CONFIG_SR_WN_WN9_HILEXIN_MULTI=y
CONFIG_SR_WN_WN9_HIESP_MULTI=y
CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8=y
CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8=y
CONFIG_SR_WN_WN8_HIESP_FIRST=y
CONFIG_SR_WN_WN8_HILEXIN_SECOND=y
CONFIG_EN_SPEECH_COMMAND_ID0=""
CONFIG_EN_SPEECH_COMMAND_ID1=""
CONFIG_EN_SPEECH_COMMAND_ID2=""
@@ -68,6 +63,11 @@ CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1024
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=8192
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
#CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
#CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
@@ -79,15 +79,17 @@ CONFIG_ESP_TASK_WDT_TIMEOUT_S=7
CONFIG_ESP_IPC_TASK_STACK_SIZE=2048
# Wi-Fi
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=3
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=4
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=4
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_TX_BA_WIN=4
CONFIG_ESP32_WIFI_RX_BA_WIN=4
CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=n
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=n
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
# Bluetooth controller
CONFIG_BT_ENABLED=y
@@ -96,13 +98,21 @@ CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
CONFIG_BT_NIMBLE_ROLE_CENTRAL=n
CONFIG_BT_NIMBLE_ROLE_OBSERVER=n
# CONFIG_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=y
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=y
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16
# CONFIG_LWIP_DHCPS is not set
# CONFIG_LWIP_ICMP is not set
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
# CONFIG_MQTT_TRANSPORT_WEBSOCKET is not set
CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_BUTTON_SHORT_PRESS_TIME_MS=100
CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000
CONFIG_ADC_BUTTON_MAX_BUTTON_PER_CHANNEL=4
+41 -28
View File
@@ -25,16 +25,21 @@
#include "esp_mn_models.h"
#include "app_sr_handler.h"
#include "model_path.h"
#include "esp_mn_speech_commands.h"
#include "esp_process_sdkconfig.h"
#define I2S_CHANNEL_NUM (2)
static const char *TAG = "app_sr";
static model_iface_data_t *model_data = NULL;
static const esp_mn_iface_t *multinet = &MULTINET_MODEL;
static const esp_afe_sr_iface_t *afe_handle = &ESP_AFE_HANDLE;
static const esp_mn_iface_t *multinet = NULL;
static const esp_afe_sr_iface_t *afe_handle = NULL;
static QueueHandle_t g_result_que = NULL;
static srmodel_list_t *models = NULL;
static FILE *fp = NULL;
static bool b_record_en = false;
@@ -83,34 +88,30 @@ static void audio_detect_task(void *pvParam)
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) pvParam;
/* Allocate buffer for detection */
size_t afe_chunk_size = afe_handle->get_fetch_chunksize(afe_data);
int16_t *detect_buff = heap_caps_malloc(afe_chunk_size * sizeof(int16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (NULL == detect_buff) {
ESP_LOGE(TAG, "Expect : %zu, avaliable : %zu",
afe_chunk_size * sizeof(int16_t),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
esp_system_abort("No mem for detect buffer");
}
int afe_chunksize = afe_handle->get_fetch_chunksize(afe_data);
/* Check for chunk size */
if (afe_chunk_size != multinet->get_samp_chunksize(model_data)) {
esp_system_abort("Invalid chunk size");
}
int mu_chunksize = multinet->get_samp_chunksize(model_data);
int chunk_num = multinet->get_samp_chunknum(model_data);
assert(mu_chunksize == afe_chunksize);
ESP_LOGI(TAG, "------------detect start------------\n");
while (true) {
afe_fetch_mode_t ret_val = afe_handle->fetch(afe_data, detect_buff);
afe_fetch_result_t* res = afe_handle->fetch(afe_data);
if (!res || res->ret_value == ESP_FAIL) {
ESP_LOGE(TAG, "fetch error!");
//break;
}
if (AFE_FETCH_WWE_DETECTED == ret_val) {
if (res->wakeup_state == WAKENET_DETECTED) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Wakeword detected");
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_DETECTED,
.state = ESP_MN_STATE_DETECTING,
.command_id = 0,
};
xQueueSend(g_result_que, &result, 10);
}
if (AFE_FETCH_CHANNEL_VERIFIED == ret_val) {
else if (res->wakeup_state == WAKENET_CHANNEL_VERIFIED) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Channel verified");
detect_flag = true;
afe_handle->disable_wakenet(afe_data);
@@ -119,12 +120,12 @@ static void audio_detect_task(void *pvParam)
if (true == detect_flag) {
/* Save audio data to file if record enabled */
if (b_record_en && (NULL != fp)) {
fwrite(detect_buff, 1, afe_chunk_size * sizeof(int16_t), fp);
fwrite(res->data, 1, afe_chunksize * sizeof(int16_t), fp);
}
esp_mn_state_t mn_state = ESP_MN_STATE_DETECTING;
if (false == app_audio_beep_is_playing()) {
mn_state = multinet->detect(model_data, detect_buff);
mn_state = multinet->detect(model_data, res->data);
} else {
continue;
}
@@ -136,7 +137,7 @@ static void audio_detect_task(void *pvParam)
if (ESP_MN_STATE_TIMEOUT == mn_state) {
ESP_LOGW(TAG, "Time out");
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_NO_DETECT,
.state = mn_state,
.command_id = 0,
};
@@ -146,7 +147,7 @@ static void audio_detect_task(void *pvParam)
continue;
}
if (ESP_MN_STATE_DETECTED <= mn_state) {
if (ESP_MN_STATE_DETECTED == mn_state) {
esp_mn_results_t *mn_result = multinet->get_results(model_data);
for (int i = 0; i < mn_result->num; i++) {
ESP_LOGI(TAG, "TOP %d, command_id: %d, phrase_id: %d, prob: %f",
@@ -156,14 +157,15 @@ static void audio_detect_task(void *pvParam)
int sr_command_id = mn_result->command_id[0];
ESP_LOGI(TAG, "Deteted command : %d", sr_command_id);
sr_result_t result = {
.fetch_mode = ret_val,
.wakenet_mode = WAKENET_NO_DETECT,
.state = mn_state,
.command_id = sr_command_id,
};
xQueueSend(g_result_que, &result, 10);
#if !SR_CONTINUE_DET
afe_handle->enable_wakenet(afe_data);
detect_flag = 0;
detect_flag = false;
#endif
if (b_record_en && (NULL != fp)) {
ESP_LOGI(TAG, "File saved");
fclose(fp);
@@ -212,11 +214,22 @@ esp_err_t app_sr_start(bool record_en)
ESP_LOGI(TAG, "File created at %s", file_name);
}
models = esp_srmodel_init("model");
afe_handle = &ESP_AFE_SR_HANDLE;
afe_config_t afe_config = AFE_CONFIG_DEFAULT();
afe_config.wakenet_model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
afe_config.aec_init = false;
// afe_config.vad_init = false;
ESP_LOGI(TAG, "load wakenet:%s", afe_config.wakenet_model_name);
esp_afe_sr_data_t *afe_data = afe_handle->create_from_config(&afe_config);
model_data = multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF, 5760);
char *mn_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
multinet = esp_mn_handle_from_name(mn_name);
ESP_LOGI(TAG, "load multinet:%s", mn_name);
model_data = multinet->create(mn_name, 5760);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
BaseType_t ret_val = xTaskCreatePinnedToCore(audio_feed_task, "Feed Task", 4 * 1024, afe_data, 5, NULL, 1);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_FAIL, TAG, "Failed create audio feed task");
@@ -234,7 +247,7 @@ esp_err_t app_sr_reset_command_list(char *command_list)
{
char *err_id = heap_caps_malloc(1024, MALLOC_CAP_SPIRAM);
ESP_RETURN_ON_FALSE(NULL != err_id, ESP_ERR_NO_MEM, TAG, "memory is not enough");
multinet->reset(model_data, command_list, err_id);
//multinet->reset(model_data, command_list, err_id);
free(err_id);
return ESP_OK;
}
+11 -1
View File
@@ -15,6 +15,16 @@
extern "C" {
#endif
#define SR_CONTINUE_DET 1
#define SR_RUN_TEST 0 /**< Just for sr experiment in laboratory >*/
#if SR_RUN_TEST
#ifdef SR_CONTINUE_DET
#undef SR_CONTINUE_DET
#define SR_CONTINUE_DET 0
#endif
#endif
/**
* @brief Speech command string
*
@@ -67,7 +77,7 @@ extern "C" {
#endif
typedef struct {
afe_fetch_mode_t fetch_mode;
wakenet_state_t wakenet_mode;
esp_mn_state_t state;
int command_id;
} sr_result_t;
@@ -15,6 +15,7 @@
#include "ui_sr.h"
#include "app_pump.h"
#include "app_sr_handler.h"
#include "esp_afe_sr_iface.h"
static const char *TAG = "sr_handler";
@@ -27,13 +28,15 @@ void sr_handler_task(void *pvParam)
sr_result_t result;
xQueueReceive(xQueue, &result, portMAX_DELAY);
ESP_LOGI(TAG, "cmd:%d, wakemode:%d,state:%d", result.command_id, result.wakenet_mode, result.state);
if (ESP_MN_STATE_TIMEOUT == result.state) {
sr_anim_set_text("Timeout");
sr_anim_stop();
continue;
}
if (AFE_FETCH_WWE_DETECTED == result.fetch_mode) {
if (WAKENET_DETECTED == result.wakenet_mode) {
sr_anim_start();
app_audio_beep_play_start();
sr_anim_set_text("Say command");
-1
View File
@@ -80,7 +80,6 @@ void app_main(void)
ESP_ERROR_CHECK(bsp_board_init());
ESP_ERROR_CHECK(bsp_board_power_ctrl(POWER_MODULE_AUDIO, true));
ESP_ERROR_CHECK(bsp_spiffs_init("model", "/srmodel", 4));
ESP_ERROR_CHECK(bsp_spiffs_init("storage", "/spiffs", 2));
ESP_ERROR_CHECK(app_lvgl_start());
+12 -3
View File
@@ -3,6 +3,7 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_DETECT is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8=y
CONFIG_CN_SPEECH_COMMAND_ID0="ting zhi jiao hua"
CONFIG_CN_SPEECH_COMMAND_ID1="ting zhi jiao shui"
CONFIG_CN_SPEECH_COMMAND_ID2="kai shi jiao hua"
@@ -25,12 +26,14 @@ CONFIG_CN_SPEECH_COMMAND_ID18=""
CONFIG_CN_SPEECH_COMMAND_ID19=""
CONFIG_LV_FONT_FMT_TXT_LARGE=y
CONFIG_LV_USE_QRCODE=y
CONFIG_LV_MEM_CUSTOM=y
CONFIG_LV_FONT_MONTSERRAT_18=y
CONFIG_LV_FONT_MONTSERRAT_28=y
CONFIG_LV_FONT_MONTSERRAT_36=y
CONFIG_LV_COLOR_16_SWAP=y
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
@@ -41,18 +44,24 @@ CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1024
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=8192
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
CONFIG_ESP_TIMER_TASK_STACK_SIZE=2048
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=6
CONFIG_ESP32_WIFI_RX_BA_WIN=12
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=3
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=4
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=4
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_TX_BA_WIN=4
CONFIG_ESP32_WIFI_RX_BA_WIN=4
CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED=y
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3072
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16
# CONFIG_LWIP_IPV6 is not set
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_BUTTON_SHORT_PRESS_TIME_MS=100