- 启动自检日志:远程日志启动后记录 endpoint、目录、待上传文件数、队列配置、coredump 状态。
- 上传状态统计:记录成功/失败次数、最后 HTTP 状态、最后错误码、最后上传时间、最后成功时间。
- 独立日志 Flash 分区:新增 logfs LittleFS 分区 512KB,日志不再占用音频资源分区;远程日志文件上限为 24 * 16KB =
384KB。
- 本地诊断 factory CLI:
- log status
- log flush
- log clear
- Coredump 支持:启用 flash coredump,新增 64KB coredump 分区;当前会上报 coredump 存在状态、地址、大小、panic
reason 和设备状态快照。
- 上传附带设备状态快照:reset reason、固件版本、project name、heap、任务数、多模态连接/活动状态、coredump 状态。
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
gifpack, data, littlefs, , 0x800000,
|
||||
gifpack, data, littlefs, , 0x780000,
|
||||
logfs, data, littlefs, , 0x80000,
|
||||
ota_0, app, ota_0, , 0x330000,
|
||||
ota_1, app, ota_1, , 0x330000,
|
||||
model, data, spiffs, , 0x180000,
|
||||
coredump, data, coredump,, 0x10000,
|
||||
|
||||
|
@@ -22,6 +22,8 @@ idf_component_register(
|
||||
"internal"
|
||||
PRIV_REQUIRES
|
||||
domain
|
||||
espcoredump
|
||||
esp_app_format
|
||||
esp_driver_gpio
|
||||
esp_timer
|
||||
esp_system
|
||||
|
||||
@@ -145,3 +145,6 @@ void control_plane_set_ptt_active(bool active);
|
||||
|
||||
esp_err_t control_plane_remote_log_start(void);
|
||||
void control_plane_remote_log_stop(int timeout_ms);
|
||||
esp_err_t control_plane_remote_log_flush_now(void);
|
||||
esp_err_t control_plane_remote_log_clear(void);
|
||||
esp_err_t control_plane_remote_log_format_status(char *out, size_t out_len);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "control_plane.h"
|
||||
#include "control_plane_internal.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
@@ -357,6 +358,41 @@ static void handle_prepare_rotate(uint32_t key_version)
|
||||
cli_write_ok();
|
||||
}
|
||||
|
||||
static void handle_log_command(size_t argc, char *argv[])
|
||||
{
|
||||
if (argc < 2 || is_text_empty(argv[1])) {
|
||||
cli_write_error("missing_log_command");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "status") == 0) {
|
||||
char json[FACTORY_CLI_JSON_MAX_LEN] = {0};
|
||||
esp_err_t err = control_plane_remote_log_format_status(json, sizeof(json));
|
||||
if (err != ESP_OK) {
|
||||
cli_write_error("log_status_failed");
|
||||
return;
|
||||
}
|
||||
cli_write_line(json);
|
||||
cli_write_ok();
|
||||
} else if (strcmp(argv[1], "flush") == 0) {
|
||||
esp_err_t err = control_plane_remote_log_flush_now();
|
||||
if (err != ESP_OK) {
|
||||
cli_write_error("log_flush_failed");
|
||||
return;
|
||||
}
|
||||
cli_write_ok();
|
||||
} else if (strcmp(argv[1], "clear") == 0) {
|
||||
esp_err_t err = control_plane_remote_log_clear();
|
||||
if (err != ESP_OK) {
|
||||
cli_write_error("log_clear_failed");
|
||||
return;
|
||||
}
|
||||
cli_write_ok();
|
||||
} else {
|
||||
cli_write_error("unknown_log_command");
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_command_line(char *line)
|
||||
{
|
||||
trim_text(line);
|
||||
@@ -429,6 +465,8 @@ static void handle_command_line(char *line)
|
||||
return;
|
||||
}
|
||||
handle_prepare_rotate(key_version);
|
||||
} else if (strcmp(cmd, "log") == 0) {
|
||||
handle_log_command(argc, argv);
|
||||
} else {
|
||||
cli_write_error("unknown_command");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "domain.h"
|
||||
#include "esp_app_desc.h"
|
||||
#include "esp_core_dump.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -76,7 +80,7 @@
|
||||
|
||||
#define REMOTE_LOG_TASK_STACK_SIZE (1024 * 8)
|
||||
#define REMOTE_LOG_TASK_PRIORITY 3
|
||||
#define REMOTE_LOG_DIR "/littlefs/remote_logs"
|
||||
#define REMOTE_LOG_DIR "/logfs/remote_logs"
|
||||
#define REMOTE_LOG_FILE_PREFIX "log_"
|
||||
#define REMOTE_LOG_FILE_SUFFIX ".jsonl"
|
||||
#define REMOTE_LOG_PATH_MAX 96
|
||||
@@ -104,6 +108,16 @@ static volatile bool s_stop_requested;
|
||||
static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static vprintf_like_t s_original_vprintf;
|
||||
static bool s_hook_installed;
|
||||
static uint32_t s_successful_uploads;
|
||||
static uint32_t s_failed_uploads;
|
||||
static int s_last_http_status = -1;
|
||||
static esp_err_t s_last_upload_err = ESP_ERR_NOT_FOUND;
|
||||
static int64_t s_last_upload_ms;
|
||||
static int64_t s_last_success_ms;
|
||||
static bool s_coredump_present;
|
||||
static bool s_coredump_reported;
|
||||
static size_t s_coredump_addr;
|
||||
static size_t s_coredump_size;
|
||||
|
||||
static bool remote_log_path_active(void)
|
||||
{
|
||||
@@ -230,6 +244,15 @@ static bool dequeue_entry(remote_log_entry_t *out_entry)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static size_t snapshot_queue_count(void)
|
||||
{
|
||||
size_t count = 0U;
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
count = s_queue_count;
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint32_t snapshot_and_clear_dropped_count(void)
|
||||
{
|
||||
uint32_t dropped = 0;
|
||||
@@ -451,6 +474,12 @@ static size_t collect_files(uint32_t *out_sequences, size_t capacity)
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t count_pending_files(void)
|
||||
{
|
||||
uint32_t sequences[CONFIG_TQ_REMOTE_LOG_MAX_FILES + 8] = {0};
|
||||
return collect_files(sequences, sizeof(sequences) / sizeof(sequences[0]));
|
||||
}
|
||||
|
||||
static void trim_old_files(void)
|
||||
{
|
||||
uint32_t sequences[CONFIG_TQ_REMOTE_LOG_MAX_FILES + 8] = {0};
|
||||
@@ -541,6 +570,102 @@ static bool realtime_path_busy(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *reset_reason_name(esp_reset_reason_t reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case ESP_RST_POWERON:
|
||||
return "poweron";
|
||||
case ESP_RST_EXT:
|
||||
return "external";
|
||||
case ESP_RST_SW:
|
||||
return "software";
|
||||
case ESP_RST_PANIC:
|
||||
return "panic";
|
||||
case ESP_RST_INT_WDT:
|
||||
return "interrupt_wdt";
|
||||
case ESP_RST_TASK_WDT:
|
||||
return "task_wdt";
|
||||
case ESP_RST_WDT:
|
||||
return "other_wdt";
|
||||
case ESP_RST_DEEPSLEEP:
|
||||
return "deepsleep";
|
||||
case ESP_RST_BROWNOUT:
|
||||
return "brownout";
|
||||
case ESP_RST_SDIO:
|
||||
return "sdio";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t append_device_state(char *body, size_t body_len, size_t *offset)
|
||||
{
|
||||
if (body == NULL || offset == NULL || *offset >= body_len) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const esp_app_desc_t *app = esp_app_get_description();
|
||||
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||
control_plane_multimodal_runtime_state_t mm = {0};
|
||||
bool have_mm = (control_plane_multimodal_get_runtime_state(&mm) == ESP_OK);
|
||||
|
||||
int written = snprintf(body + *offset,
|
||||
body_len - *offset,
|
||||
",\"device_state\":{"
|
||||
"\"reset_reason\":\"%s\","
|
||||
"\"reset_reason_code\":%d,"
|
||||
"\"firmware_version\":\"",
|
||||
reset_reason_name(reset_reason),
|
||||
(int)reset_reason);
|
||||
if (written < 0 || (size_t)written >= body_len - *offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
*offset += (size_t)written;
|
||||
json_append_escaped(body, body_len, offset, app != NULL ? app->version : "");
|
||||
written = snprintf(body + *offset,
|
||||
body_len - *offset,
|
||||
"\",\"project_name\":\"");
|
||||
if (written < 0 || (size_t)written >= body_len - *offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
*offset += (size_t)written;
|
||||
json_append_escaped(body, body_len, offset, app != NULL ? app->project_name : "");
|
||||
written = snprintf(body + *offset,
|
||||
body_len - *offset,
|
||||
"\",\"free_heap\":%lu,"
|
||||
"\"minimum_free_heap\":%lu,"
|
||||
"\"free_internal\":%lu,"
|
||||
"\"largest_internal\":%lu,"
|
||||
"\"free_spiram\":%lu,"
|
||||
"\"largest_spiram\":%lu,"
|
||||
"\"task_count\":%lu,"
|
||||
"\"multimodal_connected\":%s,"
|
||||
"\"multimodal_active_task\":%s,"
|
||||
"\"multimodal_client_speech_active\":%s,"
|
||||
"\"multimodal_remote_responding\":%s,"
|
||||
"\"coredump_present\":%s,"
|
||||
"\"coredump_size\":%lu"
|
||||
"}",
|
||||
(unsigned long)esp_get_free_heap_size(),
|
||||
(unsigned long)esp_get_minimum_free_heap_size(),
|
||||
(unsigned long)heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT),
|
||||
(unsigned long)heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT),
|
||||
(unsigned long)heap_caps_get_free_size(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT),
|
||||
(unsigned long)heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT),
|
||||
(unsigned long)uxTaskGetNumberOfTasks(),
|
||||
(have_mm && mm.connected) ? "true" : "false",
|
||||
(have_mm && mm.has_active_task) ? "true" : "false",
|
||||
(have_mm && mm.client_speech_active) ? "true" : "false",
|
||||
(have_mm && mm.remote_responding) ? "true" : "false",
|
||||
s_coredump_present ? "true" : "false",
|
||||
(unsigned long)s_coredump_size);
|
||||
if (written < 0 || (size_t)written >= body_len - *offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
*offset += (size_t)written;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t build_upload_body(uint32_t sequence,
|
||||
uint32_t dropped_count,
|
||||
char *body,
|
||||
@@ -616,7 +741,16 @@ static esp_err_t build_upload_body(uint32_t sequence,
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
written = snprintf(body + offset, body_len - offset, "]}");
|
||||
written = snprintf(body + offset, body_len - offset, "]");
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
offset += (size_t)written;
|
||||
esp_err_t state_err = append_device_state(body, body_len, &offset);
|
||||
if (state_err != ESP_OK) {
|
||||
return state_err;
|
||||
}
|
||||
written = snprintf(body + offset, body_len - offset, "}");
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
@@ -669,11 +803,16 @@ static bool upload_one_file(uint32_t sequence)
|
||||
|
||||
free(body);
|
||||
free(response);
|
||||
s_last_upload_ms = esp_timer_get_time() / 1000;
|
||||
s_last_upload_err = err;
|
||||
s_last_http_status = status;
|
||||
|
||||
if (err == ESP_OK && (status == 200 || status == 202 || status == 204)) {
|
||||
char path[REMOTE_LOG_PATH_MAX] = {0};
|
||||
make_log_path(sequence, path, sizeof(path));
|
||||
(void)unlink(path);
|
||||
s_successful_uploads++;
|
||||
s_last_success_ms = s_last_upload_ms;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -682,10 +821,12 @@ static bool upload_one_file(uint32_t sequence)
|
||||
make_log_path(sequence, path, sizeof(path));
|
||||
(void)unlink(path);
|
||||
restore_dropped_count(dropped);
|
||||
s_failed_uploads++;
|
||||
return true;
|
||||
}
|
||||
|
||||
restore_dropped_count(dropped);
|
||||
s_failed_uploads++;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -703,6 +844,144 @@ static bool upload_pending_files(void)
|
||||
return upload_one_file(sequences[0]);
|
||||
}
|
||||
|
||||
static void detect_coredump(void)
|
||||
{
|
||||
size_t addr = 0U;
|
||||
size_t size = 0U;
|
||||
esp_err_t err = esp_core_dump_image_get(&addr, &size);
|
||||
if (err == ESP_OK && size > 0U) {
|
||||
s_coredump_present = true;
|
||||
s_coredump_addr = addr;
|
||||
s_coredump_size = size;
|
||||
} else {
|
||||
s_coredump_present = false;
|
||||
s_coredump_addr = 0U;
|
||||
s_coredump_size = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t build_coredump_report_body(char *body, size_t body_len)
|
||||
{
|
||||
if (body == NULL || body_len == 0U) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
char device_id[64] = {0};
|
||||
char serial_number[64] = {0};
|
||||
domain_runtime_read_device_identity(device_id, sizeof(device_id), serial_number, sizeof(serial_number));
|
||||
|
||||
char panic_reason[192] = {0};
|
||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
|
||||
(void)esp_core_dump_get_panic_reason(panic_reason, sizeof(panic_reason));
|
||||
#endif
|
||||
|
||||
size_t offset = 0U;
|
||||
int written = snprintf(body,
|
||||
body_len,
|
||||
"{\"schema\":\"tq.coredump.report.v1\",\"device_id\":\"");
|
||||
if (written < 0 || (size_t)written >= body_len) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
offset = (size_t)written;
|
||||
json_append_escaped(body, body_len, &offset, device_id);
|
||||
written = snprintf(body + offset, body_len - offset, "\",\"serial_number\":\"");
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
offset += (size_t)written;
|
||||
json_append_escaped(body, body_len, &offset, serial_number);
|
||||
written = snprintf(body + offset,
|
||||
body_len - offset,
|
||||
"\",\"sent_at_ms\":%lld,\"coredump_addr\":%lu,\"coredump_size\":%lu,\"panic_reason\":\"",
|
||||
(long long)(esp_timer_get_time() / 1000),
|
||||
(unsigned long)s_coredump_addr,
|
||||
(unsigned long)s_coredump_size);
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
offset += (size_t)written;
|
||||
json_append_escaped(body, body_len, &offset, panic_reason);
|
||||
written = snprintf(body + offset, body_len - offset, "\"");
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
offset += (size_t)written;
|
||||
esp_err_t state_err = append_device_state(body, body_len, &offset);
|
||||
if (state_err != ESP_OK) {
|
||||
return state_err;
|
||||
}
|
||||
written = snprintf(body + offset, body_len - offset, "}");
|
||||
if (written < 0 || (size_t)written >= body_len - offset) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool upload_coredump_report(void)
|
||||
{
|
||||
if (!s_coredump_present || s_coredump_reported ||
|
||||
!control_plane_is_sta_connected() || realtime_path_busy()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *body = (char *)malloc(2048);
|
||||
char *response = (char *)malloc(REMOTE_LOG_RESPONSE_MAX);
|
||||
if (body == NULL || response == NULL) {
|
||||
free(body);
|
||||
free(response);
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t err = build_coredump_report_body(body, 2048);
|
||||
if (err != ESP_OK) {
|
||||
free(body);
|
||||
free(response);
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = -1;
|
||||
size_t response_len = 0U;
|
||||
err = domain_runtime_post_json(CONFIG_TQ_REMOTE_LOG_ENDPOINT,
|
||||
body,
|
||||
NULL,
|
||||
CONFIG_TQ_REMOTE_LOG_AUTH_TOKEN,
|
||||
CONFIG_TQ_REMOTE_LOG_UPLOAD_TIMEOUT_MS,
|
||||
0,
|
||||
0,
|
||||
response,
|
||||
REMOTE_LOG_RESPONSE_MAX,
|
||||
&response_len,
|
||||
&status);
|
||||
free(body);
|
||||
free(response);
|
||||
|
||||
s_last_upload_ms = esp_timer_get_time() / 1000;
|
||||
s_last_upload_err = err;
|
||||
s_last_http_status = status;
|
||||
if (err == ESP_OK && (status == 200 || status == 202 || status == 204)) {
|
||||
s_successful_uploads++;
|
||||
s_last_success_ms = s_last_upload_ms;
|
||||
s_coredump_reported = true;
|
||||
return true;
|
||||
}
|
||||
s_failed_uploads++;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void log_startup_self_check(void)
|
||||
{
|
||||
ESP_LOGW("remote_log",
|
||||
"enabled endpoint=%s dir=%s pending_files=%u queue=%u max_files=%u file_max=%u coredump_present=%d coredump_size=%u",
|
||||
CONFIG_TQ_REMOTE_LOG_ENDPOINT,
|
||||
REMOTE_LOG_DIR,
|
||||
(unsigned)count_pending_files(),
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_QUEUE_LEN,
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_MAX_FILES,
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES,
|
||||
s_coredump_present,
|
||||
(unsigned)s_coredump_size);
|
||||
}
|
||||
|
||||
static void install_hook(void)
|
||||
{
|
||||
if (s_hook_installed) {
|
||||
@@ -726,7 +1005,7 @@ static void remote_log_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
esp_err_t mount_err = domain_runtime_mount_littlefs();
|
||||
esp_err_t mount_err = domain_runtime_mount_logfs();
|
||||
if (mount_err != ESP_OK) {
|
||||
s_remote_log_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
@@ -734,8 +1013,10 @@ static void remote_log_task(void *arg)
|
||||
}
|
||||
(void)make_log_dir();
|
||||
s_file_sequence = find_next_file_sequence();
|
||||
detect_coredump();
|
||||
|
||||
install_hook();
|
||||
log_startup_self_check();
|
||||
|
||||
TickType_t last_flush = xTaskGetTickCount();
|
||||
uint32_t backoff_ms = 0U;
|
||||
@@ -750,6 +1031,7 @@ static void remote_log_task(void *arg)
|
||||
|
||||
if (backoff_ms == 0U || now >= next_upload_tick) {
|
||||
drain_memory_queue_to_flash();
|
||||
(void)upload_coredump_report();
|
||||
bool ok = upload_pending_files();
|
||||
if (ok) {
|
||||
backoff_ms = 0U;
|
||||
@@ -792,6 +1074,81 @@ esp_err_t control_plane_remote_log_start(void)
|
||||
return created == pdPASS ? ESP_OK : ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_flush_now(void)
|
||||
{
|
||||
if (s_remote_log_task == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
drain_memory_queue_to_flash();
|
||||
if (!control_plane_is_sta_connected()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
(void)upload_coredump_report();
|
||||
return upload_pending_files() ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_clear(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
s_queue_read = 0U;
|
||||
s_queue_count = 0U;
|
||||
s_dropped_count = 0U;
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
|
||||
uint32_t sequences[CONFIG_TQ_REMOTE_LOG_MAX_FILES + 8] = {0};
|
||||
size_t count = collect_files(sequences, sizeof(sequences) / sizeof(sequences[0]));
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
char path[REMOTE_LOG_PATH_MAX] = {0};
|
||||
make_log_path(sequences[i], path, sizeof(path));
|
||||
(void)unlink(path);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_format_status(char *out, size_t out_len)
|
||||
{
|
||||
if (out == NULL || out_len == 0U) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t dropped = 0U;
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
dropped = s_dropped_count;
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
|
||||
int written = snprintf(out,
|
||||
out_len,
|
||||
"{\"enabled\":true,\"running\":%s,\"hook_installed\":%s,"
|
||||
"\"endpoint\":\"%s\",\"dir\":\"%s\",\"queue_count\":%u,"
|
||||
"\"queue_capacity\":%u,\"pending_files\":%u,"
|
||||
"\"max_files\":%u,\"file_max_bytes\":%u,"
|
||||
"\"dropped_count\":%lu,\"successful_uploads\":%lu,"
|
||||
"\"failed_uploads\":%lu,\"last_http_status\":%d,"
|
||||
"\"last_upload_err\":%d,\"last_upload_ms\":%lld,"
|
||||
"\"last_success_ms\":%lld,\"coredump_present\":%s,"
|
||||
"\"coredump_reported\":%s,\"coredump_size\":%lu}",
|
||||
s_remote_log_task != NULL ? "true" : "false",
|
||||
s_hook_installed ? "true" : "false",
|
||||
CONFIG_TQ_REMOTE_LOG_ENDPOINT,
|
||||
REMOTE_LOG_DIR,
|
||||
(unsigned)snapshot_queue_count(),
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_QUEUE_LEN,
|
||||
(unsigned)count_pending_files(),
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_MAX_FILES,
|
||||
(unsigned)CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES,
|
||||
(unsigned long)dropped,
|
||||
(unsigned long)s_successful_uploads,
|
||||
(unsigned long)s_failed_uploads,
|
||||
s_last_http_status,
|
||||
(int)s_last_upload_err,
|
||||
(long long)s_last_upload_ms,
|
||||
(long long)s_last_success_ms,
|
||||
s_coredump_present ? "true" : "false",
|
||||
s_coredump_reported ? "true" : "false",
|
||||
(unsigned long)s_coredump_size);
|
||||
return (written > 0 && (size_t)written < out_len) ? ESP_OK : ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
void control_plane_remote_log_stop(int timeout_ms)
|
||||
{
|
||||
if (s_remote_log_task == NULL) {
|
||||
@@ -821,4 +1178,23 @@ void control_plane_remote_log_stop(int timeout_ms)
|
||||
{
|
||||
(void)timeout_ms;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_flush_now(void)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_clear(void)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t control_plane_remote_log_format_status(char *out, size_t out_len)
|
||||
{
|
||||
if (out == NULL || out_len == 0U) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int written = snprintf(out, out_len, "{\"enabled\":false}");
|
||||
return (written > 0 && (size_t)written < out_len) ? ESP_OK : ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -188,6 +188,7 @@ bool domain_runtime_slot_feature_switch_is_active(void);
|
||||
|
||||
esp_err_t domain_runtime_prepare_storage(void);
|
||||
esp_err_t domain_runtime_mount_littlefs(void);
|
||||
esp_err_t domain_runtime_mount_logfs(void);
|
||||
void domain_runtime_read_device_identity(char *device_id,
|
||||
size_t device_id_len,
|
||||
char *serial_number,
|
||||
|
||||
@@ -758,6 +758,11 @@ esp_err_t domain_runtime_mount_littlefs(void)
|
||||
return platform_mount_littlefs();
|
||||
}
|
||||
|
||||
esp_err_t domain_runtime_mount_logfs(void)
|
||||
{
|
||||
return platform_mount_logfs();
|
||||
}
|
||||
|
||||
void domain_runtime_read_device_identity(char *device_id,
|
||||
size_t device_id_len,
|
||||
char *serial_number,
|
||||
|
||||
@@ -133,6 +133,7 @@ typedef struct {
|
||||
esp_err_t platform_init(void);
|
||||
esp_err_t platform_prepare_storage(void);
|
||||
esp_err_t platform_mount_littlefs(void);
|
||||
esp_err_t platform_mount_logfs(void);
|
||||
void platform_read_device_identity(char *device_id,
|
||||
size_t device_id_len,
|
||||
char *serial_number,
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#define VOICE_PROMPT_DEFAULT_BASE_PATH "/littlefs/audio_prompts"
|
||||
#define VOICE_PROMPT_LITTLEFS_BASE_PATH "/littlefs"
|
||||
#define VOICE_PROMPT_LITTLEFS_PARTITION "gifpack"
|
||||
#define PLATFORM_LOGFS_BASE_PATH "/logfs"
|
||||
#define PLATFORM_LOGFS_PARTITION "logfs"
|
||||
#define VOICE_PROMPT_FRAME_HEADER_BYTES 4U
|
||||
#define VOICE_PROMPT_MAX_OPUS_PACKET_BYTES 2048U
|
||||
#define VOICE_PROMPT_OPUS_FRAME_MS 60U
|
||||
@@ -43,6 +45,8 @@ static const char *VOICE_TAG = "voice_prompt";
|
||||
static bool s_power_hold_configured;
|
||||
static bool s_voice_prompt_littlefs_mount_attempted;
|
||||
static esp_err_t s_voice_prompt_littlefs_mount_result = ESP_ERR_INVALID_STATE;
|
||||
static bool s_logfs_mount_attempted;
|
||||
static esp_err_t s_logfs_mount_result = ESP_ERR_INVALID_STATE;
|
||||
|
||||
static uint64_t power_manager_gpio_bit_mask(int gpio_num)
|
||||
{
|
||||
@@ -154,6 +158,49 @@ esp_err_t platform_mount_littlefs(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t platform_mount_logfs(void)
|
||||
{
|
||||
if (s_logfs_mount_attempted) {
|
||||
return s_logfs_mount_result;
|
||||
}
|
||||
|
||||
esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = PLATFORM_LOGFS_BASE_PATH,
|
||||
.partition_label = PLATFORM_LOGFS_PARTITION,
|
||||
.partition = NULL,
|
||||
.format_if_mount_failed = true,
|
||||
.dont_mount = false,
|
||||
};
|
||||
|
||||
esp_err_t err = esp_vfs_littlefs_register(&conf);
|
||||
if (err == ESP_ERR_INVALID_STATE &&
|
||||
esp_littlefs_mounted(PLATFORM_LOGFS_PARTITION)) {
|
||||
err = ESP_OK;
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
size_t total_bytes = 0;
|
||||
size_t used_bytes = 0;
|
||||
esp_err_t info_err = esp_littlefs_info(PLATFORM_LOGFS_PARTITION,
|
||||
&total_bytes,
|
||||
&used_bytes);
|
||||
if (info_err == ESP_OK) {
|
||||
ESP_LOGI(VOICE_TAG,
|
||||
"LogFS mounted at %s, used=%u total=%u",
|
||||
PLATFORM_LOGFS_BASE_PATH,
|
||||
(unsigned)used_bytes,
|
||||
(unsigned)total_bytes);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(VOICE_TAG,
|
||||
"Mount LogFS failed: %s",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
|
||||
s_logfs_mount_attempted = true;
|
||||
s_logfs_mount_result = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t voice_prompt_play_file(const char *path)
|
||||
{
|
||||
if (path == NULL || path[0] == '\0') {
|
||||
|
||||
+13
-1
@@ -34,8 +34,20 @@ CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES=256
|
||||
CONFIG_TQ_REMOTE_LOG_BATCH_MAX_ENTRIES=30
|
||||
CONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS=5000
|
||||
CONFIG_TQ_REMOTE_LOG_UPLOAD_TIMEOUT_MS=8000
|
||||
CONFIG_TQ_REMOTE_LOG_MAX_FILES=32
|
||||
CONFIG_TQ_REMOTE_LOG_MAX_FILES=24
|
||||
CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES=16384
|
||||
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
|
||||
# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
|
||||
# CONFIG_ESP_COREDUMP_ENABLE_TO_NONE is not set
|
||||
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
|
||||
# CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN is not set
|
||||
CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y
|
||||
# CONFIG_ESP_COREDUMP_CHECKSUM_SHA256 is not set
|
||||
# CONFIG_ESP_COREDUMP_CAPTURE_DRAM is not set
|
||||
CONFIG_ESP_COREDUMP_CHECK_BOOT=y
|
||||
# CONFIG_ESP_COREDUMP_LOGS is not set
|
||||
CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=16
|
||||
CONFIG_ESP_COREDUMP_STACK_SIZE=1792
|
||||
CONFIG_TQ_KEY_INPUT_ENABLE=y
|
||||
CONFIG_TQ_KEY_INPUT_TASK_STACK=4096
|
||||
CONFIG_TQ_KEY_IRQ_QUEUE_LEN=16
|
||||
|
||||
Reference in New Issue
Block a user