mirror of
https://github.com/whowechina/chu_pico.git
synced 2024-11-28 04:30:49 +01:00
Firmware done, I call it beta
This commit is contained in:
parent
94273bff74
commit
67d415db50
BIN
Production/Firmware/chu_pico.uf2
Normal file
BIN
Production/Firmware/chu_pico.uf2
Normal file
Binary file not shown.
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
169
firmware/src/lzfx.c
Normal file
169
firmware/src/lzfx.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Lzfx decompressor
|
||||
* WHowe <github.com/whowechina>
|
||||
* This is actually taken from CrazyRedMachine's repo
|
||||
* <https://github.com/CrazyRedMachine/RedBoard/blob/main/io_dll/src/utils/hid_impl.c>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
18
firmware/src/lzfx.h
Normal file
18
firmware/src/lzfx.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Lzfx decompressor
|
||||
* WHowe <github.com/whowechina>
|
||||
* This is actually taken from CrazyRedMachine's repo
|
||||
* <https://github.com/CrazyRedMachine/RedBoard/blob/main/io_dll/src/utils/hid_impl.c>
|
||||
*/
|
||||
|
||||
#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);
|
@ -7,10 +7,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user