From 1b65bb9cc37c7ed22e5f63090d3a31257e0b0809 Mon Sep 17 00:00:00 2001 From: Matt Harper Date: Thu, 7 May 2020 18:28:10 -0500 Subject: [PATCH] Rudimentary RGB Fusion 2 SMBus support --- .../RGBFusion2SMBusController.cpp | 91 ++++++++- .../RGBFusion2SMBusController.h | 10 +- .../RGBFusion2SMBusControllerDetect.cpp | 23 ++- OpenRGB.cpp | 2 + .../RGBController_RGBFusion2SMBus.cpp | 186 ++++++++++++++++++ RGBController/RGBController_RGBFusion2SMBus.h | 37 ++++ 6 files changed, 334 insertions(+), 15 deletions(-) diff --git a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.cpp b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.cpp index ac6ea0f7..1bb035ea 100644 --- a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.cpp +++ b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.cpp @@ -5,17 +5,31 @@ | SMBus lighting controller | | | | Adam Honse (CalcProgrammer1) 3/12/2020 | +| Matt Harper 5/5/2020 | \*-----------------------------------------*/ #include "RGBFusion2SMBusController.h" #include #include #include +#ifdef DEBUG +#include +#include +#endif RGBFusion2SMBusController::RGBFusion2SMBusController(i2c_smbus_interface* bus, rgb_fusion_dev_id dev) { this->bus = bus; this->dev = dev; + + memset(led_data, 0, 10*16); + + led_count = 10; // Protocol supports 10 'slots' +} + +unsigned int RGBFusion2SMBusController::GetLEDCount() +{ + return(led_count); } std::string RGBFusion2SMBusController::GetDeviceLocation() @@ -38,8 +52,75 @@ void RGBFusion2SMBusController::SetLEDEffect unsigned char blue ) { -led_data[led][RGB_FUSION_2_IDX_MODE] = mode; -led_data[led][RGB_FUSION_2_IDX_RED] = red; -led_data[led][RGB_FUSION_2_IDX_GREEN] = green; -led_data[led][RGB_FUSION_2_IDX_BLUE] = blue; -} \ No newline at end of file + led_data[led][RGB_FUSION_2_IDX_MODE] = mode; + led_data[led][RGB_FUSION_2_IDX_RED] = red; + led_data[led][RGB_FUSION_2_IDX_GREEN] = green; + led_data[led][RGB_FUSION_2_IDX_BLUE] = blue; + led_data[led][RGB_FUSION_2_IDX_BRIGHTNESS] = 0x64; // TODO - is this *really* the max value? + + // TODO - These timing calculations are weird - need to improve + led_data[led][RGB_FUSION_2_TIMER_1_LSB] = 0x20 * speed; + led_data[led][RGB_FUSION_2_TIMER_1_MSB] = 0x03 * speed; + led_data[led][RGB_FUSION_2_TIMER_2_LSB] = 0x20 * speed; + led_data[led][RGB_FUSION_2_TIMER_2_MSB] = 0x03 * speed; + + // Here be dragons + // Purpose of each index is not well understood + // Existing values taken from Windows dump + // TODO - more thorough understanding could lead to better implementation + if (mode == RGB_FUSION_2_MODE_FLASHING) { + led_data[led][0xc] = 0xd0; // ??? + led_data[led][0xd] = 0x07; // ??? + led_data[led][0xe] = 0x01 * speed; // Controls number of flashes + + // Following four fields appear to both important, and magic + // No other values appear to work, but it's probably worth further investigation + led_data[led][RGB_FUSION_2_TIMER_1_LSB] = 0x64; + led_data[led][RGB_FUSION_2_TIMER_1_MSB] = 0; + led_data[led][RGB_FUSION_2_TIMER_2_LSB] = 0xc8; // 0x64 * 2 = 0xc8 - Potentially significant? + led_data[led][RGB_FUSION_2_TIMER_2_MSB] = 0; + } + + if (mode == RGB_FUSION_2_MODE_COLOR_CYCLE) { + led_data[led][0xc] = 0xd0; // ??? + led_data[led][0xd] = 0x07; // ??? + led_data[led][0xe] = 0x07; // ??? + } + // End dragons. Well, probably. + + #ifdef DEBUG + // Print out hex for debug purposes + for (int i = 0; i < 16; i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << (int)led_data[led][i] << " "; + } + std::cout << std::endl; + #endif + + /* + * Writes occur in 32 byte blocks + * Therefore, writing the second 16 bytes necessitates writing the *first* 16 bytes as well. + * Given that reading the existing state from the device is not yet possible, + * unfortunately this implies that we may overwrite existing device states if the state + * transition did not occur within in the same OpenRGB instance. That is to say, this current + * behavior is non-ideal but the best we have. + */ + unsigned char oca = 0x20; // On chip address + unsigned short chip_offset; + if (led % 2) { + chip_offset = led-1; + } else { + chip_offset = led; + } + unsigned char write_addr = oca + chip_offset; + + #ifdef DEBUG + std::cout << "LED: " << led << "\tWrite address: " << std::hex << (int)write_addr << std::endl; + #endif + bus->i2c_smbus_write_block_data(0x68, write_addr, 32, led_data[led]); // Write 32 byte blocks at a time. Matches RGBF2 dump from Windows app. + + // Protocol expects terminating sequence 0x01ff written to register 0x17 + unsigned short terminator = 0x01ff; + unsigned char termination_addr = 0x17; + bus->i2c_smbus_write_word_data(0x68, termination_addr, terminator); +} + diff --git a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.h b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.h index bbcd5ce3..42221578 100644 --- a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.h +++ b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusController.h @@ -35,6 +35,13 @@ enum RGB_FUSION_2_MODE_FLASHING = 0x05, /* Flashing / Double Flashing mode */ }; +enum +{ + RGB_FUSION_2_SPEED_FAST = 0x01, + RGB_FUSION_2_SPEED_NORMAL = 0x02, + RGB_FUSION_2_SPEED_SLOW = 0x04 +}; + class RGBFusion2SMBusController { public: @@ -42,6 +49,7 @@ public: ~RGBFusion2SMBusController(); std::string GetDeviceLocation(); + unsigned int GetLEDCount(); void SetLEDEffect ( @@ -59,4 +67,4 @@ private: rgb_fusion_dev_id dev; unsigned char led_data[10][16]; -} \ No newline at end of file +}; diff --git a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusControllerDetect.cpp b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusControllerDetect.cpp index 5a17498e..e16837bf 100644 --- a/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusControllerDetect.cpp +++ b/Controllers/RGBFusion2SMBusController/RGBFusion2SMBusControllerDetect.cpp @@ -5,6 +5,7 @@ #include #include #include +#include /******************************************************************************************\ * * @@ -20,7 +21,6 @@ bool TestForRGBFusion2SMBusController(i2c_smbus_interface* bus, unsigned char ad bool pass = false; int res = bus->i2c_smbus_write_quick(address, I2C_SMBUS_WRITE); - if (res >= 0) { pass = true; @@ -55,13 +55,18 @@ void DetectRGBFusion2SMBusControllers(std::vector& busses, for (unsigned int bus = 0; bus < busses.size(); bus++) { - // Check for RGB Fusion 2 controller at 0x68 - if (TestForRGBFusion2SMBusController(busses[bus], 0x68)) - { - new_rgb_fusion = new RGBFusion2SMBusController(busses[bus], 0x68); - new_controller = new RGBController_RGBFusion2SMBus(new_rgb_fusion); - rgb_controllers.push_back(new_controller); - } + // TODO - Is this necessary? Or an artifact of my own system? + // Skip dmcd devices + std::string device_name = std::string(busses[bus]->device_name); + if (device_name.find("dmdc") == std::string::npos) { + // Check for RGB Fusion 2 controller at 0x68 + if (TestForRGBFusion2SMBusController(busses[bus], 0x68)) + { + new_rgb_fusion = new RGBFusion2SMBusController(busses[bus], 0x68); + new_controller = new RGBController_RGBFusion2SMBus(new_rgb_fusion); + rgb_controllers.push_back(new_controller); + } + } } -} /* DetectRGBFusion2SMBusControllers() */ \ No newline at end of file +} /* DetectRGBFusion2SMBusControllers() */ diff --git a/OpenRGB.cpp b/OpenRGB.cpp index 54e8be33..2f84fdbc 100644 --- a/OpenRGB.cpp +++ b/OpenRGB.cpp @@ -291,6 +291,7 @@ void DetectPatriotViperControllers(std::vector &busses, st void DetectPolychromeControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusionControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusionGPUControllers(std::vector& busses, std::vector& rgb_controllers); +void DetectRGBFusion2SMBusControllers(std::vector& busses, std::vector& rgb_controllers); void DetectMSIMysticLightControllers(std::vector &rgb_controllers); void DetectMSIRGBControllers(std::vector &rgb_controllers); void DetectAuraAddressableControllers(std::vector &rgb_controllers); @@ -334,6 +335,7 @@ void DetectRGBControllers(void) DetectPatriotViperControllers(busses, rgb_controllers); DetectPolychromeControllers(busses, rgb_controllers); DetectRGBFusionGPUControllers(busses, rgb_controllers); + DetectRGBFusion2SMBusControllers(busses, rgb_controllers); DetectRGBFusionControllers(busses, rgb_controllers); DetectMSIMysticLightControllers(rgb_controllers); diff --git a/RGBController/RGBController_RGBFusion2SMBus.cpp b/RGBController/RGBController_RGBFusion2SMBus.cpp index e69de29b..14c1496c 100644 --- a/RGBController/RGBController_RGBFusion2SMBus.cpp +++ b/RGBController/RGBController_RGBFusion2SMBus.cpp @@ -0,0 +1,186 @@ + +/*-----------------------------------------*\ +| RGBController_RGBFusion2SMBus.cpp | +| | +| Generic RGB Interface for OpenRGB | +| Gigabyte RGB Fusion 2SMBUS Driver | +| | +| Matt Harper (5/5/2020) | +\*-----------------------------------------*/ + +#include "RGBController_RGBFusion2SMBus.h" + +/* TODO - Validate all of these + * CPU + * ??? + * Mobo logo - Verified + * Case rear + * Case + * ??? + * ??? + * ARGB header 1 + * ARGB header 2 + * + * Do ??? actually map to anything? Are they even supported? + * If not, what is an elegant way to display but not wreck existing logic? + */ +static const char* rgb_fusion_zone_names[] = +{ + "CPU", + "???", + "Motherboard Logo", + "Case Rear", + "Case", + "???", + "???", + "ARGB Header 1", + "ARGB Header 2", + "???" +}; + +RGBController_RGBFusion2SMBus::RGBController_RGBFusion2SMBus(RGBFusion2SMBusController* rgb_fusion_ptr) +{ + rgb_fusion = rgb_fusion_ptr; + + name = "RGB Fusion 2 SMBus"; + description = "RGB Fusion 2 SMBus"; + location = rgb_fusion->GetDeviceLocation(); + + type = DEVICE_TYPE_MOTHERBOARD; + + // TODO - Something awry with modes and their default speeds. + // Setting individual LEDs work fine, but changing via Mode dropdown causes LEDs + // to exceed specified ranges + + mode Static; + Static.name = "Static"; + Static.value = RGB_FUSION_2_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Static.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Static); + + mode Pulse; + Pulse.name = "Pulse"; + Pulse.value = RGB_FUSION_2_MODE_PULSE; + Pulse.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR; + Pulse.speed_min = RGB_FUSION_2_SPEED_SLOW; + Pulse.speed_max = RGB_FUSION_2_SPEED_FAST; + Pulse.speed = RGB_FUSION_2_SPEED_NORMAL; + Pulse.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Pulse); + + mode Flashing; + Flashing.name = "Flashing"; + Flashing.value = RGB_FUSION_2_MODE_FLASHING; + Flashing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR; + Flashing.speed_min = 0x01; + Flashing.speed_max = 0x04; + Flashing.speed = 0x02; + Flashing.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Flashing); + + mode ColorCycle; + ColorCycle.name = "Color Cycle"; + ColorCycle.value = RGB_FUSION_2_MODE_COLOR_CYCLE; + ColorCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR; + ColorCycle.speed_min = RGB_FUSION_2_SPEED_SLOW; + ColorCycle.speed_max = RGB_FUSION_2_SPEED_FAST; + ColorCycle.speed = RGB_FUSION_2_SPEED_NORMAL; + ColorCycle.color_mode = MODE_COLORS_PER_LED; + modes.push_back(ColorCycle); + + SetupZones(); + + // Initialize active mode + // TODO - broken. Need to complete GetDeviceMode + active_mode = GetDeviceMode(); +} + +void RGBController_RGBFusion2SMBus::SetupZones() +{ + /*---------------------------------------------------------*\ + | Search through all LEDs and create zones for each channel | + | type | + \*---------------------------------------------------------*/ + for(unsigned int zone_idx = 0; zone_idx < rgb_fusion->GetLEDCount(); zone_idx++) + { + zone* new_zone = new zone(); + + // Set zone name to channel name + new_zone->name = rgb_fusion_zone_names[zone_idx]; + new_zone->leds_min = 1; + new_zone->leds_max = 1; + new_zone->leds_count = 1; + + // Push new zone to zones vector + zones.push_back(*new_zone); + } + + for(unsigned int led_idx = 0; led_idx < zones.size(); led_idx++) + { + led* new_led = new led(); + + // Set LED name to channel name + new_led->name = rgb_fusion_zone_names[led_idx]; + + // Push new LED to LEDs vector + leds.push_back(*new_led); + } + + SetupColors(); +} + +void RGBController_RGBFusion2SMBus::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_RGBFusion2SMBus::UpdateLEDs() +{ + for (std::size_t led = 0; led < colors.size(); led++) + { + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + int mode = modes[active_mode].value; + unsigned int speed = modes[active_mode].speed; + rgb_fusion->SetLEDEffect(led, mode, speed, red, grn, blu); + } +} + +void RGBController_RGBFusion2SMBus::UpdateZoneLEDs(int zone) +{ + RGBColor color = colors[zone]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + int mode = modes[active_mode].value; + unsigned int speed = modes[active_mode].speed; + rgb_fusion->SetLEDEffect(zone, mode, speed, red, grn, blu); +} + +void RGBController_RGBFusion2SMBus::UpdateSingleLED(int led) +{ + UpdateZoneLEDs(led); +} + +// TODO - Research if possible to read device state +int RGBController_RGBFusion2SMBus::GetDeviceMode() +{ + return(0); +} + +void RGBController_RGBFusion2SMBus::SetCustomMode() +{ + +} + +void RGBController_RGBFusion2SMBus::UpdateMode() +{ + +} diff --git a/RGBController/RGBController_RGBFusion2SMBus.h b/RGBController/RGBController_RGBFusion2SMBus.h index e69de29b..89170b44 100644 --- a/RGBController/RGBController_RGBFusion2SMBus.h +++ b/RGBController/RGBController_RGBFusion2SMBus.h @@ -0,0 +1,37 @@ + +/*-----------------------------------------*\ +| RGBController_RGBFusion2SMBus.h | +| | +| Generic RGB Interface for OpenRGB | +| Gigabyte RGB Fusion 2 SM BUs Driver | +| | +| Matt Harper (5/5/2020) | +\*-----------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "RGBFusion2SMBusController.h" + +class RGBController_RGBFusion2SMBus : public RGBController +{ +public: + RGBController_RGBFusion2SMBus(RGBFusion2SMBusController* rgb_fusion_ptr); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void UpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void SetMode(); + void UpdateMode(); + +private: + RGBFusion2SMBusController* rgb_fusion; + + int GetDeviceMode(); +};