From 979fbd48e605e96d731a7b684ea78c295db019b6 Mon Sep 17 00:00:00 2001 From: whowechina Date: Sat, 16 Sep 2023 21:20:58 +0800 Subject: [PATCH] Command line functional but not completed --- firmware/src/CMakeLists.txt | 2 +- firmware/src/cmd.c | 183 ++++++++++++++++++++++++++++++++++++ firmware/src/cmd.h | 13 +++ firmware/src/config.c | 82 +++++++--------- firmware/src/config.h | 63 +++++++------ firmware/src/main.c | 63 ++++--------- firmware/src/save.c | 16 ++-- firmware/src/save.h | 3 +- firmware/src/slider.c | 15 ++- 9 files changed, 306 insertions(+), 134 deletions(-) create mode 100644 firmware/src/cmd.c create mode 100644 firmware/src/cmd.h diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index d14c9ec..4e84747 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -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 lzfx.c usb_descriptors.c) + main.c slider.c air.c rgb.c save.c config.c cmd.c lzfx.c usb_descriptors.c) target_compile_definitions(${board} PUBLIC ${board_def}) pico_enable_stdio_usb(${board} 1) pico_enable_stdio_uart(${board} 0) diff --git a/firmware/src/cmd.c b/firmware/src/cmd.c new file mode 100644 index 0000000..3a35ac0 --- /dev/null +++ b/firmware/src/cmd.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include + +#include "pico/stdio.h" +#include "pico/stdlib.h" + +#include "config.h" + +#define MAX_COMMANDS 10 +#define MAX_COMMAND_LENGTH 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[]); + +typedef struct { + char name[MAX_COMMAND_LENGTH]; + cmd_handler_t handler; +} command_t; + +command_t commands[MAX_COMMANDS]; +int num_commands = 0; + +void register_command(char *name, cmd_handler_t handler) +{ + if (num_commands < MAX_COMMANDS) { + strcpy(commands[num_commands].name, name); + commands[num_commands].handler = handler; + num_commands++; + } +} + +void handle_help(int argc, char *argv[]) +{ + printf("Available commands:\n"); + for (int i = 0; i < num_commands; i++) { + printf("%s\n", commands[i].name); + } +} + +void handle_list(int argc, char *argv[]) +{ + printf("[Colors]\n"); + printf(" Key upper: %6x, lower: %6x, both: %6x, off: %6x\n", + chu_cfg->colors.key_on_upper, chu_cfg->colors.key_on_lower, + chu_cfg->colors.key_on_both, chu_cfg->colors.key_off); + printf(" Gap: %6x\n", chu_cfg->colors.gap); + printf("[Style]\n"); + printf(" Key: %d, Gap: %d, ToF: %d, Level: %d\n", + chu_cfg->style.key, chu_cfg->style.gap, + chu_cfg->style.tof, chu_cfg->style.level); + printf("[ToF]\n"); + printf(" Offset: %d, Pitch: %d\n", chu_cfg->tof.offset, chu_cfg->tof.pitch); + printf("[Sense]\n"); + printf(" Global: %d, debounce: %d\n", chu_cfg->sense.global, chu_cfg->sense.debounce); + printf(" | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |\n"); + printf(" -----------------------------------------------------------------\n"); + printf(" A |"); + for (int i = 0; i < 16; i++) { + printf("%3d|", chu_cfg->sense.keys[i * 2]); + } + printf("\n B |"); + for (int i = 0; i < 16; i++) { + printf("%3d|", chu_cfg->sense.keys[i * 2 + 1]); + } + printf("\n"); + + printf("[HID]\n"); + printf(" Joy: %s, NKRO: %s.\n", + chu_cfg->hid.joy ? "on" : "off", + chu_cfg->hid.nkro ? "on" : "off" ); +} + +static int fps[2]; + +void 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; +} + +void handle_fps(int argc, char *argv[]) +{ + printf("FPS: core 0: %d, core 1: %d\n", fps[0], fps[1]); +} + +void handle_hid(int argc, char *argv[]) +{ + const char *usage = "Usage: hid \n"; + if (argc != 1) { + printf(usage); + return; + } + + if (strcmp(argv[0], "joy") == 0) { + chu_cfg->hid.joy = 1; + chu_cfg->hid.nkro = 0; + } else if (strcmp(argv[0], "nkro") == 0) { + chu_cfg->hid.joy = 0; + chu_cfg->hid.nkro = 1; + } else if (strcmp(argv[0], "both") == 0) { + chu_cfg->hid.joy = 1; + chu_cfg->hid.nkro = 1; + } else { + printf(usage); + return; + } + config_changed(); +} + +void cmd_init() +{ + fcntl(0, F_SETFL, O_NONBLOCK); + register_command("?", handle_help); + register_command("list", handle_list); + register_command("fps", handle_fps); + register_command("hid", handle_hid); +} + +static char cmd_buf[256]; +static int cmd_len = 0; + +static void process_cmd() +{ + char *command; + char *argv[MAX_PARAMETERS]; + int argc; + + command = strtok(cmd_buf, " \n"); + argc = 0; + while ((argc < MAX_PARAMETERS) && + (argv[argc] = strtok(NULL, " \n")) != NULL) { + argc++; + } + + for (int i = 0; i < num_commands; i++) { + if (strcmp(commands[i].name, command) == 0) { + commands[i].handler(argc, argv); + printf("\n"); + break; + } + } +} + +void cmd_run() +{ + int c = getchar_timeout_us(0); + if (c == EOF) { + 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); +} diff --git a/firmware/src/cmd.h b/firmware/src/cmd.h new file mode 100644 index 0000000..ea277da --- /dev/null +++ b/firmware/src/cmd.h @@ -0,0 +1,13 @@ +/* + * Chu Controller Command Line + * WHowe + */ + +#ifndef CMD_H +#define CMD_H + +void cmd_init(); +void cmd_run(); +void fps_count(int core); + +#endif diff --git a/firmware/src/config.c b/firmware/src/config.c index 1e6e849..62e52b6 100644 --- a/firmware/src/config.c +++ b/firmware/src/config.c @@ -1,69 +1,59 @@ /* - * Controller Config Data + * Controller Config and Runtime Data * WHowe * * Config is a global data structure that stores all the configuration + * Runtime is something to share between files. */ #include "config.h" #include "save.h" -iidx_cfg_t *iidx_cfg; +chu_cfg_t *chu_cfg; -static iidx_cfg_t default_cfg = { - .key_off = { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}, - .key_on = { {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, - {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, +static chu_cfg_t default_cfg = { + .colors = { + .key_on_upper = 0x00FF00, + .key_on_lower = 0xff0000, + .key_on_both = 0xff0000, + .key_off = 0x000000, + .gap = 0x000000, }, - .tt_led = { - .start = 0, - .num = 24, - .effect = 0, - .param = 0, - .mode = 0, + .style = { + .key = 0, + .gap = 0, + .tof = 0, + .level = 7, }, - .tt_sensor = { - .mode = 2, - .deadzone = 1, - .ppr = 1, + .tof = { + .offset = 64, + .pitch = 16, }, - .effects = { - .e1 = 255, - .e2 = 128, - .e3 = 128, - .e4 = 128, + .sense = { + .debounce = 4, + }, + .hid = { + .joy = 0x0f, + .nkro = 0, }, - .level = 128, - .konami = false, }; +chu_runtime_t *chu_runtime; + static void config_loaded() { - if (iidx_cfg->tt_led.num == 0) { - iidx_cfg->tt_led.num = 24; + if (chu_cfg->style.level > 10) { + chu_cfg->style.level = default_cfg.style.level; config_changed(); } - if ((iidx_cfg->tt_led.start > 8) || - (iidx_cfg->tt_led.start + iidx_cfg->tt_led.num > 128)) { - iidx_cfg->tt_led.start = 0; - iidx_cfg->tt_led.num = 24; + if ((chu_cfg->tof.offset < 400) || (chu_cfg->tof.offset > 2000) || + (chu_cfg->tof.pitch < 50) || (chu_cfg->tof.pitch > 500)) { + chu_cfg->tof = default_cfg.tof; config_changed(); } - if (iidx_cfg->tt_sensor.deadzone > 2) { - iidx_cfg->tt_sensor.deadzone = 0; - config_changed(); - } - if (iidx_cfg->tt_led.mode > 2) { - iidx_cfg->tt_led.mode = 0; - config_changed(); - } - if (iidx_cfg->tt_sensor.mode > 3) { - iidx_cfg->tt_sensor.mode = 2; - config_changed(); - } - if (iidx_cfg->tt_sensor.ppr > 3) { - iidx_cfg->tt_sensor.ppr = 1; - config_changed(); + + if (chu_cfg->sense.debounce > 32) { + chu_cfg->sense.debounce = default_cfg.sense.debounce; } } @@ -74,11 +64,11 @@ void config_changed() void config_factory_reset() { - *iidx_cfg = default_cfg; + *chu_cfg = default_cfg; save_request(true); } void config_init() { - iidx_cfg = (iidx_cfg_t *)save_alloc(sizeof(iidx_cfg), &default_cfg, config_loaded); + chu_cfg = (chu_cfg_t *)save_alloc(sizeof(*chu_cfg), &default_cfg, config_loaded); } diff --git a/firmware/src/config.h b/firmware/src/config.h index 9d7353c..f6ced90 100644 --- a/firmware/src/config.h +++ b/firmware/src/config.h @@ -9,38 +9,41 @@ #include #include -typedef struct __attribute ((packed)) { - uint8_t h; // hue; - uint8_t s; // saturation; - uint8_t v; // value; -} hsv_t; +typedef struct __attribute__((packed)) { + struct { + uint32_t key_on_upper; + uint32_t key_on_lower; + uint32_t key_on_both; + uint32_t key_off; + uint32_t gap; + } colors; + struct { + uint8_t key; + uint8_t gap; + uint8_t tof; + uint8_t level; + } style; + struct { + uint8_t offset; + uint8_t pitch; + } tof; + struct { + int8_t global; + uint8_t debounce; + int8_t keys[32]; + } sense; + struct { + uint8_t joy : 4; + uint8_t nkro : 4; + } hid; +} chu_cfg_t; -typedef struct __attribute ((packed)) { - hsv_t key_off[11]; - hsv_t key_on[11]; - struct { - uint8_t start; - uint8_t num; - uint8_t effect; - uint8_t param; - uint8_t mode; /* 0: on, 1: reversed, 2: off */ - } tt_led; - struct { - uint8_t mode; /* 0: analog, 1: analog reversed, 2: i2c, 3: i2c reversed */ - uint8_t deadzone; /* only for analog */ - uint8_t ppr; /* 0: 256, 1: 128, 2: 96, 3: 64, other: 256 */ - } tt_sensor; - struct { - uint8_t e1; - uint8_t e2; - uint8_t e3; - uint8_t e4; - } effects; - uint8_t level; /* led brightness limit */ - bool konami; /* konami spoof */ -} iidx_cfg_t; +typedef struct { + uint16_t fps[2]; +} chu_runtime_t; -extern iidx_cfg_t *iidx_cfg; +extern chu_cfg_t *chu_cfg; +extern chu_runtime_t *chu_runtime; void config_init(); void config_changed(); // Notify the config has changed diff --git a/firmware/src/main.c b/firmware/src/main.c index e7d7e62..03465e4 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -22,16 +22,16 @@ #include "usb_descriptors.h" #include "board_defs.h" + +#include "save.h" +#include "config.h" +#include "cmd.h" + #include "slider.h" #include "air.h" #include "rgb.h" #include "lzfx.h" -/* Measure the time of a function call */ -#define RUN_TIME(func) \ - { uint64_t _t = time_us_64(); func; \ - printf(#func ":%lld\n", time_us_64() - _t); } - struct __attribute__((packed)) { uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping uint8_t HAT; // HAT switch; one nibble w/ unused nibble @@ -49,10 +49,13 @@ void report_usb_hid() if (tud_hid_ready()) { hid_joy.HAT = 0; hid_joy.VendorSpec = 0; - tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); - if (memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0) { + if (chu_cfg->hid.joy) { + tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); + } + if (chu_cfg->hid.nkro && + (memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0)) { sent_hid_nkro = hid_nkro; - //tud_hid_n_report(0x02, 0, &sent_hid_nkro, sizeof(sent_hid_nkro)); + tud_hid_n_report(0x02, 0, &sent_hid_nkro, sizeof(sent_hid_nkro)); } } } @@ -66,41 +69,6 @@ static void pause_core1(bool pause) sleep_ms(5); /* wait for any IO ops to finish */ } } - -static int fps[2] = {0}; - -static int get_fps(int core) -{ - return fps[core]; -} - -static void 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 print_fps() -{ - static uint32_t last = 0; - uint32_t now = time_us_32(); - if (now - last < 5000000) { - return; - } - last = now; - printf("FPS: %d %d\n", get_fps(0), get_fps(1)); -} - static void gen_joy_report() { hid_joy.axis = 0; @@ -182,7 +150,6 @@ static void core1_loop() slider_update_baseline(); fps_count(1); - print_fps(); sleep_ms(1); } } @@ -190,6 +157,8 @@ static void core1_loop() static void core0_loop() { while(1) { + cmd_run(); + save_loop(); fps_count(0); slider_update(); @@ -209,9 +178,15 @@ void init() board_init(); tusb_init(); stdio_init_all(); + + config_init(); + save_init(0xca34cafe, pause_core1); + slider_init(); air_init(); rgb_init(); + + cmd_init(); } int main(void) diff --git a/firmware/src/save.c b/firmware/src/save.c index 01365e0..07c3710 100644 --- a/firmware/src/save.c +++ b/firmware/src/save.c @@ -1,8 +1,8 @@ /* - * Controller Save Save and Load + * Controller Config Save and Load * WHowe * - * Save is stored in last sector of flash + * Config is stored in last sector of flash */ #include "save.h" @@ -27,7 +27,8 @@ static struct { } modules[8] = {0}; static int module_num = 0; -#define SAVE_PAGE_MAGIC 0x13424321 +static uint32_t my_magic = 0xcafecafe; + #define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) typedef struct __attribute ((packed)) { @@ -66,7 +67,7 @@ static void load_default() { printf("Load Default\n"); new_data = default_data; - new_data.magic = SAVE_PAGE_MAGIC; + new_data.magic = my_magic; } static const page_t *get_page(int id) @@ -78,7 +79,7 @@ static const page_t *get_page(int id) static void save_load() { for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) { - if (get_page(i)->magic != SAVE_PAGE_MAGIC) { + if (get_page(i)->magic != my_magic) { break; } data_page = i; @@ -102,8 +103,9 @@ static void save_loaded() } } -void save_init(io_locker_func locker) +void save_init(uint32_t magic, io_locker_func locker) { + my_magic = magic; io_lock = locker; save_load(); save_loop(); @@ -142,7 +144,7 @@ void save_request(bool immediately) if (!requesting_save) { printf("Save marked.\n"); requesting_save = true; - new_data.magic = SAVE_PAGE_MAGIC; + new_data.magic = my_magic; requesting_time = time_us_64(); } if (immediately) { diff --git a/firmware/src/save.h b/firmware/src/save.h index e1b9ae6..9b45750 100644 --- a/firmware/src/save.h +++ b/firmware/src/save.h @@ -7,11 +7,12 @@ #define SAVE_H #include +#include #include /* It's safer to lock other I/O ops during saving, so we need a locker */ typedef void (*io_locker_func)(bool pause); -void save_init(io_locker_func locker); +void save_init(uint32_t magic, io_locker_func locker); void save_loop(); diff --git a/firmware/src/slider.c b/firmware/src/slider.c index bec4539..9f73e86 100644 --- a/firmware/src/slider.c +++ b/firmware/src/slider.c @@ -15,9 +15,10 @@ #include "hardware/gpio.h" #include "board_defs.h" - #include "mpr121.h" +#include "config.h" + #define TOUCH_THRESHOLD 17 #define RELEASE_THRESHOLD 8 @@ -145,19 +146,23 @@ bool slider_touched(unsigned key) } int delta = baseline[key] - readout[key]; + int bias = chu_cfg->sense.global + chu_cfg->sense.keys[key]; + int touch_thre = TOUCH_THRESHOLD + bias; + int release_thre = RELEASE_THRESHOLD + bias / 2; + if (touched[key]) { - if (delta > TOUCH_THRESHOLD) { + if (delta > touch_thre) { debounce[key] = 0; } - if (debounce[key] > 4) { - if (delta < RELEASE_THRESHOLD) { + if (debounce[key] > chu_cfg->sense.debounce) { + if (delta < release_thre) { touched[key] = false; } } else { debounce[key]++; } } else if (!touched[key]) { - if (delta > TOUCH_THRESHOLD) { + if (delta > touch_thre) { touched[key] = true; } }