From 1ef3c14dfa839eea21942b4628a47934239c023b Mon Sep 17 00:00:00 2001 From: whowechina Date: Fri, 13 Sep 2024 23:18:43 +0800 Subject: [PATCH] IO4 HID --- firmware/src/CMakeLists.txt | 4 +- firmware/src/config.c | 2 +- firmware/src/config.h | 3 +- firmware/src/hid.c | 135 +++++++++++++++++++++++++++++++++ firmware/src/hid.h | 12 +++ firmware/src/main.c | 98 ++---------------------- firmware/src/tusb_config.h | 4 +- firmware/src/usb_descriptors.c | 100 ++++++++---------------- firmware/src/usb_descriptors.h | 133 ++++++++++++++++++++------------ 9 files changed, 279 insertions(+), 212 deletions(-) create mode 100644 firmware/src/hid.c create mode 100644 firmware/src/hid.h diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index ae09b4b..bc4e92a 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 light.c button.c gimbal.c sound.c wad.c vl53l0x.c save.c config.c commands.c - cli.c usb_descriptors.c) + main.c light.c button.c gimbal.c sound.c wad.c vl53l0x.c save.c config.c + commands.c cli.c hid.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/config.c b/firmware/src/config.c index 740cfad..32c520c 100644 --- a/firmware/src/config.c +++ b/firmware/src/config.c @@ -53,7 +53,7 @@ static geki_cfg_t default_cfg = { }, }; -geki_runtime_t *geki_runtime; +geki_runtime_t geki_runtime; static void config_loaded() { diff --git a/firmware/src/config.h b/firmware/src/config.h index 984d17b..0e7a9b8 100644 --- a/firmware/src/config.h +++ b/firmware/src/config.h @@ -44,10 +44,11 @@ typedef struct __attribute__((packed)) { typedef struct { uint16_t fps[2]; + bool key_stuck; } geki_runtime_t; extern geki_cfg_t *geki_cfg; -extern geki_runtime_t *geki_runtime; +extern geki_runtime_t geki_runtime; void config_init(); void config_changed(); // Notify the config has changed diff --git a/firmware/src/hid.c b/firmware/src/hid.c new file mode 100644 index 0000000..6c55984 --- /dev/null +++ b/firmware/src/hid.c @@ -0,0 +1,135 @@ +#include +#include + +#include "board_defs.h" + +#include "tusb.h" +#include "usb_descriptors.h" +#include "button.h" +#include "gimbal.h" +#include "wad.h" +#include "config.h" +#include "hid.h" + +struct __attribute__((packed)) { + uint16_t adcs[8]; + uint16_t spinners[4]; + uint16_t chutes[2]; + uint16_t buttons[2]; + uint8_t system_status; + uint8_t usb_status; + uint8_t padding[29]; +} hid_joy; + +struct __attribute__((packed)) { + uint8_t modifier; + uint8_t keymap[15]; +} hid_nkro; + +const static struct { + uint8_t group; + uint8_t bit; +} button_to_io4_map[] = { + { 0, 0 }, { 0, 5 }, { 0, 4 }, // Left ABC + { 0, 1 }, { 1, 0 }, { 0, 15 }, // Right ABC + { 1, 14 }, { 0, 13 }, // AUX 12 +}, wad_left = { 1, 15 }, wad_right = { 0, 14 }; + + +static void report_usb_hid() +{ + if (tud_hid_ready()) { + if (geki_cfg->hid.joy || geki_runtime.key_stuck) { + hid_joy.adcs[0] = (gimbal_read() - 128) << 8; + + static uint16_t last_buttons = 0; + uint16_t buttons = button_read(); + hid_joy.buttons[0] = 0; + hid_joy.buttons[1] = 0; + for (int i = 0; i < button_num(); i++) { + uint8_t group = button_to_io4_map[i].group; + uint8_t bit = button_to_io4_map[i].bit; + if (buttons & (1 << i)) { + hid_joy.buttons[group] |= (1 << bit); + } + } + if (wad_read_left()) { + hid_joy.buttons[wad_left.group] |= (1 << wad_left.bit); + } + if (wad_read_right()) { + hid_joy.buttons[wad_right.group] |= (1 << wad_right.bit); + } + + if ((last_buttons ^ buttons) & (1 << 11)) { + if (buttons & (1 << 11)) { + // just pressed coin button + hid_joy.chutes[0] += 0x100; + } + } + tud_hid_n_report(0, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); + last_buttons = buttons; + } + if (geki_cfg->hid.nkro && !geki_runtime.key_stuck) { + tud_hid_n_report(1, 0, &hid_nkro, sizeof(hid_nkro)); + } + } +} + +static void gen_nkro_report() +{ + if (!geki_cfg->hid.nkro) { + return; + } + + return; + const char keymap[] = "\x1a\x08\x07\x06\x1b\x1d\x04\x14\x20\x3a\x3b\x3c"; + uint16_t buttons = button_read(); + for (int i = 0; i < button_num(); i++) { + uint8_t code = keymap[i]; + uint8_t byte = code / 8; + uint8_t bit = code % 8; + if (buttons & (1 << i)) { + hid_nkro.keymap[byte] |= (1 << bit); + } else { + hid_nkro.keymap[byte] &= ~(1 << bit); + } + } +} + +void hid_update() +{ + gen_nkro_report(); + report_usb_hid(); +} + +typedef struct __attribute__((packed)) { + uint8_t report_id; + uint8_t cmd; + uint8_t payload[62]; +} hid_output_t; + +void hid_proc(const uint8_t *data, uint8_t len) +{ + hid_output_t *output = (hid_output_t *)data; + if (output->report_id == REPORT_ID_OUTPUT) { + switch (output->cmd) { + case 0x01: // Set Timeout + case 0x02: // Set Sampling Count + hid_joy.system_status = 0x30; + break; + case 0x03: // Clear Board Status + hid_joy.chutes[0] = 0; + hid_joy.chutes[1] = 0; + hid_joy.system_status = 0x00; + break; + case 0x04: // Set General Output + // LED + break; + case 0x41: // I don't know what this is + break; + default: + printf("USB unknown cmd: %d\n", output->cmd); + break; + } + } +} diff --git a/firmware/src/hid.h b/firmware/src/hid.h new file mode 100644 index 0000000..ea175f0 --- /dev/null +++ b/firmware/src/hid.h @@ -0,0 +1,12 @@ +/* + * HID Report Functions + * WHowe + */ + +#ifndef HID_H_ +#define HID_H_ + +void hid_update(); +void hid_proc(const uint8_t *data, uint8_t len); + +#endif diff --git a/firmware/src/main.c b/firmware/src/main.c index b46d2c9..7677d99 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -28,92 +28,14 @@ #include "cli.h" #include "commands.h" +#include "hid.h" + #include "light.h" #include "button.h" #include "gimbal.h" #include "wad.h" #include "sound.h" -struct __attribute__((packed)) { - uint16_t buttons; - uint8_t HAT; - uint8_t lx; - uint8_t ly; - uint8_t rx; - uint8_t ry; - uint8_t vendor; -} hid_joy; - -struct __attribute__((packed)) { - uint8_t modifier; - uint8_t keymap[15]; -} hid_nkro, sent_hid_nkro; - -void report_usb_hid() -{ - if (tud_hid_ready()) { - hid_joy.HAT = 0x08; - hid_joy.vendor = 0; - if (geki_cfg->hid.joy) { - tud_hid_n_report(0x00, 0, &hid_joy, sizeof(hid_joy)); - } - if (geki_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)); - } - } -} - -#define SWITCH_BIT_Y (1U << 0) -#define SWITCH_BIT_B (1U << 1) -#define SWITCH_BIT_A (1U << 2) -#define SWITCH_BIT_X (1U << 3) -#define SWITCH_BIT_L (1U << 4) -#define SWITCH_BIT_R (1U << 5) -#define SWITCH_BIT_ZL (1U << 6) -#define SWITCH_BIT_ZR (1U << 7) -#define SWITCH_BIT_MINUS (1U << 8) -#define SWITCH_BIT_PLUS (1U << 9) -#define SWITCH_BIT_L3 (1U << 10) -#define SWITCH_BIT_R3 (1U << 11) -#define SWITCH_BIT_HOME (1U << 12) - -static void gen_joy_report() -{ - hid_joy.lx = gimbal_read(); - - uint16_t button = button_read(); - hid_joy.buttons = 0; - hid_joy.buttons |= (button & 0x01) ? SWITCH_BIT_L : 0; - hid_joy.buttons |= (button & 0x02) ? SWITCH_BIT_R : 0; - if (button & 0x08) { - hid_joy.buttons |= (button & 0x04) ? SWITCH_BIT_MINUS : 0; - hid_joy.buttons |= (button & 0x10) ? SWITCH_BIT_PLUS : 0; - } else { - hid_joy.buttons |= (button & 0x04) ? SWITCH_BIT_B : 0; - hid_joy.buttons |= (button & 0x10) ? SWITCH_BIT_A : 0; - } -} - -const uint8_t keycode_table[128][2] = { HID_ASCII_TO_KEYCODE }; -const uint8_t keymap[38 + 1] = NKRO_KEYMAP; // 32 keys, 6 air keys, 1 terminator -static void gen_nkro_report() -{ - 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)) { - hid_nkro.keymap[byte] |= (1 << bit); - } else { - hid_nkro.keymap[byte] &= ~(1 << bit); - } - } -} - -static uint64_t last_hid_time = 0; - static void run_lights() { int gimbal = gimbal_read(); @@ -173,8 +95,8 @@ static void run_lights() static void run_sound() { - sound_set(0, wad_read_left()); - sound_set(1, wad_read_right()); + //sound_set(0, wad_read_left()); + //sound_set(1, wad_read_right()); } static mutex_t core1_io_lock; @@ -204,10 +126,9 @@ static void core0_loop() button_update(); wad_update(); - gen_joy_report(); - gen_nkro_report(); - report_usb_hid(); - + + hid_update(); + sleep_us(900); } } @@ -295,8 +216,5 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { - if (report_type == HID_REPORT_TYPE_OUTPUT) { - last_hid_time = time_us_64(); - return; - } + hid_proc(buffer, bufsize); } diff --git a/firmware/src/tusb_config.h b/firmware/src/tusb_config.h index 7ef973c..c2a4dc0 100644 --- a/firmware/src/tusb_config.h +++ b/firmware/src/tusb_config.h @@ -96,8 +96,8 @@ extern "C" { #endif //------------- CLASS -------------// -#define CFG_TUD_HID 3 -#define CFG_TUD_CDC 1 +#define CFG_TUD_HID 2 +#define CFG_TUD_CDC 2 #define CFG_TUD_MSC 0 #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0 diff --git a/firmware/src/usb_descriptors.c b/firmware/src/usb_descriptors.c index 7379f26..5830f38 100644 --- a/firmware/src/usb_descriptors.c +++ b/firmware/src/usb_descriptors.c @@ -24,24 +24,9 @@ */ #include "usb_descriptors.h" - +#include "pico/unique_id.h" #include "tusb.h" -/* A combination of interfaces must have a unique product id, since PC will save - * device driver after the first plug. Same VID/PID with different interface e.g - * MSC (first), then CDC (later) will possibly cause system error on PC. - * - * Auto ProductID layout's Bitmap: - * [MSB] HID | MSC | CDC [LSB] - */ -#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) -#define USB_PID \ - (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ - _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4)) - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ tusb_desc_device_t desc_device_joy = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, @@ -51,8 +36,8 @@ tusb_desc_device_t desc_device_joy = { .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0x0f0d, - .idProduct = 0x0092, + .idVendor = 0x0ca3, + .idProduct = 0x0021, .bcdDevice = 0x0100, .iManufacturer = 1, @@ -76,11 +61,6 @@ uint8_t const desc_hid_report_joy[] = { GEKI_PICO_REPORT_DESC_JOYSTICK, }; -uint8_t const desc_hid_report_led[] = { - GEKI_PICO_LED_HEADER, - GEKI_PICO_LED_FOOTER -}; - uint8_t const desc_hid_report_nkro[] = { GEKI_PICO_REPORT_DESC_NKRO, }; @@ -94,8 +74,6 @@ uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) case 0: return desc_hid_report_joy; case 1: - return desc_hid_report_led; - case 2: return desc_hid_report_nkro; default: return NULL; @@ -105,20 +83,19 @@ uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) // Configuration Descriptor //--------------------------------------------------------------------+ -enum { ITF_NUM_JOY, ITF_NUM_LED, ITF_NUM_NKRO, - ITF_NUM_CLI, ITF_NUM_CLI_DATA, +enum { ITF_NUM_JOY, ITF_NUM_NKRO, + ITF_NUM_CLI, ITF_NUM_CLI_DATA, ITF_NUM_AIME, ITF_NUM_AIME_DATA, ITF_NUM_TOTAL }; #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \ TUD_HID_INOUT_DESC_LEN * 1 + \ - TUD_HID_DESC_LEN * 2 + \ - TUD_CDC_DESC_LEN * 1) + TUD_HID_DESC_LEN * 1 + \ + TUD_CDC_DESC_LEN * 2) #define EPNUM_JOY_OUT 0x01 #define EPNUM_JOY_IN 0x81 -#define EPNUM_LED 0x86 -#define EPNUM_KEY 0x87 +#define EPNUM_NKRO 0x87 #define EPNUM_CLI_NOTIF 0x89 #define EPNUM_CLI_OUT 0x0a @@ -140,16 +117,16 @@ uint8_t const desc_configuration_joy[] = { sizeof(desc_hid_report_joy), EPNUM_JOY_OUT, EPNUM_JOY_IN, CFG_TUD_HID_EP_BUFSIZE, 1), - TUD_HID_DESCRIPTOR(ITF_NUM_LED, 5, HID_ITF_PROTOCOL_NONE, - sizeof(desc_hid_report_led), EPNUM_LED, - CFG_TUD_HID_EP_BUFSIZE, 4), - - TUD_HID_DESCRIPTOR(ITF_NUM_NKRO, 6, HID_ITF_PROTOCOL_NONE, - sizeof(desc_hid_report_nkro), EPNUM_KEY, + TUD_HID_DESCRIPTOR(ITF_NUM_NKRO, 5, HID_ITF_PROTOCOL_NONE, + sizeof(desc_hid_report_nkro), EPNUM_NKRO, CFG_TUD_HID_EP_BUFSIZE, 1), - TUD_CDC_DESCRIPTOR(ITF_NUM_CLI, 7, EPNUM_CLI_NOTIF, + TUD_CDC_DESCRIPTOR(ITF_NUM_CLI, 6, EPNUM_CLI_NOTIF, 8, EPNUM_CLI_OUT, EPNUM_CLI_IN, 64), + + TUD_CDC_DESCRIPTOR(ITF_NUM_AIME, 7, EPNUM_AIME_NOTIF, + 8, EPNUM_AIME_OUT, EPNUM_AIME_IN, 64), + }; // Invoked when received GET CONFIGURATION DESCRIPTOR @@ -162,17 +139,17 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { //--------------------------------------------------------------------+ // String Descriptors //--------------------------------------------------------------------+ +static char serial_number_str[24] = "123456\0"; -// array of pointer to string descriptors -const char *string_desc_arr[] = { +static const char *string_desc_arr[] = { (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) - "WHowe", // 1: Manufacturer - "Geki Pico Controller", // 2: Product - "123456", // 3: Serial - "Geki Pico Joystick", - "Geki Pico LED", + "SEGA", // 1: Manufacturer + "Geki Pico", // 2: Product + serial_number_str, // 3: Serials, use chip ID + "I/O CONTROL BD;15257;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;", "Geki Pico NKRO", - "Geki Pico CLI Port", + "Geki Pico CLI", + "Mai Pico AIME Port", }; // Invoked when received GET STRING DESCRIPTOR request @@ -180,39 +157,24 @@ const char *string_desc_arr[] = { // enough for transfer to complete uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - static uint16_t _desc_str[64]; + static uint16_t _desc_str[128]; if (index == 0) { memcpy(&_desc_str[1], string_desc_arr[0], 2); _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 + 2); return _desc_str; } - - const size_t base_num = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]); - const char *colors[] = {"Blue", "Red", "Green"}; - char str[64]; - if (index < base_num) { - strcpy(str, string_desc_arr[index]); - } else if (index < base_num + 48 + 45) { - const char *names[] = {"Key ", "Splitter "}; - int led = index - base_num; - int id = led / 6 + 1; - int type = led / 3 % 2; - int brg = led % 3; - sprintf(str, "%s%02d %s", names[type], id, colors[brg]); - } else if (index < base_num + 48 + 45 + 18) { - int led = index - base_num - 48 - 45; - int id = led / 3 + 1; - int brg = led % 3; - sprintf(str, "Tower %02d %s", id, colors[brg]); - } else { - sprintf(str, "Unknown %d", index); + if (index == 3) { + pico_unique_board_id_t board_id; + pico_get_unique_board_id(&board_id); + sprintf(serial_number_str, "%016llx", *(uint64_t *)&board_id); } + const char *str = string_desc_arr[index]; uint8_t chr_count = strlen(str); - if (chr_count > 63) { - chr_count = 63; + if (chr_count > count_of(_desc_str)) { + chr_count = count_of(_desc_str); } // Convert ASCII string into UTF-16 diff --git a/firmware/src/usb_descriptors.h b/firmware/src/usb_descriptors.h index 63b9bf4..e623f7c 100644 --- a/firmware/src/usb_descriptors.h +++ b/firmware/src/usb_descriptors.h @@ -6,10 +6,7 @@ enum { REPORT_ID_JOYSTICK = 1, - REPORT_ID_LED_SLIDER_16 = 4, - REPORT_ID_LED_SLIDER_15 = 5, - REPORT_ID_LED_TOWER_6 = 6, - REPORT_ID_LED_COMPRESSED = 11, + REPORT_ID_OUTPUT = 16, }; // because they are missing from tusb_hid.h @@ -20,57 +17,99 @@ enum { #define HID_STRING_MAXIMUM(x) HID_REPORT_ITEM(x, 9, RI_TYPE_LOCAL, 1) #define HID_STRING_MAXIMUM_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_LOCAL, n) -// Joystick Report Descriptor Template - Based off Drewol/rp2040-gamecon -// Button Map | X | Y -//HID_REPORT_ID(REPORT_ID_JOYSTICK) - -#define GEKI_PICO_REPORT_DESC_JOYSTICK \ +// Joystick Report Descriptor to Emulate IO4 +#define GEKI_PICO_REPORT_DESC_JOYSTICK \ HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_USAGE(HID_USAGE_DESKTOP_GAMEPAD), \ + HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \ HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \ - HID_PHYSICAL_MIN(0), HID_PHYSICAL_MAX(1), \ - HID_REPORT_SIZE(1), HID_REPORT_COUNT(16), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(16), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_REPORT_ID(REPORT_ID_JOYSTICK) \ \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_LOGICAL_MAX(7), \ - HID_PHYSICAL_MAX_N(315, 2), \ - HID_REPORT_SIZE(4), HID_REPORT_COUNT(1), \ - 0x65, 0x14, /* Unit */ \ - HID_USAGE(HID_USAGE_DESKTOP_HAT_SWITCH), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE | HID_NO_NULL_POSITION),\ - 0x65, 0x00, /* Unit None */ \ - HID_REPORT_COUNT(1), \ - HID_INPUT(HID_CONSTANT | HID_ARRAY | HID_ABSOLUTE), \ - \ - HID_LOGICAL_MAX_N(0xff, 2), HID_PHYSICAL_MAX_N(0xff, 2), /* Analog */ \ - HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \ - HID_USAGE(HID_USAGE_DESKTOP_Z), HID_USAGE(HID_USAGE_DESKTOP_RZ), \ - HID_REPORT_SIZE(8), HID_REPORT_COUNT(4), \ + HID_USAGE(HID_USAGE_DESKTOP_X), \ HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ \ - HID_USAGE_PAGE_N(HID_USAGE_PAGE_VENDOR, 2), \ - HID_USAGE(0x20), \ - HID_REPORT_COUNT(1), \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_Y), \ HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ \ - HID_USAGE_N(0x2621, 2), \ - HID_REPORT_COUNT(8), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END - -//HID_USAGE_PAGE_N(9761, 2), HID_REPORT_COUNT(8), HID_OUTPUT(2), - -#define GEKI_PICO_LED_HEADER \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \ - HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE) - -#define GEKI_PICO_LED_FOOTER \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_X), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_Y), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_X), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_Y), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_X), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_Y), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_RX), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_RY), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_RX), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_RY), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_SLIDER), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(16), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_SLIDER), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(48), HID_REPORT_SIZE(1), \ + HID_USAGE_MIN_N(1, 2), HID_USAGE_MAX_N(48, 2), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + \ + HID_REPORT_COUNT(1), HID_REPORT_SIZE(232), \ + HID_INPUT(HID_CONSTANT | HID_ABSOLUTE), \ + \ + HID_USAGE_PAGE_N(0xffa0, 2), \ + HID_USAGE(0x00), \ + HID_REPORT_ID(REPORT_ID_OUTPUT) \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + HID_USAGE(0x00), \ + HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(255), \ + HID_REPORT_COUNT(63), HID_REPORT_SIZE(8), \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_COLLECTION_END, \ HID_COLLECTION_END #define GEKI_PICO_REPORT_DESC_NKRO \