/*-----------------------------------------*\ | RGBFusion2Controller.cpp | | | | Driver for Gigabyte Aorus RGB Fusion 2.0 | | lighting controller | | | | jackun 1/8/2020 | \*-----------------------------------------*/ #include "RGBFusion2Controller.h" #include #include #include #include static LEDCount LedCountToEnum(unsigned int c) { if (c <= 32) return(LEDS_32); if (c <= 64) return(LEDS_64); if (c <= 256) return(LEDS_256); if (c <= 512) return(LEDS_512); return(LEDS_1024); } RGBFusion2Controller::RGBFusion2Controller(hid_device* handle, const char *path) : dev(handle) { int res = 0; char text[64] {}; unsigned char buffer[64] {}; if( dev ) { SetCalibration(); // hid report read needs 0x60 packet or it gives IO error SendPacket(0x60, 0x00); buffer[0] = report_id; res = hid_get_feature_report(dev, buffer, 64); if( res > 0 ) { report = *reinterpret_cast(buffer); name = std::string(report.str_product, 32); name.erase(std::find(name.begin(), name.end(), '\0'), name.end()); snprintf(text, 11, "0x%08X", report.fw_ver); version = text; snprintf(text, 11, "0x%08X", report.chip_id); chip_id = text; } loc = path; EnableBeat(false); } } RGBFusion2Controller::~RGBFusion2Controller() { if( dev ) { hid_close(dev); } } void RGBFusion2Controller::SetMode(int m) { mode = m; } // Sets RGB color mapping to LED pins. // "Custom" RGB packets don't seem to get remapped so use report.byteorderN and do it manually. // Of course it all depends how we send data to the controller, but bios/rgb fusion 2 itself // set it up like this. void RGBFusion2Controller::SetCalibration() { uint8_t buffer[64] {}; buffer[0] = report_id; buffer[1] = 0x33; // D_LED1 WS2812 GRB, 0x00RRGGBB to 0x00GGRRBB buffer[2] = 0x02; // B buffer[3] = 0x00; // G buffer[4] = 0x01; // R buffer[5] = 0x00; // D_LED2 WS2812 GRB buffer[6] = 0x02; buffer[7] = 0x00; buffer[8] = 0x01; buffer[9] = 0x00; // LED C1/C2 12vGRB, seems pins already connect to LEDs correctly buffer[10] = 0x00; buffer[11] = 0x01; buffer[12] = 0x02; buffer[13] = 0x00; SendPacket(buffer); } void RGBFusion2Controller::SetLedCount(unsigned int count) { led_count = count; LEDCount s0 = LedCountToEnum(count); SendPacket(0x34, s0 | (s0 << 4)); // D_LED1 | D_LED2 } bool RGBFusion2Controller::DisableBuiltinEffect(int enable_bit, int mask) { if(effect_disabled & enable_bit) return(true); effect_disabled &= ~mask; effect_disabled |= enable_bit; int res = SendPacket(0x32, effect_disabled); // Sometimes effect doesn't apply at first, delay a little and let MCU to react, if this packet is the cause std::this_thread::sleep_for(std::chrono::milliseconds(50)); return res; } bool RGBFusion2Controller::EnableBeat(bool e) { return SendPacket(0x31, e ? 1 : 0); } std::string RGBFusion2Controller::GetDeviceName() { return(name); } std::string RGBFusion2Controller::GetFWVersion() { return(version); } std::string RGBFusion2Controller::GetDeviceLocation() { return(loc); } std::string RGBFusion2Controller::GetSerial() { return(chip_id); } void RGBFusion2Controller::SetStripColors(unsigned int hdr, int start, int end, std::vector& colors, int single_led) { PktRGB pkt; pkt.Init(hdr, report_id); // FIXME assuming that LED strips ports are 0x58/0x59 for all boards uint32_t byteorder = hdr == HDR_D_LED1_RGB ? report.byteorder0 : report.byteorder1; unsigned char bo_r = byteorder >> 16; unsigned char bo_g = byteorder >> 8; unsigned char bo_b = byteorder & 0xFF; int res; int leds_left = end - start; int sent_data = 0; int k = 0; int leds_in_pkt = sizeof(pkt.s.leds) / sizeof(*pkt.s.leds); /* 19 */ // other leds stay at whatever the builtin effect was doing at that moment // if breathing/pulse effect faded out then they stay dark if(single_led > -1) { leds_left = 1; k = single_led - start; sent_data = k * 3; leds_in_pkt = 1; } while(leds_left > 0) { leds_in_pkt = (std::min)(leds_in_pkt, leds_left); leds_left -= leds_in_pkt; pkt.s.bcount = leds_in_pkt * 3; pkt.s.boffset = sent_data; sent_data += pkt.s.bcount; for(int i = 0; i < leds_in_pkt; i++) { RGBColor color = colors[start + k]; unsigned char red = RGBGetRValue(color); unsigned char grn = RGBGetGValue(color); unsigned char blu = RGBGetBValue(color); pkt.buffer[5 + i * 3 + bo_r] = red; pkt.buffer[5 + i * 3 + bo_g] = grn; pkt.buffer[5 + i * 3 + bo_b] = blu; k++; } res = SendPacket(pkt.buffer); if(res < 0) return; } if (hdr == HDR_D_LED1_RGB) DisableBuiltinEffect(0x01, 0x01); else DisableBuiltinEffect(0x02, 0x02); } static const std::array< std::array, 5> speeds = { { {1600, 1600, 200}, {1200, 1200, 200}, {800, 800, 200}, {400, 400, 200}, {200, 200, 200}, }, }; void RGBFusion2Controller::SetLEDEffect(unsigned int led, int mode, unsigned int speed, bool random, unsigned char r, unsigned char g, unsigned char b) { PktEffect pkt; pkt.Init(led, report_id); pkt.e.effect_type = mode; pkt.e.color0 = r << 16 | g << 8 | b; if (speed < speeds.size()) { const auto& s = speeds[speed]; pkt.e.period0 = s[0]; pkt.e.period1 = s[1]; pkt.e.period2 = s[2]; } switch(mode) { case 0: break; case 1: break; // static case 2: // breathing case 3: // blink if (random) pkt.e.effect_param0 = 7; // cycle through up to 7 (max?) colors break; case 4: // color cycle pkt.e.effect_param0 = 7; // cycle through up to 7 (max?) colors break; // "fake" effects case 10: // flashing, flashing color cycle pkt.e.period0 = 200; pkt.e.period1 = 200; pkt.e.period2 = 5000 - 1000 * speed; // time between flashing, doesn't seem to be affected by period0/period1 pkt.e.effect_type = 3; pkt.e.effect_param2 = 2; // flash twice if (random) pkt.e.effect_param0 = 7; break; } SendPacket(pkt.buffer); } bool RGBFusion2Controller::ApplyEffect() { return SendPacket(0x28, 0xFF); } bool RGBFusion2Controller::SendPacket(uint8_t a, uint8_t b, uint8_t c) { unsigned char buffer[64] {}; buffer[0] = report_id; buffer[1] = a; buffer[2] = b; buffer[3] = c; return (SendPacket(buffer) == 64); } int RGBFusion2Controller::SendPacket(unsigned char* packet) { return hid_send_feature_report(dev, packet, 64); }