diff --git a/Production/Firmware/chu_pico.uf2 b/Production/Firmware/chu_pico.uf2 new file mode 100644 index 0000000..4bf1518 Binary files /dev/null and b/Production/Firmware/chu_pico.uf2 differ diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index 15e048c..3b6316f 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 usb_descriptors.c) + main.c slider.c air.c rgb.c save.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/air.c b/firmware/src/air.c index 09e5c38..6595ead 100644 --- a/firmware/src/air.c +++ b/firmware/src/air.c @@ -21,6 +21,10 @@ static const uint8_t TOF_LIST[] = TOF_MUX_LIST; static uint16_t distances[sizeof(TOF_LIST)]; +const int offset_a = 800; +const int offset_b = 1000; +const int pitch = 200; + void air_init() { i2c_init(TOF_I2C, 400 * 1000); @@ -46,14 +50,45 @@ size_t air_num() return sizeof(TOF_LIST); } -uint16_t air_value(uint8_t index) +static inline uint8_t air_bits(int dist, int offset) +{ + if (dist < offset) { + return 0; + } + int index = (dist - offset) / pitch; + if (index >= 6) { + return 0; + } + + return 1 << index; +} + +uint8_t air_bitmap() +{ + uint8_t bitmap = 0; + for (int i = 0; i < sizeof(TOF_LIST); i++) { + bitmap |= air_bits(distances[i], offset_a); + bitmap |= air_bits(distances[i], offset_b); + } + return bitmap; +} + +unsigned air_value(uint8_t index) { if (index >= sizeof(TOF_LIST)) { return 0; } - uint16_t dist = distances[index] >> 6; - return dist < 63 ? dist : 0; + uint8_t bitmap = air_bits(distances[index], offset_a) | + air_bits(distances[index], offset_b); + + for (int i = 0; i < 6; i++) { + if (bitmap & (1 << i)) { + return i + 1; + } + } + + return 0; } void air_update() diff --git a/firmware/src/air.h b/firmware/src/air.h index 4f32628..748bdd2 100644 --- a/firmware/src/air.h +++ b/firmware/src/air.h @@ -11,7 +11,8 @@ void air_init(); size_t air_num(); -uint16_t air_value(uint8_t index); +unsigned air_value(uint8_t index); +uint8_t air_bitmap(); void air_update(); #endif diff --git a/firmware/src/lzfx.c b/firmware/src/lzfx.c new file mode 100644 index 0000000..63dddeb --- /dev/null +++ b/firmware/src/lzfx.c @@ -0,0 +1,169 @@ +/* + * Lzfx decompressor + * WHowe + * This is actually taken from CrazyRedMachine's repo + * + */ + + +#include +#include "lzfx.h" + +typedef unsigned char u8; +typedef const u8 *LZSTATE[LZFX_HSIZE]; + + +/* Guess len. No parameters may be NULL; this is not checked. */ +static int lzfx_getsize(const void *ibuf, unsigned int ilen, unsigned int *olen) +{ + + u8 const *ip = (const u8 *)ibuf; + u8 const *const in_end = ip + ilen; + int tot_len = 0; + + while (ip < in_end) + { + + unsigned int ctrl = *ip++; + + if (ctrl < (1 << 5)) + { + + ctrl++; + + if (ip + ctrl > in_end) + return LZFX_ECORRUPT; + + tot_len += ctrl; + ip += ctrl; + } + else + { + + unsigned int len = (ctrl >> 5); + + if (len == 7) + { /* i.e. format #2 */ + len += *ip++; + } + + len += 2; /* len is now #octets */ + + if (ip >= in_end) + return LZFX_ECORRUPT; + + ip++; /* skip the ref byte */ + + tot_len += len; + } + } + + *olen = tot_len; + + return 0; +} + +/* Decompressor */ +int lzfx_decompress(const void *ibuf, unsigned int ilen, + void *obuf, unsigned int *olen) +{ + + u8 const *ip = (const u8 *)ibuf; + u8 const *const in_end = ip + ilen; + u8 *op = (u8 *)obuf; + u8 const *const out_end = (olen == NULL ? NULL : op + *olen); + + unsigned int remain_len = 0; + int rc; + + if (olen == NULL) + return LZFX_EARGS; + if (ibuf == NULL) + { + if (ilen != 0) + return LZFX_EARGS; + *olen = 0; + return 0; + } + if (obuf == NULL) + { + if (olen != 0) + return LZFX_EARGS; + return lzfx_getsize(ibuf, ilen, olen); + } + + do + { + unsigned int ctrl = *ip++; + + /* Format 000LLLLL: a literal byte string follows, of length L+1 */ + if (ctrl < (1 << 5)) + { + + ctrl++; + + if (fx_expect_false(op + ctrl > out_end)) + { + --ip; /* Rewind to control byte */ + goto guess; + } + if (fx_expect_false(ip + ctrl > in_end)) + return LZFX_ECORRUPT; + + do + *op++ = *ip++; + while (--ctrl); + + /* Format #1 [LLLooooo oooooooo]: backref of length L+1+2 + ^^^^^ ^^^^^^^^ + A B + #2 [111ooooo LLLLLLLL oooooooo] backref of length L+7+2 + ^^^^^ ^^^^^^^^ + A B + In both cases the location of the backref is computed from the + remaining part of the data as follows: + + location = op - A*256 - B - 1 + */ + } + else + { + + unsigned int len = (ctrl >> 5); + u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; + + if (len == 7) + len += *ip++; /* i.e. format #2 */ + + len += 2; /* len is now #octets */ + + if (fx_expect_false(op + len > out_end)) + { + ip -= (len >= 9) ? 2 : 1; /* Rewind to control byte */ + goto guess; + } + if (fx_expect_false(ip >= in_end)) + return LZFX_ECORRUPT; + + ref -= *ip++; + + if (fx_expect_false(ref < (u8 *)obuf)) + return LZFX_ECORRUPT; + + do + *op++ = *ref++; + while (--len); + } + + } while (ip < in_end); + + *olen = op - (u8 *)obuf; + + return 0; + +guess: + rc = lzfx_getsize(ip, ilen - (ip - (u8 *)ibuf), &remain_len); + if (rc >= 0) + *olen = remain_len + (op - (u8 *)obuf); + return rc; +} diff --git a/firmware/src/lzfx.h b/firmware/src/lzfx.h new file mode 100644 index 0000000..761f624 --- /dev/null +++ b/firmware/src/lzfx.h @@ -0,0 +1,18 @@ +/* + * Lzfx decompressor + * WHowe + * This is actually taken from CrazyRedMachine's repo + * + */ + +#define LZFX_ESIZE -1 /* Output buffer too small */ +#define LZFX_ECORRUPT -2 /* Invalid data for decompression */ +#define LZFX_EARGS -3 /* Arguments invalid (NULL) */ +#define LZFX_HLOG 16 +#define LZFX_HSIZE (1 << (LZFX_HLOG)) + +#define fx_expect_false(expr) (expr) +#define fx_expect_true(expr) (expr) + +int lzfx_decompress(const void* ibuf, unsigned int ilen, + void* obuf, unsigned int *olen); \ No newline at end of file diff --git a/firmware/src/main.c b/firmware/src/main.c index c453445..d94fcc8 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -7,10 +7,11 @@ #include #include +#include "pico/stdio.h" +#include "pico/stdlib.h" #include "bsp/board.h" #include "pico/multicore.h" #include "pico/bootrom.h" -#include "pico/stdio.h" #include "hardware/gpio.h" #include "hardware/sync.h" @@ -23,6 +24,7 @@ #include "slider.h" #include "air.h" #include "rgb.h" +#include "lzfx.h" /* Measure the time of a function call */ #define RUN_TIME(func) \ @@ -39,7 +41,6 @@ struct __attribute__((packed)) { void report_usb_hid() { if (tud_hid_ready()) { - hid_joy.buttons = 0; hid_joy.HAT = 0; hid_joy.VendorSpec = 0; tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy)); @@ -56,32 +57,72 @@ static void pause_core1(bool pause) } } -static void fps_count() +static int fps[2] = {0}; + +static int get_fps(int core) { - static uint64_t last = 0; - static int fps_counter = 0; + return fps[core]; +} - fps_counter++; +static void fps_count(int core) +{ + static uint32_t last[2] = {0}; + static int counter[2] = {0}; - uint64_t now = time_us_64(); - if (now - last < 1000000) { + 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\n", fps_counter); - fps_counter = 0; + printf("FPS: %d %d\n", get_fps(0), get_fps(1)); } -static void core1_loop() +static void gen_hid_report() { - while (1) { - rgb_update(); - sleep_ms(1); + hid_joy.axis = 0; + for (int i = 0; i < 16; i++) { + if (slider_touched(i * 2)) { + hid_joy.axis |= 1 << (30 - i * 2); + } + if (slider_touched(i * 2 + 1)) { + hid_joy.axis |= 1 << (31 - i * 2); + } + } + hid_joy.axis ^= 0x80808080; // some magic number from CrazyRedMachine + hid_joy.buttons = air_bitmap(); } -static void core0_loop() +static uint64_t last_hid_time = 0; + +static void run_lights() { + uint64_t now = time_us_64(); + if (now - last_hid_time < 1000000) { + return; + } + + const uint32_t colors[] = {0x000000, 0x0000ff, 0xff0000, 0xffff00, + 0x00ff00, 0x00ffff, 0xffffff}; + for (int i = 0; i < air_num(); i++) { + int d = air_value(i); + rgb_set_color(31 + i, colors[d]); + } + for (int i = 0; i < 15; i++) { int x = 15 - i; uint8_t r = (x & 0x01) ? 10 : 0; @@ -90,50 +131,44 @@ static void core0_loop() rgb_gap_color(i, rgb32(r, g, b, false)); } + for (int i = 0; i < 16; i++) { + bool r = slider_touched(i * 2); + bool g = slider_touched(i * 2 + 1); + rgb_set_color(30 - i * 2, rgb32(r ? 80 : 0, g ? 80 : 0, 0, false)); + } +} + +static void core1_loop() +{ + while (1) { + rgb_update(); + fps_count(1); + sleep_ms(1); + } +} + +static void core0_loop() +{ while(1) { tud_task(); - report_usb_hid(); slider_update(); air_update(); -#if 0 - static uint16_t old_touch = 0; - uint16_t touch = slider_hw_touch(0); - if (touch != old_touch) { - printf("Touch: %04x\n", touch); - old_touch = touch; - } -#endif - hid_joy.axis = 0; - for (int i = 0; i < 16; i++) { - bool k1 = slider_touched(i * 2); - bool k2 = slider_touched(i * 2 + 1); + gen_hid_report(); + report_usb_hid(); - if (k1) { - hid_joy.axis |= 1 << (30 - i * 2); - } - if (k2) { - hid_joy.axis |= 1 << (31 - i * 2); - } - - uint8_t r = k1 ? 255 : 0; - uint8_t g = k2 ? 255 : 0; - rgb_key_color(i, rgb32(r, g, g, false)); - } - hid_joy.axis ^= 0x80808080; // some magic number from CrazyRedMachine - for (int i = 0; i < air_num(); i++) { - uint8_t v = air_value(i) << 2; - rgb_set_color(31 + i, rgb32(v, v, v, false)); - } + run_lights(); slider_update_baseline(); - fps_count(); + fps_count(0); + print_fps(); } } void init() { sleep_ms(200); +// set_sys_clock_khz(166000, true); board_init(); tusb_init(); stdio_init_all(); @@ -168,14 +203,26 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, uint16_t bufsize) { if (report_type == HID_REPORT_TYPE_OUTPUT) { - if (report_id == REPORT_ID_LED_SLIDER_15) { - printf("Slider 16: %d\n", bufsize); - } else if (report_id == REPORT_ID_LED_SLIDER_16) { - printf("Slider 15: %d\n", bufsize); + if (report_id == REPORT_ID_LED_SLIDER_16) { + rgb_set_brg(0, buffer, bufsize / 3); + } else if (report_id == REPORT_ID_LED_SLIDER_15) { + rgb_set_brg(16, buffer, bufsize / 3); } else if (report_id == REPORT_ID_LED_TOWER_6) { - printf("Tower 6: %d\n", bufsize); - } else { - printf("Report: %d - %d\n", report_id, bufsize); + rgb_set_brg(31, buffer, bufsize / 3); } + last_hid_time = time_us_64(); + return; + } + + if (report_type == HID_REPORT_TYPE_FEATURE) { + if (report_id == REPORT_ID_LED_COMPRESSED) { + uint8_t buf[(48 + 45 + 6) * 3]; + unsigned int olen = sizeof(buf); + if (lzfx_decompress(buffer + 1, buffer[0], buf, &olen) == 0) { + rgb_set_brg(0, buf, olen / 3); + } + } + last_hid_time = time_us_64(); + return; } } diff --git a/firmware/src/rgb.c b/firmware/src/rgb.c index 6720c79..987324c 100644 --- a/firmware/src/rgb.c +++ b/firmware/src/rgb.c @@ -22,7 +22,7 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -static uint32_t rgb_buf[48]; // 32 + 16(maximum) ToF indicators +static uint32_t rgb_buf[47]; // 16(Keys) + 15(Gaps) + 16(maximum ToF indicators) #define _MAP_LED(x) _MAKE_MAPPER(x) #define _MAKE_MAPPER(x) MAP_LED_##x @@ -61,7 +61,10 @@ static void drive_led() } last = now; - for (int i = 0; i < ARRAY_SIZE(rgb_buf); i++) { + for (int i = 30; i >= 0; i--) { + pio_sm_put_blocking(pio0, 0, rgb_buf[i] << 8u); + } + for (int i = 31; i < ARRAY_SIZE(rgb_buf); i++) { pio_sm_put_blocking(pio0, 0, rgb_buf[i] << 8u); } } @@ -101,6 +104,22 @@ void rgb_gap_color(unsigned index, uint32_t color) rgb_buf[index * 2 + 1] = color; } +void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num) +{ + if (index >= ARRAY_SIZE(rgb_buf)) { + 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] = rgb32(r, g, b, false); + } +} + void rgb_init() { diff --git a/firmware/src/rgb.h b/firmware/src/rgb.h index 67c2568..903cca0 100644 --- a/firmware/src/rgb.h +++ b/firmware/src/rgb.h @@ -22,4 +22,7 @@ void rgb_set_color(unsigned index, uint32_t color); void rgb_key_color(unsigned index, uint32_t color); void rgb_gap_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); + #endif diff --git a/firmware/src/slider.c b/firmware/src/slider.c index 8aaf396..e8f6288 100644 --- a/firmware/src/slider.c +++ b/firmware/src/slider.c @@ -90,7 +90,6 @@ void slider_update() void slider_update_baseline() { static int iteration = 0; - iteration++; for (int i = 0; i < 32; i++) { int16_t delta = readout[i] - baseline[i]; @@ -100,21 +99,18 @@ void slider_update_baseline() error[i] += delta; } + iteration++; if (iteration > 100) { iteration = 0; for (int i = 0; i < 32; i++) { if (error[i] > 100) { baseline[i] ++; - printf("+"); } else if (error[i] < -100) { baseline[i] --; - printf("-"); } else { - printf(" "); } error[i] = 0; } - printf("\n"); } } diff --git a/firmware/src/usb_descriptors.c b/firmware/src/usb_descriptors.c index f9ba2ef..47d20da 100644 --- a/firmware/src/usb_descriptors.c +++ b/firmware/src/usb_descriptors.c @@ -36,8 +36,8 @@ */ #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)) + (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4)) //--------------------------------------------------------------------+ // Device Descriptors @@ -67,7 +67,7 @@ tusb_desc_device_t desc_device_joy = { // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor uint8_t const* tud_descriptor_device_cb(void) { - return (uint8_t const*)&desc_device_joy; + return (uint8_t const*)&desc_device_joy; } //--------------------------------------------------------------------+ @@ -75,15 +75,17 @@ uint8_t const* tud_descriptor_device_cb(void) { //--------------------------------------------------------------------+ uint8_t const desc_hid_report_joy[] = { - GAMECON_REPORT_DESC_JOYSTICK(HID_REPORT_ID(REPORT_ID_JOYSTICK)), + GAMECON_REPORT_DESC_JOYSTICK, }; uint8_t const desc_hid_report_led[] = { - GAMECON_REPORT_DESC_LED_SLIDER_16(HID_REPORT_ID(REPORT_ID_LED_SLIDER_16)), - GAMECON_REPORT_DESC_LED_SLIDER_15(HID_REPORT_ID(REPORT_ID_LED_SLIDER_15)), - GAMECON_REPORT_DESC_LED_TOWER_6(HID_REPORT_ID(REPORT_ID_LED_TOWER_6)), - GAMECON_REPORT_DESC_LED_COMPRESSED(HID_REPORT_ID(REPORT_ID_LED_COMPRESSED)), + GAMECON_LED_HEADER, + GAMECON_REPORT_DESC_LED_SLIDER_16, + GAMECON_REPORT_DESC_LED_SLIDER_15, + GAMECON_REPORT_DESC_LED_TOWER_6, + GAMECON_REPORT_DESC_LED_COMPRESSED, + GAMECON_LED_FOOTER }; // Invoked when received GET HID REPORT DESCRIPTOR @@ -128,19 +130,18 @@ uint8_t const desc_configuration_joy[] = { TUD_HID_DESCRIPTOR(ITF_NUM_LED, 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report_led), EPNUM_LED, - CFG_TUD_HID_EP_BUFSIZE, 1), + CFG_TUD_HID_EP_BUFSIZE, 4), TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 6, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64) - }; +}; // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { - (void)index; // for multiple configurations - return desc_configuration_joy; + return desc_configuration_joy; } //--------------------------------------------------------------------+ @@ -153,47 +154,58 @@ const char *string_desc_arr[] = { "WHowe" , // 1: Manufacturer "Chu Pico Controller", // 2: Product "123456", // 3: Serials, should use chip ID - "Joystick Interface", - "LED Interface", - "Serial Port", + "Chu Pico Joystick", + "Chu Pico LED", + "Chu Pico Serial Port", }; -static uint16_t _desc_str[64]; - // Invoked when received GET STRING DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long // enough for transfer to complete -uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void)langid; +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + static uint16_t _desc_str[64]; - uint8_t chr_count; - - if (index == 0) { - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - } else { - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if (index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) { - const char* str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - if (chr_count > 63) chr_count = 63; - - // Convert ASCII string into UTF-16 - for (uint8_t i = 0; i < chr_count; i++) { - _desc_str[1 + i] = str[i]; - } - } else { - _desc_str[1] = 'X'; - chr_count = 1; + 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]; - // first byte is length (including header), second byte is string type - _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); + 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); + } - return _desc_str; + uint8_t chr_count = strlen(str); + if (chr_count > 63) { + chr_count = 63; + } + + // Convert ASCII string into UTF-16 + for (uint8_t i = 0; i < chr_count; i++) { + _desc_str[1 + i] = str[i]; + } + + // first byte is length (including header), second byte is string type + _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); + + return _desc_str; } diff --git a/firmware/src/usb_descriptors.h b/firmware/src/usb_descriptors.h index 591e024..9e82075 100644 --- a/firmware/src/usb_descriptors.h +++ b/firmware/src/usb_descriptors.h @@ -5,11 +5,11 @@ #include "device/usbd.h" 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_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, }; // because they are missing from tusb_hid.h @@ -22,94 +22,89 @@ enum { // Joystick Report Descriptor Template - Based off Drewol/rp2040-gamecon // Button Map | X | Y -#define GAMECON_REPORT_DESC_JOYSTICK(...) \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - __VA_ARGS__ HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(16), \ - HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \ - HID_REPORT_COUNT(16), HID_REPORT_SIZE(1), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ +#define GAMECON_REPORT_DESC_JOYSTICK \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + HID_REPORT_ID(REPORT_ID_JOYSTICK) \ + HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), \ + HID_USAGE_MIN(1), HID_USAGE_MAX(16), \ + HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \ + HID_REPORT_COUNT(16), HID_REPORT_SIZE(1), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_USAGE(HID_USAGE_DESKTOP_HAT_SWITCH), \ - HID_LOGICAL_MIN(1), HID_LOGICAL_MAX(8), \ - HID_PHYSICAL_MIN(0), HID_PHYSICAL_MAX_N(315, 2), \ - HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_HAT_SWITCH), \ + HID_LOGICAL_MIN(1), HID_LOGICAL_MAX(8), \ + HID_PHYSICAL_MIN(0), HID_PHYSICAL_MAX_N(315, 2), \ + HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \ - HID_USAGE(HID_USAGE_DESKTOP_Z), HID_USAGE(HID_USAGE_DESKTOP_RX), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), /* Analog */ \ - HID_REPORT_SIZE(8), HID_REPORT_COUNT(4), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \ + HID_USAGE(HID_USAGE_DESKTOP_Z), HID_USAGE(HID_USAGE_DESKTOP_RX), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), /* Analog */ \ + HID_REPORT_SIZE(8), HID_REPORT_COUNT(4), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ \ - HID_USAGE_PAGE_N(HID_USAGE_PAGE_VENDOR, 2), \ - HID_USAGE(0), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), \ - HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - \ - HID_COLLECTION_END + HID_USAGE_PAGE_N(HID_USAGE_PAGE_VENDOR, 2), \ + HID_USAGE(0), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), \ + HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_COLLECTION_END + +#define GAMECON_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 GAMECON_LED_FOOTER \ + HID_COLLECTION_END + +// Slider First 16 LEDs (48 rgb zones, BRG order) +#define GAMECON_REPORT_DESC_LED_SLIDER_16 \ + HID_REPORT_ID(REPORT_ID_LED_SLIDER_16) \ + HID_REPORT_COUNT(48), HID_REPORT_SIZE(8), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ + HID_USAGE_MIN(1), HID_USAGE_MAX(48), \ + HID_STRING_MINIMUM(7), HID_STRING_MAXIMUM(54), \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) + +// Slider Remaining 15 LEDs (45 rgb zones, BRG order) +#define GAMECON_REPORT_DESC_LED_SLIDER_15 \ + HID_REPORT_ID(REPORT_ID_LED_SLIDER_15) \ + HID_REPORT_COUNT(45), HID_REPORT_SIZE(8), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ + HID_USAGE_MIN(49), HID_USAGE_MAX(93), \ + HID_STRING_MINIMUM(7), HID_STRING_MAXIMUM(51), /* Delta to previous */ \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) + +// Tower LEDs (18 rgb zones, BRG order) +#define GAMECON_REPORT_DESC_LED_TOWER_6 \ + HID_REPORT_ID(REPORT_ID_LED_TOWER_6) \ + HID_REPORT_COUNT(18), HID_REPORT_SIZE(8), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ + HID_USAGE_MIN(94), HID_USAGE_MAX(111), \ + HID_STRING_MINIMUM(7), HID_STRING_MAXIMUM(24), /* Delta to previous */ \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) /* - report id 4 : slider first 48 leds (16 rgb zones, brg order) - report id 5 : slider remaining 45 leds (15 rgb zones, brg order) - report id 6 : tower 18 leds (6 rgb, brg order) + HID_STRING_MINIMUM(56), HID_STRING_MAXIMUM(100), \ + HID_STRING_MINIMUM(101), HID_STRING_MAXIMUM(117), \ */ -// Slider First 16 LEDs -#define GAMECON_REPORT_DESC_LED_SLIDER_16(...) \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - __VA_ARGS__ HID_REPORT_COUNT(48), HID_REPORT_SIZE(8), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(48), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \ - HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END - -// Slider Remaining 15 LEDs -#define GAMECON_REPORT_DESC_LED_SLIDER_15(...) \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - __VA_ARGS__ HID_REPORT_COUNT(45), HID_REPORT_SIZE(8), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(45), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \ - HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END - -// Tower LEDs -#define GAMECON_REPORT_DESC_LED_TOWER_6(...) \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - __VA_ARGS__ HID_REPORT_COUNT(18), HID_REPORT_SIZE(8), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(18), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \ - HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END - // LEDs Compressed -#define GAMECON_REPORT_DESC_LED_COMPRESSED(...) \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - __VA_ARGS__ HID_REPORT_COUNT(63), HID_REPORT_SIZE(8), \ - HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ - HID_USAGE_MIN(1), HID_USAGE_MAX(63), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \ - HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END +#define GAMECON_REPORT_DESC_LED_COMPRESSED \ + HID_REPORT_ID(REPORT_ID_LED_COMPRESSED) \ + HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \ + HID_USAGE(0x00), \ + HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ + HID_REPORT_SIZE(8), HID_REPORT_COUNT(63), \ + HID_FEATURE(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) -#endif /* USB_DESCRIPTORS_H_ */ \ No newline at end of file +#endif /* USB_DESCRIPTORS_H_ */