1
0
mirror of https://github.com/whowechina/chu_pico.git synced 2024-11-24 19:10:11 +01:00

Command line functional but not completed

This commit is contained in:
whowechina 2023-09-16 21:20:58 +08:00
parent 1b95be1144
commit 979fbd48e6
9 changed files with 306 additions and 134 deletions

View File

@ -4,7 +4,7 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip)
function(make_firmware board board_def) function(make_firmware board board_def)
pico_sdk_init() pico_sdk_init()
add_executable(${board} 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}) target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1) pico_enable_stdio_usb(${board} 1)
pico_enable_stdio_uart(${board} 0) pico_enable_stdio_uart(${board} 0)

183
firmware/src/cmd.c Normal file
View File

@ -0,0 +1,183 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#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 <joy|nkro>\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);
}

13
firmware/src/cmd.h Normal file
View File

@ -0,0 +1,13 @@
/*
* 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

@ -1,69 +1,59 @@
/* /*
* Controller Config Data * Controller Config and Runtime Data
* WHowe <github.com/whowechina> * WHowe <github.com/whowechina>
* *
* Config is a global data structure that stores all the configuration * Config is a global data structure that stores all the configuration
* Runtime is something to share between files.
*/ */
#include "config.h" #include "config.h"
#include "save.h" #include "save.h"
iidx_cfg_t *iidx_cfg; chu_cfg_t *chu_cfg;
static iidx_cfg_t default_cfg = { static chu_cfg_t default_cfg = {
.key_off = { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}, .colors = {
.key_on = { {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, .key_on_upper = 0x00FF00,
{40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, .key_on_lower = 0xff0000,
.key_on_both = 0xff0000,
.key_off = 0x000000,
.gap = 0x000000,
}, },
.tt_led = { .style = {
.start = 0, .key = 0,
.num = 24, .gap = 0,
.effect = 0, .tof = 0,
.param = 0, .level = 7,
.mode = 0,
}, },
.tt_sensor = { .tof = {
.mode = 2, .offset = 64,
.deadzone = 1, .pitch = 16,
.ppr = 1,
}, },
.effects = { .sense = {
.e1 = 255, .debounce = 4,
.e2 = 128, },
.e3 = 128, .hid = {
.e4 = 128, .joy = 0x0f,
.nkro = 0,
}, },
.level = 128,
.konami = false,
}; };
chu_runtime_t *chu_runtime;
static void config_loaded() static void config_loaded()
{ {
if (iidx_cfg->tt_led.num == 0) { if (chu_cfg->style.level > 10) {
iidx_cfg->tt_led.num = 24; chu_cfg->style.level = default_cfg.style.level;
config_changed(); config_changed();
} }
if ((iidx_cfg->tt_led.start > 8) || if ((chu_cfg->tof.offset < 400) || (chu_cfg->tof.offset > 2000) ||
(iidx_cfg->tt_led.start + iidx_cfg->tt_led.num > 128)) { (chu_cfg->tof.pitch < 50) || (chu_cfg->tof.pitch > 500)) {
iidx_cfg->tt_led.start = 0; chu_cfg->tof = default_cfg.tof;
iidx_cfg->tt_led.num = 24;
config_changed(); config_changed();
} }
if (iidx_cfg->tt_sensor.deadzone > 2) {
iidx_cfg->tt_sensor.deadzone = 0; if (chu_cfg->sense.debounce > 32) {
config_changed(); chu_cfg->sense.debounce = default_cfg.sense.debounce;
}
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();
} }
} }
@ -74,11 +64,11 @@ void config_changed()
void config_factory_reset() void config_factory_reset()
{ {
*iidx_cfg = default_cfg; *chu_cfg = default_cfg;
save_request(true); save_request(true);
} }
void config_init() 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);
} }

View File

