diff --git a/main/cli/serial_cli.c b/main/cli/serial_cli.c new file mode 100644 index 0000000..97287fd --- /dev/null +++ b/main/cli/serial_cli.c @@ -0,0 +1,307 @@ +#include "serial_cli.h" +#include "mimi_config.h" +#include "wifi/wifi_manager.h" +#include "telegram/telegram_bot.h" +#include "llm/llm_proxy.h" +#include "memory/memory_store.h" +#include "memory/session_mgr.h" + +#include +#include +#include "esp_log.h" +#include "esp_console.h" +#include "esp_system.h" +#include "esp_heap_caps.h" +#include "argtable3/argtable3.h" + +static const char *TAG = "cli"; + +/* --- wifi_set command --- */ +static struct { + struct arg_str *ssid; + struct arg_str *password; + struct arg_end *end; +} wifi_set_args; + +static int cmd_wifi_set(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&wifi_set_args); + if (nerrors != 0) { + arg_print_errors(stderr, wifi_set_args.end, argv[0]); + return 1; + } + wifi_manager_set_credentials(wifi_set_args.ssid->sval[0], + wifi_set_args.password->sval[0]); + printf("WiFi credentials saved. Restart to apply.\n"); + return 0; +} + +/* --- wifi_status command --- */ +static int cmd_wifi_status(int argc, char **argv) +{ + printf("WiFi connected: %s\n", wifi_manager_is_connected() ? "yes" : "no"); + printf("IP: %s\n", wifi_manager_get_ip()); + return 0; +} + +/* --- set_tg_token command --- */ +static struct { + struct arg_str *token; + struct arg_end *end; +} tg_token_args; + +static int cmd_set_tg_token(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&tg_token_args); + if (nerrors != 0) { + arg_print_errors(stderr, tg_token_args.end, argv[0]); + return 1; + } + telegram_set_token(tg_token_args.token->sval[0]); + printf("Telegram bot token saved.\n"); + return 0; +} + +/* --- set_api_key command --- */ +static struct { + struct arg_str *key; + struct arg_end *end; +} api_key_args; + +static int cmd_set_api_key(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&api_key_args); + if (nerrors != 0) { + arg_print_errors(stderr, api_key_args.end, argv[0]); + return 1; + } + llm_set_api_key(api_key_args.key->sval[0]); + printf("API key saved.\n"); + return 0; +} + +/* --- set_model command --- */ +static struct { + struct arg_str *model; + struct arg_end *end; +} model_args; + +static int cmd_set_model(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&model_args); + if (nerrors != 0) { + arg_print_errors(stderr, model_args.end, argv[0]); + return 1; + } + llm_set_model(model_args.model->sval[0]); + printf("Model set.\n"); + return 0; +} + +/* --- memory_read command --- */ +static int cmd_memory_read(int argc, char **argv) +{ + char buf[4096]; + if (memory_read_long_term(buf, sizeof(buf)) == ESP_OK && buf[0]) { + printf("=== MEMORY.md ===\n%s\n=================\n", buf); + } else { + printf("MEMORY.md is empty or not found.\n"); + } + return 0; +} + +/* --- memory_write command --- */ +static struct { + struct arg_str *content; + struct arg_end *end; +} memory_write_args; + +static int cmd_memory_write(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&memory_write_args); + if (nerrors != 0) { + arg_print_errors(stderr, memory_write_args.end, argv[0]); + return 1; + } + memory_write_long_term(memory_write_args.content->sval[0]); + printf("MEMORY.md updated.\n"); + return 0; +} + +/* --- session_list command --- */ +static int cmd_session_list(int argc, char **argv) +{ + printf("Sessions:\n"); + session_list(); + return 0; +} + +/* --- session_clear command --- */ +static struct { + struct arg_str *chat_id; + struct arg_end *end; +} session_clear_args; + +static int cmd_session_clear(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&session_clear_args); + if (nerrors != 0) { + arg_print_errors(stderr, session_clear_args.end, argv[0]); + return 1; + } + if (session_clear(session_clear_args.chat_id->sval[0]) == ESP_OK) { + printf("Session cleared.\n"); + } else { + printf("Session not found.\n"); + } + return 0; +} + +/* --- heap_info command --- */ +static int cmd_heap_info(int argc, char **argv) +{ + printf("Internal free: %d bytes\n", + (int)heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + printf("PSRAM free: %d bytes\n", + (int)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + printf("Total free: %d bytes\n", + (int)esp_get_free_heap_size()); + return 0; +} + +/* --- restart command --- */ +static int cmd_restart(int argc, char **argv) +{ + printf("Restarting...\n"); + esp_restart(); + return 0; /* unreachable */ +} + +esp_err_t serial_cli_init(void) +{ + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + repl_config.prompt = "mimi> "; + repl_config.max_cmdline_length = 256; + + /* USB Serial JTAG */ + esp_console_dev_usb_serial_jtag_config_t hw_config = + ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); + + ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&hw_config, &repl_config, &repl)); + + /* Register commands */ + + /* wifi_set */ + wifi_set_args.ssid = arg_str1(NULL, NULL, "", "WiFi SSID"); + wifi_set_args.password = arg_str1(NULL, NULL, "", "WiFi password"); + wifi_set_args.end = arg_end(2); + esp_console_cmd_t wifi_set_cmd = { + .command = "wifi_set", + .help = "Set WiFi SSID and password", + .func = &cmd_wifi_set, + .argtable = &wifi_set_args, + }; + esp_console_cmd_register(&wifi_set_cmd); + + /* wifi_status */ + esp_console_cmd_t wifi_status_cmd = { + .command = "wifi_status", + .help = "Show WiFi connection status", + .func = &cmd_wifi_status, + }; + esp_console_cmd_register(&wifi_status_cmd); + + /* set_tg_token */ + tg_token_args.token = arg_str1(NULL, NULL, "", "Telegram bot token"); + tg_token_args.end = arg_end(1); + esp_console_cmd_t tg_token_cmd = { + .command = "set_tg_token", + .help = "Set Telegram bot token", + .func = &cmd_set_tg_token, + .argtable = &tg_token_args, + }; + esp_console_cmd_register(&tg_token_cmd); + + /* set_api_key */ + api_key_args.key = arg_str1(NULL, NULL, "", "Anthropic API key"); + api_key_args.end = arg_end(1); + esp_console_cmd_t api_key_cmd = { + .command = "set_api_key", + .help = "Set Claude API key", + .func = &cmd_set_api_key, + .argtable = &api_key_args, + }; + esp_console_cmd_register(&api_key_cmd); + + /* set_model */ + model_args.model = arg_str1(NULL, NULL, "", "Model identifier"); + model_args.end = arg_end(1); + esp_console_cmd_t model_cmd = { + .command = "set_model", + .help = "Set LLM model (default: " MIMI_LLM_DEFAULT_MODEL ")", + .func = &cmd_set_model, + .argtable = &model_args, + }; + esp_console_cmd_register(&model_cmd); + + /* memory_read */ + esp_console_cmd_t mem_read_cmd = { + .command = "memory_read", + .help = "Read MEMORY.md", + .func = &cmd_memory_read, + }; + esp_console_cmd_register(&mem_read_cmd); + + /* memory_write */ + memory_write_args.content = arg_str1(NULL, NULL, "", "Content to write"); + memory_write_args.end = arg_end(1); + esp_console_cmd_t mem_write_cmd = { + .command = "memory_write", + .help = "Write to MEMORY.md", + .func = &cmd_memory_write, + .argtable = &memory_write_args, + }; + esp_console_cmd_register(&mem_write_cmd); + + /* session_list */ + esp_console_cmd_t sess_list_cmd = { + .command = "session_list", + .help = "List all sessions", + .func = &cmd_session_list, + }; + esp_console_cmd_register(&sess_list_cmd); + + /* session_clear */ + session_clear_args.chat_id = arg_str1(NULL, NULL, "", "Chat ID to clear"); + session_clear_args.end = arg_end(1); + esp_console_cmd_t sess_clear_cmd = { + .command = "session_clear", + .help = "Clear a session", + .func = &cmd_session_clear, + .argtable = &session_clear_args, + }; + esp_console_cmd_register(&sess_clear_cmd); + + /* heap_info */ + esp_console_cmd_t heap_cmd = { + .command = "heap_info", + .help = "Show heap memory usage", + .func = &cmd_heap_info, + }; + esp_console_cmd_register(&heap_cmd); + + /* restart */ + esp_console_cmd_t restart_cmd = { + .command = "restart", + .help = "Restart the device", + .func = &cmd_restart, + }; + esp_console_cmd_register(&restart_cmd); + + /* Start REPL */ + ESP_ERROR_CHECK(esp_console_start_repl(repl)); + ESP_LOGI(TAG, "Serial CLI started"); + + return ESP_OK; +} diff --git a/main/cli/serial_cli.h b/main/cli/serial_cli.h new file mode 100644 index 0000000..9498d3f --- /dev/null +++ b/main/cli/serial_cli.h @@ -0,0 +1,9 @@ +#pragma once + +#include "esp_err.h" + +/** + * Initialize and start the serial CLI (esp_console based). + * Registers all commands and starts the REPL on USB-JTAG serial. + */ +esp_err_t serial_cli_init(void);