From aef8ce19318f81949947a3ce3809a018a3bb1cab Mon Sep 17 00:00:00 2001 From: whowechina Date: Sat, 30 Sep 2023 20:06:35 +0800 Subject: [PATCH] Just playable now --- firmware/src/CMakeLists.txt | 4 +- firmware/src/board_defs.h | 8 +- firmware/src/button.c | 76 +++++++++++ firmware/src/button.h | 18 +++ firmware/src/io.c | 260 ++++++++++++++++++++++++++++++++++++ firmware/src/io.h | 12 ++ firmware/src/main.c | 117 ++++------------ firmware/src/rgb.c | 21 +-- firmware/src/rgb.h | 4 +- firmware/src/touch.c | 72 +++++++--- firmware/src/touch.h | 3 +- 11 files changed, 465 insertions(+), 130 deletions(-) create mode 100644 firmware/src/button.c create mode 100644 firmware/src/button.h create mode 100644 firmware/src/io.c create mode 100644 firmware/src/io.h diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index 5d63538..574aca1 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -4,8 +4,8 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip) function(make_firmware board board_def) pico_sdk_init() add_executable(${board} - main.c touch.c rgb.c save.c config.c cli.c commands.c mpr121.c - usb_descriptors.c) + main.c touch.c button.c rgb.c save.c config.c cli.c commands.c io.c + mpr121.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/board_defs.h b/firmware/src/board_defs.h index 89bac9e..945de2b 100644 --- a/firmware/src/board_defs.h +++ b/firmware/src/board_defs.h @@ -12,8 +12,14 @@ #define RGB_PIN 13 #define RGB_ORDER GRB // or RGB +#define RGB_BUTTON_MAP { 5, 4, 3, 2, 1, 0, 7, 6 } -#define NKRO_KEYMAP "1aqz2swx3dec4frv5gtb6hyn7jum8ki90olp,." +#define BUTTON_DEF { 1, 0, 4, 5, 8, 9, 3, 2 } +#define BUTTON_NKRO_MAP "WEDCXZAQ" + +#define TOUCH_MAP { E3, A2, B2, D2, E2, A1, B1, D1, E1, C2, A8, B8, \ + D8, E8, A7, B7, D7, E7, A6, B6, D6, E6, A5, B5, \ + D5, E5, C1, A4, B4, D4, E4, A3, B3, D3 } #else #endif diff --git a/firmware/src/button.c b/firmware/src/button.c new file mode 100644 index 0000000..d8c80dc --- /dev/null +++ b/firmware/src/button.c @@ -0,0 +1,76 @@ +/* + * Mai Controller Buttons + * WHowe + * + */ + +#include "button.h" + +#include +#include + +#include "hardware/gpio.h" +#include "hardware/timer.h" +#include "hardware/pwm.h" + +#include "config.h" +#include "board_defs.h" + +static const uint8_t button_gpio[] = BUTTON_DEF; + +#define BUTTON_NUM (sizeof(button_gpio)) + +static bool sw_val[BUTTON_NUM]; /* true if pressed */ +static uint64_t sw_freeze_time[BUTTON_NUM]; + +void button_init() +{ + for (int i = 0; i < BUTTON_NUM; i++) + { + sw_val[i] = false; + sw_freeze_time[i] = 0; + int8_t gpio = button_gpio[i]; + gpio_init(gpio); + gpio_set_function(gpio, GPIO_FUNC_SIO); + gpio_set_dir(gpio, GPIO_IN); + gpio_pull_up(gpio); + } +} + +uint8_t button_num() +{ + return BUTTON_NUM; +} + +static uint16_t button_reading; + +/* If a switch flips, it freezes for a while */ +#define DEBOUNCE_FREEZE_TIME_US 1000 +void button_update() +{ + uint64_t now = time_us_64(); + uint16_t buttons = 0; + + for (int i = BUTTON_NUM - 1; i >= 0; i--) { + bool sw_pressed = !gpio_get(button_gpio[i]); + + if (now >= sw_freeze_time[i]) { + if (sw_pressed != sw_val[i]) { + sw_val[i] = sw_pressed; + sw_freeze_time[i] = now + DEBOUNCE_FREEZE_TIME_US; + } + } + + buttons <<= 1; + if (sw_val[i]) { + buttons |= 1; + } + } + + button_reading = buttons; +} + +uint16_t button_read() +{ + return button_reading; +} diff --git a/firmware/src/button.h b/firmware/src/button.h new file mode 100644 index 0000000..23b0717 --- /dev/null +++ b/firmware/src/button.h @@ -0,0 +1,18 @@ +/* + * Mai Controller Buttons + * WHowe + */ + +#ifndef BUTTONS_H +#define BUTTONS_H + +#include +#include +#include "hardware/flash.h" + +void button_init(); +uint8_t button_num(); +void button_update(); +uint16_t button_read(); + +#endif diff --git a/firmware/src/io.c b/firmware/src/io.c new file mode 100644 index 0000000..e68b264 --- /dev/null +++ b/firmware/src/io.c @@ -0,0 +1,260 @@ +#include +#include + +#include "io.h" +#include "tusb.h" +#include "usb_descriptors.h" + +#include "touch.h" +#include "rgb.h" + +static struct { + bool stat; + uint64_t last_io_time; + int touch_interface; +} ctx = { false, 0, 0 }; + +typedef union { + uint8_t raw[28]; + struct { + uint8_t body; + uint8_t ext; + uint8_t side; + }; + struct { + uint8_t index; + uint8_t r; + uint8_t g; + uint8_t b; + }; + struct { + uint8_t start; + uint8_t len; + uint8_t skip; + uint8_t mr; + uint8_t mg; + uint8_t mb; + uint8_t speed; + }; + uint8_t rgb[11][3]; +} led_data_t; + +typedef struct { + int interface; + bool connected; + bool in_cmd; + bool is_touch; + bool escape; + union { + uint8_t buf[48]; + struct { + struct { + uint8_t dst; + uint8_t src; + uint8_t len; + uint8_t cmd; + } hdr; + led_data_t data; + }; + }; + uint8_t len; + uint8_t checksum; +} cdc_t; + +static cdc_t cdc[2] = { + { .interface = 1 }, + { .interface = 2 }, +}; + +static void touch_cmd(cdc_t *cdc) +{ + cdc->in_cmd = false; + if (cdc->len != 4) { + return; + } + cdc->len = 0; + ctx.last_io_time = time_us_64(); + + ctx.touch_interface = cdc->interface; + + printf("Touch CMD: %*s -> ", 4, cdc->buf); + switch (cdc->buf[2]) { + case 'E': + printf("RSET\n"); + break; + case 'L': + printf("HALT\n"); + ctx.stat = false; + break; + case 'A': + printf("STAT\n"); + ctx.stat = true; + break; + case 'r': + printf("Ratio\n"); + tud_cdc_n_write_char(cdc->interface, '('); + tud_cdc_n_write_char(cdc->interface, cdc->buf[0]); //L,R + tud_cdc_n_write_char(cdc->interface, cdc->buf[1]); //sensor + tud_cdc_n_write_char(cdc->interface, 'r'); + tud_cdc_n_write_char(cdc->interface, cdc->buf[3]); // Ratio + tud_cdc_n_write_char(cdc->interface, ')'); + tud_cdc_n_write_flush(cdc->interface); + break; + case 'k': + printf("Sense\n"); + tud_cdc_n_write_char(cdc->interface, '('); + tud_cdc_n_write_char(cdc->interface, cdc->buf[0]); //L,R + tud_cdc_n_write_char(cdc->interface, cdc->buf[1]); //sensor + tud_cdc_n_write_char(cdc->interface, 'k'); + tud_cdc_n_write_char(cdc->interface, cdc->buf[3]); // Ratio + tud_cdc_n_write_char(cdc->interface, ')'); + tud_cdc_n_write_flush(cdc->interface); + break; + default: + printf("Unknown\n"); + return; + } +} + +static void led_cmd(cdc_t *cdc) +{ + cdc->in_cmd = false; + cdc->len = 0; + ctx.last_io_time = time_us_64(); + + switch (cdc->hdr.cmd) { + case 0x31: + printf("8b\n"); + uint32_t color = rgb32(cdc->data.r, cdc->data.g, cdc->data.b, false); + rgb_set_button_color(cdc->data.index, color); + break; + case 0x32: + printf("8bM\n"); + for (int i = 0; i < cdc->data.len; i++) { + rgb_set_button_color(i + cdc->data.start, rgb32(cdc->data.mr, cdc->data.mg, cdc->data.mb, false)); + } + break; + case 0x33: + printf("8bMF\n"); + for (int i = 0; i < cdc->data.len; i++) { + rgb_set_button_color(i + cdc->data.start, rgb32(cdc->data.mr, cdc->data.mg, cdc->data.mb, false)); + } + break; + case 0x39: + printf("Fet\n"); + rgb_set_cab_color(0, rgb32(cdc->data.body, cdc->data.body, cdc->data.body, false)); + rgb_set_cab_color(1, rgb32(cdc->data.ext, cdc->data.ext, cdc->data.ext, false)); + rgb_set_cab_color(2, rgb32(cdc->data.side, cdc->data.side, cdc->data.side, false)); + break; + case 0x3C: + printf("Upd\n"); + break; + case 0x82: + printf("Dir\n"); + break; + default: + printf("LEDUnk\n"); + return; + } +} + +static inline void assemble_cmd(cdc_t *cdc, uint8_t c) +{ + if (c == 0xE0) { + cdc->len = 0; + cdc->in_cmd = true; + cdc->is_touch = false; + cdc->escape = false; + cdc->checksum = 0; + return; + } + + if ((!cdc->in_cmd || cdc->is_touch) && (c == '{')) { + cdc->len = 0; + cdc->in_cmd = true; + cdc->is_touch = true; + return; + } + + if (cdc->is_touch) { + // Touch cmd + if (c == '}') { + touch_cmd(cdc); + } else if (cdc->len < sizeof(cdc->buf)) { + cdc->buf[cdc->len] = c; + cdc->len++; + } + return; + } + + // LED cmd + if (c == 0xD0) { + cdc->escape = true; + return; + } + + if (cdc->escape) { + cdc->escape = false; + c++; + } + + if ((cdc->len == cdc->hdr.len + 3) && (cdc->checksum == c)) { + led_cmd(cdc); + return; + } + + if (cdc->len < sizeof(cdc->buf)) { + cdc->buf[cdc->len] = c; + cdc->len++; + cdc->checksum += c; + } +} + +static void update_itf(cdc_t *cdc) +{ + cdc->connected = tud_cdc_n_connected(cdc->interface); + + if (tud_cdc_n_available(cdc->interface)) { + uint8_t buf[48]; + uint32_t count = tud_cdc_n_read(cdc->interface, buf, sizeof(buf)); + for (int i = 0; i < count; i++) { + assemble_cmd(cdc, buf[i]); + } + } +} + +static void send_touch() +{ + if ((ctx.touch_interface == 0) | (!ctx.stat)) { + return; + } + + static uint32_t last_sent_time = 0; + uint32_t now = time_us_32(); + if (now - last_sent_time < 5000) { + return; + } + last_sent_time = now; + + + uint8_t report[9] = "(\0\0\0\0\0\0\0)"; + uint64_t touch = touch_touchmap(); + for (int i = 0; i < 7; i++) { + report[i + 1] = touch & 0x1f; + touch >>= 5; + } + tud_cdc_n_write(ctx.touch_interface, report, sizeof(report)); + tud_cdc_n_write_flush(ctx.touch_interface); +} + +void io_update() +{ + update_itf(cdc); + update_itf(cdc + 1); + send_touch(); +} + +uint64_t io_last_io_time() +{ + return ctx.last_io_time; +} diff --git a/firmware/src/io.h b/firmware/src/io.h new file mode 100644 index 0000000..babcbf1 --- /dev/null +++ b/firmware/src/io.h @@ -0,0 +1,12 @@ +/* + * Game I/O + * WHowe + */ + +#ifndef IO_H_ +#define IO_H_ + +void io_update(); +uint64_t io_last_io_time(); + +#endif \ No newline at end of file diff --git a/firmware/src/main.c b/firmware/src/main.c index c9903b8..903c22f 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -24,12 +24,14 @@ #include "board_defs.h" #include "touch.h" +#include "button.h" +#include "rgb.h" + #include "save.h" #include "config.h" #include "cli.h" #include "commands.h" - -#include "rgb.h" +#include "io.h" struct __attribute__((packed)) { uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping @@ -48,10 +50,7 @@ void report_usb_hid() if (tud_hid_ready()) { hid_joy.HAT = 0; hid_joy.VendorSpec = 0; - if (mai_cfg->hid.joy) { - tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); - } - if (mai_cfg->hid.nkro && + if (mai_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)); @@ -59,40 +58,16 @@ void report_usb_hid() } } -static void gen_joy_report() -{ - hid_joy.axis = 0; - for (int i = 0; i < 16; i++) { - if (touch_touched(i * 2)) { - hid_joy.axis |= 1 << (30 - i * 2); - } - if (touch_touched(i * 2 + 1)) { - hid_joy.axis |= 1 << (31 - i * 2); - } - - } - hid_joy.axis ^= 0x80808080; // some magic number from CrazyRedMachine -} - const uint8_t keycode_table[128][2] = { HID_ASCII_TO_KEYCODE }; -const char keymap[38 + 1] = NKRO_KEYMAP; // 32 keys, 6 air keys, 1 terminator +const char keymap[8] = BUTTON_NKRO_MAP; // 8 buttons static void gen_nkro_report() { - for (int i = 0; i < 32; i++) { + uint16_t buttons = button_read(); + for (int i = 0; i < 8; i++) { uint8_t code = keycode_table[keymap[i]][1]; uint8_t byte = code / 8; uint8_t bit = code % 8; - if (touch_touched(i)) { - hid_nkro.keymap[byte] |= (1 << bit); - } else { - hid_nkro.keymap[byte] &= ~(1 << bit); - } - } - for (int i = 0; i < 6; i++) { - uint8_t code = keycode_table[keymap[32 + i]][1]; - uint8_t byte = code / 8; - uint8_t bit = code % 8; - if (hid_joy.buttons & (1 << i)) { + if (buttons & (1 << i)) { hid_nkro.keymap[byte] |= (1 << bit); } else { hid_nkro.keymap[byte] &= ~(1 << bit); @@ -109,68 +84,21 @@ static void run_lights() return; } - uint32_t colors[5] = { 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xffffff }; + if (now - io_last_io_time() < 5000000) { + return; + } + uint16_t buttons = button_read(); + uint16_t touch = touch_touchmap(); for (int i = 0; i < 8; i++) { - rgb_set_color(i, 0); - } - for (int i = 0; i < 34; i++) { - if (touch_touched(i)) { - if (i < 32) { - rgb_set_color((i + 16) / 4 % 8, colors[i % 4]); - } else { - rgb_set_color(i - 32, colors[4]); - } + uint32_t color = 0; + if (buttons & (1 << i)) { + color |= 0x00ff00; } - } -// for (int i = 0; i < 15; i++) { -// uint32_t color = rgb32_from_hsv(i * 255 / 8, 255, 16); -// rgb_set_color(i, color); -// } - - for (int i = 0; i < 34; i++) { -// bool r = touch_touched(i * 2); -// bool g = touch_touched(i * 2 + 1); -// rgb_set_color(30 - i * 2, rgb32(r ? 80 : 0, g ? 80 : 0, 0, false)); - } -} - - -static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count) -{ - //tud_cdc_n_write_char(itf, buf[i]); - //tud_cdc_n_write_flush(itf); -} - -static void cdc_task(void) -{ - uint8_t itf; - - for (itf = 1; itf < CFG_TUD_CDC; itf++) - { - // connected() check for DTR bit - // Most but not all terminal client set this when making connection - // if ( tud_cdc_n_connected(itf) ) - if ( tud_cdc_n_available(itf) ) - { - uint8_t buf[64]; - - uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf)); - - if (itf == 1) { - printf("1 TXT:", itf); - for (int i = 0; i < count; i++) { - printf("%c", buf[i]); - } - printf("\n"); - } else if (itf == 2) { - printf("2 HEX:", itf); - for (int i = 0; i < count; i++) { - printf(" %02x", buf[i]); - } - printf("\n"); - } + if (touch & (1 << i)) { + color |= 0xff0000; } + rgb_set_button_color(i, color); } } @@ -192,15 +120,15 @@ static void core0_loop() { while(1) { tud_task(); - cdc_task(); + io_update(); cli_run(); save_loop(); cli_fps_count(0); touch_update(); + button_update(); - gen_joy_report(); gen_nkro_report(); report_usb_hid(); } @@ -219,6 +147,7 @@ void init() save_init(0xca34cafe, &core1_io_lock); touch_init(); + button_init(); rgb_init(); cli_init("mai_pico>", "\n << Mai Pico Controller >>\n" diff --git a/firmware/src/rgb.c b/firmware/src/rgb.c index bfc6d1b..2cd9668 100644 --- a/firmware/src/rgb.c +++ b/firmware/src/rgb.c @@ -23,6 +23,7 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static uint32_t rgb_buf[20]; +static const uint8_t button_led_map[] = RGB_BUTTON_MAP; #define _MAP_LED(x) _MAKE_MAPPER(x) #define _MAKE_MAPPER(x) MAP_LED_##x @@ -121,28 +122,20 @@ static inline uint32_t apply_level(uint32_t color) return r << 16 | g << 8 | b; } -void rgb_set_color(unsigned index, uint32_t color) +void rgb_set_button_color(unsigned index, uint32_t color) { - if (index >= ARRAY_SIZE(rgb_buf)) { + if (index >= 8) { return; } - rgb_buf[index] = apply_level(color); + rgb_buf[button_led_map[index]] = apply_level(color); } -void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num) +void rgb_set_cab_color(unsigned index, uint32_t color) { - if (index >= ARRAY_SIZE(rgb_buf)) { + if (index >= 0) { return; } - if (index + num > ARRAY_SIZE(rgb_buf)) { - num = ARRAY_SIZE(rgb_buf) - index; - } - for (int i = 0; i < num; i++) { - uint8_t b = brg_array[i * 3 + 0]; - uint8_t r = brg_array[i * 3 + 1]; - uint8_t g = brg_array[i * 3 + 2]; - rgb_buf[index + i] = apply_level(rgb32(r, g, b, false)); - } + rgb_buf[8 + index] = apply_level(color); } void rgb_init() diff --git a/firmware/src/rgb.h b/firmware/src/rgb.h index 508e15e..437940a 100644 --- a/firmware/src/rgb.h +++ b/firmware/src/rgb.h @@ -18,8 +18,8 @@ void rgb_update(); uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix); uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v); -void rgb_set_colors(const uint32_t *colors, unsigned index, size_t num); -void rgb_set_color(unsigned index, uint32_t color); +void rgb_set_button_color(unsigned index, uint32_t color); +void rgb_set_cab_color(unsigned index, uint32_t color); /* num of the rgb leds, num*3 bytes in the array */ void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num); diff --git a/firmware/src/touch.c b/firmware/src/touch.c index a04be4a..1dd3982 100644 --- a/firmware/src/touch.c +++ b/firmware/src/touch.c @@ -22,10 +22,18 @@ #define MPR121_ADDR 0x5A -static uint16_t readout[36]; static uint16_t touch[3]; static unsigned touch_counts[36]; +enum touch_pads { + A1 = 0, A2, A3, A4, A5, A6, A7, A8, + B1, B2, B3, B4, B5, B6, B7, B8, + C1, C2, D1, D2, D3, D4, D5, D6, D7, D8, + E1, E2, E3, E4, E5, E6, E7, E8, +}; + +static unsigned touch_map[] = TOUCH_MAP; + void touch_init() { i2c_init(I2C_PORT, I2C_FREQ); @@ -40,30 +48,57 @@ void touch_init() touch_update_config(); } -void touch_update() +static uint64_t touch_reading; + +static void remap_reading() { - static uint16_t last_touched[3]; - - touch[0] = mpr121_touched(MPR121_ADDR); - touch[1] = mpr121_touched(MPR121_ADDR + 1); - touch[2] = mpr121_touched(MPR121_ADDR + 2); - + uint64_t map = 0; for (int m = 0; m < 3; m++) { - uint16_t just_touched = touch[m] & ~last_touched[m]; - last_touched[m] = touch[m]; for (int i = 0; i < 12; i++) { - if (just_touched & (1 << i)) { - touch_counts[m * 12 + i]++; + if (touch[m] & (1 << i)) { + map |= 1ULL << touch_map[m * 12 + i]; } } } + touch_reading = map; +} + +static void touch_stat() +{ + static uint64_t last_reading; + + uint64_t just_touched = touch_reading & ~last_reading; + last_reading = touch_reading; + + for (int i = 0; i < 34; i++) { + if (just_touched & (1ULL << i)) { + touch_counts[i]++; + } + } +} + +void touch_update() +{ + touch[0] = mpr121_touched(MPR121_ADDR) & 0x0fff; + touch[1] = mpr121_touched(MPR121_ADDR + 1) & 0x0fff; + touch[2] = mpr121_touched(MPR121_ADDR + 2) & 0x0fff; + + remap_reading(); + + touch_stat(); } const uint16_t *touch_raw() { - mpr121_raw(MPR121_ADDR, readout, 12); - mpr121_raw(MPR121_ADDR + 1, readout + 12, 12); - mpr121_raw(MPR121_ADDR + 2, readout + 24, 12); + static uint16_t readout[36]; + uint16_t buf[36]; + mpr121_raw(MPR121_ADDR, buf, 12); + mpr121_raw(MPR121_ADDR + 1, buf + 12, 12); + mpr121_raw(MPR121_ADDR + 2, buf + 24, 10); + + for (int i = 0; i < 34; i++) { + readout[touch_map[i]] = buf[i]; + } return readout; } @@ -72,7 +107,12 @@ bool touch_touched(unsigned key) if (key >= 34) { return 0; } - return touch[key / 12] & (1 << (key % 12)); + return touch_reading & (1ULL << key); +} + +uint64_t touch_touchmap() +{ + return touch_reading; } unsigned touch_count(unsigned key) diff --git a/firmware/src/touch.h b/firmware/src/touch.h index b98719f..129650b 100644 --- a/firmware/src/touch.h +++ b/firmware/src/touch.h @@ -12,10 +12,11 @@ void touch_init(); void touch_update(); bool touch_touched(unsigned key); +uint64_t touch_touchmap(); + const uint16_t *touch_raw(); void touch_update_config(); unsigned touch_count(unsigned key); void touch_reset_stat(); - #endif