@ -9,38 +9,41 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
typedef struct __attribute ((packed)) { typedef struct __attribute__((packed)) {
uint8_t h; // hue; struct {
uint8_t s; // saturation; uint32_t key_on_upper;
uint8_t v; // value; uint32_t key_on_lower;
} hsv_t; 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)) { typedef struct {
hsv_t key_off[11]; uint16_t fps[2];
hsv_t key_on[11]; } chu_runtime_t;
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;
extern iidx_cfg_t *iidx_cfg; extern chu_cfg_t *chu_cfg;
extern chu_runtime_t *chu_runtime;
void config_init(); void config_init();
void config_changed(); // Notify the config has changed void config_changed(); // Notify the config has changed

View File

@ -22,16 +22,16 @@
#include "usb_descriptors.h" #include "usb_descriptors.h"
#include "board_defs.h" #include "board_defs.h"
#include "save.h"
#include "config.h"
#include "cmd.h"
#include "slider.h" #include "slider.h"
#include "air.h" #include "air.h"
#include "rgb.h" #include "rgb.h"
#include "lzfx.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)) { struct __attribute__((packed)) {
uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping
uint8_t HAT; // HAT switch; one nibble w/ unused nibble uint8_t HAT; // HAT switch; one nibble w/ unused nibble
@ -49,10 +49,13 @@ void report_usb_hid()
if (tud_hid_ready()) { if (tud_hid_ready()) {
hid_joy.HAT = 0; hid_joy.HAT = 0;
hid_joy.VendorSpec = 0; hid_joy.VendorSpec = 0;
if (chu_cfg->hid.joy) {
tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); 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.nkro &&
(memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0)) {
sent_hid_nkro = hid_nkro; 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 */ 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() static void gen_joy_report()
{ {
hid_joy.axis = 0; hid_joy.axis = 0;
@ -182,7 +150,6 @@ static void core1_loop()
slider_update_baseline(); slider_update_baseline();
fps_count(1); fps_count(1);
print_fps();
sleep_ms(1); sleep_ms(1);
} }
} }
@ -190,6 +157,8 @@ static void core1_loop()
static void core0_loop() static void core0_loop()
{ {
while(1) { while(1) {
cmd_run();
save_loop();
fps_count(0); fps_count(0);
slider_update(); slider_update();
@ -209,9 +178,15 @@ void init()
board_init(); board_init();
tusb_init(); tusb_init();
stdio_init_all(); stdio_init_all();
config_init();
save_init(0xca34cafe, pause_core1);
slider_init(); slider_init();
air_init(); air_init();
rgb_init(); rgb_init();
cmd_init();
} }
int main(void) int main(void)

View File

@ -1,8 +1,8 @@
/* /*
* Controller Save Save and Load * Controller Config Save and Load
* WHowe <github.com/whowechina> * WHowe <github.com/whowechina>
* *
* Save is stored in last sector of flash * Config is stored in last sector of flash
*/ */
#include "save.h" #include "save.h"
@ -27,7 +27,8 @@ static struct {
} modules[8] = {0}; } modules[8] = {0};
static int module_num = 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) #define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
typedef struct __attribute ((packed)) { typedef struct __attribute ((packed)) {
@ -66,7 +67,7 @@ static void load_default()
{ {
printf("Load Default\n"); printf("Load Default\n");
new_data = default_data; new_data = default_data;
new_data.magic = SAVE_PAGE_MAGIC; new_data.magic = my_magic;
} }
static const page_t *get_page(int id) static const page_t *get_page(int id)
@ -78,7 +79,7 @@ static const page_t *get_page(int id)
static void save_load() static void save_load()
{ {
for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) { 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; break;
} }
data_page = i; 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; io_lock = locker;
save_load(); save_load();
save_loop(); save_loop();
@ -142,7 +144,7 @@ void save_request(bool immediately)
if (!requesting_save) { if (!requesting_save) {
printf("Save marked.\n"); printf("Save marked.\n");
requesting_save = true; requesting_save = true;
new_data.magic = SAVE_PAGE_MAGIC; new_data.magic = my_magic;
requesting_time = time_us_64(); requesting_time = time_us_64();
} }
if (immediately) { if (immediately) {

View File

@ -7,11 +7,12 @@
#define SAVE_H #define SAVE_H
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/* It's safer to lock other I/O ops during saving, so we need a locker */ /* It's safer to lock other I/O ops during saving, so we need a locker */
typedef void (*io_locker_func)(bool pause); 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(); void save_loop();

View File

@ -15,9 +15,10 @@
#include "hardware/gpio.h" #include "hardware/gpio.h"
#include "board_defs.h" #include "board_defs.h"
#include "mpr121.h" #include "mpr121.h"
#include "config.h"
#define TOUCH_THRESHOLD 17 #define TOUCH_THRESHOLD 17
#define RELEASE_THRESHOLD 8 #define RELEASE_THRESHOLD 8
@ -145,19 +146,23 @@ bool slider_touched(unsigned key)
} }
int delta = baseline[key] - readout[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 (touched[key]) {
if (delta > TOUCH_THRESHOLD) { if (delta > touch_thre) {
debounce[key] = 0; debounce[key] = 0;
} }
if (debounce[key] > 4) { if (debounce[key] > chu_cfg->sense.debounce) {
if (delta < RELEASE_THRESHOLD) { if (delta < release_thre) {
touched[key] = false; touched[key] = false;
} }
} else { } else {
debounce[key]++; debounce[key]++;
} }
} else if (!touched[key]) { } else if (!touched[key]) {
if (delta > TOUCH_THRESHOLD) { if (delta > touch_thre) {
touched[key] = true; touched[key] = true;
} }
} }