From fd4403ec68028c430a4148938e2a61d17c3dd668 Mon Sep 17 00:00:00 2001 From: Fefedu973 Date: Sat, 3 May 2025 22:59:43 +0000 Subject: [PATCH] Add support for the Alienware AW3423DWF and AW3225QF monitors --- .../AlienwareAW3423DWFController.cpp | 178 ++++++++++++++++++ .../AlienwareAW3423DWFController.h | 40 ++++ .../AlienwareAW3423DWFControllerDetect.cpp | 39 ++++ .../RGBController_AlienwareAW3423DWF.cpp | 132 +++++++++++++ .../RGBController_AlienwareAW3423DWF.h | 34 ++++ 5 files changed, 423 insertions(+) create mode 100644 Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.cpp create mode 100644 Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.h create mode 100644 Controllers/AlienwareMonitorController/AlienwareAW3423DWFControllerDetect.cpp create mode 100644 Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.cpp create mode 100644 Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.h diff --git a/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.cpp b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.cpp new file mode 100644 index 00000000..6955eb30 --- /dev/null +++ b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.cpp @@ -0,0 +1,178 @@ +/*---------------------------------------------------------*\ +| AlienwareAW3423DWFController.cpp | +| | +| Driver for the Alienware AW3423DWF monitor | +| | +| Ferréol DUBOIS COLI (Fefe_du_973) 23 Jan 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "AlienwareAW3423DWFController.h" +#include "StringUtils.h" +#include +#include + +AlienwareAW3423DWFController::AlienwareAW3423DWFController(hid_device *dev_handle, const char *path) : dev(dev_handle), location(path){} + +void AlienwareAW3423DWFController::SendControlPacket(const unsigned char *data, size_t length) +{ + unsigned char buffer[256] = {0x00}; + memcpy(buffer + 1, data, length); + + hid_write(dev, buffer, length + 1); +} + +std::vector AlienwareAW3423DWFController::GetReportResponse() +{ + uint8_t buffer[193]; + + memset(buffer, 0, 193); + + hid_get_input_report(dev, buffer, 193); + + return std::vector(buffer + 1, buffer + 18); +} + +void AlienwareAW3423DWFController::PerformLogin() +{ + unsigned char init_packet[64] = + { + 0x40, 0xE1, 0x01 + }; + SendControlPacket(init_packet, 4); + + std::vector response = GetReportResponse(); + + std::vector key = GenerateKey(response); + + unsigned char login_packet[192] = {0x00}; + login_packet[0] = 0x40; + login_packet[1] = 0xE1; + login_packet[2] = 0x02; + memcpy(login_packet + 64, key.data(), key.size()); + + SendControlPacket(login_packet, 192); +} + +void AlienwareAW3423DWFController::SendColor(unsigned char led_id, unsigned char r, unsigned char g, unsigned char b) +{ + unsigned char led_id_2 = (led_id == 0x01) ? 0xf6 : (led_id == 0x02) ? 0xf5 + : (led_id == 0x08) ? 0xff + : 0xfc; + PerformLogin(); + + unsigned char color_packet[192] = {0x00}; + + color_packet[0] = 0x40; + color_packet[1] = 0xC6; + color_packet[6] = 0x0A; + color_packet[8] = 0x6E; + color_packet[10] = 0x82; + color_packet[64] = 0x51; + color_packet[65] = 0x87; + color_packet[66] = 0xD0; + color_packet[67] = 0x04; + + color_packet[68] = led_id; + color_packet[69] = r; + color_packet[70] = g; + color_packet[71] = b; + color_packet[72] = 0x64; + color_packet[73] = led_id_2; + + SendControlPacket(color_packet, 192); +} + +std::vector AlienwareAW3423DWFController::GenerateKey( + const std::vector &response) +{ + std::vector syn_key(8, 0); + + const std::vector oem_key = { + 0xf5, 0x3f, 0xc1, 0x39, 0x44, 0x3a, 0x31, 0x79, 0x0d, 0xb1, 0x82, 0x76 + }; + + size_t sk_idx = 0, ok_idx = 0; + while(ok_idx < oem_key.size() && sk_idx < 8) + { + unsigned char ok_sub_len = (oem_key[ok_idx] & 1) + ((oem_key[ok_idx] & 0x10) >> 4); + + for(unsigned int i = 0; i < ok_sub_len && sk_idx < 8; i++) + { + syn_key[sk_idx] = oem_key[ok_idx + 1] ^ oem_key[ok_idx]; + ok_idx++; + sk_idx++; + } + ok_idx++; + } + + std::vector out_buffer; + + uint16_t v15 = static_cast(response[15]) | + (static_cast(response[0]) << 8); + bool parity_odd = (std::bitset<16>(v15).count() % 2 != 0); + + if(parity_odd) + { + size_t end = std::min(8, response.size()); + out_buffer = std::vector(response.begin(), response.begin() + end); + + if(response.size() > 14) + { + unsigned char idx = response[14] & 0x07; + if((idx + 8) < response.size()) + { + out_buffer[idx] ^= response[idx + 8]; + } + } + } + else + { + size_t start = std::min(8, response.size()); + size_t end = std::min(start + 8, response.size()); + out_buffer = std::vector(response.begin() + start, response.begin() + end); + + if(response.size() > 6) + { + unsigned char idx = response[6] & 0x07; + if(idx < response.size()) + { + out_buffer[idx] ^= response[idx]; + } + } + } + + for(size_t i = 0; i < 8 && i < out_buffer.size(); i++) + { + syn_key[i] ^= out_buffer[i]; + } + + return syn_key; +} + +AlienwareAW3423DWFController::~AlienwareAW3423DWFController() +{ + if(dev) + { + hid_close(dev); + dev = nullptr; + } +} + +std::string AlienwareAW3423DWFController::GetLocation() +{ + return "HID: " + location; +} + +std::string AlienwareAW3423DWFController::GetSerialString() +{ + wchar_t serial[256]; + if(hid_get_serial_number_string(dev, serial, 256) >= 0) + { + std::wstring ws(serial); + return StringUtils::wstring_to_string(ws); + } + return ""; +} diff --git a/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.h b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.h new file mode 100644 index 00000000..8e4532e6 --- /dev/null +++ b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFController.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------*\ +| AlienwareAW3423DWFController.h | +| | +| Driver for the Alienware AW3423DWF monitor | +| | +| Ferréol DUBOIS COLI (Fefe_du_973) 23 Jan 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +class AlienwareAW3423DWFController +{ +public: + AlienwareAW3423DWFController(hid_device* dev_handle, const char* path); + ~AlienwareAW3423DWFController(); + + std::string GetLocation(); + std::string GetSerialString(); + void SendColor(unsigned char led_id, unsigned char r, unsigned char g, unsigned char b); + +private: + hid_device* dev; + std::string location; + unsigned char endpoint_out = 0x02; + unsigned char endpoint_in = 0x81; + + static const std::vector> OEM_KEYS; + + void PerformLogin(); + std::vector GenerateKey(const std::vector& response); + void SendControlPacket(const unsigned char* data, size_t length); + std::vector GetReportResponse(); +}; diff --git a/Controllers/AlienwareMonitorController/AlienwareAW3423DWFControllerDetect.cpp b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFControllerDetect.cpp new file mode 100644 index 00000000..04387573 --- /dev/null +++ b/Controllers/AlienwareMonitorController/AlienwareAW3423DWFControllerDetect.cpp @@ -0,0 +1,39 @@ +#include "Detector.h" +#include "AlienwareAW3423DWFController.h" +#include "RGBController_AlienwareAW3423DWF.h" +#include + +/*---------------------------------------------------------*\ +| Alienware Vendor ID | +\*---------------------------------------------------------*/ +#define ALIENWARE_VID 0x187C + +/*---------------------------------------------------------*\ +| Alienware Vendor ID | +\*---------------------------------------------------------*/ +#define ALIENWARE_AW3423DWF_PID 0x100E +#define ALIENWARE_AW3225QF_PID 0x1013 +#define ALIENWARE_USAGE_PAGE 0xFFDA +#define ALIENWARE_USAGE 0x00DA + +/******************************************************************************************\ +* * +* AlienwareAW3423DWFControllerDetect * +* * +* Tests the USB address to see if an Alienware AW3423DWF exists there. * +* * +\******************************************************************************************/ + +void DetectAlienwareAW3423DWFControllers(hid_device_info* info, const std::string&) +{ + hid_device* dev = hid_open_path(info->path); + if(dev) + { + AlienwareAW3423DWFController* controller = new AlienwareAW3423DWFController(dev, info->path); + RGBController_AlienwareAW3423DWF* rgb_controller = new RGBController_AlienwareAW3423DWF(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +REGISTER_HID_DETECTOR("Alienware AW3423DWF", DetectAlienwareAW3423DWFControllers, ALIENWARE_VID, ALIENWARE_AW3423DWF_PID); +REGISTER_HID_DETECTOR("Alienware AW3225QF", DetectAlienwareAW3423DWFControllers, ALIENWARE_VID, ALIENWARE_AW3225QF_PID); diff --git a/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.cpp b/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.cpp new file mode 100644 index 00000000..bf1c1c94 --- /dev/null +++ b/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.cpp @@ -0,0 +1,132 @@ +/*---------------------------------------------------------*\ +| RGBController_AlienwareAW3423DWF.cpp | +| | +| RGBController for the Alienware AW3423DWF monitor | +| | +| Ferréol DUBOIS COLI (Fefe_du_973) 23 Jan 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "RGBController_AlienwareAW3423DWF.h" +#include + +using namespace std::chrono_literals; + +/**------------------------------------------------------------------*\ + @name AW3423DWF + @category Accessory + @type USB + @save :x: + @direct :white_check_mark: + @effects :x: + @detectors DetectAlienwareAW3423DWFControllers + @comment The prefered way of interacting with this device is + to use the direct mode, in this mode you cannot choose the + individual LED colors (all the LED will be the same color) BUT + the frame rate of the color will be more than 3 times higher + (better for dynamic effects). However, If you still want to + individually control your LEDs set the mode to Static, here + you will be able to individually set a different color for each + LED but don't expect a frame rate higher than 1fps. +\*-------------------------------------------------------------------*/ +RGBController_AlienwareAW3423DWF::RGBController_AlienwareAW3423DWF(AlienwareAW3423DWFController* controller_ptr) : + controller(controller_ptr) +{ + name = "Alienware AW3423DWF"; + vendor = "Alienware"; + type = DEVICE_TYPE_ACCESSORY; + description = "Alienware QD-OLED Monitor"; + location = controller->GetLocation(); + serial = controller->GetSerialString(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Static; + Static.name = "Static (indivdual LED control)"; + Static.value = 1; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Static.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Static); + + SetupZones(); +} + +void RGBController_AlienwareAW3423DWF::SetupZones() +{ + std::vector led_names = {"Alien", "Number", "Switch", "All"}; + + zone new_zone; + new_zone.name = "Monitor Lighting"; + new_zone.type = ZONE_TYPE_LINEAR; + new_zone.leds_min = led_names.size(); + new_zone.leds_max = led_names.size(); + new_zone.leds_count = led_names.size(); + new_zone.matrix_map = NULL; + zones.push_back(new_zone); + + for(const std::string& name : led_names) + { + led new_led; + new_led.name = name; + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_AlienwareAW3423DWF::DeviceUpdateLEDs() +{ + if(modes[active_mode].value == 0) + { + UpdateSingleLED(3); + } + else + { + for(unsigned int led_idx = 0; led_idx < leds.size() - 1; led_idx++) + { + UpdateSingleLED(led_idx); + std::this_thread::sleep_for(200ms); + } + } +} + +void RGBController_AlienwareAW3423DWF::UpdateSingleLED(int led) +{ + unsigned char led_id = 0x00; + + switch(led) + { + case 0: led_id = 0x01; break; + case 1: led_id = 0x02; break; + case 2: led_id = 0x08; break; + case 3: led_id = 0x0b; break; + } + + RGBColor color = colors[led]; + controller->SendColor(led_id, + RGBGetRValue(color), + RGBGetGValue(color), + RGBGetBValue(color)); +} + +RGBController_AlienwareAW3423DWF::~RGBController_AlienwareAW3423DWF() +{ + delete controller; +} + +void RGBController_AlienwareAW3423DWF::UpdateZoneLEDs(int zone) +{ +} + +void RGBController_AlienwareAW3423DWF::DeviceUpdateMode() +{ +} + +void RGBController_AlienwareAW3423DWF::ResizeZone(int, int) {} diff --git a/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.h b/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.h new file mode 100644 index 00000000..eda92719 --- /dev/null +++ b/Controllers/AlienwareMonitorController/RGBController_AlienwareAW3423DWF.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------*\ +| RGBController_AlienwareAW3423DWF.h | +| | +| RGBController for the Alienware AW3423DWF monitor | +| | +| Ferréol DUBOIS COLI (Fefe_du_973) 23 Jan 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "AlienwareAW3423DWFController.h" + +class RGBController_AlienwareAW3423DWF : public RGBController +{ +public: + explicit RGBController_AlienwareAW3423DWF(AlienwareAW3423DWFController* controller_ptr); + ~RGBController_AlienwareAW3423DWF() override; + + void SetupZones(); + void ResizeZone(int zone, int new_size) override; + + void DeviceUpdateLEDs() override; + void UpdateZoneLEDs(int zone) override; + void UpdateSingleLED(int led) override; + + void DeviceUpdateMode() override; + +private: + AlienwareAW3423DWFController* controller; +};