From 7bab3ef3f00e76c7932fc0ccba730b75f2b4c21f Mon Sep 17 00:00:00 2001 From: whowechina Date: Wed, 24 Apr 2024 20:50:24 +0800 Subject: [PATCH] Cleanup headers --- firmware/src/air.c | 249 ++++++++++++----------- firmware/src/rgb.c | 355 ++++++++++++++++----------------- firmware/src/save.c | 355 ++++++++++++++++----------------- firmware/src/slider.c | 205 ++++++++++--------- firmware/src/tusb_config.h | 5 - firmware/src/usb_descriptors.h | 280 +++++++++++++------------- 6 files changed, 719 insertions(+), 730 deletions(-) diff --git a/firmware/src/air.c b/firmware/src/air.c index 556317e..ab7712a 100644 --- a/firmware/src/air.c +++ b/firmware/src/air.c @@ -1,125 +1,124 @@ -/* - * Chu Pico Air Sensor - * WHowe - * - * Use ToF (Sharp GP2Y0E03) to detect air keys - */ - -#include "air.h" - -#include -#include - -#include "bsp/board.h" -#include "hardware/gpio.h" - -#include "board_defs.h" -#include "config.h" - -#include "gp2y0e.h" -#include "vl53l0x.h" -#include "i2c_hub.h" - -static const uint8_t TOF_LIST[] = TOF_MUX_LIST; -static uint8_t tof_model[sizeof(TOF_LIST)]; -static uint16_t distances[sizeof(TOF_LIST)]; - -void air_init() -{ - i2c_init(I2C_PORT, I2C_FREQ); - gpio_set_function(I2C_SDA, GPIO_FUNC_I2C); - gpio_set_function(I2C_SCL, GPIO_FUNC_I2C); - gpio_pull_up(I2C_SDA); - gpio_pull_up(I2C_SCL); - - i2c_hub_init(); - vl53l0x_init(I2C_PORT, 0); - - for (int i = 0; i < sizeof(TOF_LIST); i++) { - i2c_select(I2C_PORT, 1 << TOF_LIST[i]); - if (vl53l0x_is_present()) { - tof_model[i] = 1; - } else if (gp2y0e_is_present(I2C_PORT)) { - tof_model[i] = 2; - } else { - tof_model[i] = 0; - } - if (tof_model[i] == 1) { - vl53l0x_init_tof(i); - vl53l0x_start_continuous(i); - } else if (tof_model[i] == 2) { - gp2y03_init(I2C_PORT); - } - } -} - -size_t air_num() -{ - return sizeof(TOF_LIST); -} - -static inline uint8_t air_bits(int dist, int offset) -{ - if ((dist < offset) || (dist == 4095)) { - return 0; - } - - int pitch = chu_cfg->tof.pitch * 10; - int index = (dist - offset) / pitch; - if (index >= 6) { - return 0; - } - - return 1 << index; -} - -uint8_t air_bitmap() -{ - int offset = chu_cfg->tof.offset * 10; - int pitch = chu_cfg->tof.pitch * 10; - uint8_t bitmap = 0; - for (int i = 0; i < sizeof(TOF_LIST); i++) { - bitmap |= air_bits(distances[i], offset) | - air_bits(distances[i], offset + pitch); - } - return bitmap; -} - -unsigned air_value(uint8_t index) -{ - if (index >= sizeof(TOF_LIST)) { - return 0; - } - int offset = chu_cfg->tof.offset * 10; - int pitch = chu_cfg->tof.pitch * 10; - uint8_t bitmap = air_bits(distances[index], offset) | - air_bits(distances[index], offset + pitch); - - for (int i = 0; i < 6; i++) { - if (bitmap & (1 << i)) { - return i + 1; // lowest detected position - } - } - - return 0; -} - -void air_update() -{ - for (int i = 0; i < sizeof(TOF_LIST); i++) { - i2c_select(I2C_PORT, 1 << TOF_LIST[i]); - if (tof_model[i] == 1) { - distances[i] = readRangeContinuousMillimeters(i) * 10; - } else if (tof_model[i] == 2) { - distances[i] = gp2y0e_dist16_mm(I2C_PORT) * 10; - } - } -} - -uint16_t air_raw(uint8_t index) -{ - if (index >= sizeof(TOF_LIST)) { - return 0; - } - return distances[index]; -} +/* + * Chu Pico Air Sensor + * WHowe + * + * Use ToF (Sharp GP2Y0E03) to detect air keys + */ + +#include "air.h" + +#include +#include + +#include "hardware/gpio.h" + +#include "board_defs.h" +#include "config.h" + +#include "gp2y0e.h" +#include "vl53l0x.h" +#include "i2c_hub.h" + +static const uint8_t TOF_LIST[] = TOF_MUX_LIST; +static uint8_t tof_model[sizeof(TOF_LIST)]; +static uint16_t distances[sizeof(TOF_LIST)]; + +void air_init() +{ + i2c_init(I2C_PORT, I2C_FREQ); + gpio_set_function(I2C_SDA, GPIO_FUNC_I2C); + gpio_set_function(I2C_SCL, GPIO_FUNC_I2C); + gpio_pull_up(I2C_SDA); + gpio_pull_up(I2C_SCL); + + i2c_hub_init(); + vl53l0x_init(I2C_PORT, 0); + + for (int i = 0; i < sizeof(TOF_LIST); i++) { + i2c_select(I2C_PORT, 1 << TOF_LIST[i]); + if (vl53l0x_is_present()) { + tof_model[i] = 1; + } else if (gp2y0e_is_present(I2C_PORT)) { + tof_model[i] = 2; + } else { + tof_model[i] = 0; + } + if (tof_model[i] == 1) { + vl53l0x_init_tof(i); + vl53l0x_start_continuous(i); + } else if (tof_model[i] == 2) { + gp2y03_init(I2C_PORT); + } + } +} + +size_t air_num() +{ + return sizeof(TOF_LIST); +} + +static inline uint8_t air_bits(int dist, int offset) +{ + if ((dist < offset) || (dist == 4095)) { + return 0; + } + + int pitch = chu_cfg->tof.pitch * 10; + int index = (dist - offset) / pitch; + if (index >= 6) { + return 0; + } + + return 1 << index; +} + +uint8_t air_bitmap() +{ + int offset = chu_cfg->tof.offset * 10; + int pitch = chu_cfg->tof.pitch * 10; + uint8_t bitmap = 0; + for (int i = 0; i < sizeof(TOF_LIST); i++) { + bitmap |= air_bits(distances[i], offset) | + air_bits(distances[i], offset + pitch); + } + return bitmap; +} + +unsigned air_value(uint8_t index) +{ + if (index >= sizeof(TOF_LIST)) { + return 0; + } + int offset = chu_cfg->tof.offset * 10; + int pitch = chu_cfg->tof.pitch * 10; + uint8_t bitmap = air_bits(distances[index], offset) | + air_bits(distances[index], offset + pitch); + + for (int i = 0; i < 6; i++) { + if (bitmap & (1 << i)) { + return i + 1; // lowest detected position + } + } + + return 0; +} + +void air_update() +{ + for (int i = 0; i < sizeof(TOF_LIST); i++) { + i2c_select(I2C_PORT, 1 << TOF_LIST[i]); + if (tof_model[i] == 1) { + distances[i] = readRangeContinuousMillimeters(i) * 10; + } else if (tof_model[i] == 2) { + distances[i] = gp2y0e_dist16_mm(I2C_PORT) * 10; + } + } +} + +uint16_t air_raw(uint8_t index) +{ + if (index >= sizeof(TOF_LIST)) { + return 0; + } + return distances[index]; +} diff --git a/firmware/src/rgb.c b/firmware/src/rgb.c index c626cdd..d656843 100644 --- a/firmware/src/rgb.c +++ b/firmware/src/rgb.c @@ -1,178 +1,177 @@ -/* - * RGB LED (WS2812) Strip control - * WHowe - * - */ - -#include "rgb.h" - -#include -#include -#include -#include - -#include "bsp/board.h" -#include "hardware/pio.h" -#include "hardware/timer.h" - -#include "ws2812.pio.h" - -#include "board_defs.h" -#include "config.h" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -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 -#define MAP_LED_RGB { c1 = r; c2 = g; c3 = b; } -#define MAP_LED_GRB { c1 = g; c2 = r; c3 = b; } - -#define REMAP_BUTTON_RGB _MAP_LED(BUTTON_RGB_ORDER) -#define REMAP_TT_RGB _MAP_LED(TT_RGB_ORDER) - -static inline uint32_t _rgb32(uint32_t c1, uint32_t c2, uint32_t c3, bool gamma_fix) -{ - if (gamma_fix) { - c1 = ((c1 + 1) * (c1 + 1) - 1) >> 8; - c2 = ((c2 + 1) * (c2 + 1) - 1) >> 8; - c3 = ((c3 + 1) * (c3 + 1) - 1) >> 8; - } - - return (c1 << 16) | (c2 << 8) | (c3 << 0); -} - -uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix) -{ -#if BUTTON_RGB_ORDER == GRB - return _rgb32(g, r, b, gamma_fix); -#else - return _rgb32(r, g, b, gamma_fix); -#endif -} - -uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v) -{ - uint32_t region, remainder, p, q, t; - - if (s == 0) { - return v << 16 | v << 8 | v; - } - - region = h / 43; - remainder = (h % 43) * 6; - - p = (v * (255 - s)) >> 8; - q = (v * (255 - ((s * remainder) >> 8))) >> 8; - t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; - - switch (region) { - case 0: - return v << 16 | t << 8 | p; - case 1: - return q << 16 | v << 8 | p; - case 2: - return p << 16 | v << 8 | t; - case 3: - return p << 16 | q << 8 | v; - case 4: - return t << 16 | p << 8 | v; - default: - return v << 16 | p << 8 | q; - } -} - -static void drive_led() -{ - static uint64_t last = 0; - uint64_t now = time_us_64(); - if (now - last < 4000) { // no faster than 250Hz - return; - } - last = now; - - 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); - } -} - -void rgb_set_colors(const uint32_t *colors, unsigned index, size_t num) -{ - if (index >= ARRAY_SIZE(rgb_buf)) { - return; - } - if (index + num > ARRAY_SIZE(rgb_buf)) { - num = ARRAY_SIZE(rgb_buf) - index; - } - memcpy(&rgb_buf[index], colors, num * sizeof(*colors)); -} - -static inline uint32_t apply_level(uint32_t color) -{ - unsigned r = (color >> 16) & 0xff; - unsigned g = (color >> 8) & 0xff; - unsigned b = color & 0xff; - - r = r * chu_cfg->style.level / 255; - g = g * chu_cfg->style.level / 255; - b = b * chu_cfg->style.level / 255; - - return r << 16 | g << 8 | b; -} - -void rgb_set_color(unsigned index, uint32_t color) -{ - if (index >= ARRAY_SIZE(rgb_buf)) { - return; - } - rgb_buf[index] = apply_level(color); -} - -void rgb_key_color(unsigned index, uint32_t color) -{ - if (index > 16) { - return; - } - rgb_buf[index * 2] = apply_level(color); -} - -void rgb_gap_color(unsigned index, uint32_t color) -{ - if (index > 15) { - return; - } - rgb_buf[index * 2 + 1] = apply_level(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] = apply_level(rgb32(r, g, b, false)); - } -} - -void rgb_init() -{ - uint pio0_offset = pio_add_program(pio0, &ws2812_program); - - gpio_set_drive_strength(RGB_PIN, GPIO_DRIVE_STRENGTH_2MA); - ws2812_program_init(pio0, 0, pio0_offset, RGB_PIN, 800000, false); -} - -void rgb_update() -{ - drive_led(); -} +/* + * RGB LED (WS2812) Strip control + * WHowe + * + */ + +#include "rgb.h" + +#include +#include +#include +#include + +#include "hardware/pio.h" +#include "hardware/timer.h" + +#include "ws2812.pio.h" + +#include "board_defs.h" +#include "config.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +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 +#define MAP_LED_RGB { c1 = r; c2 = g; c3 = b; } +#define MAP_LED_GRB { c1 = g; c2 = r; c3 = b; } + +#define REMAP_BUTTON_RGB _MAP_LED(BUTTON_RGB_ORDER) +#define REMAP_TT_RGB _MAP_LED(TT_RGB_ORDER) + +static inline uint32_t _rgb32(uint32_t c1, uint32_t c2, uint32_t c3, bool gamma_fix) +{ + if (gamma_fix) { + c1 = ((c1 + 1) * (c1 + 1) - 1) >> 8; + c2 = ((c2 + 1) * (c2 + 1) - 1) >> 8; + c3 = ((c3 + 1) * (c3 + 1) - 1) >> 8; + } + + return (c1 << 16) | (c2 << 8) | (c3 << 0); +} + +uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix) +{ +#if BUTTON_RGB_ORDER == GRB + return _rgb32(g, r, b, gamma_fix); +#else + return _rgb32(r, g, b, gamma_fix); +#endif +} + +uint32_t rgb32_from_hsv(uint8_t h, uint8_t s, uint8_t v) +{ + uint32_t region, remainder, p, q, t; + + if (s == 0) { + return v << 16 | v << 8 | v; + } + + region = h / 43; + remainder = (h % 43) * 6; + + p = (v * (255 - s)) >> 8; + q = (v * (255 - ((s * remainder) >> 8))) >> 8; + t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; + + switch (region) { + case 0: + return v << 16 | t << 8 | p; + case 1: + return q << 16 | v << 8 | p; + case 2: + return p << 16 | v << 8 | t; + case 3: + return p << 16 | q << 8 | v; + case 4: + return t << 16 | p << 8 | v; + default: + return v << 16 | p << 8 | q; + } +} + +static void drive_led() +{ + static uint64_t last = 0; + uint64_t now = time_us_64(); + if (now - last < 4000) { // no faster than 250Hz + return; + } + last = now; + + 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); + } +} + +void rgb_set_colors(const uint32_t *colors, unsigned index, size_t num) +{ + if (index >= ARRAY_SIZE(rgb_buf)) { + return; + } + if (index + num > ARRAY_SIZE(rgb_buf)) { + num = ARRAY_SIZE(rgb_buf) - index; + } + memcpy(&rgb_buf[index], colors, num * sizeof(*colors)); +} + +static inline uint32_t apply_level(uint32_t color) +{ + unsigned r = (color >> 16) & 0xff; + unsigned g = (color >> 8) & 0xff; + unsigned b = color & 0xff; + + r = r * chu_cfg->style.level / 255; + g = g * chu_cfg->style.level / 255; + b = b * chu_cfg->style.level / 255; + + return r << 16 | g << 8 | b; +} + +void rgb_set_color(unsigned index, uint32_t color) +{ + if (index >= ARRAY_SIZE(rgb_buf)) { + return; + } + rgb_buf[index] = apply_level(color); +} + +void rgb_key_color(unsigned index, uint32_t color) +{ + if (index > 16) { + return; + } + rgb_buf[index * 2] = apply_level(color); +} + +void rgb_gap_color(unsigned index, uint32_t color) +{ + if (index > 15) { + return; + } + rgb_buf[index * 2 + 1] = apply_level(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] = apply_level(rgb32(r, g, b, false)); + } +} + +void rgb_init() +{ + uint pio0_offset = pio_add_program(pio0, &ws2812_program); + + gpio_set_drive_strength(RGB_PIN, GPIO_DRIVE_STRENGTH_2MA); + ws2812_program_init(pio0, 0, pio0_offset, RGB_PIN, 800000, false); +} + +void rgb_update() +{ + drive_led(); +} diff --git a/firmware/src/save.c b/firmware/src/save.c index 3afec3c..fc729df 100644 --- a/firmware/src/save.c +++ b/firmware/src/save.c @@ -1,178 +1,177 @@ -/* - * Controller Config Save and Load - * WHowe - * - * Config is stored in last sector of flash - */ - -#include "save.h" - -#include -#include -#include -#include - - -#include "bsp/board.h" -#include "pico/bootrom.h" -#include "pico/stdio.h" - -#include "hardware/flash.h" -#include "pico/multicore.h" -#include "pico/unique_id.h" - -static struct { - size_t size; - size_t offset; - void (*after_load)(); -} modules[8] = {0}; -static int module_num = 0; - -static uint32_t my_magic = 0xcafecafe; - -#define SAVE_TIMEOUT_US 5000000 - -#define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) - -typedef struct __attribute ((packed)) { - uint32_t magic; - uint8_t data[FLASH_PAGE_SIZE - 4]; -} page_t; - -static page_t old_data = {0}; -static page_t new_data = {0}; -static page_t default_data = {0}; -static int data_page = -1; - -static bool requesting_save = false; -static uint64_t requesting_time = 0; - -static mutex_t *io_lock; - -static void save_program() -{ - old_data = new_data; - - data_page = (data_page + 1) % (FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE); - printf("\nProgram Flash %d %8lx\n", data_page, old_data.magic); - if (mutex_enter_timeout_us(io_lock, 100000)) { - sleep_ms(10); /* wait for all io operations to finish */ - uint32_t ints = save_and_disable_interrupts(); - if (data_page == 0) { - flash_range_erase(SAVE_SECTOR_OFFSET, FLASH_SECTOR_SIZE); - } - flash_range_program(SAVE_SECTOR_OFFSET + data_page * FLASH_PAGE_SIZE, - (uint8_t *)&old_data, FLASH_PAGE_SIZE); - restore_interrupts(ints); - mutex_exit(io_lock); - } else { - printf("Program Flash Failed.\n"); - } -} - -static void load_default() -{ - printf("Load Default\n"); - new_data = default_data; - new_data.magic = my_magic; -} - -static const page_t *get_page(int id) -{ - int addr = XIP_BASE + SAVE_SECTOR_OFFSET; - return (page_t *)(addr + FLASH_PAGE_SIZE * id); -} - -static void save_load() -{ - for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) { - if (get_page(i)->magic != my_magic) { - break; - } - data_page = i; - } - - if (data_page < 0) { - load_default(); - save_request(false); - return; - } - - old_data = *get_page(data_page); - new_data = old_data; - printf("Page Loaded %d %8lx\n", data_page, new_data.magic); -} - -static void save_loaded() -{ - for (int i = 0; i < module_num; i++) { - modules[i].after_load(); - } -} - -static union __attribute__((packed)) { - pico_unique_board_id_t id; - struct { - uint32_t id32h; - uint32_t id32l; - }; - uint64_t id64; -} board_id; - -uint32_t board_id_32() -{ - pico_get_unique_board_id(&board_id.id); - return board_id.id32h ^ board_id.id32l; -} - -uint64_t board_id_64() -{ - pico_get_unique_board_id(&board_id.id); - return board_id.id64; -} - -void save_init(uint32_t magic, mutex_t *locker) -{ - my_magic = magic; - io_lock = locker; - save_load(); - save_loop(); - save_loaded(); -} - -void save_loop() -{ - if (requesting_save && (time_us_64() - requesting_time > SAVE_TIMEOUT_US)) { - requesting_save = false; - /* only when data is actually changed */ - if (memcmp(&old_data, &new_data, sizeof(old_data)) == 0) { - return; - } - save_program(); - } -} - -void *save_alloc(size_t size, void *def, void (*after_load)()) -{ - modules[module_num].size = size; - size_t offset = module_num > 0 ? modules[module_num - 1].offset + size : 0; - modules[module_num].offset = offset; - modules[module_num].after_load = after_load; - module_num++; - memcpy(default_data.data + offset, def, size); // backup the default - return new_data.data + offset; -} - -void save_request(bool immediately) -{ - if (!requesting_save) { - printf("Save requested.\n"); - requesting_save = true; - new_data.magic = my_magic; - requesting_time = time_us_64(); - } - if (immediately) { - requesting_time = 0; - save_loop(); - } -} +/* + * Controller Config Save and Load + * WHowe + * + * Config is stored in last sector of flash + */ + +#include "save.h" + +#include +#include +#include +#include +#include + +#include "pico/bootrom.h" +#include "pico/stdio.h" + +#include "hardware/flash.h" +#include "pico/multicore.h" +#include "pico/unique_id.h" + +static struct { + size_t size; + size_t offset; + void (*after_load)(); +} modules[8] = {0}; +static int module_num = 0; + +static uint32_t my_magic = 0xcafecafe; + +#define SAVE_TIMEOUT_US 5000000 + +#define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) + +typedef struct __attribute ((packed)) { + uint32_t magic; + uint8_t data[FLASH_PAGE_SIZE - 4]; +} page_t; + +static page_t old_data = {0}; +static page_t new_data = {0}; +static page_t default_data = {0}; +static int data_page = -1; + +static bool requesting_save = false; +static uint64_t requesting_time = 0; + +static mutex_t *io_lock; + +static void save_program() +{ + old_data = new_data; + + data_page = (data_page + 1) % (FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE); + printf("\nProgram Flash %d %8lx\n", data_page, old_data.magic); + if (mutex_enter_timeout_us(io_lock, 100000)) { + sleep_ms(10); /* wait for all io operations to finish */ + uint32_t ints = save_and_disable_interrupts(); + if (data_page == 0) { + flash_range_erase(SAVE_SECTOR_OFFSET, FLASH_SECTOR_SIZE); + } + flash_range_program(SAVE_SECTOR_OFFSET + data_page * FLASH_PAGE_SIZE, + (uint8_t *)&old_data, FLASH_PAGE_SIZE); + restore_interrupts(ints); + mutex_exit(io_lock); + } else { + printf("Program Flash Failed.\n"); + } +} + +static void load_default() +{ + printf("Load Default\n"); + new_data = default_data; + new_data.magic = my_magic; +} + +static const page_t *get_page(int id) +{ + int addr = XIP_BASE + SAVE_SECTOR_OFFSET; + return (page_t *)(addr + FLASH_PAGE_SIZE * id); +} + +static void save_load() +{ + for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) { + if (get_page(i)->magic != my_magic) { + break; + } + data_page = i; + } + + if (data_page < 0) { + load_default(); + save_request(false); + return; + } + + old_data = *get_page(data_page); + new_data = old_data; + printf("Page Loaded %d %8lx\n", data_page, new_data.magic); +} + +static void save_loaded() +{ + for (int i = 0; i < module_num; i++) { + modules[i].after_load(); + } +} + +static union __attribute__((packed)) { + pico_unique_board_id_t id; + struct { + uint32_t id32h; + uint32_t id32l; + }; + uint64_t id64; +} board_id; + +uint32_t board_id_32() +{ + pico_get_unique_board_id(&board_id.id); + return board_id.id32h ^ board_id.id32l; +} + +uint64_t board_id_64() +{ + pico_get_unique_board_id(&board_id.id); + return board_id.id64; +} + +void save_init(uint32_t magic, mutex_t *locker) +{ + my_magic = magic; + io_lock = locker; + save_load(); + save_loop(); + save_loaded(); +} + +void save_loop() +{ + if (requesting_save && (time_us_64() - requesting_time > SAVE_TIMEOUT_US)) { + requesting_save = false; + /* only when data is actually changed */ + if (memcmp(&old_data, &new_data, sizeof(old_data)) == 0) { + return; + } + save_program(); + } +} + +void *save_alloc(size_t size, void *def, void (*after_load)()) +{ + modules[module_num].size = size; + size_t offset = module_num > 0 ? modules[module_num - 1].offset + size : 0; + modules[module_num].offset = offset; + modules[module_num].after_load = after_load; + module_num++; + memcpy(default_data.data + offset, def, size); // backup the default + return new_data.data + offset; +} + +void save_request(bool immediately) +{ + if (!requesting_save) { + printf("Save requested.\n"); + requesting_save = true; + new_data.magic = my_magic; + requesting_time = time_us_64(); + } + if (immediately) { + requesting_time = 0; + save_loop(); + } +} diff --git a/firmware/src/slider.c b/firmware/src/slider.c index 494ac2b..c8fead3 100644 --- a/firmware/src/slider.c +++ b/firmware/src/slider.c @@ -1,103 +1,102 @@ -/* - * Chu Pico Silder Keys - * WHowe - * - * MPR121 CapSense based Keys - */ - -#include "slider.h" - -#include -#include -#include - -#include "bsp/board.h" -#include "hardware/gpio.h" -#include "hardware/i2c.h" - -#include "board_defs.h" - -#include "config.h" -#include "mpr121.h" - -#define MPR121_ADDR 0x5A - -static uint16_t readout[36]; -static uint16_t touch[3]; -static unsigned touch_count[36]; - -void slider_init() -{ - i2c_init(I2C_PORT, I2C_FREQ); - gpio_set_function(I2C_SDA, GPIO_FUNC_I2C); - gpio_set_function(I2C_SCL, GPIO_FUNC_I2C); - gpio_pull_up(I2C_SDA); - gpio_pull_up(I2C_SCL); - - for (int m = 0; m < 3; m++) { - mpr121_init(MPR121_ADDR + m); - } - slider_update_config(); -} - -void slider_update() -{ - 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); - - 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_count[m * 12 + i]++; - } - } - } -} - -const uint16_t *slider_raw() -{ - mpr121_raw(MPR121_ADDR, readout, 12); - mpr121_raw(MPR121_ADDR + 1, readout + 12, 12); - mpr121_raw(MPR121_ADDR + 2, readout + 24, 12); - return readout; -} - -bool slider_touched(unsigned key) -{ - if (key >= 32) { - return 0; - } - return touch[key / 12] & (1 << (key % 12)); -} - -unsigned slider_count(unsigned key) -{ - if (key >= 32) { - return 0; - } - return touch_count[key]; -} - -void slider_reset_stat() -{ - memset(touch_count, 0, sizeof(touch_count)); -} - -void slider_update_config() -{ - for (int m = 0; m < 3; m++) { - mpr121_debounce(MPR121_ADDR + m, chu_cfg->sense.debounce_touch, - chu_cfg->sense.debounce_release); - mpr121_sense(MPR121_ADDR + m, chu_cfg->sense.global, - chu_cfg->sense.keys + m * 12, - m != 2 ? 12 : 8); - mpr121_filter(MPR121_ADDR + m, chu_cfg->sense.filter >> 6, - (chu_cfg->sense.filter >> 4) & 0x03, - chu_cfg->sense.filter & 0x07); - } -} +/* + * Chu Pico Silder Keys + * WHowe + * + * MPR121 CapSense based Keys + */ + +#include "slider.h" + +#include +#include +#include +#include +#include "hardware/gpio.h" +#include "hardware/i2c.h" + +#include "board_defs.h" + +#include "config.h" +#include "mpr121.h" + +#define MPR121_ADDR 0x5A + +static uint16_t readout[36]; +static uint16_t touch[3]; +static unsigned touch_count[36]; + +void slider_init() +{ + i2c_init(I2C_PORT, I2C_FREQ); + gpio_set_function(I2C_SDA, GPIO_FUNC_I2C); + gpio_set_function(I2C_SCL, GPIO_FUNC_I2C); + gpio_pull_up(I2C_SDA); + gpio_pull_up(I2C_SCL); + + for (int m = 0; m < 3; m++) { + mpr121_init(MPR121_ADDR + m); + } + slider_update_config(); +} + +void slider_update() +{ + 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); + + 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_count[m * 12 + i]++; + } + } + } +} + +const uint16_t *slider_raw() +{ + mpr121_raw(MPR121_ADDR, readout, 12); + mpr121_raw(MPR121_ADDR + 1, readout + 12, 12); + mpr121_raw(MPR121_ADDR + 2, readout + 24, 12); + return readout; +} + +bool slider_touched(unsigned key) +{ + if (key >= 32) { + return 0; + } + return touch[key / 12] & (1 << (key % 12)); +} + +unsigned slider_count(unsigned key) +{ + if (key >= 32) { + return 0; + } + return touch_count[key]; +} + +void slider_reset_stat() +{ + memset(touch_count, 0, sizeof(touch_count)); +} + +void slider_update_config() +{ + for (int m = 0; m < 3; m++) { + mpr121_debounce(MPR121_ADDR + m, chu_cfg->sense.debounce_touch, + chu_cfg->sense.debounce_release); + mpr121_sense(MPR121_ADDR + m, chu_cfg->sense.global, + chu_cfg->sense.keys + m * 12, + m != 2 ? 12 : 8); + mpr121_filter(MPR121_ADDR + m, chu_cfg->sense.filter >> 6, + (chu_cfg->sense.filter >> 4) & 0x03, + chu_cfg->sense.filter & 0x07); + } +} diff --git a/firmware/src/tusb_config.h b/firmware/src/tusb_config.h index 610a6c4..cb44bd8 100644 --- a/firmware/src/tusb_config.h +++ b/firmware/src/tusb_config.h @@ -105,11 +105,6 @@ extern "C" { // HID buffer size Should be sufficient to hold ID (if any) + Data #define CFG_TUD_HID_EP_BUFSIZE 64 -#define CFG_TUD_VENDOR 0 - -// HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE 64 - // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 128) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 128) diff --git a/firmware/src/usb_descriptors.h b/firmware/src/usb_descriptors.h index c1217dd..c1f81a1 100644 --- a/firmware/src/usb_descriptors.h +++ b/firmware/src/usb_descriptors.h @@ -1,141 +1,139 @@ -#ifndef USB_DESCRIPTORS_H_ -#define USB_DESCRIPTORS_H_ - -#include "common/tusb_common.h" -#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, -}; - -// because they are missing from tusb_hid.h -#define HID_STRING_INDEX(x) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, 1) -#define HID_STRING_INDEX_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, n) -#define HID_STRING_MINIMUM(x) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, 1) -#define HID_STRING_MINIMUM_N(x, n) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, n) -#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 -#define CHUPICO_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_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 - -#define CHUPICO_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 CHUPICO_LED_FOOTER \ - HID_COLLECTION_END - -// Slider First 16 LEDs (48 rgb zones, BRG order) -#define CHUPICO_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(8), HID_STRING_MAXIMUM(55), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) - -// Slider Remaining 15 LEDs (45 rgb zones, BRG order) -#define CHUPICO_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(8), HID_STRING_MAXIMUM(52), /* Delta to previous */ \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) - -// Tower LEDs (18 rgb zones, BRG order) -#define CHUPICO_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(8), HID_STRING_MAXIMUM(25), /* Delta to previous */ \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) - -// LEDs Compressed -#define CHUPICO_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) - -#define CHUPICO_REPORT_DESC_NKRO \ - HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ - HID_USAGE(HID_USAGE_DESKTOP_KEYBOARD), \ - HID_COLLECTION(HID_COLLECTION_APPLICATION), \ - /* Modifier */ \ - 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_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - /* LED output that we don't care */ \ - HID_REPORT_COUNT(5), \ - HID_REPORT_SIZE(1), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_LED), \ - HID_USAGE_MIN(1), \ - HID_USAGE_MAX(5), \ - HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_REPORT_COUNT(1), \ - HID_REPORT_SIZE(3), \ - HID_OUTPUT(HID_CONSTANT), \ - /* Full Keyboard Bitmap */ \ - HID_REPORT_SIZE(1), \ - HID_REPORT_COUNT(120), \ - HID_LOGICAL_MIN(0), \ - HID_LOGICAL_MAX(1), \ - HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \ - HID_USAGE_MIN(0), \ - HID_USAGE_MAX(119), \ - HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ - HID_COLLECTION_END - -// HID_REPORT_ID(REPORT_ID_NKRO) - -#endif /* USB_DESCRIPTORS_H_ */ +#ifndef USB_DESCRIPTORS_H_ +#define USB_DESCRIPTORS_H_ + +#include "common/tusb_common.h" +#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, +}; + +// because they are missing from tusb_hid.h +#define HID_STRING_INDEX(x) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, 1) +#define HID_STRING_INDEX_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, n) +#define HID_STRING_MINIMUM(x) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, 1) +#define HID_STRING_MINIMUM_N(x, n) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, n) +#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 +#define CHUPICO_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_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 + +#define CHUPICO_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 CHUPICO_LED_FOOTER \ + HID_COLLECTION_END + +// Slider First 16 LEDs (48 rgb zones, BRG order) +#define CHUPICO_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(8), HID_STRING_MAXIMUM(55), \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) + +// Slider Remaining 15 LEDs (45 rgb zones, BRG order) +#define CHUPICO_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(8), HID_STRING_MAXIMUM(52), /* Delta to previous */ \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) + +// Tower LEDs (18 rgb zones, BRG order) +#define CHUPICO_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(8), HID_STRING_MAXIMUM(25), /* Delta to previous */ \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE) + +// LEDs Compressed +#define CHUPICO_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) + +#define CHUPICO_REPORT_DESC_NKRO \ + HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ + HID_USAGE(HID_USAGE_DESKTOP_KEYBOARD), \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + /* Modifier */ \ + 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_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + /* LED output that we don't care */ \ + HID_REPORT_COUNT(5), \ + HID_REPORT_SIZE(1), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_LED), \ + HID_USAGE_MIN(1), \ + HID_USAGE_MAX(5), \ + HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_REPORT_COUNT(1), \ + HID_REPORT_SIZE(3), \ + HID_OUTPUT(HID_CONSTANT), \ + /* Full Keyboard Bitmap */ \ + HID_REPORT_SIZE(1), \ + HID_REPORT_COUNT(120), \ + HID_LOGICAL_MIN(0), \ + HID_LOGICAL_MAX(1), \ + HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \ + HID_USAGE_MIN(0), \ + HID_USAGE_MAX(119), \ + HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ + HID_COLLECTION_END + +#endif /* USB_DESCRIPTORS_H_ */