complete refactor to directly pass reports and interfaces

This commit is contained in:
2025-08-23 15:06:10 -04:00
parent 86ecb819b0
commit 0aebadf829
15 changed files with 681 additions and 660 deletions
+3 -3
View File
@@ -11,10 +11,10 @@ add_subdirectory(${PICO_PIO_USB_PATH} pico_pio_usb)
add_executable(${PROJECT}) add_executable(${PROJECT})
target_sources(${PROJECT} PRIVATE target_sources(${PROJECT} PRIVATE
main_device.c
main_host.c
usb_descriptors.c
hyperx_elite2.c hyperx_elite2.c
main.c
usb_host.c
usb_device.c
) )
# print memory usage, enable all warnings # print memory usage, enable all warnings
Binary file not shown.
+35 -173
View File
@@ -5,11 +5,13 @@
#include "hardware/adc.h" #include "hardware/adc.h"
#include "hyperx_elite2.h" #include "hyperx_elite2.h"
#include "usb_descriptors.h"
static bool sending = false; static bool sending = false;
static absolute_time_t lastTime; static absolute_time_t lastSend;
static absolute_time_t lastRead;
static bool backlight = false; static bool backlight = false;
static uint16_t adc_value = 0;
static bool mute = false;
static const unsigned int SKIP_INDICES[] = { 23, 29, 41, 47, 70, 71, 76, 87, 88, 93, 99, 100, 102, 108, 113 }; static const unsigned int SKIP_INDICES[] = { 23, 29, 41, 47, 70, 71, 76, 87, 88, 93, 99, 100, 102, 108, 113 };
@@ -20,30 +22,23 @@ static uint8_t color_idx = 0;
static uint8_t skipped = 0; static uint8_t skipped = 0;
const unsigned int* skip_idx = &SKIP_INDICES[0]; const unsigned int* skip_idx = &SKIP_INDICES[0];
static unsigned char nkro_buf[NKRO_BUF_SIZE]; static void send_color(uint8_t dev_addr, uint8_t red, uint8_t green, uint8_t blue);
static unsigned char nkro_buf1[NKRO_BUF_SIZE]; static void send_initial(uint8_t dev_addr);
static unsigned char nkro_buf2[NKRO_BUF_SIZE];
static unsigned char mediakeys[1] = {0};
static unsigned char key_buf[KEY_BUF_SIZE];
static uint8_t buf_start=0;
static uint8_t buf_end=0;
static uint8_t mediabit=0;
static uint8_t pos=0;
static bool mute=false;
static bool sendkeys=false;
static bool sendmedia=false;
void get_light() { void get_light() {
// get ADC reading from LDR // get ADC reading from LDR every 500ms
// if above threshold, set backlight to off // if above threshold, set backlight to off
if (adc_read() > 400) { if ( absolute_time_diff_us(lastRead, get_absolute_time()) >= 500000) {
backlight = false; adc_value = adc_read();
} else { if (backlight && adc_value >= LDR_OFF_THRESHOLD) {
backlight = true; backlight = false;
} else if (!backlight && adc_value <= LDR_ON_THRESHOLD) {
backlight = true;
}
} }
} }
void rgb_task(uint8_t dev_addr, uint8_t instance, uint8_t report_id) { void rgb_task(uint8_t dev_addr) {
// the RGB protocol used by HyperX sends individual key RGB data in // the RGB protocol used by HyperX sends individual key RGB data in
// multiple packets // multiple packets
// the code here will determine if we are in the middle of sending // the code here will determine if we are in the middle of sending
@@ -51,26 +46,26 @@ void rgb_task(uint8_t dev_addr, uint8_t instance, uint8_t report_id) {
// packet if so at a rate of one packet every 20ms // packet if so at a rate of one packet every 20ms
// otherwise, wait 1s before sending the next set of color packets // otherwise, wait 1s before sending the next set of color packets
if (sending) { if (sending) {
if ( absolute_time_diff_us(lastTime, get_absolute_time()) > 20000) { if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 20000) {
if( backlight) { if( backlight) {
send_color(dev_addr, instance, report_id, 0x20, 0x20, 0x20); send_color(dev_addr, 0x20, 0x20, 0x20);
// send a dim white color (#202020) for all keys // send a dim white color (#202020) for all keys
} else{ } else{
send_color(dev_addr, instance, report_id, 0x00, 0x00, 0x00); send_color(dev_addr, 0x00, 0x00, 0x00);
// turn off all lighting by sending (#000000) for all keys // turn off all lighting by sending (#000000) for all keys
} }
lastTime = get_absolute_time(); lastSend = get_absolute_time();
} }
} else { } else {
if ( absolute_time_diff_us(lastTime, get_absolute_time()) > 500000) { if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 500000) {
send_initial(dev_addr, instance, report_id); send_initial(dev_addr);
lastTime = get_absolute_time(); lastSend = get_absolute_time();
} }
} }
} }
// send an individual color packett with the desired RGB color // send an individual color packett with the desired RGB color
void send_color(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t red, uint8_t green, uint8_t blue) { static void send_color(uint8_t dev_addr, uint8_t red, uint8_t green, uint8_t blue) {
memset(buf, 0x00, BUF_SIZE); memset(buf, 0x00, BUF_SIZE);
buf_idx = 0; buf_idx = 0;
@@ -129,7 +124,7 @@ void send_color(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t r
buf_idx += 4; buf_idx += 4;
} }
if(tuh_hid_set_report(dev_addr, instance, report_id, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE)) if(tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{ {
// packet sent successfully, increment // packet sent successfully, increment
packets_sent++; packets_sent++;
@@ -140,7 +135,7 @@ void send_color(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t r
// all keys have been sent, but the protocol expects NUM_PACKETS // all keys have been sent, but the protocol expects NUM_PACKETS
// packets to be sent in total; if we have not sent enough packets, // packets to be sent in total; if we have not sent enough packets,
// send extra packets of all 0x00 until done // send extra packets of all 0x00 until done
if(tuh_hid_set_report(dev_addr, instance, report_id, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE)) if(tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{ {
packets_sent++; packets_sent++;
} }
@@ -153,7 +148,7 @@ void send_color(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t r
// send the special initialization packet that tells the keyboard to expect // send the special initialization packet that tells the keyboard to expect
// color packets to follow // color packets to follow
void send_initial(uint8_t dev_addr, uint8_t instance, uint8_t report_id) { static void send_initial(uint8_t dev_addr) {
memset(buf, 0x00, BUF_SIZE); memset(buf, 0x00, BUF_SIZE);
color_idx = 0; color_idx = 0;
@@ -164,7 +159,7 @@ void send_initial(uint8_t dev_addr, uint8_t instance, uint8_t report_id) {
buf[0x00] = 0x04; buf[0x00] = 0x04;
buf[0x01] = 0xf2; buf[0x01] = 0xf2;
if (tuh_hid_set_report(dev_addr, instance, report_id, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE)) if (tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{ {
// we have begun sending packets, so set flag to continue sending // we have begun sending packets, so set flag to continue sending
// packets at regular intervals // packets at regular intervals
@@ -177,148 +172,15 @@ void send_initial(uint8_t dev_addr, uint8_t instance, uint8_t report_id) {
void startADC() { void startADC() {
stdio_init_all(); stdio_init_all();
adc_init(); adc_init();
adc_gpio_init(28); adc_gpio_init(LDR_PIN);
adc_select_input(2); adc_select_input(LDR_ADC);
} }
// process media key presses and prepare HID Consumer Control byte // forward HID report after processing
void send_media(uint8_t const* report, uint16_t len) { bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len) {
(void) len; if (instance == 0x01 && report[0] == 0x03 && report[1] == 0xE2) {
if ( report[0]==0x05 ) { mute = !mute;
switch(report[2]) {
case 0xB0: // next
mediabit = 0;
break;
case 0xB1: // prev
mediabit = 1;
break;
case 0xB3: // play/pause
mediabit = 2;
break;
case 0xB5: // mute
mediabit = 3;
if (report[3]) {
mute = !mute;
}
break;
default:
return;
}
if (report[3]) {
SET_KEYBIT(mediakeys, mediabit);
} else {
CLEAR_KEYBIT(mediakeys, mediabit);
}
// set flag to send media keys during the next sending round
sendmedia = true;
} else if ( report[0]==0x03 ) {
switch(report[1]) {
case 0xE9: // vol up
SET_KEYBIT(mediakeys, 4);
break;
case 0xEA: // vol down
SET_KEYBIT(mediakeys, 5);
break;
case 0x00: // none
CLEAR_KEYBIT(mediakeys, 4);
CLEAR_KEYBIT(mediakeys, 5);
break;
default:
return;
}
sendmedia = true;
} }
return tud_hid_n_report(instance, 0, report, len);
} }
// process new HID reports from the keyboard and set them up to forward to host
void process_report(uint8_t instance, uint8_t const* report, uint16_t len) {
if (instance==HYPERX_ITF_KEYBOARD || instance==HYPERX_ITF_NKRO) {
// received regular keyboard key events
if (sendkeys) {
// keyboard is currently sending to the host, add to queue
key_buf[buf_end]=len;
key_buf[buf_end+2]=instance;
memcpy(&key_buf[buf_end+2], report, len);
buf_end += (len + 2);
} else {
// immediately process keys and send new HID report to host
updatekeys(instance, report, len);
}
} else if (instance==HYPERX_ITF_KEYPRESS) {
// received media key events
send_media(report, len);
}
}
// merge key states from boot keyboard and NKRO keyboard interfaces into a
// single packet to send to the host
void updatekeys(uint8_t instance, uint8_t const* report, uint16_t len) {
if(instance==HYPERX_ITF_KEYBOARD) {
boot2nkro(report, nkro_buf1, len);
sendkeys=true;
} else if (instance==HYPERX_ITF_NKRO) {
memcpy(nkro_buf2, report, len);
sendkeys=true;
}
merge_bitmap(nkro_buf, nkro_buf1, nkro_buf2);
}
// set initial state of keyboard
void reset_keyboard() {
memset(nkro_buf, 0x00, NKRO_BUF_SIZE);
memset(nkro_buf1, 0x00, NKRO_BUF_SIZE);
memset(nkro_buf2, 0x00, NKRO_BUF_SIZE);
memset(key_buf, 0x00, KEY_BUF_SIZE);
buf_start=0;
buf_end=0;
sendkeys=false;
sendmedia=false;
}
// check if there are any key events waiting to be sent to the host and send
void keyboard_task() {
if (sendkeys) {
// send the current keyboard state to the host
if (tud_hid_report(REPORT_ID_KEYBOARD, nkro_buf, NKRO_BUF_SIZE)) {
sendkeys=false;
}
} else if (sendmedia) {
// send the media keys state to the the host
if (tud_hid_report(REPORT_ID_CONSUMER_CONTROL, mediakeys, 1)) {
sendmedia=false;
}
} else if (buf_start != buf_end) {
// previous key state has been send, but a new key state is waiting
// in the buffer
// load from buffer and setup for sending in the next round
updatekeys(key_buf[buf_start+1], &key_buf[buf_start+2], key_buf[buf_start]);
buf_start += (key_buf[buf_start] + 2);
} else if (buf_start == buf_end) {
// the buffer has been cleared, so reset the buffer position to front
buf_start = 0;
buf_end = 0;
}
}
// convert a boot keyboard packet into the NKRO bitmap format used by HyperX
void boot2nkro(uint8_t const* boot_report, uint8_t* nkro_report, uint16_t len) {
memset(nkro_report, 0x00, NKRO_BUF_SIZE);
(void) len;
// copy modifiers
nkro_report[0] = boot_report[0];
// set regular keyboard keys
for (pos=2; pos<8; pos++) {
if (boot_report[pos] > 0) {
SET_KEYBIT(nkro_report, boot_report[pos]+8);
}
}
}
// merge two NKRO keyboard bitmaps into a single NKRO keyboard bitmap
void merge_bitmap(uint8_t* nkro_report, uint8_t const* nkro_report1, uint8_t const* nkro_report2){
for (pos=0; pos < NKRO_BUF_SIZE; pos++) {
nkro_report[pos] = nkro_report1[pos] | nkro_report2[pos];
}
}
+7 -26
View File
@@ -1,6 +1,11 @@
#ifndef HYPERX_ELITE2_H_ #ifndef HYPERX_ELITE2_H_
#define HYPERX_ELITE2_H_ #define HYPERX_ELITE2_H_
#define LDR_PIN 28
#define LDR_ADC 2
#define LDR_OFF_THRESHOLD 500
#define LDR_ON_THRESHOLD 400
enum enum
{ {
HYPERX_KEYBOARD_VID = 0x0951, HYPERX_KEYBOARD_VID = 0x0951,
@@ -8,35 +13,11 @@ enum
NUM_KEYS = 128, NUM_KEYS = 128,
BUF_SIZE = 64, BUF_SIZE = 64,
NUM_PACKETS = 10, NUM_PACKETS = 10,
NKRO_BUF_SIZE = 15,
KEY_BUF_SIZE = 16*16,
};
enum
{
HYPERX_ITF_KEYBOARD = 0,
HYPERX_ITF_KEYPRESS,
HYPERX_ITF_NKRO
}; };
void get_light(); void get_light();
void rgb_task(uint8_t dev_addr, uint8_t instance, uint8_t report_id); void rgb_task(uint8_t dev_addr);
void send_color(uint8_t dev_addr, uint8_t instance, uint8_t report_id,
uint8_t red, uint8_t green, uint8_t blue);
void send_initial(uint8_t dev_addr, uint8_t instance, uint8_t report_id);
void startADC(); void startADC();
void send_media(uint8_t const* report, uint16_t len); bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len);
void keyboard_task();
void reset_keyboard();
void updatekeys(uint8_t instance, uint8_t const* report, uint16_t len);
void process_report(uint8_t instance, uint8_t const* report, uint16_t len);
void merge_bitmap(uint8_t* nkro_report, uint8_t const* nkro_report1, uint8_t const* nkro_report2);
void boot2nkro(uint8_t const* boot_report, uint8_t* nkro_report, uint16_t len);
#define SET_KEYBIT(array, index) do { (array)[(index) / 8] |= 1 << ((index) % 8); } while(0)
#define CLEAR_KEYBIT(array, index) do { (array)[(index) / 8] &= ~(1 << ((index) % 8)); } while(0)
#endif #endif
+24
View File
@@ -0,0 +1,24 @@
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "hardware/clocks.h"
#include "usb_device.h"
#include "usb_host.h"
// main loop
int main(void) {
// default 125MHz is not appropreate. Sysclock should be multiple of 12MHz.
set_sys_clock_khz(144000, true);
sleep_ms(10);
// run usb host on core 1
multicore_reset_core1();
multicore_launch_core1(usb_host_main);
// run usb device on core 0
usb_device_main();
return 0;
}
-93
View File
@@ -1,93 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "hardware/clocks.h"
#include "tusb.h"
#include "usb_descriptors.h"
#include "hyperx_elite2.h"
#include "main_host.h"
static absolute_time_t lastRead;
extern void core1_main();
int main(void) {
// default 125MHz is not appropreate. Sysclock should be multiple of 12MHz.
set_sys_clock_khz(144000, true);
// start ADC for reading LDR
startADC();
sleep_ms(10);
multicore_reset_core1();
// run TinyUSB host on core 1
multicore_launch_core1(core1_main);
// run TinyUSB device on core 0
tud_init(0);
while (true) {
if ( absolute_time_diff_us(lastRead, get_absolute_time()) > 500000) {
// read the ADC every 500ms to determine RGB lighting
get_light();
}
// check keyboard packet queue and send to TinyUSB device
keyboard_task();
// TinyUSB device task
tud_task();
}
return 0;
}
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
if (instance == 0 && report_type==HID_REPORT_TYPE_OUTPUT && report_id==REPORT_ID_KEYBOARD) {
// received keyboard indicator LED status from host, so update on
// the keyboard
set_indicator(buffer,bufsize);
}
// echo the HID report to CDC for debugging
char tempbuf[128];
size_t count;
if(bufsize>0) {
count = sprintf(tempbuf, "\nReceived device set report type %u on interface %u with ID %u (%u)\n", report_type, instance, report_id, bufsize);
tud_cdc_write(tempbuf, count);
for(int i=0;i<bufsize;i++){
count=sprintf(tempbuf,"%02X ",buffer[i]);
tud_cdc_write(tempbuf,count);
}
count = sprintf(tempbuf, "\n");
tud_cdc_write(tempbuf,count);
tud_cdc_write_flush();
}
}
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
(void) instance;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
return 0;
}
-117
View File
@@ -1,117 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "pio_usb.h"
#include "tusb.h"
#include "usb_descriptors.h"
#include "hyperx_elite2.h"
#include "main_host.h"
static bool enabled=false;
static uint8_t kb_addr=0;
// main process for core 1 to handle USB host events
void core1_main() {
sleep_ms(10);
// configure PIO USB for use as TinyUSB host
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.alarm_pool = (void*) alarm_pool_create(2,1);
tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
tuh_init(1);
while (true) {
if (enabled) {
// keyboard is plugged in, so send RGB states on regular intervals
rgb_task(kb_addr, HYPERX_ITF_KEYBOARD, REPORT_ID_KEYBOARD);
}
tuh_task(); // tinyusb host task
}
}
// Invoked when device with hid interface is mounted
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
{
(void)desc_report;
(void)desc_len;
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
// send device vid:pid information to CDC for debugging
char tempbuf[128];
size_t count = sprintf(tempbuf, "[%04x:%04x][%u] HID Interface %u, Protocol = %s \n", vid, pid, dev_addr, instance, protocol_str[itf_protocol]);
tud_cdc_write(tempbuf, count);
tud_cdc_write_flush();
// request to receive report if mounted device matches HyperX Alloy Elite 2
if (vid==HYPERX_KEYBOARD_VID && pid==HYPERX_ELITE2_PID)
{
enabled = true;
kb_addr = dev_addr;
reset_keyboard();
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
//tud_cdc_write_str("Error: cannot request report\r\n");
}
}
}
// Invoked when device with hid interface is un-mounted
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
(void) instance;
if(dev_addr==kb_addr){
kb_addr=0;
enabled=false;
}
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
char tempbuf[64];
size_t count;
if(len>0) {
// echo HID report to CDC for debugging
count = sprintf(tempbuf, "\n[%u] Received message on interface %u (%u)\n", dev_addr, instance, len);
tud_cdc_write(tempbuf, count);
for(int i=0;i<len;i++){
count=sprintf(tempbuf,"%02X ",report[i]);
tud_cdc_write(tempbuf,count);
}
count = sprintf(tempbuf, "\n");
tud_cdc_write(tempbuf,count);
tud_cdc_write_flush();
// send report for processing to send to host
if (enabled && kb_addr == dev_addr) {
process_report(instance, report, len);
}
}
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
//tud_cdc_write_str("Error: cannot request report\r\n");
}
}
void set_indicator(uint8_t const* buffer, uint16_t len) {
// received new keyboard indicator LED status from host - pass to
// keyboard device so indicators can be updated
tuh_hid_set_report(kb_addr, HYPERX_ITF_KEYBOARD, REPORT_ID_KEYBOARD, HID_REPORT_TYPE_OUTPUT, buffer, len);
}
-7
View File
@@ -1,7 +0,0 @@
#ifndef MAIN_HOST_H_
#define MAIN_HOST_H_
void set_indicator(uint8_t const* buffer, uint16_t len);
#endif
+1 -1
View File
@@ -84,7 +84,7 @@
//-----------------------Driver configuration------------------------- //-----------------------Driver configuration-------------------------
#define CFG_TUD_CDC 1 #define CFG_TUD_CDC 1
#define CFG_TUD_HID 1 #define CFG_TUD_HID 4
// CDC FIFO size of TX and RX // CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE 128 #define CFG_TUD_CDC_RX_BUFSIZE 128
-175
View File
@@ -1,175 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* sekigon-gonnoc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
#include "bsp/board_api.h"
#include "usb_descriptors.h"
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// 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;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
uint8_t const desc_hid_report[] =
{
TUD_HID_REPORT_DESC_NKRO( HID_REPORT_ID(REPORT_ID_KEYBOARD)),
TUD_HID_REPORT_DESC_MEDIA( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL)),
};
// full speed configuration
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, protocol, report descriptor len, EP In address, size
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 1),
};
// 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_fs_configuration;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Raspberry Pi", // 1: Manufacturer
"Pico HyperX RGB Controller", // 2: Product
NULL, // 3: Serials, should use chip ID
"Pico HyperX CDC", // 4: CDC
"Pico HyperX HID", // 5: HID
};
static uint16_t _desc_str[32+1];
// 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;
uint8_t chr_count;
switch (index) {
case 0: // langid
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
break;
case 3: // serial
chr_count = board_usb_get_serial(_desc_str+1, 32);
break;
default:
// 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])) ) return NULL;
char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++) {
_desc_str[1+i] = str[i];
}
break;
}
// 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;
}
//--------------------------------------------------------------------+
// Device HID
//--------------------------------------------------------------------+
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
{
(void) itf;
return desc_hid_report;
}
-65
View File
@@ -1,65 +0,0 @@
#ifndef USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_
enum
{
REPORT_ID_KEYBOARD = 1,
REPORT_ID_CONSUMER_CONTROL,
REPORT_ID_COUNT
};
enum
{
ITF_NUM_CDC=0,
ITF_NUM_CDC_DATA,
ITF_NUM_HID,
ITF_NUM_TOTAL
};
#define USB_PID 0xE2BD
#define USB_VID 0xCEC0
#define USB_BCD 0x0200
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_HID 0x83
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_DESC_LEN)
#define TUD_HID_REPORT_DESC_NKRO(...) \
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(HID_USAGE_PAGE_KEYBOARD), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
__VA_ARGS__ HID_REPORT_SIZE(1), HID_REPORT_COUNT(8), \
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(224), \
HID_USAGE_MAX(231), HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \
HID_INPUT(HID_VARIABLE), \
HID_REPORT_SIZE(1), HID_REPORT_COUNT(5), \
HID_USAGE_PAGE(HID_USAGE_PAGE_LED), HID_USAGE_MIN(1), HID_USAGE_MAX(5), \
HID_OUTPUT(HID_VARIABLE), HID_REPORT_SIZE(3), HID_REPORT_COUNT(1),\
HID_OUTPUT(HID_CONSTANT), \
HID_REPORT_SIZE(1), HID_REPORT_COUNT(14 * 8), \
HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(0), \
HID_USAGE_MAX(14 * 8 - 1), HID_INPUT(HID_VARIABLE), HID_COLLECTION_END
#define TUD_HID_REPORT_DESC_MEDIA(...) \
HID_USAGE_PAGE(HID_USAGE_PAGE_CONSUMER), \
HID_USAGE(HID_USAGE_CONSUMER_CONTROL), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
__VA_ARGS__ \
HID_LOGICAL_MIN(0), \
HID_LOGICAL_MAX(1), \
HID_REPORT_SIZE(1), \
HID_REPORT_COUNT(8), \
/* next, previous, play/pause, mute, vol up, vol down*/ \
HID_USAGE(0xB5), \
HID_USAGE(0xB6), \
HID_USAGE(0xCD), \
HID_USAGE(0xE2), \
HID_USAGE(0xE9), \
HID_USAGE(0xEA), \
HID_INPUT(HID_VARIABLE), \
HID_COLLECTION_END
#endif /* USB_DESCRIPTORS_H_ */
+229
View File
@@ -0,0 +1,229 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "bsp/board_api.h"
#include "tusb.h"
#include "hyperx_elite2.h"
#include "usb_host.h"
#include "usb_device.h"
char cdc_buf[64];
uint16_t cdc_len;
size_t cdc_count;
device_state_t device_state;
static uint8_t desc_configuration[DESC_CFG_MAX];
static uint16_t _desc_str[32+1];
static tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Raspberry Pi", // 1: Manufacturer
"Pico HyperX Elite 2 RGB Controller", // 2: Product
NULL, // 3: Serials, should use chip ID
"Pico HyperX Elite 2 CDC", // 4: CDC
"Pico HyperX Elite 2 HID", // 5: HID
};
static void usb_device_init(void);
// main task for USB device
void usb_device_main(void) {
// start ADC for reading LDR
startADC();
// initialize TinyUSB device
device_state = DEVICE_INACTIVE;
usb_device_init();
while (true) {
switch ( device_state ) {
case DEVICE_ACTIVE:
break;
case DEVICE_INACTIVE:
break;
case DEVICE_RESTART:
if (tud_disconnect()) {
sleep_ms(100);
if (tud_connect()) {
if ( host_state == HOST_INACTIVE ) {
device_state = DEVICE_INACTIVE;
} else {
device_state = DEVICE_ACTIVE;
}
}
}
break;
default:
break;
}
get_light(); // get the ADC LDR reading
tud_task();
tud_cdc_write_flush();
}
}
// initialize the TinyUSB device
static void usb_device_init(void) {
// run TinyUSB device
tusb_rhport_init_t dev_init = {
.role = TUSB_ROLE_DEVICE,
.speed = TUSB_SPEED_AUTO,
};
tusb_init(BOARD_TUH_RHPORT, &dev_init);
}
// 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;
}
// 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
memset(desc_configuration, 0, sizeof(desc_configuration));
uint8_t desc_initial[TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+1] = {
TUD_CONFIG_DESCRIPTOR(1, 2+num_mounted, 0, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+num_mounted*TUD_HID_DESC_LEN, 0x00, 100),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
};
memcpy(desc_configuration, desc_initial, TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN);
if ( descriptors != NULL) {
struct report_desc *descriptor;
for (uint8_t i=0; i<num_mounted; i++) {
descriptor = report_desc_find(descriptors->dev_addr, i);
uint8_t hid_desc[TUD_HID_DESC_LEN+1] = {
TUD_HID_DESCRIPTOR(ITF_NUM_HID+i, 5, HID_ITF_PROTOCOL_NONE, descriptor->desc_len, EPNUM_HID+i, CFG_TUD_HID_EP_BUFSIZE, 1)
};
memcpy(&desc_configuration[TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN+i*TUD_HID_DESC_LEN], hid_desc, TUD_HID_DESC_LEN);
}
}
return desc_configuration;
}
// 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;
uint8_t chr_count;
switch (index) {
case 0: // langid
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
break;
case 3: // serial
chr_count = board_usb_get_serial(_desc_str+1, 32);
break;
default:
// 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])) ) return NULL;
char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++) {
_desc_str[1+i] = str[i];
}
break;
}
// 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;
}
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
{
if ( descriptors != NULL) {
struct report_desc * descriptor = report_desc_find(descriptors->dev_addr, itf);
if ( descriptor != NULL ) {
return descriptor->descriptor;
}
}
return NULL;
}
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
// forward to device connected to host
if (descriptors != NULL) {
tuh_hid_set_report(descriptors->dev_addr, instance, report_id, report_type, buffer, bufsize);
}
}
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
(void) instance;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
return 0;
}
// print message to CDC in raw hex
void cdc_print_hex(uint8_t const* msg, uint16_t msg_len) {
(void) msg;
(void) msg_len;
for (int i=0; i<msg_len; i++) {
cdc_count=sprintf(cdc_buf, "%02X ", msg[i]);
tud_cdc_write(cdc_buf, cdc_count);
}
tud_cdc_write_str("\n");
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef USB_DEVICE_H_
#define USB_DEVICE_H_
#define DESC_CFG_MAX TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN
#define USB_PID 0xE2BD
#define USB_VID 0xCEC0
#define USB_BCD 0x0200
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_HID 0x83
enum
{
ITF_NUM_CDC=0,
ITF_NUM_CDC_DATA,
ITF_NUM_HID
};
typedef enum {
DEVICE_INACTIVE=0,
DEVICE_ACTIVE,
DEVICE_RESTART,
} device_state_t;
extern char cdc_buf[64];
extern uint16_t cdc_len;
extern size_t cdc_count;
extern device_state_t device_state;
void usb_device_main(void);
void cdc_print_hex(uint8_t const* msg, uint16_t msg_len);
#endif
+300
View File
@@ -0,0 +1,300 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pio_usb.h"
#include "tusb.h"
#include "hyperx_elite2.h"
#include "usb_device.h"
#include "usb_host.h"
host_state_t host_state;
struct report_desc *descriptors;
uint8_t num_mounted=0;
static absolute_time_t request_time;
static struct report_data *report;
static bool enabled=false;
static uint8_t kb_addr=0;
static void usb_host_init(void);
static void host_ready(void);
static bool request_hid_report(uint8_t dev_addr, uint8_t instance);
static bool stop_hid_report(uint8_t dev_addr, uint8_t instance);
static bool request_hid_reports_all(void);
static bool stop_hid_reports_all(void);
static struct report_desc* report_desc_alloc(void);
static void report_desc_init(struct report_desc *descriptor);
static void report_desc_free(struct report_desc *descriptor);
static bool add_descriptor(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
static void remove_instance(uint8_t dev_addr, uint8_t instance);
// initialize usb host
static void usb_host_init(void) {
// configure PIO USB for TinyUSB host
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.alarm_pool = (void*) alarm_pool_create(2,1);
tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
// run TinyUSB host
tusb_rhport_init_t host_init = {
.role = TUSB_ROLE_HOST,
.speed = TUSB_SPEED_AUTO,
};
tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
tusb_init(BOARD_TUH_RHPORT, &host_init);
host_state=HOST_INACTIVE;
}
void usb_host_main(void) {
usb_host_init();
while (true) {
switch ( host_state ) {
case HOST_MOUNTED:
device_state = DEVICE_RESTART;
host_ready();
break;
case HOST_UNMOUNTED:
host_state = HOST_MOUNTED;
break;
case HOST_START_LISTEN:
request_hid_reports_all();
break;
case HOST_STOP_LISTEN:
stop_hid_reports_all();
break;
case HOST_LISTENING:
if (enabled) {
rgb_task(kb_addr);
}
break;
default:
break;
}
tuh_task();
}
}
// Invoked when device with hid interface is mounted
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
{
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
/// send device vid:pid information to CDC for debugging
cdc_count = sprintf(cdc_buf, "Mount: [%04x:%04x][%u:%u] Protocol = %u\n", vid, pid, dev_addr, instance, itf_protocol);
tud_cdc_write(cdc_buf, cdc_count);
if (vid==HYPERX_KEYBOARD_VID && pid==HYPERX_ELITE2_PID) {
kb_addr = dev_addr;
enabled = true;
}
// add to HID report descriptor
if ( add_descriptor(dev_addr, instance, desc_report, desc_len)) {
num_mounted++;
host_state=HOST_MOUNTED;
request_time=get_absolute_time();
}
}
// Invoked when device with hid interface is un-mounted
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
// send device address:instance to CDC for debugging
cdc_count = sprintf(cdc_buf, "Unmount: [%u:%u]\n", dev_addr, instance);
tud_cdc_write(cdc_buf, cdc_count);
if (stop_hid_report(dev_addr, instance)) {
tud_cdc_write_str("Successfully stopped receiving reports\n");
}
remove_instance(dev_addr, instance);
if (dev_addr == kb_addr) {
enabled = false;
}
num_mounted--;
host_state=HOST_UNMOUNTED;
request_time=get_absolute_time();
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
if (len > 0 ) {
cdc_count = sprintf(cdc_buf, "[%u:%u](%u) ", dev_addr, instance, len);
tud_cdc_write(cdc_buf,cdc_count);
cdc_print_hex(report, len);
}
forward_report(instance, report, len);
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
tud_cdc_write_str("Error: cannot request report\r\n");
}
}
// start listening on host for HID events
static void host_ready(void) {
if (absolute_time_diff_us(request_time, get_absolute_time()) >= 500000){
if( descriptors != NULL ) {
host_state = HOST_START_LISTEN;
} else {
host_state = HOST_INACTIVE;
}
}
}
// request HID input reports on specified device address and instance
static bool request_hid_report(uint8_t dev_addr, uint8_t instance) {
// request to receive reports HID devices
if ( !tuh_hid_receive_report(dev_addr, instance) ) {
cdc_count = sprintf(cdc_buf, "Error: cannot request report on [%u:%u]\n", dev_addr, instance);
tud_cdc_write(cdc_buf, cdc_count);
return false;
}
return true;
}
// stop receiving HID input reports on specified device address and instance
static bool stop_hid_report(uint8_t dev_addr, uint8_t instance) {
if (!tuh_hid_receive_abort(dev_addr, instance)) {
tud_cdc_write_str("Error: could not stop receiving reports\n");
return false;
}
return true;
}
// start listening to HID input reports on all mounted devices
static bool request_hid_reports_all(void) {
// send request to receive reports on all mounted devices
struct report_desc * current;
for (current=descriptors; current != NULL; current=current->next) {
if (! current->listening) {
if(request_hid_report(current->dev_addr, current->instance)) {
cdc_count = sprintf(cdc_buf, "Listening to input reports on [%u:%u]\n", current->dev_addr, current->instance);
tud_cdc_write(cdc_buf, cdc_count);
current->listening = true;
} else {
tud_cdc_write_str("Error listening to input report(s)\n");
stop_hid_reports_all();
return false;
}
}
}
host_state = HOST_LISTENING;
return true;
}
// stop listening to HID input reports on all mounted devices
static bool stop_hid_reports_all(void) {
// send request to stop reports on all mounted devices
struct report_desc * current;
for (current=descriptors; current != NULL; current=current->next) {
if (current->listening) {
if(stop_hid_report(current->dev_addr, current->instance)) {
cdc_count = sprintf(cdc_buf, "Stopping input reports on [%u:%u]\n", current->dev_addr, current->instance);
tud_cdc_write(cdc_buf, cdc_count);
current->listening = false;
} else {
tud_cdc_write_str("Error stopping input report(s)\n");
return false;
}
}
}
host_state = HOST_INACTIVE;
return true;
}
// allocate memory for USB interface report descriptor
static struct report_desc * report_desc_alloc(void) {
struct report_desc *ret = REPORT_DESC_ALLOC();
if (ret != NULL) {
report_desc_init(ret);
if (descriptors == NULL) {
descriptors = ret;
} else {
struct report_desc *last;
for (last = descriptors; last->next != NULL; last=last->next);
last->next = ret;
}
}
return ret;
}
// initialize report descriptor struct
static void report_desc_init(struct report_desc *descriptor) {
memset(descriptor, 0, sizeof(struct report_desc));
descriptor->next = NULL;
}
// free memory and teardown usb->bt report ID mappings for report descriptor struct
static void report_desc_free(struct report_desc *descriptor) {
if (descriptor != NULL) {
if (descriptors == descriptor) {
descriptors = descriptor->next;
} else {
struct report_desc *last;
for (last = descriptors; last->next != NULL; last = last->next) {
if ((last->next) == descriptor) {
last->next = descriptor->next;
break;
}
}
}
free(descriptor);
}
}
// add report descriptor for new HID interface
static bool add_descriptor(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
struct report_desc * descriptor = report_desc_alloc();
if (descriptor == NULL) {
return false;
}
memcpy(descriptor->descriptor, desc_report, desc_len);
descriptor->desc_len = desc_len;
descriptor->dev_addr = dev_addr;
descriptor->instance = instance;
descriptor->listening = false;
return true;
}
// remove report descriptor for HID interface
static void remove_instance(uint8_t dev_addr, uint8_t instance) {
struct report_desc *descriptor = report_desc_find(dev_addr, instance);
if (descriptor != NULL) {
report_desc_free(descriptor);
}
}
// find report descriptor by device address and instance
struct report_desc * report_desc_find(uint8_t dev_addr, uint8_t instance) {
struct report_desc *descriptor;
for (descriptor = descriptors; descriptor != NULL; descriptor = descriptor->next) {
if (descriptor->dev_addr==dev_addr && descriptor->instance==instance) {
break;
}
}
return descriptor;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef USB_HOST_H_
#define USB_HOST_H_
#define REPORT_MAX_SIZE 64
#define REPORT_BUF_SIZE 256
#define DESCRIPTOR_MAX_SIZE 256
typedef enum {
HOST_INACTIVE=0,
HOST_MOUNTED,
HOST_UNMOUNTED,
HOST_START_LISTEN,
HOST_LISTENING,
HOST_STOP_LISTEN,
} host_state_t;
struct report_desc {
uint8_t dev_addr;
uint8_t instance;
uint8_t descriptor[DESCRIPTOR_MAX_SIZE];
uint16_t desc_len;
struct report_desc *next;
bool listening;
};
struct report_data {
uint8_t dev_addr;
uint8_t instance;
uint8_t report[REPORT_MAX_SIZE];
uint16_t len;
};
#define REPORT_DESC_ALLOC() (struct report_desc *)malloc(sizeof(struct report_desc))
#define REPORT_DATA_ALLOC() (struct report_data *)malloc(sizeof(struct report_data))
extern host_state_t host_state;
extern struct report_desc *descriptors;
extern uint8_t num_mounted;
void usb_host_main(void);
struct report_desc * report_desc_find(uint8_t dev_addr, uint8_t instance);
#endif