Files
2025-11-03 16:53:46 -06:00

192 lines
6.4 KiB
C++

/*---------------------------------------------------------*\
| HyperXAlloyOriginsCoreController.cpp |
| |
| Driver for HyperX Alloy Origins Core keyboard |
| |
| Volodymyr Nazarchuk (Vavooon) 28 Apr 2021 |
| Mike White (kamaaina) 09 Jun 2021 |
| carlos jordao 15 Mar 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "HyperXAlloyOriginsCoreController.h"
#include "StringUtils.h"
#include "LogManager.h"
HyperXAlloyOriginsCoreController::HyperXAlloyOriginsCoreController(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name)
{
dev = dev_handle;
location = dev_info->path;
name = dev_name;
/*-----------------------------------------------------*\
| Get the firmware version from the device info |
\*-----------------------------------------------------*/
char fw_version_buf[8];
memset(fw_version_buf, '\0', sizeof(fw_version_buf));
unsigned short version = dev_info->release_number;
snprintf(fw_version_buf, 8, "%.2X.%.2X", (version & 0xFF00) >> 8, version & 0x00FF);
firmware_version = fw_version_buf;
}
HyperXAlloyOriginsCoreController::~HyperXAlloyOriginsCoreController()
{
hid_close(dev);
}
std::string HyperXAlloyOriginsCoreController::GetDeviceLocation()
{
return("HID " + location);
}
std::string HyperXAlloyOriginsCoreController::GetNameString()
{
return(name);
}
std::string HyperXAlloyOriginsCoreController::GetSerialString()
{
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string HyperXAlloyOriginsCoreController::GetFirmwareVersion()
{
return(firmware_version);
}
unsigned int HyperXAlloyOriginsCoreController::GetVariant()
{
unsigned char packet[65];
unsigned int variant = 0;
int actual = 0;
memset(packet, 0x00, sizeof(packet));
/*---------------------------------------*\
| Command 10 asks some data from keyboard |
| The answer looks like: |
| * command answer header (bytes 0-4) |
| * data length: byte 4 |
| * version (bytes 5-6) |
| * Product string (bytes 9-33) |
| * Layout variant (byte 56) |
\*---------------------------------------*/
packet[1] = 0x10;
hid_write(dev, packet, 65);
memset(packet, 0x00, sizeof(packet));
actual = hid_read(dev, packet, 65);
if(actual > 0)
variant = packet[56];
else
variant = 0;
LOG_DEBUG("[HyperX Alloy Origins Core] variant: 0x%02X", variant);
return variant;
}
void HyperXAlloyOriginsCoreController::SetBrightness(unsigned int brightness)
{
unsigned char packet[65];
memset(packet, 0x00, sizeof(packet));
packet[1] = 0xA7;
packet[4] = 0x01;
packet[5] = brightness;
hid_write(dev, packet, 65);
}
void HyperXAlloyOriginsCoreController::SetLEDsDirect(std::vector<led> leds, std::vector<RGBColor> colors)
{
/*------------------------------------------------------------------------------*\
| * Always send 380 bytes to the keyboard and a total of 94 led indexes. |
| The colors are grouped into segments of 48 bytes. |
| Each one is divided into: |
| 6 Green + 2 zeroes + 6 Green + 2 zeroes + |
| 6 Red + 2 zeroes + 6 Red + 2 zeroes + |
| 6 Blue + 2 zeroes + 6 Blue + 2 zeroes |
| \=---> sector 0 \=--> sector 1 |
| Every 6 colors form a sector. The names are arbitrary, just to make clear how |
| to set the colors into the buffer. |
| So each segment has 2 sectors and 12 colors. |
| The last 10 colors don't fill completely the last segment. |
| * All 94 colors can be sent even if some of them aren't used by the physical |
| keyboard. This allows to lit every key, even if not mapped directly. |
\*------------------------------------------------------------------------------*/
unsigned int segment = 0, sector = 0, sequence = 0;
unsigned int total_colors = 0;
memset(color_buf, 0x00, sizeof(color_buf));
/*---------------------------------------------------------------------------*\
| transfer the colors to the buffer. Max 94 colors to avoid buffer overflow. |
\*---------------------------------------------------------------------------*/
if(colors.size() > 94)
{
total_colors = 94;
}
else
{
total_colors = (unsigned int)colors.size();
}
unsigned int pos = 0, color_idx = 0;
for(unsigned int i = 0; i < total_colors; i++)
{
color_idx = leds[i].value;
segment = (color_idx / 12) * 48;
sector = ((color_idx / 6) & 1) * 8;
sequence = color_idx % 6;
pos = segment + sector + sequence;
color_buf[pos ] = RGBGetGValue(colors[i]);
color_buf[pos + 16] = RGBGetRValue(colors[i]);
color_buf[pos + 32] = RGBGetBValue(colors[i]);
}
}
void HyperXAlloyOriginsCoreController::SendRGBToDevice()
{
unsigned int sentBytes = 0;
unsigned int bytesToSend = sizeof(color_buf);
unsigned int payloadSize = 60;
unsigned int seq = 0;
while(sentBytes < bytesToSend)
{
if (bytesToSend - sentBytes < payloadSize)
{
payloadSize = bytesToSend - sentBytes;
}
unsigned char packet[65];
memset(packet, 0x00, sizeof(packet));
packet[1] = 0xA2;
packet[2] = seq++;
packet[4] = payloadSize;
memcpy(&packet[5], &color_buf[sentBytes], payloadSize);
hid_write(dev, packet, payloadSize + 5);
sentBytes += payloadSize;
}
}