#include "os_cli.h" #include "os_app.h" #include "os_input.h" #include "os_gfx.h" #include "os_oled.h" #include "os_status.h" #include "sys_uart.h" #include "sys_time.h" #include #include #include #include #include "esp_console.h" #include "esp_system.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" static const char *TAG = "SYS_CLI"; static int cmd_time(int argc, char **argv) { if (argc >= 2 && strcmp(argv[1], "sync") == 0) { printf("Triggering SNTP network time sync...\n"); sys_time_start_sntp(); return 0; } else if (argc >= 3 && strcmp(argv[1], "set") == 0) { time_t epoch = (time_t)strtoull(argv[2], NULL, 10); if (sys_time_set_epoch(epoch) == ESP_OK) { printf("System time successfully set to epoch: %lld\n", (long long)epoch); return 0; } else { printf("Failed to set time. Usage: time set \n"); return 1; } } struct tm tm_info; bool synced = sys_time_get_local(&tm_info); time_t now = sys_time_get_epoch(); char strftime_buf[64]; strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S (%A)", &tm_info); printf("\n=== System Wall Clock ===\n"); printf("Status: %s\n", synced ? "SYNCHRONIZED" : "UNSYNCHRONIZED (Uptime only)"); printf("Local: %s\n", strftime_buf); printf("Epoch: %lld\n", (long long)now); printf("Timezone: %s\n", sys_time_get_timezone()); printf("\nCommands: time sync | time set \n"); return 0; } static int cmd_tz(int argc, char **argv) { if (argc >= 2) { if (sys_time_set_timezone(argv[1]) == ESP_OK) { printf("Timezone set to '%s'\n", argv[1]); return 0; } else { printf("Failed to set timezone\n"); return 1; } } printf("Current Timezone: %s\n", sys_time_get_timezone()); printf("Examples: tz \"GMT0BST,M3.5.0/1,M10.5.0\" (UK)\n"); printf(" tz \"EST5EDT,M3.2.0,M11.1.0\" (US Eastern)\n"); printf(" tz \"CST-8\" (China / Asia)\n"); printf(" tz \"UTC0\" (UTC)\n"); return 0; } static int cmd_uart(int argc, char **argv) { if (argc < 2) { printf("Usage: uart | baud | stats | clear>\n"); return 1; } if (strcmp(argv[1], "send") == 0 && argc >= 3) { sys_uart_write_str(argv[2]); sys_uart_write_str("\r\n"); printf("Sent over UART TX: %s\n", argv[2]); return 0; } else if (strcmp(argv[1], "baud") == 0 && argc >= 3) { uint32_t baud = (uint32_t)strtoul(argv[2], NULL, 10); if (baud > 0 && sys_uart_set_baud_rate(baud) == ESP_OK) { printf("UART baud rate changed to %lu\n", (unsigned long)baud); return 0; } else { printf("Failed to set baud rate\n"); return 1; } } else if (strcmp(argv[1], "stats") == 0) { uint32_t rx = 0, tx = 0; sys_uart_get_stats(&rx, &tx); printf("\n=== UART Status (TX: GPIO 21, RX: GPIO 20) ===\n"); printf("Active Baud Rate: %lu\n", (unsigned long)sys_uart_get_baud_rate()); printf("Total RX Bytes: %lu\n", (unsigned long)rx); printf("Total TX Bytes: %lu\n", (unsigned long)tx); return 0; } else if (strcmp(argv[1], "clear") == 0) { sys_uart_clear_rx_buffer(); printf("UART RX buffer cleared\n"); return 0; } printf("Unknown uart sub-command\n"); return 1; } static int cmd_ps(int argc, char **argv) { printf("\n=== Running FreeRTOS Tasks ===\n"); char task_buf[512]; vTaskList(task_buf); printf("TaskName\tStatus\tPrio\tStack\tNum\n"); printf("%s\n", task_buf); return 0; } static int cmd_free(int argc, char **argv) { printf("\n=== Memory Allocation ===\n"); printf("Current Free Heap: %lu bytes\n", (unsigned long)esp_get_free_heap_size()); printf("Minimum Free Heap: %lu bytes\n", (unsigned long)esp_get_minimum_free_heap_size()); return 0; } static int cmd_app(int argc, char **argv) { if (argc < 2) { printf("Usage: app | home>\n"); return 1; } if (strcmp(argv[1], "list") == 0) { size_t count = sys_app_get_count(); printf("\n=== Registered Apps (%u) ===\n", (unsigned int)count); for (size_t i = 0; i < count; i++) { const sys_app_t *app = sys_app_get_by_index(i); printf(" [%u] %-12s (ID: %s)\n", (unsigned int)i, app->name, app->id); } return 0; } else if (strcmp(argv[1], "launch") == 0 && argc >= 3) { esp_err_t err = sys_app_launch_by_id(argv[2]); if (err == ESP_OK) { printf("Launched app: %s\n", argv[2]); } else { printf("Failed to launch app: %s\n", argv[2]); } return 0; } else if (strcmp(argv[1], "home") == 0) { sys_app_launch_launcher(); printf("Switched to Home Launcher\n"); return 0; } printf("Unknown app sub-command\n"); return 1; } static int cmd_input(int argc, char **argv) { if (argc < 2) { printf("Usage: input \n"); return 1; } if (strcmp(argv[1], "click") == 0) { sys_input_inject(INPUT_ACTION_CLICK); } else if (strcmp(argv[1], "double") == 0) { sys_input_inject(INPUT_ACTION_DOUBLE_CLICK); } else if (strcmp(argv[1], "long") == 0) { sys_input_inject(INPUT_ACTION_LONG_PRESS); } else if (strcmp(argv[1], "home") == 0) { sys_input_inject(INPUT_ACTION_HOLD_HOME); } else { printf("Invalid action\n"); return 1; } printf("Injected action: %s\n", argv[1]); return 0; } static int cmd_reboot(int argc, char **argv) { printf("Restarting system...\n"); esp_restart(); return 0; } static int cmd_contrast(int argc, char **argv) { if (argc < 2) { printf("Usage: contrast <0-255>\n"); return 1; } int val = atoi(argv[1]); if (val < 0 || val > 255) { printf("Value must be 0 to 255\n"); return 1; } oled_driver_set_contrast((uint8_t)val); printf("Contrast set to %d\n", val); return 0; } esp_err_t sys_cli_init(void) { esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); repl_config.prompt = "esp32c3-os> "; repl_config.max_cmdline_args = 8; repl_config.max_cmdline_length = 256; esp_console_dev_usb_serial_jtag_config_t hw_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); esp_console_repl_t *repl = NULL; esp_err_t err = esp_console_new_repl_usb_serial_jtag(&hw_config, &repl_config, &repl); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to create USB Serial/JTAG REPL: %s", esp_err_to_name(err)); return err; } esp_console_register_help_command(); const esp_console_cmd_t time_cmd = { .command = "time", .help = "View or configure real-time clock (time | time sync | time set )", .hint = ">", .func = &cmd_time, }; esp_console_cmd_register(&time_cmd); const esp_console_cmd_t tz_cmd = { .command = "tz", .help = "View or configure timezone string", .hint = "", .func = &cmd_tz, }; esp_console_cmd_register(&tz_cmd); const esp_console_cmd_t ps_cmd = { .command = "ps", .help = "List active FreeRTOS tasks and memory", .hint = NULL, .func = &cmd_ps, }; esp_console_cmd_register(&ps_cmd); const esp_console_cmd_t free_cmd = { .command = "free", .help = "Display system heap status", .hint = NULL, .func = &cmd_free, }; esp_console_cmd_register(&free_cmd); const esp_console_cmd_t app_cmd = { .command = "app", .help = "App management (list, launch , home)", .hint = "", .func = &cmd_app, }; esp_console_cmd_register(&app_cmd); const esp_console_cmd_t input_cmd = { .command = "input", .help = "Simulate button input (click, double, long, home)", .hint = "", .func = &cmd_input, }; esp_console_cmd_register(&input_cmd); const esp_console_cmd_t contrast_cmd = { .command = "contrast", .help = "Set OLED contrast (0-255)", .hint = "", .func = &cmd_contrast, }; esp_console_cmd_register(&contrast_cmd); const esp_console_cmd_t reboot_cmd = { .command = "reboot", .help = "Reboot the MCU", .hint = NULL, .func = &cmd_reboot, }; esp_console_cmd_register(&reboot_cmd); const esp_console_cmd_t uart_cmd = { .command = "uart", .help = "Hardware UART control (send, baud, stats, clear)", .hint = "", .func = &cmd_uart, }; esp_console_cmd_register(&uart_cmd); err = esp_console_start_repl(repl); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to start USB Serial/JTAG REPL: %s", esp_err_to_name(err)); return err; } ESP_LOGI(TAG, "CLI shell initialized"); return ESP_OK; }