远程日志系统基本运行成功

This commit is contained in:
CSBOOK\44744
2026-06-27 22:12:28 +08:00
parent caa4a7eded
commit 87ba891a8d
12 changed files with 1058 additions and 7 deletions
@@ -0,0 +1,824 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "control_plane_internal.h"
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "domain.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#ifndef CONFIG_TQ_REMOTE_LOG_ENABLE
#define CONFIG_TQ_REMOTE_LOG_ENABLE 0
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_ENDPOINT
#define CONFIG_TQ_REMOTE_LOG_ENDPOINT ""
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_AUTH_TOKEN
#define CONFIG_TQ_REMOTE_LOG_AUTH_TOKEN ""
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_MIN_LEVEL
#define CONFIG_TQ_REMOTE_LOG_MIN_LEVEL 2
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_PRESERVE_LOCAL_OUTPUT
#define CONFIG_TQ_REMOTE_LOG_PRESERVE_LOCAL_OUTPUT 1
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_QUEUE_LEN
#define CONFIG_TQ_REMOTE_LOG_QUEUE_LEN 128
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES
#define CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES 256
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_BATCH_MAX_ENTRIES
#define CONFIG_TQ_REMOTE_LOG_BATCH_MAX_ENTRIES 30
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS
#define CONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS 5000
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_UPLOAD_TIMEOUT_MS
#define CONFIG_TQ_REMOTE_LOG_UPLOAD_TIMEOUT_MS 8000
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_MAX_FILES
#define CONFIG_TQ_REMOTE_LOG_MAX_FILES 32
#endif
#ifndef CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES
#define CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES 16384
#endif
#ifndef CONFIG_TQ_NETWORK_TASK_CORE
#define CONFIG_TQ_NETWORK_TASK_CORE 0
#endif
#define REMOTE_LOG_TASK_STACK_SIZE (1024 * 8)
#define REMOTE_LOG_TASK_PRIORITY 3
#define REMOTE_LOG_DIR "/littlefs/remote_logs"
#define REMOTE_LOG_FILE_PREFIX "log_"
#define REMOTE_LOG_FILE_SUFFIX ".jsonl"
#define REMOTE_LOG_PATH_MAX 96
#define REMOTE_LOG_RESPONSE_MAX 256
#define REMOTE_LOG_UPLOAD_BODY_MAX (CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES + 4096)
#define REMOTE_LOG_BACKOFF_MAX_MS 300000
#define REMOTE_LOG_POLL_MS 200
#if CONFIG_TQ_REMOTE_LOG_ENABLE
typedef struct {
int64_t ts_ms;
char level;
bool truncated;
char text[CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES];
} remote_log_entry_t;
static remote_log_entry_t s_queue[CONFIG_TQ_REMOTE_LOG_QUEUE_LEN];
static size_t s_queue_read;
static size_t s_queue_count;
static uint32_t s_dropped_count;
static uint32_t s_file_sequence;
static TaskHandle_t s_remote_log_task;
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 bool remote_log_path_active(void)
{
return xTaskGetCurrentTaskHandle() == s_remote_log_task;
}
static char log_level_from_line(const char *line)
{
if (line == NULL || line[0] == '\0') {
return 'I';
}
if ((line[0] == 'E' || line[0] == 'W' || line[0] == 'I' ||
line[0] == 'D' || line[0] == 'V') &&
line[1] == ' ') {
return line[0];
}
return 'I';
}
static int log_level_rank(char level)
{
switch (level) {
case 'E':
return 1;
case 'W':
return 2;
case 'I':
return 3;
case 'D':
case 'V':
return 4;
default:
return 3;
}
}
static bool should_capture_level(char level)
{
int min_level = CONFIG_TQ_REMOTE_LOG_MIN_LEVEL;
if (min_level <= 0) {
return false;
}
return log_level_rank(level) <= min_level;
}
static void enqueue_line(const char *line, bool truncated)
{
if (line == NULL || line[0] == '\0') {
return;
}
char level = log_level_from_line(line);
if (!should_capture_level(level)) {
return;
}
portENTER_CRITICAL(&s_lock);
size_t write_index = (s_queue_read + s_queue_count) % CONFIG_TQ_REMOTE_LOG_QUEUE_LEN;
if (s_queue_count == CONFIG_TQ_REMOTE_LOG_QUEUE_LEN) {
s_queue_read = (s_queue_read + 1U) % CONFIG_TQ_REMOTE_LOG_QUEUE_LEN;
s_queue_count--;
s_dropped_count++;
}
remote_log_entry_t *entry = &s_queue[write_index];
entry->ts_ms = esp_timer_get_time() / 1000;
entry->level = level;
entry->truncated = truncated;
strlcpy(entry->text, line, sizeof(entry->text));
s_queue_count++;
portEXIT_CRITICAL(&s_lock);
}
static int remote_log_vprintf(const char *fmt, va_list args)
{
int ret = 0;
#if CONFIG_TQ_REMOTE_LOG_PRESERVE_LOCAL_OUTPUT
if (s_original_vprintf != NULL) {
va_list local_args;
va_copy(local_args, args);
ret = s_original_vprintf(fmt, local_args);
va_end(local_args);
}
#endif
if (remote_log_path_active()) {
return ret;
}
char line[CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES];
va_list copy_args;
va_copy(copy_args, args);
int written = vsnprintf(line, sizeof(line), fmt, copy_args);
va_end(copy_args);
if (written < 0) {
return ret;
}
bool truncated = written >= (int)sizeof(line);
size_t len = strlen(line);
while (len > 0U && (line[len - 1U] == '\n' || line[len - 1U] == '\r')) {
line[--len] = '\0';
}
enqueue_line(line, truncated);
return ret;
}
static bool dequeue_entry(remote_log_entry_t *out_entry)
{
if (out_entry == NULL) {
return false;
}
bool ok = false;
portENTER_CRITICAL(&s_lock);
if (s_queue_count > 0U) {
*out_entry = s_queue[s_queue_read];
s_queue_read = (s_queue_read + 1U) % CONFIG_TQ_REMOTE_LOG_QUEUE_LEN;
s_queue_count--;
ok = true;
}
portEXIT_CRITICAL(&s_lock);
return ok;
}
static uint32_t snapshot_and_clear_dropped_count(void)
{
uint32_t dropped = 0;
portENTER_CRITICAL(&s_lock);
dropped = s_dropped_count;
s_dropped_count = 0;
portEXIT_CRITICAL(&s_lock);
return dropped;
}
static void restore_dropped_count(uint32_t dropped)
{
if (dropped == 0U) {
return;
}
portENTER_CRITICAL(&s_lock);
s_dropped_count += dropped;
portEXIT_CRITICAL(&s_lock);
}
static void sanitize_value(char *text, const char *key)
{
if (text == NULL || key == NULL || key[0] == '\0') {
return;
}
size_t key_len = strlen(key);
char *cursor = text;
while ((cursor = strstr(cursor, key)) != NULL) {
char *value = cursor + key_len;
while (value[0] == ' ' || value[0] == ':' || value[0] == '=') {
value++;
}
if (value[0] == '\0') {
break;
}
char *end = value;
while (end[0] != '\0' && end[0] != ' ' && end[0] != ',' &&
end[0] != '&' && end[0] != '"' && end[0] != '\'') {
end++;
}
const char *replacement = "***REDACTED***";
size_t repl_len = strlen(replacement);
size_t tail_len = strlen(end);
if (repl_len <= (size_t)(end - value)) {
memcpy(value, replacement, repl_len);
memmove(value + repl_len, end, tail_len + 1U);
cursor = value + repl_len;
} else {
cursor = end;
}
}
}
static void sanitize_log_line(char *text)
{
sanitize_value(text, "password");
sanitize_value(text, "Password");
sanitize_value(text, "pwd");
sanitize_value(text, "token");
sanitize_value(text, "Token");
sanitize_value(text, "Bearer");
sanitize_value(text, "secret");
sanitize_value(text, "api_key");
}
static void json_append_escaped(char *out, size_t out_len, size_t *offset, const char *text)
{
if (out == NULL || out_len == 0U || offset == NULL || *offset >= out_len) {
return;
}
for (const char *p = text != NULL ? text : ""; p[0] != '\0' && *offset < out_len - 1U; ++p) {
unsigned char ch = (unsigned char)p[0];
const char *escape = NULL;
switch (ch) {
case '\\':
escape = "\\\\";
break;
case '"':
escape = "\\\"";
break;
case '\b':
escape = "\\b";
break;
case '\f':
escape = "\\f";
break;
case '\n':
escape = "\\n";
break;
case '\r':
escape = "\\r";
break;
case '\t':
escape = "\\t";
break;
default:
break;
}
if (escape != NULL) {
int written = snprintf(out + *offset, out_len - *offset, "%s", escape);
if (written < 0) {
return;
}
*offset += (size_t)written;
} else if (ch < 0x20U) {
int written = snprintf(out + *offset, out_len - *offset, "\\u%04x", ch);
if (written < 0) {
return;
}
*offset += (size_t)written;
} else {
out[(*offset)++] = (char)ch;
out[*offset] = '\0';
}
}
}
static bool make_log_dir(void)
{
struct stat st = {0};
if (stat(REMOTE_LOG_DIR, &st) == 0 && S_ISDIR(st.st_mode)) {
return true;
}
return mkdir(REMOTE_LOG_DIR, 0755) == 0 || errno == EEXIST;
}
static void make_log_path(uint32_t sequence, char *out, size_t out_len)
{
snprintf(out,
out_len,
"%s/%s%08lu%s",
REMOTE_LOG_DIR,
REMOTE_LOG_FILE_PREFIX,
(unsigned long)sequence,
REMOTE_LOG_FILE_SUFFIX);
}
static bool parse_log_filename(const char *name, uint32_t *out_sequence)
{
if (name == NULL || out_sequence == NULL) {
return false;
}
size_t prefix_len = strlen(REMOTE_LOG_FILE_PREFIX);
size_t suffix_len = strlen(REMOTE_LOG_FILE_SUFFIX);
size_t name_len = strlen(name);
if (name_len <= prefix_len + suffix_len ||
strncmp(name, REMOTE_LOG_FILE_PREFIX, prefix_len) != 0 ||
strcmp(name + name_len - suffix_len, REMOTE_LOG_FILE_SUFFIX) != 0) {
return false;
}
char number[12] = {0};
size_t number_len = name_len - prefix_len - suffix_len;
if (number_len >= sizeof(number)) {
return false;
}
memcpy(number, name + prefix_len, number_len);
char *end = NULL;
unsigned long value = strtoul(number, &end, 10);
if (end == NULL || end[0] != '\0') {
return false;
}
*out_sequence = (uint32_t)value;
return true;
}
static uint32_t find_next_file_sequence(void)
{
DIR *dir = opendir(REMOTE_LOG_DIR);
if (dir == NULL) {
return 1U;
}
uint32_t max_sequence = 0U;
struct dirent *entry = NULL;
while ((entry = readdir(dir)) != NULL) {
uint32_t sequence = 0U;
if (parse_log_filename(entry->d_name, &sequence) && sequence > max_sequence) {
max_sequence = sequence;
}
}
closedir(dir);
return max_sequence + 1U;
}
static size_t collect_files(uint32_t *out_sequences, size_t capacity)
{
if (out_sequences == NULL || capacity == 0U) {
return 0U;
}
DIR *dir = opendir(REMOTE_LOG_DIR);
if (dir == NULL) {
return 0U;
}
size_t count = 0U;
struct dirent *entry = NULL;
while ((entry = readdir(dir)) != NULL) {
uint32_t sequence = 0U;
if (parse_log_filename(entry->d_name, &sequence)) {
if (count < capacity) {
out_sequences[count++] = sequence;
}
}
}
closedir(dir);
for (size_t i = 0; i < count; ++i) {
for (size_t j = i + 1U; j < count; ++j) {
if (out_sequences[j] < out_sequences[i]) {
uint32_t tmp = out_sequences[i];
out_sequences[i] = out_sequences[j];
out_sequences[j] = tmp;
}
}
}
return count;
}
static void trim_old_files(void)
{
uint32_t sequences[CONFIG_TQ_REMOTE_LOG_MAX_FILES + 8] = {0};
size_t count = collect_files(sequences, sizeof(sequences) / sizeof(sequences[0]));
while (count > CONFIG_TQ_REMOTE_LOG_MAX_FILES) {
char path[REMOTE_LOG_PATH_MAX] = {0};
make_log_path(sequences[0], path, sizeof(path));
(void)unlink(path);
memmove(&sequences[0], &sequences[1], (count - 1U) * sizeof(sequences[0]));
count--;
}
}
static esp_err_t append_entry_to_file(const remote_log_entry_t *entry)
{
if (entry == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (!make_log_dir()) {
return ESP_FAIL;
}
char path[REMOTE_LOG_PATH_MAX] = {0};
make_log_path(s_file_sequence, path, sizeof(path));
struct stat st = {0};
if (stat(path, &st) == 0 && st.st_size >= CONFIG_TQ_REMOTE_LOG_FILE_MAX_BYTES) {
s_file_sequence++;
make_log_path(s_file_sequence, path, sizeof(path));
}
FILE *file = fopen(path, "a");
if (file == NULL) {
return ESP_FAIL;
}
char text[CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES];
strlcpy(text, entry->text, sizeof(text));
sanitize_log_line(text);
char escaped[CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES * 2];
escaped[0] = '\0';
size_t escaped_len = 0U;
json_append_escaped(escaped, sizeof(escaped), &escaped_len, text);
int written = fprintf(file,
"{\"ts_ms\":%lld,\"level\":\"%c\",\"truncated\":%s,\"message\":\"%s\"}\n",
(long long)entry->ts_ms,
entry->level,
entry->truncated ? "true" : "false",
escaped);
int flush_err = fflush(file);
int fsync_err = fsync(fileno(file));
int close_err = fclose(file);
if (written <= 0 || flush_err != 0 || fsync_err != 0 || close_err != 0) {
return ESP_FAIL;
}
trim_old_files();
return ESP_OK;
}
static void drain_memory_queue_to_flash(void)
{
remote_log_entry_t entry = {0};
while (dequeue_entry(&entry)) {
if (append_entry_to_file(&entry) != ESP_OK) {
portENTER_CRITICAL(&s_lock);
s_dropped_count++;
portEXIT_CRITICAL(&s_lock);
break;
}
}
}
static bool realtime_path_busy(void)
{
#if CONFIG_ENABLE_MULTIMODAL_INTERACTION
control_plane_multimodal_runtime_state_t state = {0};
if (control_plane_multimodal_get_runtime_state(&state) != ESP_OK) {
return false;
}
return state.client_speech_active ||
state.remote_responding ||
state.request_to_speak_pending ||
state.received_downstream_audio;
#else
return false;
#endif
}
static esp_err_t build_upload_body(uint32_t sequence,
uint32_t dropped_count,
char *body,
size_t body_len,
size_t *out_entry_count)
{
if (body == NULL || body_len == 0U || out_entry_count == NULL) {
return ESP_ERR_INVALID_ARG;
}
*out_entry_count = 0U;
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));
size_t offset = 0U;
int written = snprintf(body,
body_len,
"{\"schema\":\"tq.remote_log.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,
"\",\"batch_id\":\"%lu\",\"sent_at_ms\":%lld,\"dropped_count\":%lu,\"entries\":[",
(unsigned long)sequence,
(long long)(esp_timer_get_time() / 1000),
(unsigned long)dropped_count);
if (written < 0 || (size_t)written >= body_len - offset) {
return ESP_ERR_INVALID_SIZE;
}
offset += (size_t)written;
char path[REMOTE_LOG_PATH_MAX] = {0};
make_log_path(sequence, path, sizeof(path));
FILE *file = fopen(path, "r");
if (file == NULL) {
return ESP_ERR_NOT_FOUND;
}
char line[CONFIG_TQ_REMOTE_LOG_ENTRY_MAX_BYTES * 3];
bool first = true;
while (fgets(line, sizeof(line), file) != NULL) {
size_t line_len = strlen(line);
while (line_len > 0U && (line[line_len - 1U] == '\n' || line[line_len - 1U] == '\r')) {
line[--line_len] = '\0';
}
if (line_len == 0U) {
continue;
}
written = snprintf(body + offset,
body_len - offset,
"%s%s",
first ? "" : ",",
line);
if (written < 0 || (size_t)written >= body_len - offset) {
fclose(file);
return ESP_ERR_INVALID_SIZE;
}
offset += (size_t)written;
first = false;
(*out_entry_count)++;
}
fclose(file);
written = snprintf(body + offset, body_len - offset, "]}");
if (written < 0 || (size_t)written >= body_len - offset) {
return ESP_ERR_INVALID_SIZE;
}
return (*out_entry_count > 0U || dropped_count > 0U) ? ESP_OK : ESP_ERR_NOT_FOUND;
}
static bool upload_one_file(uint32_t sequence)
{
uint32_t dropped = snapshot_and_clear_dropped_count();
char *body = (char *)malloc(REMOTE_LOG_UPLOAD_BODY_MAX);
char *response = (char *)malloc(REMOTE_LOG_RESPONSE_MAX);
if (body == NULL || response == NULL) {
free(body);
free(response);
restore_dropped_count(dropped);
return false;
}
size_t entry_count = 0U;
esp_err_t err = build_upload_body(sequence,
dropped,
body,
REMOTE_LOG_UPLOAD_BODY_MAX,
&entry_count);
if (err != ESP_OK) {
free(body);
free(response);
restore_dropped_count(dropped);
if (err == ESP_ERR_NOT_FOUND) {
char path[REMOTE_LOG_PATH_MAX] = {0};
make_log_path(sequence, path, sizeof(path));
(void)unlink(path);
}
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);
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);
return true;
}
if (err == ESP_OK && status == 400) {
char path[REMOTE_LOG_PATH_MAX] = {0};
make_log_path(sequence, path, sizeof(path));
(void)unlink(path);
restore_dropped_count(dropped);
return true;
}
restore_dropped_count(dropped);
return false;
}
static bool upload_pending_files(void)
{
if (!control_plane_is_sta_connected() || realtime_path_busy()) {
return false;
}
uint32_t sequences[CONFIG_TQ_REMOTE_LOG_MAX_FILES] = {0};
size_t count = collect_files(sequences, CONFIG_TQ_REMOTE_LOG_MAX_FILES);
if (count == 0U) {
return true;
}
return upload_one_file(sequences[0]);
}
static void install_hook(void)
{
if (s_hook_installed) {
return;
}
s_original_vprintf = esp_log_set_vprintf(remote_log_vprintf);
s_hook_installed = true;
}
static void uninstall_hook(void)
{
if (!s_hook_installed) {
return;
}
(void)esp_log_set_vprintf(s_original_vprintf);
s_original_vprintf = NULL;
s_hook_installed = false;
}
static void remote_log_task(void *arg)
{
(void)arg;
esp_err_t mount_err = domain_runtime_mount_littlefs();
if (mount_err != ESP_OK) {
s_remote_log_task = NULL;
vTaskDelete(NULL);
return;
}
(void)make_log_dir();
s_file_sequence = find_next_file_sequence();
install_hook();
TickType_t last_flush = xTaskGetTickCount();
uint32_t backoff_ms = 0U;
TickType_t next_upload_tick = xTaskGetTickCount();
while (!s_stop_requested) {
TickType_t now = xTaskGetTickCount();
if ((now - last_flush) >= pdMS_TO_TICKS(CONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS)) {
drain_memory_queue_to_flash();
last_flush = now;
}
if (backoff_ms == 0U || now >= next_upload_tick) {
drain_memory_queue_to_flash();
bool ok = upload_pending_files();
if (ok) {
backoff_ms = 0U;
} else if (control_plane_is_sta_connected()) {
backoff_ms = backoff_ms == 0U ? 5000U : backoff_ms * 2U;
if (backoff_ms > REMOTE_LOG_BACKOFF_MAX_MS) {
backoff_ms = REMOTE_LOG_BACKOFF_MAX_MS;
}
next_upload_tick = xTaskGetTickCount() + pdMS_TO_TICKS(backoff_ms);
}
}
vTaskDelay(pdMS_TO_TICKS(REMOTE_LOG_POLL_MS));
}
drain_memory_queue_to_flash();
uninstall_hook();
s_remote_log_task = NULL;
vTaskDelete(NULL);
}
esp_err_t control_plane_remote_log_start(void)
{
if (CONFIG_TQ_REMOTE_LOG_ENDPOINT[0] == '\0') {
return ESP_ERR_INVALID_ARG;
}
if (s_remote_log_task != NULL) {
return ESP_OK;
}
s_stop_requested = false;
BaseType_t created = xTaskCreatePinnedToCore(remote_log_task,
"cp_remote_log",
REMOTE_LOG_TASK_STACK_SIZE,
NULL,
REMOTE_LOG_TASK_PRIORITY,
&s_remote_log_task,
CONFIG_TQ_NETWORK_TASK_CORE < 0 ? tskNO_AFFINITY :
(BaseType_t)CONFIG_TQ_NETWORK_TASK_CORE);
return created == pdPASS ? ESP_OK : ESP_ERR_NO_MEM;
}
void control_plane_remote_log_stop(int timeout_ms)
{
if (s_remote_log_task == NULL) {
return;
}
s_stop_requested = true;
TickType_t start = xTaskGetTickCount();
TickType_t timeout_ticks = pdMS_TO_TICKS(timeout_ms > 0 ? timeout_ms : 1);
while (s_remote_log_task != NULL &&
(xTaskGetTickCount() - start) < timeout_ticks) {
vTaskDelay(pdMS_TO_TICKS(20));
}
if (s_remote_log_task != NULL) {
uninstall_hook();
vTaskDelete(s_remote_log_task);
s_remote_log_task = NULL;
}
}
#else
esp_err_t control_plane_remote_log_start(void)
{
return ESP_ERR_NOT_SUPPORTED;
}
void control_plane_remote_log_stop(int timeout_ms)
{
(void)timeout_ms;
}
#endif
@@ -24,6 +24,7 @@
#define CONTROL_PLANE_LCD_RENDER_LOOP_TASK_STACK_SIZE (1024 * 12)
#define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 12)
#define CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE (1024 * 6)
#define CONTROL_PLANE_REMOTE_LOG_STOP_WAIT_MS 1500
#define CONTROL_PLANE_MODEL_CMD_QUEUE_LEN 4
#define CONTROL_PLANE_MODEL_CMD_RECV_TIMEOUT_MS 200
#define CONTROL_PLANE_TASK_STOP_WAIT_MS 1500
@@ -1812,6 +1813,11 @@ esp_err_t control_plane_start_runtime_workers(void)
return key_input_err;
}
esp_err_t remote_log_err = control_plane_remote_log_start();
if (remote_log_err != ESP_OK && remote_log_err != ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG, "Remote log start failed: %s", esp_err_to_name(remote_log_err));
}
#if CONFIG_FORTUNE_ENABLE
if (control_plane_get_task_handle(&s_daily_fortune_task) == NULL) {
control_plane_request_fortune_refresh();
@@ -1856,6 +1862,7 @@ void control_plane_stop_event_observer_runtime(void)
control_plane_set_runtime_stop_requested(true);
control_plane_stop_key_input_task();
control_plane_stop_system_event_task();
control_plane_remote_log_stop(CONTROL_PLANE_REMOTE_LOG_STOP_WAIT_MS);
control_plane_set_runtime_stop_requested(false);
}