ESP32/components/cmd_transport/cmd_transport.c

132 lines
3.6 KiB
C

#include "cmd_transport.h"
#include "esp_log.h"
#include "esp_console.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_caps.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#if SOC_USB_SERIAL_JTAG_SUPPORTED
#include "driver/usb_serial_jtag.h"
#endif
static const char *TAG = "CMD_TP";
#define MAX_LISTENERS 4
static cmd_line_handler_t s_listeners[MAX_LISTENERS] = {0};
static int s_listener_count = 0;
static bool s_inited = false;
void cmd_transport_register_listener(cmd_line_handler_t handler) {
if (s_listener_count < MAX_LISTENERS) {
s_listeners[s_listener_count++] = handler;
}
}
// Trim trailing whitespace (CR, LF)
static void trim_trailing(char *s) {
int n = strlen(s);
while (n > 0 && (s[n-1] == '\r' || s[n-1] == '\n' || isspace((unsigned char)s[n-1]))) {
s[--n] = 0;
}
}
// Dispatch line to listeners, then to ESP Console
static void dispatch_line(char *line, cmd_reply_func_t reply_func, void *reply_ctx) {
bool handled = false;
// 1. Offer to registered listeners (e.g. wifi_cfg)
for (int i = 0; i < s_listener_count; i++) {
if (s_listeners[i] && s_listeners[i](line, reply_func, reply_ctx)) {
handled = true;
break;
}
}
// 2. If not handled, pass to system console (for commands like 'mode_monitor')
if (!handled && strlen(line) > 0) {
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
// Unrecognized command - silent ignore or reply error
} else if (err != ESP_OK) {
ESP_LOGE(TAG, "Console run error: %s", esp_err_to_name(err));
}
}
}
// --- UART (stdin/stdout) Support ---
static void uart_reply(const char *msg, void *ctx) {
(void)ctx;
printf("%s", msg);
fflush(stdout);
}
static void uart_listener_task(void *arg) {
char line[256];
// Disable buffering
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
while (1) {
if (fgets(line, sizeof(line), stdin)) {
trim_trailing(line);
dispatch_line(line, uart_reply, NULL);
} else {
vTaskDelay(pdMS_TO_TICKS(20));
}
}
}
// --- USB Serial/JTAG Support ---
#if SOC_USB_SERIAL_JTAG_SUPPORTED
static void usb_reply(const char *msg, void *ctx) {
(void)ctx;
usb_serial_jtag_write_bytes((const uint8_t*)msg, strlen(msg), pdMS_TO_TICKS(50));
}
static void usb_listener_task(void *arg) {
usb_serial_jtag_driver_config_t d = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
if (usb_serial_jtag_driver_install(&d) != ESP_OK) {
ESP_LOGE(TAG, "Failed to install USB-Serial/JTAG driver");
vTaskDelete(NULL);
}
char buf[256];
size_t idx = 0;
uint8_t c;
while (1) {
int n = usb_serial_jtag_read_bytes(&c, 1, pdMS_TO_TICKS(20));
if (n > 0) {
if (c == '\n' || c == '\r') {
if (idx > 0) {
buf[idx] = 0;
dispatch_line(buf, usb_reply, NULL);
idx = 0;
}
} else {
if (idx < sizeof(buf) - 1) {
buf[idx++] = (char)c;
}
}
}
}
}
#endif
void cmd_transport_init(void) {
if (s_inited) return;
s_inited = true;
// Start UART Listener
xTaskCreatePinnedToCore(uart_listener_task, "cmd_uart", 4096, NULL, 5, NULL, tskNO_AFFINITY);
// Start USB Listener (if supported)
#if SOC_USB_SERIAL_JTAG_SUPPORTED
xTaskCreatePinnedToCore(usb_listener_task, "cmd_usb", 4096, NULL, 5, NULL, tskNO_AFFINITY);
#endif
}