1
0
mirror of https://github.com/whowechina/chu_pico.git synced 2024-09-24 02:58:20 +02:00

CLI refactoring

This commit is contained in:
whowechina 2023-09-29 20:46:38 +08:00
parent e0bf2af8bc
commit 949f8139ad
8 changed files with 246 additions and 191 deletions

Binary file not shown.

View File

@ -4,7 +4,7 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip)
function(make_firmware board board_def)
pico_sdk_init()
add_executable(${board}
main.c slider.c air.c rgb.c save.c config.c cmd.c lzfx.c
main.c slider.c air.c rgb.c save.c config.c cli.c commands.c lzfx.c
vl53l0x.c mpr121.c usb_descriptors.c)
target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1)

182
firmware/src/cli.c Normal file
View File

@ -0,0 +1,182 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include "pico/stdio.h"
#include "pico/stdlib.h"
#include "cli.h"
#define MAX_COMMANDS 32
#define MAX_PARAMETERS 6
#define MAX_PARAMETER_LENGTH 20
const char *cli_prompt = "cli>";
const char *cli_logo = "CLI";
static const char *commands[MAX_COMMANDS];
static const char *helps[MAX_COMMANDS];
static cmd_handler_t handlers[MAX_COMMANDS];
static int max_cmd_len = 0;
static int num_commands = 0;
void cli_register(const char *cmd, cmd_handler_t handler, const char *help)
{
if (num_commands < MAX_COMMANDS) {
commands[num_commands] = cmd;
handlers[num_commands] = handler;
helps[num_commands] = help;
num_commands++;
if (strlen(cmd) > max_cmd_len) {
max_cmd_len = strlen(cmd);
}
}
}
// return -1 if not matched, return -2 if ambiguous
int cli_match_prefix(const char *str[], int num, const char *prefix)
{
int match = -1;
bool found = false;
for (int i = 0; (i < num) && str[i]; i++) {
if (strncasecmp(str[i], prefix, strlen(prefix)) == 0) {
if (found) {
return -2;
}
found = true;
match = i;
}
}
return match;
}
static void handle_help(int argc, char *argv[])
{
printf("%s", cli_logo);
printf("Available commands:\n");
for (int i = 0; i < num_commands; i++) {
printf("%*s: %s\n", max_cmd_len + 2, commands[i], helps[i]);
}
}
static int fps[2];
void cli_fps_count(int core)
{
static uint32_t last[2] = {0};
static int counter[2] = {0};
counter[core]++;
uint32_t now = time_us_32();
if (now - last[core] < 1000000) {
return;
}
last[core] = now;
fps[core] = counter[core];
counter[core] = 0;
}
static void handle_fps(int argc, char *argv[])
{
printf("FPS: core 0: %d, core 1: %d\n", fps[0], fps[1]);
}
int cli_extract_non_neg_int(const char *param, int len)
{
if (len == 0) {
len = strlen(param);
}
int result = 0;
for (int i = 0; i < len; i++) {
if (!isdigit(param[i])) {
return -1;
}
result = result * 10 + param[i] - '0';
}
return result;
}
static char cmd_buf[256];
static int cmd_len = 0;
static void process_cmd()
{
char *argv[MAX_PARAMETERS];
int argc;
char *cmd = strtok(cmd_buf, " \n");
if (strlen(cmd) == 0) {
return;
}
argc = 0;
while ((argc < MAX_PARAMETERS) &&
(argv[argc] = strtok(NULL, " ,\n")) != NULL) {
argc++;
}
int match = cli_match_prefix(commands, num_commands, cmd);
if (match == -2) {
printf("Ambiguous command.\n");
return;
} else if (match == -1) {
printf("Unknown command.\n");
handle_help(0, NULL);
return;
}
handlers[match](argc, argv);
}
void cli_run()
{
int c = getchar_timeout_us(0);
if (c == EOF) {
return;
}
if (c == '\b' || c == 127) { // both backspace and delete
if (cmd_len > 0) {
cmd_len--;
printf("\b \b");
}
return;
}
if ((c != '\n') && (c != '\r')) {
if (cmd_len < sizeof(cmd_buf) - 2) {
cmd_buf[cmd_len] = c;
printf("%c", c);
cmd_len++;
}
return;
}
cmd_buf[cmd_len] = '\0';
cmd_len = 0;
printf("\n");
process_cmd();
printf(cli_prompt);
}
void cli_init(const char *prompt, const char *logo)
{
if (prompt) {
cli_prompt = prompt;
}
if (logo) {
cli_logo = logo;
}
cli_register("?", handle_help, "Display this help message.");
cli_register("fps", handle_fps, "Display FPS.");
}

20
firmware/src/cli.h Normal file
View File

@ -0,0 +1,20 @@
/*
* Chu Controller Command Line Framework
* WHowe <github.com/whowechina>
*/
#ifndef CLI_H
#define CLI_H
typedef void (*cmd_handler_t)(int argc, char *argv[]);
void cli_init();
void cli_register(const char *cmd, cmd_handler_t handler, const char *help);
void cli_run();
void cli_fps_count(int core);
int cli_extract_non_neg_int(const char *param, int len);
int cli_match_prefix(const char *str[], int num, const char *prefix);
#endif

