/*-----------------------------------------*\ | RGBController_ASRockPolychromeSMBus.cpp | | | | Generic RGB Interface for OpenRGB | | ASRock ASR LED and Polychrome RGB Driver | | | | Adam Honse (CalcProgrammer1) 12/15/2019 | \*-----------------------------------------*/ #include "LogManager.h" #include "RGBController_ASRockPolychromeV1SMBus.h" static const char* polychrome_v1_zone_names[] = { "RGB LED 1 Header", "RGB LED 2 Header", "PCH", "IO Cover", "Audio", "Addressable Header" }; /**------------------------------------------------------------------*\ @name ASRock Polychrome v1 SMBus @category Motherboard @type SMBus @save :robot: @direct :x: @effects :white_check_mark: @detectors DetectASRockSMBusControllers @comment ASRock Polychrome v1 controllers will save with each update. Per ARGB LED support is not possible with these devices. ARGB size and color order is set using the `ARGB Header Config mode` `Right` = GRB mode that is needed for WS2812B ARGB devices and `Left` = RGB used for WS2811 strips The modes speed slider will set the size of the header Spectrum Cycles uses the RGB values to set the individual color brightness. \*-------------------------------------------------------------------*/ RGBController_ASRockPolychromeV1SMBus::RGBController_ASRockPolychromeV1SMBus(ASRockPolychromeV1SMBusController* controller_ptr) { controller = controller_ptr; name = controller->GetDeviceName(); vendor = "ASRock"; version = controller->GetFirmwareVersion(); type = DEVICE_TYPE_MOTHERBOARD; description = "ASRock Polychrome v1 Device"; location = controller->GetDeviceLocation(); mode Off; Off.name = "Off"; Off.value = POLYCHROME_V1_MODE_OFF; Off.flags = MODE_FLAG_AUTOMATIC_SAVE; Off.color_mode = MODE_COLORS_NONE; modes.push_back(Off); mode Static; Static.name = "Static"; Static.value = POLYCHROME_V1_MODE_STATIC; Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE; Static.color_mode = MODE_COLORS_PER_LED; modes.push_back(Static); mode Breathing; Breathing.name = "Breathing"; Breathing.value = POLYCHROME_V1_MODE_BREATHING; Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE; Breathing.speed_min = POLYCHROME_V1_SPEED_MIN_BREATHING; Breathing.speed_max = POLYCHROME_V1_SPEED_MAX_BREATHING; Breathing.speed = POLYCHROME_V1_SPEED_DEFAULT_BREATHING; Breathing.color_mode = MODE_COLORS_PER_LED; modes.push_back(Breathing); mode Strobe; Strobe.name = "Strobe"; Strobe.value = POLYCHROME_V1_MODE_STROBE; Strobe.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE; Strobe.speed_min = POLYCHROME_V1_SPEED_MIN_STROBE; Strobe.speed_max = POLYCHROME_V1_SPEED_MAX_STROBE; Strobe.speed = POLYCHROME_V1_SPEED_DEFAULT_STROBE; Strobe.color_mode = MODE_COLORS_PER_LED; modes.push_back(Strobe); mode SpectrumCycle; SpectrumCycle.name = "Spectrum Cycle"; SpectrumCycle.value = POLYCHROME_V1_MODE_SPECTRUM_CYCLE; SpectrumCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; SpectrumCycle.speed_min = POLYCHROME_V1_SPEED_MIN_CYCLE; SpectrumCycle.speed_max = POLYCHROME_V1_SPEED_MAX_CYCLE; SpectrumCycle.speed = POLYCHROME_V1_SPEED_DEFAULT_CYCLE; SpectrumCycle.color_mode = MODE_COLORS_PER_LED; modes.push_back(SpectrumCycle); mode Random; Random.name = "Random"; Random.value = POLYCHROME_V1_MODE_RANDOM; Random.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Random.speed_min = POLYCHROME_V1_SPEED_MIN_RANDOM; Random.speed_max = POLYCHROME_V1_SPEED_MAX_RANDOM; Random.speed = POLYCHROME_V1_SPEED_DEFAULT_RANDOM; Random.color_mode = MODE_COLORS_NONE; modes.push_back(Random); mode Music; Music.name = "Music"; Music.value = POLYCHROME_V1_MODE_MUSIC; Music.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE; Music.color_mode = MODE_COLORS_NONE; modes.push_back(Music); mode Wave; Wave.name = "Wave"; Wave.value = POLYCHROME_V1_MODE_WAVE; Wave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Wave.speed_min = POLYCHROME_V1_SPEED_MIN_WAVE; Wave.speed_max = POLYCHROME_V1_SPEED_MAX_WAVE; Wave.speed = POLYCHROME_V1_SPEED_DEFAULT_WAVE; Wave.color_mode = MODE_COLORS_NONE; modes.push_back(Wave); /*---------------------------------------------------------------------*\ | Comment out until per zone modes are working. These are only for ARGB | \*---------------------------------------------------------------------*/ /* mode Spring; Spring.name = "Spring"; Spring.value = POLYCHROME_V1_MODE_SPRING; Spring.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Spring.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Spring.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Spring.speed = POLYCHROME_V1_SPEED_DEFAULT_SPRING; Spring.color_mode = MODE_COLORS_PER_LED; modes.push_back(Spring); mode Stack; Stack.name = "Stack"; Stack.value = POLYCHROME_V1_MODE_STACK; Stack.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Stack.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Stack.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Stack.speed = POLYCHROME_V1_SPEED_DEFAULT_STACK; Stack.color_mode = MODE_COLORS_PER_LED; modes.push_back(Stack); mode Cram; Cram.name = "Cram"; Cram.value = POLYCHROME_V1_MODE_CRAM; Cram.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Cram.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Cram.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Cram.speed = POLYCHROME_V1_SPEED_DEFAULT_CRAM; Cram.color_mode = MODE_COLORS_PER_LED; modes.push_back(Cram); mode Scan; Scan.name = "Scan"; Scan.value = POLYCHROME_V1_MODE_SCAN; Scan.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Scan.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Scan.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Scan.speed = POLYCHROME_V1_SPEED_DEFAULT_SCAN; Scan.color_mode = MODE_COLORS_PER_LED; modes.push_back(Scan); mode Neon; Neon.name = "Neon"; Neon.value = POLYCHROME_V1_MODE_NEON; Neon.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Neon.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Neon.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Neon.speed = POLYCHROME_V1_SPEED_DEFAULT_NEON; Neon.color_mode = MODE_COLORS_PER_LED; modes.push_back(Neon); mode Water; Water.name = "Water"; Water.value = POLYCHROME_V1_MODE_WATER; Water.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Water.speed_min = POLYCHROME_V1_SPEED_MIN_ARGB; Water.speed_max = POLYCHROME_V1_SPEED_MAX_ARGB; Water.speed = POLYCHROME_V1_SPEED_DEFAULT_WATER; Water.color_mode = MODE_COLORS_PER_LED; modes.push_back(Water); mode Rainbow; Rainbow.name = "Rainbow"; Rainbow.value = POLYCHROME_V1_MODE_RAINBOW; Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; Rainbow.speed_min = POLYCHROME_V1_SPEED_MIN_RAINBOW; Rainbow.speed_max = POLYCHROME_V1_SPEED_MAX_RAINBOW; Rainbow.speed = POLYCHROME_V1_SPEED_DEFAULT_RAINBOW; Rainbow.color_mode = MODE_COLORS_NONE; modes.push_back(Rainbow); */ /*---------------------------------------------------------------------*\ | This ARGB_Config section is a hack to allow users to configure the | | RGB vs GRB mode using the direction of the mode as well as set the | | size of the devices connected to the header using the brightness | | value. | | | | The mode should be removed onece the device settings are avaiable. | \*---------------------------------------------------------------------*/ mode ARGB_Config; ARGB_Config.name = "ARGB Header Config"; ARGB_Config.value = POLYCHROME_V1_REG_ARGB_GRB; ARGB_Config.flags = MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE; ARGB_Config.speed = controller->zone_led_count[POLYCHROME_V1_ZONE_ADDRESSABLE]; ARGB_Config.speed_min = 1; ARGB_Config.speed_max = POLYCHROME_V1_ZONE_ADDRESSABLE_MAX; ARGB_Config.direction = controller -> GetARGBColorOrder(); ARGB_Config.color_mode = MODE_COLORS_NONE; modes.push_back(ARGB_Config); SetupZones(); controller->LoadZoneConfig(); active_mode = getModeIndex(controller->zone_config[0].mode); // Hard coding zone 0 until per zone modes are available. if(active_mode != POLYCHROME_V1_MODE_OFF) { for( uint8_t zone_idx = 0; zone_idx < zoneIndexMap.size(); zone_idx++) { zones[zone_idx].colors[0] = controller->GetZoneColor(zoneIndexMap[zone_idx]); } } } RGBController_ASRockPolychromeV1SMBus::~RGBController_ASRockPolychromeV1SMBus() { delete controller; } uint8_t RGBController_ASRockPolychromeV1SMBus::getModeIndex(uint8_t mode_value) { for(uint8_t mode_index = 0; mode_index < modes.size(); mode_index++) { if (modes[mode_index].value == mode_value) { return mode_index; } } return 0; } void RGBController_ASRockPolychromeV1SMBus::SetupZones() { /*---------------------------------------------------------*\ | Polychrome motherboards should set up zones based on LED | | configuration register read from device | \*---------------------------------------------------------*/ /*---------------------------------------------------------*\ | Set up zones | \*---------------------------------------------------------*/ for(uint8_t zone_idx = 0; zone_idx < POLYCHROME_V1_ZONE_COUNT; zone_idx++) { if(controller->zone_led_count[zone_idx] > 0) { zone* new_zone = new zone(); /*---------------------------------------------------------*\ | Set zone name to channel name | \*---------------------------------------------------------*/ new_zone->name = polychrome_v1_zone_names[zone_idx]; new_zone->type = ZONE_TYPE_SINGLE; new_zone->leds_min = 1; new_zone->leds_max = 1; new_zone->leds_count = 1; new_zone->matrix_map = NULL; if(zone_idx == POLYCHROME_V1_ZONE_ADDRESSABLE) { new_zone->leds_max = POLYCHROME_V1_ZONE_ADDRESSABLE_MAX; } /*---------------------------------------------------------*\ | Push new zone to zones vector | \*---------------------------------------------------------*/ zones.push_back(*new_zone); /*---------------------------------------------------------*\ | Each zone only has one LED | \*---------------------------------------------------------*/ led* new_led = new led(); new_led->name = polychrome_v1_zone_names[zone_idx]; new_led->value = zone_idx; /*---------------------------------------------------------*\ | Push new LED to LEDs vector | \*---------------------------------------------------------*/ leds.push_back(*new_led); zoneIndexMap.push_back(zone_idx); } } SetupColors(); } void RGBController_ASRockPolychromeV1SMBus::ResizeZone(int zone, int new_size) { LOG_TRACE("[%s] ResizeZone(%02X, %02X)", name.c_str(), zone, new_size); controller-> SetARGBSize(new_size & 0xFF); zones[POLYCHROME_V1_ZONE_ADDRESSABLE].leds_count = 1; } void RGBController_ASRockPolychromeV1SMBus::DeviceUpdateLEDs() { LOG_TRACE("[%s] DeviceUpdateLEDs()", name.c_str()); for (uint8_t zone_idx = 0; zone_idx < zoneIndexMap.size(); zone_idx++) { UpdateSingleLED(zone_idx); } } void RGBController_ASRockPolychromeV1SMBus::UpdateZoneLEDs(int /*zone*/) { LOG_TRACE("[%s] UpdateZoneLEDs()", name.c_str()); DeviceUpdateLEDs(); } void RGBController_ASRockPolychromeV1SMBus::UpdateSingleLED(int zone) { LOG_TRACE("[%s] UpdateSingleLED(%02X)", name.c_str(), zone); uint8_t red = RGBGetRValue(colors[zone]); uint8_t grn = RGBGetGValue(colors[zone]); uint8_t blu = RGBGetBValue(colors[zone]); controller->SetColorsAndSpeed(zoneIndexMap[zone], red, grn, blu); } void RGBController_ASRockPolychromeV1SMBus::DeviceUpdateMode() { LOG_TRACE("[%s] DeviceUpdateMode()", name.c_str()); if(modes[active_mode].value != POLYCHROME_V1_REG_ARGB_GRB) { for(uint8_t zone_idx = 0; zone_idx < zoneIndexMap.size(); zone_idx++) { controller->SetMode(zoneIndexMap[zone_idx], modes[active_mode].value, modes[active_mode].speed); UpdateSingleLED(zone_idx); } } else { controller-> SetARGBColorOrder(modes[active_mode].direction); controller-> SetARGBSize(modes[active_mode].speed); } }