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
+35 -173
View File
@@ -5,11 +5,13 @@
#include "hardware/adc.h"
#include "hyperx_elite2.h"
#include "usb_descriptors.h"
static bool sending = false;
static absolute_time_t lastTime;
static absolute_time_t lastSend;
static absolute_time_t lastRead;
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 };
@@ -20,30 +22,23 @@ static uint8_t color_idx = 0;
static uint8_t skipped = 0;
const unsigned int* skip_idx = &SKIP_INDICES[0];
static unsigned char nkro_buf[NKRO_BUF_SIZE];
static unsigned char nkro_buf1[NKRO_BUF_SIZE];
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;
static void send_color(uint8_t dev_addr, uint8_t red, uint8_t green, uint8_t blue);
static void send_initial(uint8_t dev_addr);
void get_light() {
// get ADC reading from LDR
// get ADC reading from LDR every 500ms
// if above threshold, set backlight to off
if (adc_read() > 400) {
backlight = false;
} else {
backlight = true;
if ( absolute_time_diff_us(lastRead, get_absolute_time()) >= 500000) {
adc_value = adc_read();
if (backlight && adc_value >= LDR_OFF_THRESHOLD) {
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
// multiple packets
// 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
// otherwise, wait 1s before sending the next set of color packets
if (sending) {
if ( absolute_time_diff_us(lastTime, get_absolute_time()) > 20000) {
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 20000) {
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
} 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
}
lastTime = get_absolute_time();
lastSend = get_absolute_time();
}
} else {
if ( absolute_time_diff_us(lastTime, get_absolute_time()) > 500000) {
send_initial(dev_addr, instance, report_id);
lastTime = get_absolute_time();
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 500000) {
send_initial(dev_addr);
lastSend = get_absolute_time();
}
}
}
// 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);
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;
}
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
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
// packets to be sent in total; if we have not sent enough packets,
// 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++;
}
@@ -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
// 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);
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[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
// packets at regular intervals
@@ -177,148 +172,15 @@ void send_initial(uint8_t dev_addr, uint8_t instance, uint8_t report_id) {
void startADC() {
stdio_init_all();
adc_init();
adc_gpio_init(28);
adc_select_input(2);
adc_gpio_init(LDR_PIN);
adc_select_input(LDR_ADC);
}
// process media key presses and prepare HID Consumer Control byte
void send_media(uint8_t const* report, uint16_t len) {
(void) len;
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;
}
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;
// forward HID report after processing
bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len) {
if (instance == 0x01 && report[0] == 0x03 && report[1] == 0xE2) {
mute = !mute;
}
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];
}
}