Add support for the Alienware AW3423DWF and AW3225QF monitors

This commit is contained in:
Fefedu973 2025-05-03 22:59:43 +00:00 committed by Adam Honse
parent ce62d9998e
commit fd4403ec68
5 changed files with 423 additions and 0 deletions

View file

@ -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 <cstring>
#include <bitset>
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<unsigned char> AlienwareAW3423DWFController::GetReportResponse()
{
uint8_t buffer[193];
memset(buffer, 0, 193);
hid_get_input_report(dev, buffer, 193);
return std::vector<unsigned char>(buffer + 1, buffer + 18);
}
void AlienwareAW3423DWFController::PerformLogin()
{
unsigned char init_packet[64] =
{
0x40, 0xE1, 0x01
};
SendControlPacket(init_packet, 4);
std::vector<unsigned char> response = GetReportResponse();
std::vector<unsigned char> 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<unsigned char> AlienwareAW3423DWFController::GenerateKey(
const std::vector<unsigned char> &response)
{
std::vector<unsigned char> syn_key(8, 0);
const std::vector<unsigned char> 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<unsigned char> out_buffer;
uint16_t v15 = static_cast<uint16_t>(response[15]) |
(static_cast<uint16_t>(response[0]) << 8);
bool parity_odd = (std::bitset<16>(v15).count() % 2 != 0);
if(parity_odd)
{
size_t end = std::min<size_t>(8, response.size());
out_buffer = std::vector<unsigned char>(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<size_t>(8, response.size());
size_t end = std::min<size_t>(start + 8, response.size());
out_buffer = std::vector<unsigned char>(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 "";
}

View file

@ -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 <hidapi.h>
#include <vector>
#include <string>
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<std::vector<unsigned char>> OEM_KEYS;
void PerformLogin();
std::vector<unsigned char> GenerateKey(const std::vector<unsigned char>& response);
void SendControlPacket(const unsigned char* data, size_t length);
std::vector<unsigned char> GetReportResponse();
};

View file

@ -0,0 +1,39 @@
#include "Detector.h"
#include "AlienwareAW3423DWFController.h"
#include "RGBController_AlienwareAW3423DWF.h"
#include <hidapi.h>
/*---------------------------------------------------------*\
| 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);

View file

@ -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 <thread>
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<std::string> 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) {}

View file

@ -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;
};