Improve watchdog monitoring and CLI
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "dcdc_controller.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -18,8 +19,12 @@
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
#include "ws2812_status.h"
|
||||
#include "watch_config.h"
|
||||
#include "esp_system.h"
|
||||
#include "ina226_monitor.h"
|
||||
#include "uart_mux.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
#define CLI_LINE_MAX_LEN 128
|
||||
#define CLI_QUEUE_LEN 8
|
||||
@@ -45,6 +50,10 @@ static bool s_host_ready;
|
||||
static void usb_cli_task(void *arg);
|
||||
static void usb_cli_process_line(char *line);
|
||||
static void usb_cli_prompt(void);
|
||||
static void usb_cli_enter_bootloader(void);
|
||||
static void usb_cli_handle_config(char *args);
|
||||
static void usb_cli_print_config(void);
|
||||
static void usb_cli_handle_reset(void);
|
||||
|
||||
static void usb_cli_write_raw(const char *data, size_t len)
|
||||
{
|
||||
@@ -112,10 +121,16 @@ static void usb_cli_print_status(void)
|
||||
usb_cli_printf("\r\nСтан каналів:\r\n");
|
||||
for (size_t i = 0; i < dcdc_channel_count(); ++i) {
|
||||
dcdc_channel_t ch = (dcdc_channel_t)i;
|
||||
usb_cli_printf(" - CH%u: %s (GPIO %d)\r\n",
|
||||
uart_mux_channel_stats_t stats = {0};
|
||||
if (uart_mux_ready()) {
|
||||
uart_mux_get_channel_stats(i, &stats);
|
||||
}
|
||||
usb_cli_printf(" - CH%u: %s (GPIO %d) | miss=%u restart=%u\r\n",
|
||||
(unsigned)i,
|
||||
dcdc_get_state(ch) ? "ON" : "OFF",
|
||||
(int)dcdc_get_gpio(ch));
|
||||
(int)dcdc_get_gpio(ch),
|
||||
(unsigned)stats.missed_heartbeats,
|
||||
(unsigned)stats.restart_count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +139,18 @@ static void usb_cli_prompt(void)
|
||||
usb_cli_write_raw(PROMPT, strlen(PROMPT));
|
||||
}
|
||||
|
||||
static void usb_cli_enter_bootloader(void)
|
||||
{
|
||||
usb_cli_printf("\r\nПерехід у режим прошивки esptool...\r\n"
|
||||
"Після перезавантаження з’явиться ROM-порт USB CDC/Serial.\r\n"
|
||||
"Запустіть esptool.py або idf.py flash та прошийте пристрій. "
|
||||
"Для виходу з bootloader виконайте 'esptool.py --after hard_reset reset' або перезавантажте живлення.\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
tinyusb_driver_uninstall();
|
||||
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
static void usb_cli_handle_switch(const char *cmd, char *args)
|
||||
{
|
||||
dcdc_channel_t channel;
|
||||
@@ -246,14 +273,22 @@ static void usb_cli_process_line(char *line)
|
||||
if (strcasecmp(cmd, "help") == 0) {
|
||||
usb_cli_printf(
|
||||
"\r\nДоступні команди:\r\n"
|
||||
" help - показати довідку\r\n"
|
||||
" status - стан всіх каналів\r\n"
|
||||
" enable <n> - увімкнути канал n\r\n"
|
||||
" disable <n> - вимкнути канал n\r\n"
|
||||
" toggle <n> - перемкнути канал n\r\n"
|
||||
" sense [n] - показати напругу/струм/потужність (опц. канал)\r\n"
|
||||
" uart send <n> <msg> - відправити повідомлення Pi n\r\n"
|
||||
" uart read <n> [len] - прочитати дані з Pi n\r\n");
|
||||
" help - показати цю довідку\r\n"
|
||||
" status - показати стан усіх каналів DCDC\r\n"
|
||||
" enable <n> - увімкнути канал n (0..4)\r\n"
|
||||
" disable <n> - вимкнути канал n\r\n"
|
||||
" toggle <n> - перемкнути канал n\r\n"
|
||||
" sense - виміряти напругу/струм/потужність INA226\r\n"
|
||||
" uart send <n> <msg> - надіслати текстове повідомлення в Raspberry Pi n\r\n"
|
||||
" uart read <n> [len] - прочитати до [len] байт відповіді від Raspberry Pi n\r\n"
|
||||
" config show - показати збережені таймінги heartbeat/DCDC\r\n"
|
||||
" config set hb_period <сек> - змінити інтервал відправки heartbeat\r\n"
|
||||
" config set dcdc_off <сек> - задати тривалість вимкнення DCDC при рестарті\r\n"
|
||||
" config set hb_start <сек> - налаштувати затримку перед стартом опитування після boot\r\n"
|
||||
" config set hb_monitor <0|1> - увімкнути/вимкнути контроль відповіді heartbeat\r\n"
|
||||
" config set hb_miss <шт> - кількість пропусків відповіді до рестарту каналу\r\n"
|
||||
" reset - м'яко перезавантажити ESP32-S3\r\n"
|
||||
" bootloader - перезавантажити ESP32-S3 у ROM bootloader для esptool\r\n");
|
||||
} else if (strcasecmp(cmd, "status") == 0) {
|
||||
usb_cli_print_status();
|
||||
} else if (strcasecmp(cmd, "enable") == 0 ||
|
||||
@@ -264,11 +299,109 @@ static void usb_cli_process_line(char *line)
|
||||
usb_cli_handle_sense(save_ptr);
|
||||
} else if (strcasecmp(cmd, "uart") == 0) {
|
||||
usb_cli_handle_uart(save_ptr);
|
||||
} else if (strcasecmp(cmd, "config") == 0) {
|
||||
usb_cli_handle_config(save_ptr);
|
||||
} else if (strcasecmp(cmd, "reset") == 0) {
|
||||
usb_cli_handle_reset();
|
||||
} else if (strcasecmp(cmd, "bootloader") == 0) {
|
||||
usb_cli_enter_bootloader();
|
||||
} else {
|
||||
usb_cli_printf("\r\nНевідома команда '%s'\r\n", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_print_config(void)
|
||||
{
|
||||
const watch_config_t *cfg = watch_config_get();
|
||||
usb_cli_printf(
|
||||
"\r\nПоточні налаштування:\r\n"
|
||||
" hb_period: %u с\r\n"
|
||||
" dcdc_off: %u с\r\n"
|
||||
" hb_start_delay: %u с\r\n"
|
||||
" hb_monitor: %s\r\n"
|
||||
" hb_miss_limit: %u зап.\r\n",
|
||||
(unsigned)cfg->heartbeat_period_sec,
|
||||
(unsigned)cfg->dcdc_restart_off_sec,
|
||||
(unsigned)cfg->heartbeat_start_delay_sec,
|
||||
cfg->heartbeat_monitor_enabled ? "on" : "off",
|
||||
(unsigned)cfg->heartbeat_miss_limit);
|
||||
}
|
||||
|
||||
static void usb_cli_handle_config(char *args)
|
||||
{
|
||||
if (!args || *args == '\0') {
|
||||
usb_cli_print_config();
|
||||
return;
|
||||
}
|
||||
|
||||
char *ctx = NULL;
|
||||
char *action = strtok_r(args, " ", &ctx);
|
||||
if (!action || strcasecmp(action, "show") == 0) {
|
||||
usb_cli_print_config();
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(action, "set") != 0) {
|
||||
usb_cli_printf("\r\nВикористання: config show | config set <hb_period|dcdc_off|hb_start|hb_monitor|hb_miss> <знач>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *param = strtok_r(NULL, " ", &ctx);
|
||||
char *value_str = strtok_r(NULL, " ", &ctx);
|
||||
if (!param || !value_str) {
|
||||
usb_cli_printf("\r\nВкажіть параметр і значення в секундах\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t value = (uint32_t)strtoul(value_str, NULL, 10);
|
||||
|
||||
watch_config_t new_cfg = *watch_config_get();
|
||||
if (strcasecmp(param, "hb_period") == 0) {
|
||||
if (value == 0) {
|
||||
usb_cli_printf("\r\nЗначення має бути більше нуля\r\n");
|
||||
return;
|
||||
}
|
||||
new_cfg.heartbeat_period_sec = value;
|
||||
} else if (strcasecmp(param, "dcdc_off") == 0) {
|
||||
if (value == 0) {
|
||||
usb_cli_printf("\r\nЗначення має бути більше нуля\r\n");
|
||||
return;
|
||||
}
|
||||
new_cfg.dcdc_restart_off_sec = value;
|
||||
} else if (strcasecmp(param, "hb_start") == 0 ||
|
||||
strcasecmp(param, "hb_start_delay") == 0) {
|
||||
if (value == 0) {
|
||||
usb_cli_printf("\r\nЗначення має бути більше нуля\r\n");
|
||||
return;
|
||||
}
|
||||
new_cfg.heartbeat_start_delay_sec = value;
|
||||
} else if (strcasecmp(param, "hb_monitor") == 0) {
|
||||
if (value != 0 && value != 1) {
|
||||
usb_cli_printf("\r\nhb_monitor приймає 0 або 1\r\n");
|
||||
return;
|
||||
}
|
||||
new_cfg.heartbeat_monitor_enabled = (value != 0);
|
||||
} else if (strcasecmp(param, "hb_miss") == 0 ||
|
||||
strcasecmp(param, "hb_miss_limit") == 0) {
|
||||
if (value == 0) {
|
||||
usb_cli_printf("\r\nhb_miss має бути більше нуля\r\n");
|
||||
return;
|
||||
}
|
||||
new_cfg.heartbeat_miss_limit = value;
|
||||
} else {
|
||||
usb_cli_printf("\r\nНевідомий параметр '%s'\r\n", param);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = watch_config_save(&new_cfg);
|
||||
if (err == ESP_OK) {
|
||||
usb_cli_printf("\r\nПараметр оновлено\r\n");
|
||||
usb_cli_print_config();
|
||||
} else {
|
||||
usb_cli_printf("\r\nПомилка збереження конфігурації: %s\r\n", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_task(void *arg)
|
||||
{
|
||||
usb_cli_msg_t msg;
|
||||
@@ -285,14 +418,17 @@ static void usb_cli_task(void *arg)
|
||||
usb_cli_process_line(line);
|
||||
line_len = 0;
|
||||
}
|
||||
usb_cli_write_raw("\r\n", 2);
|
||||
usb_cli_prompt();
|
||||
} else if (ch == 0x7F || ch == '\b') {
|
||||
if (line_len > 0) {
|
||||
line_len--;
|
||||
usb_cli_write_raw("\b \b", 3);
|
||||
}
|
||||
} else if (isprint((unsigned char)ch)) {
|
||||
if (line_len < CLI_LINE_MAX_LEN - 1) {
|
||||
line[line_len++] = ch;
|
||||
usb_cli_write_raw(&ch, 1);
|
||||
} else {
|
||||
usb_cli_printf("\r\nРядок занадто довгий\r\n");
|
||||
line_len = 0;
|
||||
@@ -386,3 +522,9 @@ esp_err_t usb_cdc_cli_init(void)
|
||||
ESP_LOGI(TAG, "USB CDC CLI ініціалізовано");
|
||||
return ESP_OK;
|
||||
}
|
||||
static void usb_cli_handle_reset(void)
|
||||
{
|
||||
usb_cli_printf("\r\nПерезавантаження пристрою...\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user