Files
alloy_elite2_rgb/hyperx_elite2.c
T
2025-08-23 21:13:11 -04:00

185 lines
5.2 KiB
C

#include <stdlib.h>
#include "pico/stdlib.h"
#include "tusb.h"
#include "hardware/adc.h"
#include "hyperx_elite2.h"
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 };
static unsigned char buf[BUF_SIZE];
static uint8_t buf_idx=0;
static uint8_t packets_sent=0;
static uint8_t color_idx = 0;
static uint8_t skipped = 0;
const unsigned int* skip_idx = &SKIP_INDICES[0];
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 every 500ms
// if above threshold, set backlight to off
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) {
// 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
// updated color info (packets_sent>0) and continue to send the next
// packet if so at a rate of one packet every 20ms
// otherwise, wait 0.5s before sending the next set of color packets
if (packets_sent>0) {
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 20000) {
if( backlight) {
send_color(dev_addr, 0x20, 0x20, 0x20);
// send a dim white color (#202020) for all keys
} else{
send_color(dev_addr, 0x00, 0x00, 0x00);
// turn off all lighting by sending (#000000) for all keys
}
lastSend = get_absolute_time();
}
} else {
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
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;
// check if there are still keys left to send and send updated colors
// for those keys
// each key gets 4 bytes - an init byte (0x81) plus 3 bytes for RGB
if(color_idx < NUM_KEYS)
{
while(color_idx < NUM_KEYS && buf_idx < BUF_SIZE){
if(*skip_idx == color_idx + skipped)
{
// keys in skip_idx are not assigned to a key, so send all 0x00
buf[buf_idx] = 0x00;
buf[buf_idx + 1] = 0x00;
buf[buf_idx + 2] = 0x00;
buf[buf_idx + 3] = 0x00;
skip_idx++;
if(skip_idx >= SKIP_INDICES + sizeof(SKIP_INDICES) / sizeof(unsigned int))
{
skip_idx = SKIP_INDICES;
}
skipped++;
} else {
// start by sending color init byte for the current key
buf[buf_idx] = 0x81;
// turn rewind, play, and fast forward keys to white
if(color_idx==105 || color_idx==108 || color_idx==109) {
buf[buf_idx + 1] = 0x20;
buf[buf_idx + 2] = 0x20;
buf[buf_idx + 3] = 0x20;
} else if(color_idx==99) {
// set color of mute button to green or red based on mute
// toggle - note that this toggle is not synced to the PC's
// audio state and is presumed to be unmuted when the keyboard
// first receives power
if(mute) {
buf[buf_idx + 1] = 0x40;
buf[buf_idx + 2] = 0x00;
buf[buf_idx + 3] = 0x00;
} else {
buf[buf_idx + 1] = 0x00;
buf[buf_idx + 2] = 0x40;
buf[buf_idx + 3] = 0x00;
}
} else {
// for a normal key, send the desired RGB colors
buf[buf_idx + 1] = red;
buf[buf_idx + 2] = green;
buf[buf_idx + 3] = blue;
}
color_idx++;
}
buf_idx += 4;
}
if(tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{
// packet sent successfully, increment
packets_sent++;
}
} else {
if(packets_sent < 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,
// send extra packets of all 0x00 until done
if(tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{
packets_sent++;
}
} else {
// a full round of color packets completed, reset packets to 0
packets_sent=0;
}
}
}
// send the special initialization packet that tells the keyboard to expect
// color packets to follow
static void send_initial(uint8_t dev_addr) {
memset(buf, 0x00, BUF_SIZE);
color_idx = 0;
skipped = 0;
skip_idx = &SKIP_INDICES[0];
// send initialization packet
buf[0x00] = 0x04;
buf[0x01] = 0xf2;
if (tuh_hid_set_report(dev_addr, 0, 0, HID_REPORT_TYPE_FEATURE, buf, BUF_SIZE))
{
// we have begun sending packets, so indicate first packet was sent
// remaining packets will be sent at regular intervals
packets_sent=1;
}
}
// initialize the ADC for reading the LDR
void startADC() {
stdio_init_all();
adc_init();
adc_gpio_init(LDR_PIN);
adc_select_input(LDR_ADC);
}
// 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);
}