View File

@ -1,13 +0,0 @@
/*
* Chu Controller Command Line
* WHowe <github.com/whowechina>
*/
#ifndef CMD_H
#define CMD_H
void cmd_init();
void cmd_run();
void fps_count(int core);
#endif

View File

@ -11,67 +11,11 @@
#include "air.h"
#include "slider.h"
#include "save.h"
#include "cli.h"
#define SENSE_LIMIT_MAX 9
#define SENSE_LIMIT_MIN -9
#define MAX_COMMANDS 20
#define MAX_PARAMETERS 5
#define MAX_PARAMETER_LENGTH 20
const char *chu_prompt = "chu_pico>";
typedef void (*cmd_handler_t)(int argc, char *argv[]);
static const char *commands[MAX_COMMANDS];
static const char *helps[MAX_COMMANDS];
static cmd_handler_t handlers[MAX_COMMANDS];
static int max_cmd_len = 0;
static int num_commands = 0;
static void register_command(const char *cmd, cmd_handler_t handler, const char *help)
{
if (num_commands < MAX_COMMANDS) {
commands[num_commands] = cmd;
handlers[num_commands] = handler;
helps[num_commands] = help;
num_commands++;
if (strlen(cmd) > max_cmd_len) {
max_cmd_len = strlen(cmd);
}
}
}
// return -1 if not matched, return -2 if ambiguous
static int match_prefix(const char *str[], int num, const char *prefix)
{
int match = -1;
bool found = false;
for (int i = 0; (i < num) && str[i]; i++) {
if (strncasecmp(str[i], prefix, strlen(prefix)) == 0) {
if (found) {
return -2;
}
found = true;
match = i;
}
}
return match;
}
static void handle_help(int argc, char *argv[])
{
printf("\n << Chu Pico Controller >>\n");
printf(" https://github.com/whowechina\n\n");
printf("Available commands:\n");
for (int i = 0; i < num_commands; i++) {
printf("%*s: %s\n", max_cmd_len + 2, commands[i], helps[i]);
}
}
static void disp_colors()
{
printf("[Colors]\n");
@ -143,7 +87,7 @@ void handle_display(int argc, char *argv[])
}
const char *choices[] = {"colors", "style", "tof", "sense", "hid"};
switch (match_prefix(choices, 5, argv[0])) {
switch (cli_match_prefix(choices, 5, argv[0])) {
case 0:
disp_colors();
break;
@ -182,26 +126,6 @@ void fps_count(int core)
counter[core] = 0;
}
static void handle_fps(int argc, char *argv[])
{
printf("FPS: core 0: %d, core 1: %d\n", fps[0], fps[1]);
}
static int extract_non_neg_int(const char *param, int len)
{
if (len == 0) {
len = strlen(param);
}
int result = 0;
for (int i = 0; i < len; i++) {
if (!isdigit(param[i])) {
return -1;
}
result = result * 10 + param[i] - '0';
}
return result;
}
static void handle_level(int argc, char *argv[])
{
const char *usage = "Usage: level <0..255>\n";
@ -210,7 +134,7 @@ static void handle_level(int argc, char *argv[])
return;
}
int level = extract_non_neg_int(argv[0], 0);
int level = cli_extract_non_neg_int(argv[0], 0);
if ((level < 0) || (level > 255)) {
printf(usage);
return;
@ -252,7 +176,7 @@ static void handle_hid(int argc, char *argv[])
}
const char *choices[] = {"joy", "nkro", "both"};
int match = match_prefix(choices, 3, argv[0]);
int match = cli_match_prefix(choices, 3, argv[0]);
if (match < 0) {
printf(usage);
return;
@ -286,10 +210,10 @@ static void handle_tof(int argc, char *argv[])
int offset = chu_cfg->tof.offset;
int pitch = chu_cfg->tof.pitch;
if (argc >= 1) {
offset = extract_non_neg_int(argv[0], 0);
offset = cli_extract_non_neg_int(argv[0], 0);
}
if (argc == 2) {
pitch = extract_non_neg_int(argv[1], 0);
pitch = cli_extract_non_neg_int(argv[1], 0);
}
if ((offset < 40) || (offset > 255) || (pitch < 4) || (pitch > 50)) {
@ -315,11 +239,11 @@ static void handle_filter(int argc, char *argv[])
return;
}
int ffi = extract_non_neg_int(argv[0], 0);
int sfi = extract_non_neg_int(argv[1], 0);
int ffi = cli_extract_non_neg_int(argv[0], 0);
int sfi = cli_extract_non_neg_int(argv[1], 0);
int intv = chu_cfg->sense.filter & 0x07;
if (argc == 3) {
intv = extract_non_neg_int(argv[2], 0);
intv = cli_extract_non_neg_int(argv[2], 0);
}
if ((ffi < 0) || (ffi > 3) || (sfi < 0) || (sfi > 3) ||
@ -348,7 +272,7 @@ static uint8_t *extract_key(const char *param)
return NULL;
}
int id = extract_non_neg_int(param, len - 1) - 1;
int id = cli_extract_non_neg_int(param, len - 1) - 1;
if ((id < 0) || (id > 15)) {
return NULL;
}
@ -425,10 +349,10 @@ static void handle_debounce(int argc, char *argv[])
int touch = chu_cfg->sense.debounce_touch;
int release = chu_cfg->sense.debounce_release;
if (argc >= 1) {
touch = extract_non_neg_int(argv[0], 0);
touch = cli_extract_non_neg_int(argv[0], 0);
}
if (argc == 2) {
release = extract_non_neg_int(argv[1], 0);
release = cli_extract_non_neg_int(argv[1], 0);
}
if ((touch < 0) || (release < 0) ||
@ -471,89 +395,17 @@ static void handle_factory_reset()
printf("Factory reset done.\n");
}
void cmd_init()
void commands_init()
{
register_command("?", handle_help, "Display this help message.");
register_command("display", handle_display, "Display all config.");
register_command("fps", handle_fps, "Display FPS.");
register_command("level", handle_level, "Set LED brightness level.");
register_command("stat", handle_stat, "Display or reset statistics.");
register_command("hid", handle_hid, "Set HID mode.");
register_command("tof", handle_tof, "Set ToF config.");
register_command("filter", handle_filter, "Set pre-filter config.");
register_command("sense", handle_sense, "Set sensitivity config.");
register_command("debounce", handle_debounce, "Set debounce config.");
register_command("raw", handle_raw, "Show key raw readings.");
register_command("save", handle_save, "Save config to flash.");
register_command("factory", config_factory_reset, "Reset everything to default.");
}
static char cmd_buf[256];
static int cmd_len = 0;
static void process_cmd()
{
char *argv[MAX_PARAMETERS];
int argc;
char *cmd = strtok(cmd_buf, " \n");
if (strlen(cmd) == 0) {
return;
}
argc = 0;
while ((argc < MAX_PARAMETERS) &&
(argv[argc] = strtok(NULL, " \n")) != NULL) {
argc++;
}
int match = match_prefix(commands, num_commands, cmd);
if (match == -2) {
printf("Ambiguous command.\n");
return;
}
if (match == -1) {
printf("Unknown command.\n");
handle_help(0, NULL);
return;
}
handlers[match](argc, argv);
}
void cmd_run()
{
int c = getchar_timeout_us(0);
if (c == EOF) {
return;
}
if (c == '\b' || c == 127) { // both backspace and delete
if (cmd_len > 0) {
cmd_len--;
printf("\b \b");
}
return;
}
if ((c != '\n') && (c != '\r')) {
if (cmd_len < sizeof(cmd_buf) - 2) {
cmd_buf[cmd_len] = c;
printf("%c", c);
cmd_len++;
}
return;
}
cmd_buf[cmd_len] = '\0';
cmd_len = 0;
printf("\n");
process_cmd();
printf(chu_prompt);
cli_register("display", handle_display, "Display all config.");
cli_register("level", handle_level, "Set LED brightness level.");
cli_register("stat", handle_stat, "Display or reset statistics.");
cli_register("hid", handle_hid, "Set HID mode.");
cli_register("tof", handle_tof, "Set ToF config.");
cli_register("filter", handle_filter, "Set pre-filter config.");
cli_register("sense", handle_sense, "Set sensitivity config.");
cli_register("debounce", handle_debounce, "Set debounce config.");
cli_register("raw", handle_raw, "Show key raw readings.");
cli_register("save", handle_save, "Save config to flash.");
cli_register("factory", config_factory_reset, "Reset everything to default.");
}

11
firmware/src/commands.h Normal file
View File

@ -0,0 +1,11 @@
/*
* Chu Controller Command Line Commands
* WHowe <github.com/whowechina>
*/
#ifndef COMMANDS_H
#define COMMANDS_H
void commands_init();
#endif

View File

@ -25,7 +25,8 @@
#include "save.h"
#include "config.h"
#include "cmd.h"
#include "cli.h"
#include "commands.h"
#include "slider.h"
#include "air.h"
@ -139,7 +140,7 @@ static void core1_loop()
rgb_update();
mutex_exit(&core1_io_lock);
}
fps_count(1);
cli_fps_count(1);
sleep_ms(1);
}
}
@ -149,9 +150,9 @@ static void core0_loop()
while(1) {
tud_task();
cmd_run();
cli_run();
save_loop();
fps_count(0);
cli_fps_count(0);
slider_update();
air_update();
@ -178,7 +179,9 @@ void init()
air_init();
rgb_init();
cmd_init();
cli_init("chu_pico>", "\n << Chu Pico Controller >>\n"
" https://github.com/whowechina\n\n");
commands_init();
}
int main(void)