#include #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); }