Add reboot command and late terminal activation

This commit is contained in:
2026-08-23 16:14:19 +02:00
parent f9d3e9ece5
commit 0dcc0d20d4
8 changed files with 86 additions and 2 deletions
+12
View File
@@ -70,6 +70,18 @@ The firmware starts an interactive console on UART0 with the prompt `serial-tool
The console provides line editing, history for the current session, terminal-aware cursor movement, and Tab completion. ESP-IDF supplies completion for root commands; the project extends it to nested `debug`, `serial`, `broker`, `usb`, and `wifi` subcommands plus safe fixed values such as AP policy and serial framing. Password values are intentionally never completion candidates. The console provides line editing, history for the current session, terminal-aware cursor movement, and Tab completion. ESP-IDF supplies completion for root commands; the project extends it to nested `debug`, `serial`, `broker`, `usb`, and `wifi` subcommands plus safe fixed values such as AP policy and serial framing. Password values are intentionally never completion candidates.
ESP-IDF normally probes terminal cursor support once while constructing the UART REPL. If the board boots without a terminal attached, that probe times out and selects dumb mode. The DevKit's USB-to-UART bridge exposes no host-open signal that firmware can monitor, and entering enhanced mode before a terminal exists would block linenoise while it waits for a cursor-position response.
The project therefore preserves safe dumb mode until the first real UART byte arrives. Attach picoterm, picocom, minicom, PuTTY, or another ANSI-capable terminal and press Enter once. That empty line is consumed by the basic reader and promotes the next prompt to enhanced mode, enabling history, Delete, cursor keys, and completion without rebooting. This detects terminal activity rather than electrical USB attachment; a genuinely non-ANSI terminal is not automatically distinguishable on this hardware profile.
The root-level lifecycle command is:
```text
reboot
```
It acknowledges the request, waits briefly for UART output to drain, and calls the ESP-IDF software restart. RAM-only serial or Wi-Fi changes are lost unless they were persisted first with `serial save` or `wifi save`.
### Phase 1 serial service ### Phase 1 serial service
The `serial` command manages the working configuration and UART1 service: The `serial` command manages the working configuration and UART1 service:
+2
View File
@@ -3,6 +3,7 @@ idf_component_register(
"main.c" "main.c"
"console_completion.c" "console_completion.c"
"network_console.c" "network_console.c"
"system_console.c"
"status_led.c" "status_led.c"
"rs232_hw_test.c" "rs232_hw_test.c"
"rs232_port_owner.c" "rs232_port_owner.c"
@@ -25,6 +26,7 @@ idf_component_register(
esp_event esp_event
esp_netif esp_netif
esp_psram esp_psram
esp_system
esp_timer esp_timer
esp_tinyusb esp_tinyusb
esp_wifi esp_wifi
+19
View File
@@ -5,6 +5,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "esp_console.h" #include "esp_console.h"
#include "linenoise/linenoise.h" #include "linenoise/linenoise.h"
@@ -109,6 +110,22 @@ static const char *const s_completion_candidates[] = {
"wifi traceroute", "wifi traceroute",
}; };
static ssize_t console_read_with_late_terminal_upgrade(int file_descriptor,
void *buffer,
size_t size)
{
ssize_t received = read(file_descriptor, buffer, size);
if (received > 0 && linenoiseIsDumbMode()) {
/*
* The current line remains in the safe dumb reader. The next call to
* linenoise() starts enhanced mode only after a terminal has proven it
* can send data, so its cursor-position query cannot block unattended.
*/
linenoiseSetDumbMode(0);
}
return received;
}
static void console_completion_callback(const char *buffer, linenoiseCompletions *completions) static void console_completion_callback(const char *buffer, linenoiseCompletions *completions)
{ {
/* Preserve ESP-IDF completion for registered root command names. */ /* Preserve ESP-IDF completion for registered root command names. */
@@ -134,5 +151,7 @@ static void console_completion_callback(const char *buffer, linenoiseCompletions
void console_completion_install(void) void console_completion_install(void)
{ {
/* Preserve ESP-IDF's safe boot-time mode until actual UART input arrives. */
linenoiseSetReadFunction(&console_read_with_late_terminal_upgrade);
linenoiseSetCompletionCallback(&console_completion_callback); linenoiseSetCompletionCallback(&console_completion_callback);
} }
+1 -1
View File
@@ -6,7 +6,7 @@
extern "C" { extern "C" {
#endif #endif
/* Install project-specific nested command completion for the console. */ /* Install late-terminal upgrade handling and project-specific completion. */
void console_completion_install(void); void console_completion_install(void);
#ifdef __cplusplus #ifdef __cplusplus
+3 -1
View File
@@ -13,6 +13,7 @@
#include "session_broker.h" #include "session_broker.h"
#include "session_console.h" #include "session_console.h"
#include "status_led.h" #include "status_led.h"
#include "system_console.h"
#include "usb_cdc_transport.h" #include "usb_cdc_transport.h"
#include "usb_console.h" #include "usb_console.h"
#include "wifi_config.h" #include "wifi_config.h"
@@ -132,7 +133,8 @@ void app_main(void)
ESP_ERROR_CHECK(usb_console_register_commands()); ESP_ERROR_CHECK(usb_console_register_commands());
ESP_ERROR_CHECK(wifi_console_register_commands()); ESP_ERROR_CHECK(wifi_console_register_commands());
ESP_ERROR_CHECK(network_console_register_root_commands()); ESP_ERROR_CHECK(network_console_register_root_commands());
/* ESP-IDF handles root completion; this wrapper adds nested subcommands. */ ESP_ERROR_CHECK(system_console_register_commands());
/* Upgrade late UART terminals safely and add nested completion. */
console_completion_install(); console_completion_install();
ESP_ERROR_CHECK(esp_console_start_repl(repl)); ESP_ERROR_CHECK(esp_console_start_repl(repl));
+39
View File
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-3.0-only */
/* Root-level system lifecycle commands for the physical administration console. */
#include "system_console.h"
#include <stdio.h>
#include "esp_console.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static int command_reboot(int argc, char **argv)
{
(void)argv;
if (argc != 1) {
printf("Usage: reboot\n");
return 1;
}
printf("Rebooting now; unsaved RAM-only configuration changes will be lost.\n");
fflush(stdout);
/* Give the UART driver time to transmit the acknowledgement before reset. */
vTaskDelay(pdMS_TO_TICKS(100U));
esp_restart();
return 0;
}
esp_err_t system_console_register_commands(void)
{
const esp_console_cmd_t command = {
.command = "reboot",
.help = "Restart the ESP32; unsaved RAM-only configuration is lost",
.hint = NULL,
.func = &command_reboot,
.argtable = NULL,
};
return esp_console_cmd_register(&command);
}
+8
View File
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-3.0-only */
#pragma once
#include "esp_err.h"
/* Register root-level system lifecycle commands such as `reboot`. */
esp_err_t system_console_register_commands(void);
+2
View File
@@ -100,6 +100,8 @@ This hardware profile uses both USB controllers for different purposes:
GPIO19 and GPIO20 are connected to the native USB connector and must not be assigned to the MAX3243, display, buttons, or other peripherals while USB CDC is enabled. Both connectors may be attached to the development host during testing so UART0 logs remain available while native USB carries broker data. Compatible DevKit clones can differ in connector labels and power-path design; verify the board schematic before assuming that two attached cables cannot back-power one another. GPIO19 and GPIO20 are connected to the native USB connector and must not be assigned to the MAX3243, display, buttons, or other peripherals while USB CDC is enabled. Both connectors may be attached to the development host during testing so UART0 logs remain available while native USB carries broker data. Compatible DevKit clones can differ in connector labels and power-path design; verify the board schematic before assuming that two attached cables cannot back-power one another.
The USB-to-UART bridge's host DTR/RTS controls are used for automatic boot/reset circuitry and do not provide firmware with a reliable host-open indication. Consequently, attachment cannot be detected like native CDC DTR. After an unattended boot, the UART0 REPL remains in safe basic mode until it receives its first byte; pressing Enter once after attaching an ANSI terminal enables full line editing for the next prompt.
CDC DTR indicates that the host application has opened the native serial port. It controls the lifetime of the `usb-cdc` broker client but is not directly forwarded to the physical DE-9 DTR output. Physical DTR follows the firmware's `serial` configuration. Likewise, host CDC RTS is status information only; GPIO15/DE-9 RTS remains dedicated to UART1 receive flow control when `flow=rts-cts` is enabled. CDC DTR indicates that the host application has opened the native serial port. It controls the lifetime of the `usb-cdc` broker client but is not directly forwarded to the physical DE-9 DTR output. Physical DTR follows the firmware's `serial` configuration. Likewise, host CDC RTS is status information only; GPIO15/DE-9 RTS remains dedicated to UART1 receive flow control when `flow=rts-cts` is enabled.
## Phase 0 loopback tests ## Phase 0 loopback tests