From a1cb13a2f9a97e902f351dc6feb70b11727cc3d5 Mon Sep 17 00:00:00 2001 From: kenji Date: Sat, 6 Sep 2025 12:01:00 -0400 Subject: [PATCH] Add Pico 2 support --- CMakeLists.txt | 6 +++++- README.md | 34 +++++++++++++++++----------------- hyperx_elite2.c | 30 +++++++----------------------- hyperx_elite2.h | 10 +++++++++- my_fsdata.c | 26 +++++++++++++++++++++++++- usb_device.c | 4 ++-- usb_device.h | 4 ++-- websocket.c | 9 +++++---- websocket.h | 2 +- 9 files changed, 73 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 361ffa5..5054aa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.13) set(PICO_SDK_PATH /home/kenji/programming/pico/c/pico-sdk) set(PICO_PIO_USB_PATH /home/kenji/programming/pico/c/Pico-PIO-USB) set(TUSB_NETWORKING_PATH ${PICO_SDK_PATH}/lib/tinyusb/lib/networking) +if (NOT DEFINED PICO_BOARD) + set(PICO_BOARD pico) +endif() include (${PICO_SDK_PATH}/external/pico_sdk_import.cmake) project(${PROJECT} C CXX ASM) @@ -67,5 +70,6 @@ target_link_libraries(${PROJECT} PRIVATE hardware_adc ) -pico_add_extra_outputs(${PROJECT}) +set_target_properties(${PROJECT} PROPERTIES OUTPUT_NAME "${PROJECT}-${PICO_BOARD}") +pico_add_extra_outputs(${PROJECT}) diff --git a/README.md b/README.md index 4598a60..d37af5d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # HyperX Alloy Elite 2 RGB Controller This project provides individual controls of the RGB LEDs of a HyperX Alloy -Elite 2 keyboard using a webpage served over a USB connection. ADC readings -from an attached light dependent resistor can also be used to make the -lighting adaptive to the environment. +Elite 2 keyboard using a webpage served over a USB connection from a Raspberry +Pi Pico (2). ADC readings from an attached light dependent resistor can also be +used to make the lighting adaptive to the environment. ![Web interface for setting individual LED RGB values](ui.png) @@ -12,23 +12,23 @@ lighting adaptive to the environment. ### Hardware You will need the following hardware to make the device: -- Raspberry Pi Pico +- Raspberry Pi Pico or Raspberry Pi Pico 2 - USB extension cable - light dependent resistor such as GL5528 (specific part number may vary) - 10k ohm resistor (resistance value may vary) You will need to cut the USB extension in half and connect the wires from the -female end to the Raspberry Pi Pico. The default configuration is to attach the -USB's green wire to pin 1/GP0 and USB's white wire to pin 2/GP1. You will also -need to connect the red to 5V VBUS/VSYS (since you'll be powering from the +female end to the Raspberry Pi Pico (2). The default configuration is to attach +the USB's green wire to pin 1/GP0 and USB's white wire to pin 2/GP1. You will +also need to connect the red to 5V VBUS/VSYS (since you'll be powering from the USB host device, VBUS should be fine) and the black to any ground pin. Pin 38 is the closest and most convenient. While you can connect the Raspberry Pi Pico -to the host device using the micro USB port and a micro USB cable, since +(2) to the host device using the micro USB port and a micro USB cable, since you have already sacrificed half of the USB extension cable, you might as well use the male half to create a standard USB-A connection. If you wish to do so, then simply connect the red and black wires of the male connector end to VBUS (5V) and GND, respectively. For the data wires, you can solder them to the -two test points TP2 and TP3 on the back of the Raspberry Pi Pico. The white +two test points TP2 and TP3 on the back of the Raspberry Pi Pico (2). The white cable goes to TP2 and the green cable to TP3. ![Back of Raspberry Pi Pico with USB connections to TP2 and TP3](back.jpg) @@ -49,23 +49,23 @@ hole for the LDR to detect ambient light. ## Software -Flash the elite2_rgb.uf2 file from the latest +Flash the elite2_rgb-pico.uf2 or elite2_rgb-pico2.uf2 file from the latest [release](https://git.kkozai.com/kenji/alloy_elite2_rgb/releases) to the -Raspberry Pi Pico, and connect the keyboard to the female USB port and insert -the male USB connector of the device into your host device such as PC. +Raspberry Pi Pico (2), and connect the keyboard to the female USB port and +insert the male USB connector of the device into your host device such as PC. To load the UI for configuring the RGB lighting, open a browser to the page at http://alloyelite2.usb, or if that doesn't load, to http://192.168.226.1 -(226 is E2 for "Elite 2" in hexademical). From the webpage, you can click on +(226 is E2 for "Elite 2" in hexadecimal). From the webpage, you can click on any individual key that you want to configure and change the color using the color selector or by manually inputting the RGB color value into the text boxes. To finalize setting the color for the selected key(s), click on the "Set Color" button. -To save the lighting configuration to the Pico 2 so that it loads the next time -it is powered on, click on the "Save" button under the "Flash Memory" section. -If you make unsaved changes and want to reload the configuration from memory, -you can also click the "Load" button to reset to the last saved setting. +To save the lighting configuration to the Pico (2) so that it loads the next +time it is powered on, click on the "Save" button under the "Flash Memory" +section. If you make unsaved changes and want to reload the configuration from +memory, you can also click the "Load" button to reset to the last saved setting. If the checkbox next to "Adaptive" is selected when setting the color, the key's brightness will automatically adjust with the ambient lighting, as determined by diff --git a/hyperx_elite2.c b/hyperx_elite2.c index aef2e61..e13a68b 100644 --- a/hyperx_elite2.c +++ b/hyperx_elite2.c @@ -1,4 +1,5 @@ #include +#include #include "pico/stdlib.h" #include "pico/multicore.h" @@ -13,7 +14,8 @@ static absolute_time_t lastSend; static absolute_time_t lastRead; -static uint16_t adc_value = 0; +//static uint16_t adc_value = 0; +static uint8_t adc_value = 0; static bool mute = false; static unsigned char buf[BUF_SIZE]; @@ -165,7 +167,7 @@ static struct key key_list[NUM_KEYS] = void get_light() { // get ADC reading from LDR every 500ms if ( absolute_time_diff_us(lastRead, get_absolute_time()) >= 500000) { - adc_value = adc_read(); + adc_value = log2(adc_read()); } } @@ -176,24 +178,6 @@ void rgb_task(uint8_t dev_addr) { // 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(); - } - }*/ if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= delay) { if ( packets_sent == 0) { // first packet is initialization packet @@ -227,9 +211,9 @@ static void send_color(uint8_t dev_addr) { buf[buf_idx] = 0x81; switch (key_list[key_idx].mode) { case RGB_MODE_ADAPTIVE: // adjust brightness based on LDR ADC reading - buf[buf_idx+1] = (ADC_MAX-adc_value)*key_list[key_idx].red/ADC_MAX; - buf[buf_idx+2] = (ADC_MAX-adc_value)*key_list[key_idx].green/ADC_MAX; - buf[buf_idx+3] = (ADC_MAX-adc_value)*key_list[key_idx].blue/ADC_MAX; + buf[buf_idx+1] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].red/ADC_MAX_LOG2; + buf[buf_idx+2] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].green/ADC_MAX_LOG2; + buf[buf_idx+3] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].blue/ADC_MAX_LOG2; break; case RGB_MODE_MUTE: if (mute) { diff --git a/hyperx_elite2.h b/hyperx_elite2.h index b301b5d..c1472ed 100644 --- a/hyperx_elite2.h +++ b/hyperx_elite2.h @@ -11,6 +11,7 @@ #define NUM_KEYS 126 #define BUF_SIZE 64 #define ADC_MAX 4096 +#define ADC_MAX_LOG2 log2(ADC_MAX) enum { RGG_MODE_INVALID=0, @@ -187,6 +188,13 @@ bool load_rgb_config(void); #define CFG_SIGNATURE 0x9e4c -#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) +#if PICO_RP2040 + #define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) +#elif PICO_RP2350 + #define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_BLOCK_SIZE - FLASH_SECTOR_SIZE) +#else + #error "Unsupported device. Expected RP2040 or RP2350." +#endif + #endif diff --git a/my_fsdata.c b/my_fsdata.c index b43e45a..781f5af 100644 --- a/my_fsdata.c +++ b/my_fsdata.c @@ -1034,7 +1034,31 @@ static const unsigned char data_index_html[] = { 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x3c, 0x20, 0x30, 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, - 0x3d, 0x20, 0x30, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9, + 0x3d, 0x20, 0x30, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0x20, 0x65, + 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x20, 0x69, + 0x73, 0x4e, 0x61, 0x4e, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, + 0x49, 0x6e, 0x74, 0x28, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x29, 0x20, + 0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x2f, 0x2f, 0x20, + 0x6e, 0x6f, 0x6e, 0x2d, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x20, 0x73, + 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x3d, 0x20, 0x31, 0x32, 0x38, 0x3b, 0xa, 0x9, 0x9, + 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0xa, 0x9, + 0x9, 0x9, 0x2f, 0x2f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x62, + 0x6f, 0x78, 0x20, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, + 0x73, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x6b, 0x73, + 0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, + 0x70, 0x61, 0x72, 0x73, 0x65, 0x49, 0x6e, 0x74, 0x28, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9, 0x7d, 0xa, 0xa, 0x9, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x72, diff --git a/usb_device.c b/usb_device.c index d184a6a..cc267a3 100644 --- a/usb_device.c +++ b/usb_device.c @@ -13,9 +13,9 @@ #include "usb_device.h" -char cdc_buf[64]; +char cdc_buf[128]; uint16_t cdc_len; -size_t cdc_count; +uint32_t cdc_count; device_state_t device_state; static uint8_t desc_configuration[DESC_CFG_MAX]; diff --git a/usb_device.h b/usb_device.h index 9d0b662..49b559a 100644 --- a/usb_device.h +++ b/usb_device.h @@ -30,9 +30,9 @@ typedef enum { DEVICE_RESTART, } device_state_t; -extern char cdc_buf[64]; +extern char cdc_buf[128]; extern uint16_t cdc_len; -extern size_t cdc_count; +extern uint32_t cdc_count; extern device_state_t device_state; void usb_device_main(void); diff --git a/websocket.c b/websocket.c index 9df358a..54deee0 100644 --- a/websocket.c +++ b/websocket.c @@ -354,12 +354,14 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p uint8_t masked = data[1] & 0x80; uint16_t msg_len = data[1] & 0x7F; uint8_t *msg; - + uint8_t *mask; + switch (msg_len) { case 126: // next two bytes are length - memcpy(&msg_len, &data[2], 2); + msg_len = ( (uint16_t)data[2] << 8) | data[3]; if (len >= 8) { msg = &data[8]; + mask = &data[4]; } break; case 127: // next four bytes are length @@ -369,6 +371,7 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p default: if (len >= 6) { msg = &data[6]; + mask = &data[2]; } break; } @@ -382,8 +385,6 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p if (msg && ws_receive_cb != NULL) { // unmask the data if mask bit is received if (masked) { - uint8_t *mask = &data[2]; - for (int i=0; i