diff --git a/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.cpp b/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.cpp similarity index 74% rename from Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.cpp rename to Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.cpp index 5103a6cf6..2c8d96482 100644 --- a/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.cpp +++ b/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.cpp @@ -1,5 +1,5 @@ /*---------------------------------------------------------*\ -| RGBController_ValveSteamMachine_Linux.cpp | +| RGBController_ValveSteamMachine_Windows_Linux.cpp | | | | RGBController for Valve Steam Machine LEDs | | | @@ -9,7 +9,7 @@ | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ -#include "RGBController_ValveSteamMachine_Linux.h" +#include "RGBController_ValveSteamMachine_Windows_Linux.h" #include /**------------------------------------------------------------------*\ @@ -31,7 +31,7 @@ RGBController_ValveSteamMachine::RGBController_ValveSteamMachine(ValveSteamMachi vendor = "Valve"; type = DEVICE_TYPE_LEDSTRIP; description = "Valve Steam Machine Device"; - location = controller->GetLEDPath(0); + location = controller->GetLocation(); /*-----------------------------------------------------*\ | If the device supports hardware effects, add them as | @@ -40,6 +40,17 @@ RGBController_ValveSteamMachine::RGBController_ValveSteamMachine(ValveSteamMachi \*-----------------------------------------------------*/ effects = controller->GetAvailableEffects(); + /*-----------------------------------------------------*\ + | Add a Disabled mode as the first mode. When this | + | mode is active, the device's enabled flag is set to | + | false, turning the LEDs off without applying any | + | hardware effect. | + \*-----------------------------------------------------*/ + mode disabled_mode; + disabled_mode.name = "Disabled"; + disabled_mode.color_mode = MODE_COLORS_NONE; + modes.push_back(disabled_mode); + for(unsigned int effect_idx = 0; effect_idx < effects.size(); effect_idx++) { unsigned int effect_color_mode; @@ -51,7 +62,7 @@ RGBController_ValveSteamMachine::RGBController_ValveSteamMachine(ValveSteamMachi \*-------------------------------------------------*/ if(effect_name == controller->GetEffect()) { - active_mode = effect_idx; + active_mode = effect_idx + 1; } /*-------------------------------------------------*\ @@ -108,6 +119,16 @@ RGBController_ValveSteamMachine::RGBController_ValveSteamMachine(ValveSteamMachi modes.push_back(new_mode); } + /*-----------------------------------------------------*\ + | If the device is not enabled at startup, initialize | + | active_mode to the Disabled mode (index 0) instead | + | of forcibly enabling it. | + \*-----------------------------------------------------*/ + if(!controller->GetEnabled()) + { + active_mode = 0; + } + SetupZones(); } @@ -162,19 +183,32 @@ void RGBController_ValveSteamMachine::DeviceUpdateZoneLEDs(int /*zone*/) void RGBController_ValveSteamMachine::DeviceUpdateSingleLED(int led) { - unsigned char red = RGBGetRValue(colors[led]); - unsigned char grn = RGBGetGValue(colors[led]); - unsigned char blu = RGBGetBValue(colors[led]); - - controller->SetLEDColor(led, red, grn, blu); + controller->SetLEDColor(led, colors[led]); } void RGBController_ValveSteamMachine::DeviceUpdateMode() { - if((unsigned int)active_mode < effects.size()) + /*-----------------------------------------------------*\ + | If the active mode is Disabled (index 0), set | + | enabled to false on the device instead of forcibly | + | enabling it. | + \*-----------------------------------------------------*/ + if(active_mode == 0) { - controller->SetEffect(effects[active_mode]); - controller->SetBrightness(modes[active_mode].brightness); - controller->SetDelay(modes[active_mode].speed); + controller->SetEnabled(false); + } + else + { + if(!controller->GetEnabled()) + { + controller->SetEnabled(true); + } + + if((unsigned int)(active_mode - 1) < effects.size()) + { + controller->SetEffect(effects[active_mode - 1]); + controller->SetBrightness(modes[active_mode].brightness); + controller->SetDelay(modes[active_mode].speed); + } } } diff --git a/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.h b/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.h similarity index 93% rename from Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.h rename to Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.h index 29a55f13d..21e269b9b 100644 --- a/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Linux.h +++ b/Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.h @@ -12,7 +12,11 @@ #pragma once #include "RGBController.h" +#ifdef __linux__ #include "ValveSteamMachineController_Linux.h" +#else +#include "ValveSteamMachineController_Windows.h" +#endif class RGBController_ValveSteamMachine : public RGBController { diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Linux.cpp b/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Linux.cpp index 4f8d0a545..48b4fd3b7 100644 --- a/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Linux.cpp +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Linux.cpp @@ -15,7 +15,8 @@ #include #include "DetectionManager.h" #include "filesystem.h" -#include "RGBController_ValveSteamMachine_Linux.h" +#include "RGBController_ValveSteamMachine_Windows_Linux.h" +#include "ValveSteamMachineController_Linux.h" /*---------------------------------------------------------*\ | Helper function to extract the numeric index enclosed | diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Windows.cpp b/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Windows.cpp new file mode 100644 index 000000000..4af1105fd --- /dev/null +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Windows.cpp @@ -0,0 +1,51 @@ +/*---------------------------------------------------------*\ +| ValveSteamMachineControllerDetect_Windows.cpp | +| | +| Detector for Valve Steam Machine LEDs | +| | +| Adam Honse (calcprogrammer1@gmail.com) 28 Jul 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "dmiinfo.h" +#include "LogManager.h" +#include "PawnIOLib.h" +#include "DetectionManager.h" +#include "i2c_smbus_pawnio.h" +#include "ValveSteamMachineController_Windows.h" +#include "RGBController_ValveSteamMachine_Windows_Linux.h" + +DetectedControllers DetectValveSteamMachineControllers() +{ + DetectedControllers detected_controllers; + DMIInfo dmi; + HANDLE pawnio_handle; + HRESULT status; + + /*-----------------------------------------------------*\ + | The LedsValve PawnIO module is not capable of DMI | + | checking itself, so ensure the DMI info matches that | + | of the Steam Machine using the same DMI checks that | + | the official Linux leds-valve driver uses. | + \*-----------------------------------------------------*/ + if((dmi.getManufacturer() == "OEM" && dmi.getProductName() == "F7F") + ||(dmi.getManufacturer() == "Valve" && dmi.getProductName() == "Fremont")) + { + status = i2c_smbus_pawnio::start_pawnio("LedsValve.bin", &pawnio_handle); + + if(status == S_OK) + { + ValveSteamMachineController* controller = new ValveSteamMachineController(pawnio_handle, "Valve Steam Machine"); + RGBController_ValveSteamMachine* rgb_controller = new RGBController_ValveSteamMachine(controller); + + detected_controllers.push_back(rgb_controller); + } + } + + return(detected_controllers); +} + +REGISTER_DETECTOR("Valve Steam Machine", DetectValveSteamMachineControllers); \ No newline at end of file diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.cpp b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.cpp index 628dde200..97e474374 100644 --- a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.cpp +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.cpp @@ -43,12 +43,8 @@ void ValveSteamMachineController::AddLED(std::string led_path) led_paths.push_back(path); /*-----------------------------------------------------*\ - | Open the brightness and multi_intensity files | + | Open the multi_intensity files | \*-----------------------------------------------------*/ - std::ofstream brightness_file; - brightness_file.open(path + "brightness"); - led_brightness.push_back(std::move(brightness_file)); - std::ofstream multi_intensity_file; multi_intensity_file.open(path + "multi_intensity"); led_multi_intensity.push_back(std::move(multi_intensity_file)); @@ -62,6 +58,13 @@ void ValveSteamMachineController::AddLED(std::string led_path) { led_brightness_scale.open(path + "brightness_scale"); led_delay.open(path + "delay"); + led_enabled.open(path + "enabled"); + led_breath_offset.open(path + "breath_offset"); + led_breath_level.open(path + "breath_level"); + led_patrol_num.open(path + "patrol_num"); + led_color_shift.open(path + "color_shift"); + led_multi_intensity_startup.open(path + "multi_intensity_startup"); + led_brightness_startup.open(path + "brightness_startup"); } /*-----------------------------------------------------*\ @@ -100,14 +103,9 @@ size_t ValveSteamMachineController::GetLEDCount() return(led_paths.size()); } -std::string ValveSteamMachineController::GetLEDPath(unsigned int led_idx) +std::string ValveSteamMachineController::GetLocation() { - if(led_idx < led_paths.size()) - { - return(led_paths[led_idx]); - } - - return(""); + return(led_paths[0]); } std::vector ValveSteamMachineController::GetAvailableEffects() @@ -174,6 +172,134 @@ std::string ValveSteamMachineController::GetEffect() return(""); } +bool ValveSteamMachineController::GetEnabled() +{ + if(led_enabled.is_open()) + { + std::ifstream enabled_file(led_paths[0] + "enabled"); + + if(enabled_file.good()) + { + unsigned int enabled = 0; + enabled_file >> std::hex >> enabled; + enabled_file.close(); + return(enabled != 0); + } + } + + return(false); +} + +unsigned int ValveSteamMachineController::GetBreathOffset() +{ + if(led_breath_offset.is_open()) + { + std::ifstream breath_offset_file(led_paths[0] + "breath_offset"); + + if(breath_offset_file.good()) + { + unsigned int breath_offset = 0; + breath_offset_file >> std::hex >> breath_offset; + breath_offset_file.close(); + return(breath_offset); + } + } + + return(0); +} + +unsigned int ValveSteamMachineController::GetBreathLevel() +{ + if(led_breath_level.is_open()) + { + std::ifstream breath_level_file(led_paths[0] + "breath_level"); + + if(breath_level_file.good()) + { + unsigned int breath_level = 0; + breath_level_file >> std::hex >> breath_level; + breath_level_file.close(); + return(breath_level); + } + } + + return(0); +} + +unsigned int ValveSteamMachineController::GetPatrolNum() +{ + if(led_patrol_num.is_open()) + { + std::ifstream patrol_num_file(led_paths[0] + "patrol_num"); + + if(patrol_num_file.good()) + { + unsigned int patrol_num = 0; + patrol_num_file >> std::hex >> patrol_num; + patrol_num_file.close(); + return(patrol_num); + } + } + + return(0); +} + +unsigned int ValveSteamMachineController::GetColorShift() +{ + if(led_color_shift.is_open()) + { + std::ifstream color_shift_file(led_paths[0] + "color_shift"); + + if(color_shift_file.good()) + { + unsigned int color_shift = 0; + color_shift_file >> std::hex >> color_shift; + color_shift_file.close(); + return(color_shift); + } + } + + return(0); +} + +RGBColor ValveSteamMachineController::GetStartupColor() +{ + if(led_multi_intensity_startup.is_open()) + { + std::ifstream startup_color_file(led_paths[0] + "multi_intensity_startup"); + + if(startup_color_file.good()) + { + unsigned int red = 0; + unsigned int grn = 0; + unsigned int blu = 0; + startup_color_file >> std::hex >> red >> grn >> blu; + startup_color_file.close(); + return(ToRGBColor(red, grn, blu)); + } + } + + return(0); +} + +unsigned int ValveSteamMachineController::GetBrightnessStartup() +{ + if(led_brightness_startup.is_open()) + { + std::ifstream brightness_startup_file(led_paths[0] + "brightness_startup"); + + if(brightness_startup_file.good()) + { + unsigned int brightness_startup = 0; + brightness_startup_file >> std::hex >> brightness_startup; + brightness_startup_file.close(); + return(brightness_startup); + } + } + + return(0); +} + void ValveSteamMachineController::ReadAvailableEffects(std::string first_led_path) { std::ifstream effect_index_file(first_led_path + "effect_index"); @@ -204,7 +330,7 @@ void ValveSteamMachineController::ReadAvailableEffects(std::string first_led_pat } } -void ValveSteamMachineController::SetLEDColor(unsigned int led_idx, unsigned char red, unsigned char grn, unsigned char blu) +void ValveSteamMachineController::SetLEDColor(unsigned int led_idx, RGBColor color) { if(led_idx >= led_paths.size()) { @@ -215,9 +341,9 @@ void ValveSteamMachineController::SetLEDColor(unsigned int led_idx, unsigned cha | Use multi_intensity to set RGB values. This is the | | leds-valve sysfs LED interface pattern. | \*-----------------------------------------------------*/ - std::string color_str = std::to_string((unsigned int)red) + " " - + std::to_string((unsigned int)grn) + " " - + std::to_string((unsigned int)blu); + std::string color_str = std::to_string(RGBGetRValue(color)) + " " + + std::to_string(RGBGetGValue(color)) + " " + + std::to_string(RGBGetBValue(color)); led_multi_intensity[led_idx].write(color_str.c_str(), color_str.length()); led_multi_intensity[led_idx].flush(); @@ -256,3 +382,81 @@ void ValveSteamMachineController::SetDelay(unsigned int delay) led_delay.flush(); } } + +void ValveSteamMachineController::SetEnabled(bool enabled) +{ + if(led_enabled.is_open()) + { + std::string enabled_str = std::to_string(enabled ? 1 : 0); + led_enabled.write(enabled_str.c_str(), enabled_str.length()); + led_enabled.flush(); + } +} + +void ValveSteamMachineController::SetBreathOffset(unsigned int breath_offset) +{ + if(led_breath_offset.is_open()) + { + std::string breath_offset_str = std::to_string(breath_offset); + led_breath_offset.write(breath_offset_str.c_str(), breath_offset_str.length()); + led_breath_offset.flush(); + } +} + +void ValveSteamMachineController::SetBreathLevel(unsigned int breath_level) +{ + if(led_breath_level.is_open()) + { + std::string breath_level_str = std::to_string(breath_level); + led_breath_level.write(breath_level_str.c_str(), breath_level_str.length()); + led_breath_level.flush(); + } +} + +void ValveSteamMachineController::SetPatrolNum(unsigned int patrol_num) +{ + if(led_patrol_num.is_open()) + { + std::string patrol_num_str = std::to_string(patrol_num); + led_patrol_num.write(patrol_num_str.c_str(), patrol_num_str.length()); + led_patrol_num.flush(); + } +} + +void ValveSteamMachineController::SetColorShift(unsigned int color_shift) +{ + if(led_color_shift.is_open()) + { + std::string color_shift_str = std::to_string(color_shift); + led_color_shift.write(color_shift_str.c_str(), color_shift_str.length()); + led_color_shift.flush(); + } +} + +void ValveSteamMachineController::SetStartupColor(RGBColor color) +{ + if(led_multi_intensity_startup.is_open()) + { + /*-----------------------------------------------------*\ + | Use multi_intensity_startup to set RGB values. This | + | is the leds-valve sysfs LED interface pattern for | + | the startup color. | + \*-----------------------------------------------------*/ + std::string color_str = std::to_string(RGBGetRValue(color)) + " " + + std::to_string(RGBGetGValue(color)) + " " + + std::to_string(RGBGetBValue(color)); + + led_multi_intensity_startup.write(color_str.c_str(), color_str.length()); + led_multi_intensity_startup.flush(); + } +} + +void ValveSteamMachineController::SetBrightnessStartup(unsigned int brightness_startup) +{ + if(led_brightness_startup.is_open()) + { + std::string brightness_startup_str = std::to_string(brightness_startup); + led_brightness_startup.write(brightness_startup_str.c_str(), brightness_startup_str.length()); + led_brightness_startup.flush(); + } +} diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.h b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.h index 9fbbfcac0..de148fc64 100644 --- a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.h +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Linux.h @@ -14,6 +14,7 @@ #include #include #include +#include "RGBControllerInterface.h" class ValveSteamMachineController { @@ -25,30 +26,47 @@ public: void AddLED(std::string led_path); size_t GetLEDCount(); - - std::string GetLEDPath(unsigned int led_idx); + std::string GetLocation(); std::vector GetAvailableEffects(); unsigned int GetBrightness(); unsigned int GetDelay(); std::string GetEffect(); + bool GetEnabled(); + unsigned int GetBreathOffset(); + unsigned int GetBreathLevel(); + unsigned int GetPatrolNum(); + unsigned int GetColorShift(); + RGBColor GetStartupColor(); + unsigned int GetBrightnessStartup(); - bool SupportsEffects(); - - void SetLEDColor(unsigned int led_idx, unsigned char red, unsigned char grn, unsigned char blu); + void SetLEDColor(unsigned int led_idx, RGBColor color); void SetEffect(std::string effect); void SetBrightness(unsigned int brightness); void SetDelay(unsigned int delay); + void SetEnabled(bool enabled); + void SetBreathOffset(unsigned int breath_offset); + void SetBreathLevel(unsigned int breath_level); + void SetPatrolNum(unsigned int patrol_num); + void SetColorShift(unsigned int color_shift); + void SetStartupColor(RGBColor color); + void SetBrightnessStartup(unsigned int brightness_startup); private: std::string name; std::vector led_paths; - std::vector led_brightness; std::vector led_multi_intensity; std::vector led_effect; std::ofstream led_brightness_scale; std::ofstream led_delay; + std::ofstream led_enabled; + std::ofstream led_breath_offset; + std::ofstream led_breath_level; + std::ofstream led_patrol_num; + std::ofstream led_color_shift; + std::ofstream led_multi_intensity_startup; + std::ofstream led_brightness_startup; std::vector available_effects; void ReadAvailableEffects(std::string first_led_path); diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.cpp b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.cpp new file mode 100644 index 000000000..320fbd17a --- /dev/null +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.cpp @@ -0,0 +1,641 @@ +/*---------------------------------------------------------*\ +| ValveSteamMachineController_Windows.cpp | +| | +| Driver for Valve Steam Machine LEDs | +| | +| Adam Honse (calcprogrammer1@gmail.com) 28 Jul 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "LogManager.h" +#include "ValveSteamMachineController_Windows.h" + +/*---------------------------------------------------------*\ +| Name for log entries | +\*---------------------------------------------------------*/ +static const char* VALVESTEAMMACHINECONTROLLER = "ValveSteamMachineController"; + +static const std::vector effects = +{ + "patrol", + "breath", + "factory", + "normal", + "off", + "rainbow", + "demo", + "manual" +}; + +ValveSteamMachineController::ValveSteamMachineController(HANDLE dev_handle, std::string dev_name) +{ + name = dev_name; + pawnio_handle = dev_handle; + + /*-----------------------------------------------------*\ + | Initialize driver | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_init", in, 0, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_init failed", VALVESTEAMMACHINECONTROLLER); + } +} + +ValveSteamMachineController::~ValveSteamMachineController() +{ + +} + +std::string ValveSteamMachineController::GetName() +{ + return(name); +} + +size_t ValveSteamMachineController::GetLEDCount() +{ + return(17); +} + +std::string ValveSteamMachineController::GetLocation() +{ + return("PawnIO leds-valve"); +} + +std::vector ValveSteamMachineController::GetAvailableEffects() +{ + return(effects); +} + +unsigned int ValveSteamMachineController::GetBrightness() +{ + /*-----------------------------------------------------*\ + | Get brightness | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_brightness_scale", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_brightness_scale failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_brightness_scale delay out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +unsigned int ValveSteamMachineController::GetDelay() +{ + /*-----------------------------------------------------*\ + | Get delay | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_delay", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_delay failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 20) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_delay delay out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +std::string ValveSteamMachineController::GetEffect() +{ + /*-----------------------------------------------------*\ + | Get effect | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_effect", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_effect failed", VALVESTEAMMACHINECONTROLLER); + return(""); + } + + if(out[0] < effects.size()) + { + return(effects[out[0]]); + } + else + { + LOG_ERROR("[%s] ioctl_get_effect effect out of range", VALVESTEAMMACHINECONTROLLER); + return(""); + } +} + +bool ValveSteamMachineController::GetEnabled() +{ + /*-----------------------------------------------------*\ + | Get enabled | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_enabled", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_enabled failed", VALVESTEAMMACHINECONTROLLER); + return(false); + } + + return((out[0] & 0xFF) != 0); +} + +unsigned int ValveSteamMachineController::GetBreathOffset() +{ + /*-----------------------------------------------------*\ + | Get breath offset | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_breath_offset", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_breath_offset failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_breath_offset out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +unsigned int ValveSteamMachineController::GetBreathLevel() +{ + /*-----------------------------------------------------*\ + | Get breath level | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_breath_level", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_breath_level failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_breath_level out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +unsigned int ValveSteamMachineController::GetPatrolNum() +{ + /*-----------------------------------------------------*\ + | Get patrol num | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_patrol_num", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_patrol_num failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_patrol_num out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +unsigned int ValveSteamMachineController::GetColorShift() +{ + /*-----------------------------------------------------*\ + | Get color shift | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_color_shift", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_color_shift failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_color_shift out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +bool ValveSteamMachineController::GetPersistence() +{ + /*-----------------------------------------------------*\ + | Get persistence | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_persistence", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_persistence failed", VALVESTEAMMACHINECONTROLLER); + return(false); + } + + return((out[0] & 0xFF) != 0); +} + +RGBColor ValveSteamMachineController::GetStartupColor() +{ + /*-----------------------------------------------------*\ + | Get startup color | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[3]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_startup_color", in, 0, out, 3, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_startup_color failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + return(ToRGBColor(out[0], out[1], out[2])); +} + +unsigned int ValveSteamMachineController::GetBrightnessStartup() +{ + /*-----------------------------------------------------*\ + | Get brightness startup | + \*-----------------------------------------------------*/ + ULONG64 in[1]; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_get_brightness_startup", in, 0, out, 1, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_get_brightness_startup failed", VALVESTEAMMACHINECONTROLLER); + return(0); + } + + if(out[0] <= 255) + { + return(out[0]); + } + else + { + LOG_ERROR("[%s] ioctl_get_brightness_startup out of range", VALVESTEAMMACHINECONTROLLER); + return(0); + } +} + +void ValveSteamMachineController::SetLEDColor(unsigned int led_idx, RGBColor color) +{ + if(led_idx >= GetLEDCount()) + { + LOG_ERROR("[%s] ioctl_set_led_color led index out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Reverse order of LEDs | + \*-----------------------------------------------------*/ + led_idx = (GetLEDCount() - 1) - led_idx; + + /*-----------------------------------------------------*\ + | Set LED color | + \*-----------------------------------------------------*/ + ULONG64 in[4] = {led_idx, RGBGetRValue(color), RGBGetGValue(color), RGBGetBValue(color)}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_led_color", in, 4, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_led_color failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetEffect(std::string effect) +{ + /*-----------------------------------------------------*\ + | Determine effect index | + \*-----------------------------------------------------*/ + std::size_t effect_idx; + + for(effect_idx = 0; effect_idx < effects.size(); effect_idx++) + { + if(effect == effects[effect_idx]) + { + break; + } + } + + if(effect_idx >= effects.size()) + { + LOG_ERROR("[%s] ioctl_set_effect effect out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set effect | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {effect_idx}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_effect", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_effect failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetBrightness(unsigned int brightness) +{ + if(brightness > 255) + { + LOG_ERROR("[%s] ioctl_set_brightness_scale brightness out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set brightness | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {brightness}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_brightness_scale", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_brightness_scale failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetDelay(unsigned int delay) +{ + if(delay > 20) + { + LOG_ERROR("[%s] ioctl_set_delay delay out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set delay | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {delay}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_delay", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_delay failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetEnabled(bool enabled) +{ + /*-----------------------------------------------------*\ + | Set enabled | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {enabled ? 1 : 0}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_enabled", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_enabled failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetBreathOffset(unsigned int breath_offset) +{ + if(breath_offset > 255) + { + LOG_ERROR("[%s] ioctl_set_breath_offset out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set breath offset | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {breath_offset}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_breath_offset", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_breath_offset failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetBreathLevel(unsigned int breath_level) +{ + if(breath_level > 255) + { + LOG_ERROR("[%s] ioctl_set_breath_level out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set breath level | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {breath_level}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_breath_level", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_breath_level failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetPatrolNum(unsigned int patrol_num) +{ + if(patrol_num > 255) + { + LOG_ERROR("[%s] ioctl_set_patrol_num out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set patrol num | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {patrol_num}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_patrol_num", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_patrol_num failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetColorShift(unsigned int color_shift) +{ + if(color_shift > 255) + { + LOG_ERROR("[%s] ioctl_set_color_shift out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set color shift | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {color_shift}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_color_shift", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_color_shift failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetStartupColor(RGBColor color) +{ + /*-----------------------------------------------------*\ + | Set startup color | + \*-----------------------------------------------------*/ + ULONG64 in[3] = {RGBGetRValue(color), RGBGetGValue(color), RGBGetBValue(color)}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_startup_color", in, 3, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_startup_color failed", VALVESTEAMMACHINECONTROLLER); + } +} + +void ValveSteamMachineController::SetBrightnessStartup(unsigned int brightness_startup) +{ + if(brightness_startup > 255) + { + LOG_ERROR("[%s] ioctl_set_brightness_startup out of range", VALVESTEAMMACHINECONTROLLER); + return; + } + + /*-----------------------------------------------------*\ + | Set brightness startup | + \*-----------------------------------------------------*/ + ULONG64 in[1] = {brightness_startup}; + ULONG64 out[1]; + SIZE_T return_size; + HRESULT status; + + status = pawnio_execute(pawnio_handle, "ioctl_set_brightness_startup", in, 1, out, 0, &return_size); + + if(status != S_OK) + { + LOG_ERROR("[%s] ioctl_set_brightness_startup failed", VALVESTEAMMACHINECONTROLLER); + } +} diff --git a/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.h b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.h new file mode 100644 index 000000000..5f49d4d1a --- /dev/null +++ b/Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------*\ +| ValveSteamMachineController_Windows.h | +| | +| Driver for Valve Steam Machine LEDs | +| | +| Adam Honse (calcprogrammer1@gmail.com) 28 Jul 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include "PawnIOLib.h" +#include "RGBControllerInterface.h" + +class ValveSteamMachineController +{ +public: + ValveSteamMachineController(HANDLE dev_handle, std::string dev_name); + ~ValveSteamMachineController(); + + std::string GetName(); + size_t GetLEDCount(); + std::string GetLocation(); + + std::vector GetAvailableEffects(); + unsigned int GetBrightness(); + unsigned int GetDelay(); + std::string GetEffect(); + bool GetEnabled(); + unsigned int GetBreathOffset(); + unsigned int GetBreathLevel(); + unsigned int GetPatrolNum(); + unsigned int GetColorShift(); + bool GetPersistence(); + RGBColor GetStartupColor(); + unsigned int GetBrightnessStartup(); + + bool SupportsEffects(); + + void SetLEDColor(unsigned int led_idx, RGBColor color); + void SetEffect(std::string effect); + void SetBrightness(unsigned int brightness); + void SetDelay(unsigned int delay); + void SetEnabled(bool enabled); + void SetBreathOffset(unsigned int breath_offset); + void SetBreathLevel(unsigned int breath_level); + void SetPatrolNum(unsigned int patrol_num); + void SetColorShift(unsigned int color_shift); + void SetStartupColor(RGBColor color); + void SetBrightnessStartup(unsigned int brightness_startup); + +private: + std::string name; + HANDLE pawnio_handle; +}; \ No newline at end of file diff --git a/OpenRGB.pro b/OpenRGB.pro index cec129a02..325331e3e 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -338,6 +338,20 @@ win32:INCLUDEPATH += win32:SOURCES += $$CONTROLLER_CPP_WINDOWS +#-----------------------------------------------------------------------------------------------# +# Exclude controllers that depend on PawnIO from the 32-bit BUILDDATE_STRING # +#-----------------------------------------------------------------------------------------------# +win32:!contains(QMAKE_TARGET.arch, x86_64) { + win32:SOURCES -= \ + Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.cpp \ + Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.cpp \ + Controllers/ValveSteamMachineController/ValveSteamMachineControllerDetect_Windows.cpp \ + + win32:HEADERS -= \ + Controllers/ValveSteamMachineController/RGBController_ValveSteamMachine_Windows_Linux.h \ + Controllers/ValveSteamMachineController/ValveSteamMachineController_Windows.h \ +} + win32:SOURCES += \ dependencies/hueplusplus-1.2.0/src/WinHttpHandler.cpp \ dependencies/NVFC/nvapi.cpp \ @@ -441,6 +455,7 @@ win32:contains(QMAKE_TARGET.arch, x86_64) { copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/SmbusIntelSkylakeIMC.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/SmbusNCT6793.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/LpcIO.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) + copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/LedsValve.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) first.depends = $(first) copydata export(first.depends) export(copydata.commands) diff --git a/dependencies/PawnIO/modules/LedsValve.bin b/dependencies/PawnIO/modules/LedsValve.bin new file mode 100644 index 000000000..7798fb1f9 Binary files /dev/null and b/dependencies/PawnIO/modules/LedsValve.bin differ