mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-09-14 14:17:46 -04:00
225 lines
6.1 KiB
C++
225 lines
6.1 KiB
C++
/*---------------------------------------------------------*\
|
|
| AkkoKeyboardController.cpp |
|
|
| |
|
|
| Driver for Akko Multi-modes keyboards |
|
|
| |
|
|
| Protocol based on the RongYuan/ROYUAN HID protocol |
|
|
| documented by the akko-light project |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#include "AkkoKeyboardController.h"
|
|
#include "LogManager.h"
|
|
#include "StringUtils.h"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include <thread>
|
|
|
|
AkkoKeyboardController::AkkoKeyboardController(hid_device* dev_handle, char* path)
|
|
{
|
|
dev = dev_handle;
|
|
location = path;
|
|
valid = false;
|
|
|
|
current_mode = AKKO_EFFECT_STATIC;
|
|
current_speed = AKKO_SPEED_DEFAULT;
|
|
current_brightness = AKKO_BRIGHTNESS_DEFAULT;
|
|
current_option = AKKO_OPTION_FIXED_COLOR;
|
|
current_red = 0x00;
|
|
current_green = 0x75;
|
|
current_blue = 0xFF;
|
|
|
|
wchar_t name_string[AKKO_HID_MAX_STR] = { 0 };
|
|
|
|
if(hid_get_manufacturer_string(dev, name_string, AKKO_HID_MAX_STR) == 0)
|
|
{
|
|
device_name = StringUtils::wstring_to_string(name_string);
|
|
}
|
|
|
|
std::memset(name_string, 0, sizeof(name_string));
|
|
|
|
if(hid_get_product_string(dev, name_string, AKKO_HID_MAX_STR) == 0)
|
|
{
|
|
std::string product_name = StringUtils::wstring_to_string(name_string);
|
|
|
|
if(!product_name.empty())
|
|
{
|
|
if(!device_name.empty())
|
|
{
|
|
device_name.append(" ");
|
|
}
|
|
|
|
device_name.append(product_name);
|
|
}
|
|
}
|
|
|
|
if(device_name.empty())
|
|
{
|
|
device_name = "Akko Multi-modes Keyboard-B";
|
|
}
|
|
|
|
valid = ReadState();
|
|
}
|
|
|
|
AkkoKeyboardController::~AkkoKeyboardController()
|
|
{
|
|
hid_close(dev);
|
|
}
|
|
|
|
bool AkkoKeyboardController::IsValid() const
|
|
{
|
|
return(valid);
|
|
}
|
|
|
|
std::string AkkoKeyboardController::GetDeviceName()
|
|
{
|
|
return(device_name);
|
|
}
|
|
|
|
std::string AkkoKeyboardController::GetSerial()
|
|
{
|
|
wchar_t serial_string[AKKO_HID_MAX_STR] = { 0 };
|
|
|
|
if(hid_get_serial_number_string(dev, serial_string, AKKO_HID_MAX_STR) != 0)
|
|
{
|
|
return("");
|
|
}
|
|
|
|
return(StringUtils::wstring_to_string(serial_string));
|
|
}
|
|
|
|
std::string AkkoKeyboardController::GetLocation()
|
|
{
|
|
return("HID: " + location);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetMode() const
|
|
{
|
|
return(current_mode);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetSpeed() const
|
|
{
|
|
return(current_speed);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetBrightness() const
|
|
{
|
|
return(current_brightness);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetRed() const
|
|
{
|
|
return(current_red);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetGreen() const
|
|
{
|
|
return(current_green);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::GetBlue() const
|
|
{
|
|
return(current_blue);
|
|
}
|
|
|
|
unsigned char AkkoKeyboardController::CalculateChecksum(const unsigned char* data, std::size_t length)
|
|
{
|
|
unsigned int sum = 0;
|
|
|
|
for(std::size_t index = 0; index < length; index++)
|
|
{
|
|
sum += data[index];
|
|
}
|
|
|
|
return(static_cast<unsigned char>(0xFF - (sum & 0xFF)));
|
|
}
|
|
|
|
bool AkkoKeyboardController::ReadState()
|
|
{
|
|
unsigned char request[AKKO_REPORT_LENGTH + 1] = { 0x00 };
|
|
|
|
request[1] = AKKO_COMMAND_GET_LED_PARAMS;
|
|
request[8] = CalculateChecksum(&request[1], 7);
|
|
|
|
int result = hid_send_feature_report(dev, request, sizeof(request));
|
|
|
|
if(result < 0)
|
|
{
|
|
LOG_DEBUG("[AKKO]: GET_LEDPARAM request failed: %ls", hid_error(dev));
|
|
return(false);
|
|
}
|
|
|
|
for(unsigned int attempt = 0; attempt < 5; attempt++)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(80));
|
|
|
|
unsigned char response[AKKO_REPORT_LENGTH + 1] = { 0x00 };
|
|
result = hid_get_feature_report(dev, response, sizeof(response));
|
|
|
|
if(result > 8 && response[1] == AKKO_COMMAND_GET_LED_PARAMS)
|
|
{
|
|
current_mode = response[2];
|
|
current_speed = response[3] <= AKKO_SPEED_MAX ? AKKO_SPEED_MAX - response[3] : AKKO_SPEED_DEFAULT;
|
|
current_brightness = std::min<unsigned char>(response[4], AKKO_BRIGHTNESS_MAX);
|
|
current_option = response[5];
|
|
current_red = response[6];
|
|
current_green = response[7];
|
|
current_blue = response[8];
|
|
return(true);
|
|
}
|
|
}
|
|
|
|
LOG_DEBUG("[AKKO]: Device did not answer GET_LEDPARAM");
|
|
return(false);
|
|
}
|
|
|
|
bool AkkoKeyboardController::SendUpdate()
|
|
{
|
|
unsigned char buffer[AKKO_REPORT_LENGTH + 1] = { 0x00 };
|
|
|
|
buffer[1] = AKKO_COMMAND_SET_LED_PARAMS;
|
|
buffer[2] = current_mode;
|
|
buffer[3] = AKKO_SPEED_MAX - std::min<unsigned char>(current_speed, AKKO_SPEED_MAX);
|
|
buffer[4] = std::min<unsigned char>(current_brightness, AKKO_BRIGHTNESS_MAX);
|
|
buffer[5] = current_option;
|
|
buffer[6] = current_red;
|
|
buffer[7] = current_green;
|
|
buffer[8] = current_blue;
|
|
buffer[9] = CalculateChecksum(&buffer[1], 8);
|
|
|
|
int result = hid_send_feature_report(dev, buffer, sizeof(buffer));
|
|
|
|
if(result < 0)
|
|
{
|
|
LOG_ERROR("[AKKO]: SET_LEDPARAM failed: %ls", hid_error(dev));
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
void AkkoKeyboardController::SetMode(unsigned char mode, unsigned char speed, unsigned char brightness)
|
|
{
|
|
current_mode = mode;
|
|
current_speed = std::min<unsigned char>(speed, AKKO_SPEED_MAX);
|
|
current_brightness = std::min<unsigned char>(brightness, AKKO_BRIGHTNESS_MAX);
|
|
current_option = AKKO_OPTION_FIXED_COLOR;
|
|
|
|
SendUpdate();
|
|
}
|
|
|
|
void AkkoKeyboardController::SetColor(unsigned char red, unsigned char green, unsigned char blue)
|
|
{
|
|
current_red = red;
|
|
current_green = green;
|
|
current_blue = blue;
|
|
current_option = AKKO_OPTION_FIXED_COLOR;
|
|
|
|
SendUpdate();
|
|
}
|