complete refactor to directly pass reports and interfaces
This commit is contained in:
+3
-3
@@ -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.
+32
-170
@@ -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) {
|
||||||
|
adc_value = adc_read();
|
||||||
|
if (backlight && adc_value >= LDR_OFF_THRESHOLD) {
|
||||||
backlight = false;
|
backlight = false;
|
||||||
} else {
|
} else if (!backlight && adc_value <= LDR_ON_THRESHOLD) {
|
||||||
backlight = true;
|
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 ) {
|
|
||||||
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;
|
mute = !mute;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
return tud_hid_n_report(instance, 0, report, len);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
@@ -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");
|
||||||
|
}
|
||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user