From 16effbe35befc3d480e27bec64781b83b8080039 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Fri, 22 Jul 2022 03:23:31 +0000 Subject: [PATCH] Initial support for SRGBmods Raspberry Pi Pico LED Controller --- .../RGBController_SRGBmodsPico.cpp | 157 ++++++++++++++++++ .../RGBController_SRGBmodsPico.h | 38 +++++ .../SRGBmodsControllerDetect.cpp | 45 +++++ .../SRGBmodsPicoController.cpp | 129 ++++++++++++++ .../SRGBmodsPicoController.h | 45 +++++ OpenRGB.pro | 6 + 6 files changed, 420 insertions(+) create mode 100644 Controllers/SRGBmodsController/RGBController_SRGBmodsPico.cpp create mode 100644 Controllers/SRGBmodsController/RGBController_SRGBmodsPico.h create mode 100644 Controllers/SRGBmodsController/SRGBmodsControllerDetect.cpp create mode 100644 Controllers/SRGBmodsController/SRGBmodsPicoController.cpp create mode 100644 Controllers/SRGBmodsController/SRGBmodsPicoController.h diff --git a/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.cpp b/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.cpp new file mode 100644 index 00000000..ba88bdd8 --- /dev/null +++ b/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.cpp @@ -0,0 +1,157 @@ +/*-----------------------------------------*\ +| RGBController_SRGBmodsPico.cpp | +| | +| Generic RGB Interface for SRGBmods | +| Raspberry Pi Pico LED Controller | +| | +| Adam Honse (CalcProgrammer1) 7/21/2022 | +\*-----------------------------------------*/ + +#include "RGBController_SRGBmodsPico.h" + +/**------------------------------------------------------------------*\ + @name SRGBmods Raspberry Pi Pico LED Controller + @category LEDStrip + @type USB + @save :x: + @direct :white_check_mark: + @effects :white_check_mark: + @detectors DetectSRGBmodsControllers + @comment +\*-------------------------------------------------------------------*/ + +RGBController_SRGBmodsPico::RGBController_SRGBmodsPico(SRGBmodsPicoController* controller_ptr) +{ + controller = controller_ptr; + + name = "SRGBmods Device"; + vendor = "SRGBmods.net"; + description = "SRGBmods Pico LED Controller Device"; + type = DEVICE_TYPE_LEDSTRIP; + location = controller->GetLocationString(); + serial = controller->GetSerialString(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_SRGBmodsPico::~RGBController_SRGBmodsPico() +{ + delete controller; +} + +void RGBController_SRGBmodsPico::SetupZones() +{ + /*-------------------------------------------------*\ + | Only set LED count on the first run | + \*-------------------------------------------------*/ + bool first_run = false; + + if(zones.size() == 0) + { + first_run = true; + } + + /*-------------------------------------------------*\ + | Clear any existing color/LED configuration | + \*-------------------------------------------------*/ + leds.clear(); + colors.clear(); + zones.resize(SRGBMODS_PICO_NUM_CHANNELS); + + /*-------------------------------------------------*\ + | Set zones and leds | + \*-------------------------------------------------*/ + for(unsigned int channel_idx = 0; channel_idx < SRGBMODS_PICO_NUM_CHANNELS; channel_idx++) + { + char ch_idx_string[2]; + sprintf(ch_idx_string, "%d", channel_idx + 1); + + zones[channel_idx].name = "Channel "; + zones[channel_idx].name.append(ch_idx_string); + zones[channel_idx].type = ZONE_TYPE_LINEAR; + + /*-------------------------------------------------*\ + | The maximum number of LEDs per channel is 512 | + | according to https://srgbmods.net/picoled/ | + \*-------------------------------------------------*/ + zones[channel_idx].leds_min = 0; + zones[channel_idx].leds_max = 512; + + if(first_run) + { + zones[channel_idx].leds_count = 0; + } + + zones[channel_idx].matrix_map = NULL; + + for(unsigned int led_ch_idx = 0; led_ch_idx < zones[channel_idx].leds_count; led_ch_idx++) + { + char led_idx_string[4]; + sprintf(led_idx_string, "%d", led_ch_idx + 1); + + led new_led; + new_led.name = "LED "; + new_led.name.append(led_idx_string); + + leds.push_back(new_led); + leds_channel.push_back(channel_idx); + } + } + + SetupColors(); +} + +void RGBController_SRGBmodsPico::ResizeZone(int zone, int new_size) +{ + if((size_t) zone >= zones.size()) + { + return; + } + + if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max)) + { + zones[zone].leds_count = new_size; + + SetupZones(); + } +} + +void RGBController_SRGBmodsPico::DeviceUpdateLEDs() +{ + for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + if(zones[zone_idx].leds_count > 0) + { + controller->SetChannelLEDs(zone_idx, zones[zone_idx].colors, zones[zone_idx].leds_count); + } + } +} + +void RGBController_SRGBmodsPico::UpdateZoneLEDs(int zone) +{ + controller->SetChannelLEDs(zone, zones[zone].colors, zones[zone].leds_count); +} + +void RGBController_SRGBmodsPico::UpdateSingleLED(int led) +{ + unsigned int channel = leds_channel[led]; + + controller->SetChannelLEDs(channel, zones[channel].colors, zones[channel].leds_count); +} + +void RGBController_SRGBmodsPico::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_SRGBmodsPico::DeviceUpdateMode() +{ + DeviceUpdateLEDs(); +} \ No newline at end of file diff --git a/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.h b/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.h new file mode 100644 index 00000000..3f5e80ba --- /dev/null +++ b/Controllers/SRGBmodsController/RGBController_SRGBmodsPico.h @@ -0,0 +1,38 @@ +/*-----------------------------------------*\ +| RGBController_SRGBmodsPico.h | +| | +| Generic RGB Interface for SRGBmods | +| Raspberry Pi Pico LED Controller | +| | +| Adam Honse (CalcProgrammer1) 7/21/2022 | +\*-----------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "SRGBmodsPicoController.h" + +#define SRGBMODS_PICO_NUM_CHANNELS 2 + +class RGBController_SRGBmodsPico : public RGBController +{ +public: + RGBController_SRGBmodsPico(SRGBmodsPicoController* controller_ptr); + ~RGBController_SRGBmodsPico(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void DeviceUpdateMode(); + +private: + SRGBmodsPicoController* controller; + std::vector leds_channel; + std::vector zones_channel; +}; diff --git a/Controllers/SRGBmodsController/SRGBmodsControllerDetect.cpp b/Controllers/SRGBmodsController/SRGBmodsControllerDetect.cpp new file mode 100644 index 00000000..8f47402b --- /dev/null +++ b/Controllers/SRGBmodsController/SRGBmodsControllerDetect.cpp @@ -0,0 +1,45 @@ +#include "Detector.h" +#include "SRGBmodsPicoController.h" +#include "RGBController.h" +#include "RGBController_SRGBmodsPico.h" +#include +#include + +#define SRGBMODS_PICO_VID 0x16D0 +#define SRGBMODS_PICO_PID 0x1123 + +/******************************************************************************************\ +* * +* DetectSRGBmodsControllers * +* * +* Detect devices supported by the SRGBmods driver * +* * +\******************************************************************************************/ + +void DetectSRGBmodsControllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + wchar_t product[128]; + hid_get_product_string(dev, product, 128); + + std::wstring product_str(product); + + /*-------------------------------------------------------------------------*\ + | Test the product string in case this USB ID is reused for other Pi Pico | + | projects | + \*-------------------------------------------------------------------------*/ + if(product_str == L"SRGBmods Pico LED Controller") + { + SRGBmodsPicoController* controller = new SRGBmodsPicoController(dev, info->path); + RGBController_SRGBmodsPico* rgb_controller = new RGBController_SRGBmodsPico(controller); + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + } +} /* DetectSRGBmodsControllers() */ + +REGISTER_HID_DETECTOR("SRGBmods Pico LED Controller", DetectSRGBmodsControllers, SRGBMODS_PICO_VID, SRGBMODS_PICO_PID); diff --git a/Controllers/SRGBmodsController/SRGBmodsPicoController.cpp b/Controllers/SRGBmodsController/SRGBmodsPicoController.cpp new file mode 100644 index 00000000..f6dc2407 --- /dev/null +++ b/Controllers/SRGBmodsController/SRGBmodsPicoController.cpp @@ -0,0 +1,129 @@ +/*-----------------------------------------*\ +| ZalmanZSyncController.cpp | +| | +| Driver for SRGBmods Raspberry Pi Pico | +| LED Controller | +| | +| Adam Honse (CalcProgrammer1) 7/21/2022 | +\*-----------------------------------------*/ + +#include "SRGBmodsPicoController.h" +#include + +using namespace std::chrono_literals; + +SRGBmodsPicoController::SRGBmodsPicoController(hid_device* dev_handle, const char* path) +{ + dev = dev_handle; + location = path; + + /*-----------------------------------------------------*\ + | The SRGBmods Pico controller requires a packet within | + | 10 seconds of sending the lighting change in order | + | to not revert back into hardware mode. Start a thread| + | to continuously send a keepalive packet every 5s | + \*-----------------------------------------------------*/ + keepalive_thread_run = 1; + keepalive_thread = new std::thread(&SRGBmodsPicoController::KeepaliveThread, this); +} + +SRGBmodsPicoController::~SRGBmodsPicoController() +{ + keepalive_thread_run = 0; + keepalive_thread->join(); + delete keepalive_thread; + + hid_close(dev); +} + +void SRGBmodsPicoController::KeepaliveThread() +{ + while(keepalive_thread_run.load()) + { + if((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::seconds(1)) + { + SendPacket(1, 0, 0, false, NULL, 0); + } + std::this_thread::sleep_for(5s); + } +} + +std::string SRGBmodsPicoController::GetLocationString() +{ + return("HID: " + location); +} + +std::string SRGBmodsPicoController::GetSerialString() +{ + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + return(""); + } + + std::wstring return_wstring = serial_string; + std::string return_string(return_wstring.begin(), return_wstring.end()); + + return(return_string); +} + +void SRGBmodsPicoController::SetChannelLEDs(unsigned char channel, RGBColor* colors, unsigned int num_colors) +{ + unsigned int num_packets = num_colors / 20 + ((num_colors % 20) > 0); + unsigned int color_idx = 0; + + for(unsigned int packet_idx = 0; packet_idx < num_packets; packet_idx++) + { + unsigned int colors_in_packet = 20; + + if(num_colors - color_idx < colors_in_packet) + { + colors_in_packet = num_colors - color_idx; + } + + SendPacket(channel, packet_idx + 1, num_packets, false, &colors[color_idx * 3], colors_in_packet); + + color_idx += colors_in_packet; + } +} + +void SRGBmodsPicoController::SendPacket + ( + unsigned char channel, + unsigned char this_packet_id, + unsigned char last_packet_id, + bool reset, + RGBColor* colors, + unsigned int num_colors + ) +{ + unsigned char usb_buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up Firmware Version Request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; /* hidapi Report ID*/ + usb_buf[0x01] = this_packet_id; /* This Packet ID */ + usb_buf[0x02] = reset; /* Reset Flag */ + usb_buf[0x03] = last_packet_id; /* Last Packet ID */ + usb_buf[0x04] = channel + 1; /* Channel (1 or 2)*/ + + for(unsigned int color_idx = 0; color_idx < num_colors; color_idx++) + { + usb_buf[0x05 + (color_idx * 3)] = RGBGetRValue(colors[color_idx]); + usb_buf[0x06 + (color_idx * 3)] = RGBGetGValue(colors[color_idx]); + usb_buf[0x07 + (color_idx * 3)] = RGBGetBValue(colors[color_idx]); + } + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, 65); +} \ No newline at end of file diff --git a/Controllers/SRGBmodsController/SRGBmodsPicoController.h b/Controllers/SRGBmodsController/SRGBmodsPicoController.h new file mode 100644 index 00000000..62134292 --- /dev/null +++ b/Controllers/SRGBmodsController/SRGBmodsPicoController.h @@ -0,0 +1,45 @@ +/*-----------------------------------------*\ +| ZalmanZSyncController.h | +| | +| Definitions and types for SRGBmods | +| Raspberry Pi Pico LED Controller | +| | +| Adam Honse (CalcProgrammer1) 7/21/2022 | +\*-----------------------------------------*/ + +#include "RGBController.h" +#include +#include +#include + +#pragma once + +class SRGBmodsPicoController +{ +public: + SRGBmodsPicoController(hid_device* dev_handle, const char* path); + ~SRGBmodsPicoController(); + + std::string GetLocationString(); + std::string GetSerialString(); + + void SetChannelLEDs(unsigned char channel, RGBColor * colors, unsigned int num_colors); + + void KeepaliveThread(); +private: + hid_device* dev; + std::string location; + std::thread* keepalive_thread; + std::atomic keepalive_thread_run; + std::chrono::time_point last_commit_time; + + void SendPacket + ( + unsigned char channel, + unsigned char this_packet_id, + unsigned char last_packet_id, + bool reset, + RGBColor* colors, + unsigned int num_colors + ); +}; \ No newline at end of file diff --git a/OpenRGB.pro b/OpenRGB.pro index a84e801b..2ca37d17 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -154,6 +154,7 @@ INCLUDEPATH += Controllers/SapphireGPUController/ \ Controllers/SinowealthController/ \ Controllers/SonyGamepadController/ \ + Controllers/SRGBmodsController/ \ Controllers/SteelSeriesController/ \ Controllers/TecknetController/ \ Controllers/ThermaltakePoseidonZRGBController/ \ @@ -538,6 +539,8 @@ HEADERS += Controllers/SonyGamepadController/RGBController_SonyDualSense.h \ Controllers/SonyGamepadController/SonyDS4Controller.h \ Controllers/SonyGamepadController/RGBController_SonyDS4.h \ + Controllers/SRGBmodsController/SRGBmodsPicoController.h \ + Controllers/SRGBmodsController/RGBController_SRGBmodsPico.h \ Controllers/SteelSeriesController/color32.h \ Controllers/SteelSeriesController/SteelSeriesAerox3Controller.h \ Controllers/SteelSeriesController/SteelSeriesApexBaseController.h \ @@ -1078,6 +1081,9 @@ SOURCES += Controllers/SonyGamepadController/SonyDS4Controller.cpp \ Controllers/SonyGamepadController/RGBController_SonyDS4.cpp \ Controllers/SonyGamepadController/SonyGamepadControllerDetect.cpp \ + Controllers/SRGBmodsController/SRGBmodsPicoController.cpp \ + Controllers/SRGBmodsController/SRGBmodsControllerDetect.cpp \ + Controllers/SRGBmodsController/RGBController_SRGBmodsPico.cpp \ Controllers/SteelSeriesController/SteelSeriesAerox3Controller.cpp \ Controllers/SteelSeriesController/SteelSeriesApexController.cpp \ Controllers/SteelSeriesController/SteelSeriesApexMController.cpp \