From 860f83ca0db783248f54d698834152bc0aed90c3 Mon Sep 17 00:00:00 2001 From: amass <168062547@qq.com> Date: Thu, 16 May 2024 01:09:36 +0800 Subject: [PATCH] add console code. --- .clang-format | 17 ++ .gitignore | 44 ++++ components/command/CMakeLists.txt | 9 + components/command/cmd_custom.c | 18 ++ components/command/cmd_custom.h | 6 + components/command/cmd_system.c | 18 ++ components/command/cmd_system.h | 26 +++ components/command/cmd_system_common.c | 274 +++++++++++++++++++++++++ components/command/cmd_system_sleep.c | 222 ++++++++++++++++++++ main/main.c | 121 ++++++++++- partitions.csv | 6 + sdkconfig.defaults | 20 ++ 12 files changed, 779 insertions(+), 2 deletions(-) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 components/command/CMakeLists.txt create mode 100644 components/command/cmd_custom.c create mode 100644 components/command/cmd_custom.h create mode 100644 components/command/cmd_system.c create mode 100644 components/command/cmd_system.h create mode 100644 components/command/cmd_system_common.c create mode 100644 components/command/cmd_system_sleep.c create mode 100644 partitions.csv create mode 100644 sdkconfig.defaults diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f3960e2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,17 @@ +BasedOnStyle: LLVM + +ObjCBlockIndentWidth: 4 +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -4 +ColumnLimit: 120 + +#模板声明后换行 +AlwaysBreakTemplateDeclarations: true + +# 是否允许短if单行 If true, if (a) return; 可以放到同一行 +AllowShortIfStatementsOnASingleLine: true + +#短句 while (true) continue; 能被放到单行。 +AllowShortLoopsOnASingleLine: true +AllowShortFunctionsOnASingleLine: false \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d137e6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +*.qmlc +*.jsc +Makefile* +*build-* + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator CMake +CMakeLists.txt.user* +build +sdkconfig \ No newline at end of file diff --git a/components/command/CMakeLists.txt b/components/command/CMakeLists.txt new file mode 100644 index 0000000..3ff1a85 --- /dev/null +++ b/components/command/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRCS + cmd_system.c + cmd_system_common.c + cmd_custom.c + INCLUDE_DIRS . + REQUIRES console spi_flash driver +) + +target_sources(${COMPONENT_LIB} PRIVATE cmd_system_sleep.c) \ No newline at end of file diff --git a/components/command/cmd_custom.c b/components/command/cmd_custom.c new file mode 100644 index 0000000..8345a0d --- /dev/null +++ b/components/command/cmd_custom.c @@ -0,0 +1,18 @@ +#include "cmd_custom.h" +#include "esp_console.h" + + +static int custom_command(int argc, char **argv) { + printf("i am amass.\n"); + return 0; +} + +void register_custom() { + const esp_console_cmd_t heap_cmd = { + .command = "amass", + .help = "test command.", + .hint = NULL, + .func = &custom_command, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&heap_cmd)); +} diff --git a/components/command/cmd_custom.h b/components/command/cmd_custom.h new file mode 100644 index 0000000..6bc1e20 --- /dev/null +++ b/components/command/cmd_custom.h @@ -0,0 +1,6 @@ +#ifndef __CMD_CUSTOM_H__ +#define __CMD_CUSTOM_H__ + +void register_custom(); + +#endif // __CMD_CUSTOM_H__ \ No newline at end of file diff --git a/components/command/cmd_system.c b/components/command/cmd_system.c new file mode 100644 index 0000000..4b9612b --- /dev/null +++ b/components/command/cmd_system.c @@ -0,0 +1,18 @@ +/* Console example — various system commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + + +#include "cmd_system.h" +#include "sdkconfig.h" + +void register_system(void) +{ + register_system_common(); + register_system_sleep(); +} diff --git a/components/command/cmd_system.h b/components/command/cmd_system.h new file mode 100644 index 0000000..1f35d31 --- /dev/null +++ b/components/command/cmd_system.h @@ -0,0 +1,26 @@ +/* Console example — various system commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// Register all system functions +void register_system(void); + +// Register common system functions: "version", "restart", "free", "heap", "tasks" +void register_system_common(void); + +// Register deep and light sleep functions +void register_system_sleep(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/command/cmd_system_common.c b/components/command/cmd_system_common.c new file mode 100644 index 0000000..a7761b1 --- /dev/null +++ b/components/command/cmd_system_common.c @@ -0,0 +1,274 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Console example — various system commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_console.h" +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "argtable3/argtable3.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "cmd_system.h" +#include "sdkconfig.h" + +#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS +#define WITH_TASKS_INFO 1 +#endif + +static const char *TAG = "cmd_system_common"; + +static void register_free(void); +static void register_heap(void); +static void register_version(void); +static void register_restart(void); +#if WITH_TASKS_INFO +static void register_tasks(void); +#endif +static void register_log_level(void); + +void register_system_common(void) +{ + register_free(); + register_heap(); + register_version(); + register_restart(); +#if WITH_TASKS_INFO + register_tasks(); +#endif + register_log_level(); +} + + +/* 'version' command */ +static int get_version(int argc, char **argv) +{ + const char *model; + esp_chip_info_t info; + uint32_t flash_size; + esp_chip_info(&info); + + switch(info.model) { + case CHIP_ESP32: + model = "ESP32"; + break; + case CHIP_ESP32S2: + model = "ESP32-S2"; + break; + case CHIP_ESP32S3: + model = "ESP32-S3"; + break; + case CHIP_ESP32C3: + model = "ESP32-C3"; + break; + case CHIP_ESP32H2: + model = "ESP32-H2"; + break; + case CHIP_ESP32C2: + model = "ESP32-C2"; + break; + default: + model = "Unknown"; + break; + } + + if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { + printf("Get flash size failed"); + return 1; + } + printf("IDF Version:%s\r\n", esp_get_idf_version()); + printf("Chip info:\r\n"); + printf("\tmodel:%s\r\n", model); + printf("\tcores:%d\r\n", info.cores); + printf("\tfeature:%s%s%s%s%"PRIu32"%s\r\n", + info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "", + info.features & CHIP_FEATURE_BLE ? "/BLE" : "", + info.features & CHIP_FEATURE_BT ? "/BT" : "", + info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:", + flash_size / (1024 * 1024), " MB"); + printf("\trevision number:%d\r\n", info.revision); + return 0; +} + +static void register_version(void) +{ + const esp_console_cmd_t cmd = { + .command = "version", + .help = "Get version of chip and SDK", + .hint = NULL, + .func = &get_version, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'restart' command restarts the program */ + +static int restart(int argc, char **argv) +{ + ESP_LOGI(TAG, "Restarting"); + esp_restart(); +} + +static void register_restart(void) +{ + const esp_console_cmd_t cmd = { + .command = "restart", + .help = "Software reset of the chip", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'free' command prints available heap memory */ + +static int free_mem(int argc, char **argv) +{ + printf("%"PRIu32"\n", esp_get_free_heap_size()); + return 0; +} + +static void register_free(void) +{ + const esp_console_cmd_t cmd = { + .command = "free", + .help = "Get the current size of free heap memory", + .hint = NULL, + .func = &free_mem, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/* 'heap' command prints minumum heap size */ +static int heap_size(int argc, char **argv) +{ + uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT); + printf("min heap size: %"PRIu32"\n", heap_size); + return 0; +} + +static void register_heap(void) +{ + const esp_console_cmd_t heap_cmd = { + .command = "heap", + .help = "Get minimum size of free heap memory that was available during program execution", + .hint = NULL, + .func = &heap_size, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) ); + +} + +/** 'tasks' command prints the list of tasks and related information */ +#if WITH_TASKS_INFO + +static int tasks_info(int argc, char **argv) +{ + const size_t bytes_per_task = 40; /* see vTaskList description */ + char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task); + if (task_list_buffer == NULL) { + ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output"); + return 1; + } + fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout); +#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + fputs("\tAffinity", stdout); +#endif + fputs("\n", stdout); + vTaskList(task_list_buffer); + fputs(task_list_buffer, stdout); + free(task_list_buffer); + return 0; +} + +static void register_tasks(void) +{ + const esp_console_cmd_t cmd = { + .command = "tasks", + .help = "Get information about running tasks", + .hint = NULL, + .func = &tasks_info, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +#endif // WITH_TASKS_INFO + +/** log_level command changes log level via esp_log_level_set */ + +static struct { + struct arg_str *tag; + struct arg_str *level; + struct arg_end *end; +} log_level_args; + +static const char* s_log_level_names[] = { + "none", + "error", + "warn", + "info", + "debug", + "verbose" +}; + +static int log_level(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &log_level_args); + if (nerrors != 0) { + arg_print_errors(stderr, log_level_args.end, argv[0]); + return 1; + } + assert(log_level_args.tag->count == 1); + assert(log_level_args.level->count == 1); + const char* tag = log_level_args.tag->sval[0]; + const char* level_str = log_level_args.level->sval[0]; + esp_log_level_t level; + size_t level_len = strlen(level_str); + for (level = ESP_LOG_NONE; level <= ESP_LOG_VERBOSE; level++) { + if (memcmp(level_str, s_log_level_names[level], level_len) == 0) { + break; + } + } + if (level > ESP_LOG_VERBOSE) { + printf("Invalid log level '%s', choose from none|error|warn|info|debug|verbose\n", level_str); + return 1; + } + if (level > CONFIG_LOG_MAXIMUM_LEVEL) { + printf("Can't set log level to %s, max level limited in menuconfig to %s. " + "Please increase CONFIG_LOG_MAXIMUM_LEVEL in menuconfig.\n", + s_log_level_names[level], s_log_level_names[CONFIG_LOG_MAXIMUM_LEVEL]); + return 1; + } + esp_log_level_set(tag, level); + return 0; +} + +static void register_log_level(void) +{ + log_level_args.tag = arg_str1(NULL, NULL, "", "Log tag to set the level for, or * to set for all tags"); + log_level_args.level = arg_str1(NULL, NULL, "", "Log level to set. Abbreviated words are accepted."); + log_level_args.end = arg_end(2); + + const esp_console_cmd_t cmd = { + .command = "log_level", + .help = "Set log level for all tags or a specific tag.", + .hint = NULL, + .func = &log_level, + .argtable = &log_level_args + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} diff --git a/components/command/cmd_system_sleep.c b/components/command/cmd_system_sleep.c new file mode 100644 index 0000000..15d0b40 --- /dev/null +++ b/components/command/cmd_system_sleep.c @@ -0,0 +1,222 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Console example — various sleep-related commands + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_console.h" +#include "esp_chip_info.h" +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "driver/uart.h" +#include "argtable3/argtable3.h" +#include "cmd_system.h" +#include "sdkconfig.h" + +static const char *TAG = "cmd_system_sleep"; + +static void register_deep_sleep(void); +static void register_light_sleep(void); + +void register_system_sleep(void) +{ + register_deep_sleep(); + register_light_sleep(); +} + + +/** 'deep_sleep' command puts the chip into deep sleep mode */ + +static struct { + struct arg_int *wakeup_time; +#if SOC_PM_SUPPORT_EXT0_WAKEUP || SOC_PM_SUPPORT_EXT1_WAKEUP + struct arg_int *wakeup_gpio_num; + struct arg_int *wakeup_gpio_level; +#endif + struct arg_end *end; +} deep_sleep_args; + + +static int deep_sleep(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &deep_sleep_args); + if (nerrors != 0) { + arg_print_errors(stderr, deep_sleep_args.end, argv[0]); + return 1; + } + if (deep_sleep_args.wakeup_time->count) { + uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0]; + ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout); + ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) ); + } + +#if SOC_PM_SUPPORT_EXT1_WAKEUP + if (deep_sleep_args.wakeup_gpio_num->count) { + int io_num = deep_sleep_args.wakeup_gpio_num->ival[0]; + if (!esp_sleep_is_valid_wakeup_gpio(io_num)) { + ESP_LOGE(TAG, "GPIO %d is not an RTC IO", io_num); + return 1; + } + int level = 0; + if (deep_sleep_args.wakeup_gpio_level->count) { + level = deep_sleep_args.wakeup_gpio_level->ival[0]; + if (level != 0 && level != 1) { + ESP_LOGE(TAG, "Invalid wakeup level: %d", level); + return 1; + } + } + ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level", + io_num, level ? "HIGH" : "LOW"); + + ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) ); + ESP_LOGE(TAG, "GPIO wakeup from deep sleep currently unsupported on ESP32-C3"); + } +#endif // SOC_PM_SUPPORT_EXT1_WAKEUP + +#if CONFIG_IDF_TARGET_ESP32 + rtc_gpio_isolate(GPIO_NUM_12); +#endif //CONFIG_IDF_TARGET_ESP32 + + esp_deep_sleep_start(); + return 1; +} + +static void register_deep_sleep(void) +{ + int num_args = 1; + deep_sleep_args.wakeup_time = + arg_int0("t", "time", "", "Wake up time, ms"); +#if SOC_PM_SUPPORT_EXT0_WAKEUP || SOC_PM_SUPPORT_EXT1_WAKEUP + deep_sleep_args.wakeup_gpio_num = + arg_int0(NULL, "io", "", + "If specified, wakeup using GPIO with given number"); + deep_sleep_args.wakeup_gpio_level = + arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup"); + num_args += 2; +#endif + deep_sleep_args.end = arg_end(num_args); + + const esp_console_cmd_t cmd = { + .command = "deep_sleep", + .help = "Enter deep sleep mode. " +#if SOC_PM_SUPPORT_EXT0_WAKEUP || SOC_PM_SUPPORT_EXT1_WAKEUP + "Two wakeup modes are supported: timer and GPIO. " +#else + "Timer wakeup mode is supported. " +#endif + "If no wakeup option is specified, will sleep indefinitely.", + .hint = NULL, + .func = &deep_sleep, + .argtable = &deep_sleep_args + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'light_sleep' command puts the chip into light sleep mode */ + +static struct { + struct arg_int *wakeup_time; + struct arg_int *wakeup_gpio_num; + struct arg_int *wakeup_gpio_level; + struct arg_end *end; +} light_sleep_args; + +static int light_sleep(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &light_sleep_args); + if (nerrors != 0) { + arg_print_errors(stderr, light_sleep_args.end, argv[0]); + return 1; + } + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); + if (light_sleep_args.wakeup_time->count) { + uint64_t timeout = 1000ULL * light_sleep_args.wakeup_time->ival[0]; + ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout); + ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) ); + } + int io_count = light_sleep_args.wakeup_gpio_num->count; + if (io_count != light_sleep_args.wakeup_gpio_level->count) { + ESP_LOGE(TAG, "Should have same number of 'io' and 'io_level' arguments"); + return 1; + } + for (int i = 0; i < io_count; ++i) { + int io_num = light_sleep_args.wakeup_gpio_num->ival[i]; + int level = light_sleep_args.wakeup_gpio_level->ival[i]; + if (level != 0 && level != 1) { + ESP_LOGE(TAG, "Invalid wakeup level: %d", level); + return 1; + } + ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level", + io_num, level ? "HIGH" : "LOW"); + + ESP_ERROR_CHECK( gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL) ); + } + if (io_count > 0) { + ESP_ERROR_CHECK( esp_sleep_enable_gpio_wakeup() ); + } + if (CONFIG_ESP_CONSOLE_UART_NUM >= 0 && CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) { + ESP_LOGI(TAG, "Enabling UART wakeup (press ENTER to exit light sleep)"); + ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_ESP_CONSOLE_UART_NUM, 3) ); + ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) ); + } + fflush(stdout); + fsync(fileno(stdout)); + esp_light_sleep_start(); + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + const char *cause_str; + switch (cause) { + case ESP_SLEEP_WAKEUP_GPIO: + cause_str = "GPIO"; + break; + case ESP_SLEEP_WAKEUP_UART: + cause_str = "UART"; + break; + case ESP_SLEEP_WAKEUP_TIMER: + cause_str = "timer"; + break; + default: + cause_str = "unknown"; + printf("%d\n", cause); + } + ESP_LOGI(TAG, "Woke up from: %s", cause_str); + return 0; +} + +static void register_light_sleep(void) +{ + light_sleep_args.wakeup_time = + arg_int0("t", "time", "", "Wake up time, ms"); + light_sleep_args.wakeup_gpio_num = + arg_intn(NULL, "io", "", 0, 8, + "If specified, wakeup using GPIO with given number"); + light_sleep_args.wakeup_gpio_level = + arg_intn(NULL, "io_level", "<0|1>", 0, 8, "GPIO level to trigger wakeup"); + light_sleep_args.end = arg_end(3); + + const esp_console_cmd_t cmd = { + .command = "light_sleep", + .help = "Enter light sleep mode. " + "Two wakeup modes are supported: timer and GPIO. " + "Multiple GPIO pins can be specified using pairs of " + "'io' and 'io_level' arguments. " + "Will also wake up on UART input.", + .hint = NULL, + .func = &light_sleep, + .argtable = &light_sleep_args + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} diff --git a/main/main.c b/main/main.c index 1585876..33f89ab 100644 --- a/main/main.c +++ b/main/main.c @@ -1,6 +1,123 @@ +#include "cmd_custom.h" +#include "cmd_system.h" +#include "driver/uart.h" +#include "esp_console.h" +#include "esp_log.h" +#include "esp_system.h" +#include "esp_vfs_dev.h" +#include "esp_vfs_fat.h" +#include "linenoise/linenoise.h" +#include "nvs.h" +#include "nvs_flash.h" #include -void app_main(void) -{ +#define PROMPT_STR CONFIG_IDF_TARGET +#define MOUNT_PATH "/data" +#define HISTORY_PATH MOUNT_PATH "/history.txt" + +static const char *TAG = "main"; + +static void initialize_nvs(); +static void initialize_filesystem(); +static void initialize_console(); + +void app_main() { + const char *prompt = LOG_COLOR_I PROMPT_STR "> " LOG_RESET_COLOR; + initialize_nvs(); + initialize_filesystem(); + initialize_console(); + esp_console_register_help_command(); + register_system_common(); + register_system_sleep(); + register_custom(); + while (true) { + char *line = linenoise(prompt); + if (line == NULL) { /* Break on EOF or error */ + // break; + continue; + } + if (strlen(line) > 0) { + linenoiseHistoryAdd(line); + linenoiseHistorySave(HISTORY_PATH); + } + + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + } else if (err == ESP_OK && ret != ESP_OK) { + printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret)); + } else if (err != ESP_OK) { + printf("Internal error: %s\n", esp_err_to_name(err)); + } + /* linenoise allocates line buffer on the heap, so need to free it */ + linenoiseFree(line); + } + esp_console_deinit(); +} + +static void initialize_console() { + fflush(stdout); + fsync(fileno(stdout)); + + setvbuf(stdin, NULL, _IONBF, 0); + + esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); + esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); + + const uart_config_t uart_config = { + .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .source_clk = UART_SCLK_REF_TICK, + }; + + ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); + + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); + + esp_console_config_t console_config = { + .max_cmdline_args = 8, + .max_cmdline_length = 256, + .hint_color = atoi(LOG_COLOR_CYAN), + }; + ESP_ERROR_CHECK(esp_console_init(&console_config)); + + linenoiseSetMultiLine(1); + + linenoiseSetCompletionCallback(&esp_console_get_completion); + linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint); + + linenoiseHistorySetMaxLen(100); + linenoiseSetMaxLineLen(console_config.max_cmdline_length); + + linenoiseAllowEmpty(false); + linenoiseHistoryLoad(HISTORY_PATH); +} + +static void initialize_nvs() { + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); +} + +static void initialize_filesystem(void) { + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true, + }; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } } diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..cc5ccab --- /dev/null +++ b/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, fat, , 1M, diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..35982bd --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,20 @@ +# Reduce bootloader log verbosity +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_BOOTLOADER_LOG_LEVEL=2 + +# Increase main task stack size +CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 + +# Enable filesystem +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +# Enable FreeRTOS stats formatting functions, needed for 'tasks' command +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +# On chips with USB serial, disable secondary console which does not make sense when using console component +CONFIG_ESP_CONSOLE_SECONDARY_NONE=y