307 lines
9.2 KiB
C
307 lines
9.2 KiB
C
#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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#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 <epoch_seconds>\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 <epoch>\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 <send <msg> | baud <rate> | 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 <list | launch <id> | 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 <click | double | long | home>\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 <epoch>)",
|
|
.hint = "<sync|set <epoch>>",
|
|
.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 = "<tz_string>",
|
|
.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 <id>, home)",
|
|
.hint = "<list|launch|home>",
|
|
.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 = "<click|double|long|home>",
|
|
.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 = "<value>",
|
|
.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 = "<send|baud|stats|clear>",
|
|
.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;
|
|
}
|