From b17ce2efda3ef933290be57f0b68da6320f47040 Mon Sep 17 00:00:00 2001 From: Nicholas G Date: Mon, 26 Jul 2021 11:56:38 -0400 Subject: [PATCH] NKRO Added --- README.md | 15 ++++++++++--- build_uf2/Pico_Game_Controller.uf2 | Bin 71680 -> 71168 bytes src/pico_game_controller.c | 35 ++++++++++------------------- src/tusb_config.h | 2 +- src/usb_descriptors.c | 2 +- src/usb_descriptors.h | 12 ++++++++++ 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2b0e1a6..80bb1a6 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Pico-Game-Controller -WIP code for a rhythm game controller using a Raspberry Pi Pico. Intended for SDVX but is capable of handling 11 buttons, 11 LEDs, and 2 encoders. +WIP code for a rhythm game controller using a Raspberry Pi Pico. Intended for SDVX or IIDX but is capable of handling 11 buttons, 11 LEDs, and 2 encoders. Currently working/fixed: - Gamepad mode - default boot mode -- Keyboard & Mouse Mode - limited to 6KRO - hold btn-a to enter kb mode +- NKRO Keyboard & Mouse Mode - hold first button to enter kb mode - HID LEDs with Reactive LED fallback - sdvx/iidx spoof - Tested on EAC - 1000hz polling @@ -16,7 +16,6 @@ Currently working/fixed: TODO: - Store last mode in flash memory https://www.raspberrypi.org/forums/viewtopic.php?t=305570 -- nkro - debounce - ws2812b rgb on second core? - split input updating into pi pico's second core? @@ -29,3 +28,13 @@ How to Use: - Move pico-sdk back outside to the same level directory as Pico-Game-Controller. - Open Pico-Game-Controller in VSCode(assuming this is setup for the Pi Pico) and see if everything builds. - Tweakable parameters: Pinout, bindings in pico_game_controller.c, USB device reporting as SDVX/IIDX(con_mode) in usb_descriptors.c + +Thanks to: + +- Everyone in the Cons & Stuff Discord for providing near instant support to questions. +- https://github.com/hathach/tinyusb/tree/master/examples/device/hid_composite +- https://github.com/mdxtinkernick/pico_encoders for encoders which performed better than both interrupts and polling. +- My SE buddies who helped come up with a solution for the encoder rollover edge case scenario. +- https://github.com/Drewol/rp2040-gamecon for usb gamepad descriptor info. +- https://github.com/veroxzik/arduino-konami-spoof for konami spoof usb descriptor info. +- https://github.com/veroxzik/roxy-firmware for nkro descriptor and logic info. \ No newline at end of file diff --git a/build_uf2/Pico_Game_Controller.uf2 b/build_uf2/Pico_Game_Controller.uf2 index 1af9ff5f9a2922625418b56970ed114fe7095037..048bd735fc903e2ca9aaf156316dca0f7e6fb074 100644 GIT binary patch delta 10602 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 delta 10765 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 @@ -29,7 +26,7 @@ // MODIFY KEYBINDS HERE, MAKE SURE LENGTHS MATCH SW_GPIO_SIZE const uint8_t SW_KEYCODE[] = {HID_KEY_D, HID_KEY_F, HID_KEY_J, HID_KEY_K, HID_KEY_C, HID_KEY_M, HID_KEY_A, HID_KEY_B, - HID_KEY_1, HID_KEY_C, HID_KEY_D}; + HID_KEY_1, HID_KEY_E, HID_KEY_G}; const uint8_t SW_GPIO[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 27, }; @@ -157,31 +154,23 @@ void key_mode() { if (tud_hid_ready()) { /*------------- Keyboard -------------*/ if (sw_changed) { - bool is_pressed = false; - int keycode_idx = 0; - uint8_t keycode[6] = {0}; // looks like we are limited to 6kro? + uint8_t nkro_report[32] = {0}; for (int i = 0; i < SW_GPIO_SIZE; i++) { if (sw_val[i]) { - // use to avoid send multiple consecutive zero report for keyboard - keycode[keycode_idx] = SW_KEYCODE[i]; - keycode_idx = ++keycode_idx % SW_GPIO_SIZE; - is_pressed = true; + uint8_t bit = SW_KEYCODE[i] % 8; + uint8_t byte = (SW_KEYCODE[i] / 8) + 1; + if (SW_KEYCODE[i] >= 240 && SW_KEYCODE[i] <= 247) { + nkro_report[0] |= (1 << bit); + } else if (byte > 0 && byte <= 31) { + nkro_report[byte] |= (1 << bit); + } prev_sw_val[i] = sw_val[i]; - // Reactive Lighting On - gpio_put(LED_GPIO[i], 1); - } else { - // Reactive Lighting Off - gpio_put(LED_GPIO[i], 0); } } - if (is_pressed) { - // Send key report - tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); - } else { - // Send empty key report if previously has key pressed - tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); - } + // Send key report + tud_hid_n_report(0x00, REPORT_ID_KEYBOARD, &nkro_report, + sizeof(nkro_report)); sw_changed = false; } diff --git a/src/tusb_config.h b/src/tusb_config.h index 071ae69..2c1de22 100644 --- a/src/tusb_config.h +++ b/src/tusb_config.h @@ -103,7 +103,7 @@ extern "C" { #define CFG_TUD_VENDOR 0 // HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE 16 +#define CFG_TUD_HID_EP_BUFSIZE 64 #ifdef __cplusplus } diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index 708b533..a879cf9 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c @@ -76,7 +76,7 @@ uint8_t const* tud_descriptor_device_cb(void) { uint8_t const desc_hid_report[] = { GAMECON_REPORT_DESC_JOYSTICK(HID_REPORT_ID(REPORT_ID_JOYSTICK)), GAMECON_REPORT_DESC_LIGHTS(HID_REPORT_ID(REPORT_ID_LIGHTS)), - TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)), + GAMECON_REPORT_DESC_NKRO(HID_REPORT_ID(REPORT_ID_KEYBOARD)), TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_MOUSE))}; // Invoked when received GET HID REPORT DESCRIPTOR diff --git a/src/usb_descriptors.h b/src/usb_descriptors.h index c09dfba..7b65e53 100644 --- a/src/usb_descriptors.h +++ b/src/usb_descriptors.h @@ -42,3 +42,15 @@ enum { HID_REPORT_COUNT(1), HID_REPORT_SIZE(40), /*Padding*/ \ HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ HID_COLLECTION_END + +// NKRO Descriptor +#define GAMECON_REPORT_DESC_NKRO(...) \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(HID_USAGE_PAGE_KEYBOARD), \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + __VA_ARGS__ HID_REPORT_SIZE(1), HID_REPORT_COUNT(8), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(224), \ + HID_USAGE_MAX(231), HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \ + HID_INPUT(HID_VARIABLE), HID_REPORT_SIZE(1), HID_REPORT_COUNT(31 * 8), \ + HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(0), \ + HID_USAGE_MAX(31 * 8 - 1), HID_INPUT(HID_VARIABLE), HID_COLLECTION_END