Files
OpenRGB/Controllers/EVisionKeyboardController/EVisionV2KeyboardController.cpp
2025-01-17 00:15:18 -06:00

475 lines
15 KiB
C++

/*---------------------------------------------------------*\
| EVisionV2KeyboardController.cpp |
| |
| Driver for EVision V2 keyboard |
| |
| Le Philousophe 25 Dec 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <cstring>
#include "LogManager.h"
#include "EVisionV2KeyboardController.h"
#include "StringUtils.h"
#define BLANK_SPACE 6
#define query_check_buffer(c) \
do \
{ \
if(!(c)) \
{ \
return -256; \
} \
} while(0)
using namespace std::chrono_literals;
static uint8_t evisionv2_map[EVISION_V2_MATRIX_WIDTH * EVISION_V2_MATRIX_HEIGHT] =
{
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 19 20 */
0, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96,
1, 7, 13, 19, 25, 31, 37, 43, 49, 55, 61, 67, 73, 79, 85, 91, 97, 103, 109, 115, 121,
2, 8, 14, 20, 26, 32, 38, 44, 50, 56, 62, 68, 74, 80, 86, 92, 98, 104, 110, 116, 122,
3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 105, 111, 117,
4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 82, 94, 106, 112, 118, 124,
5, 11, 17, 41, 65, 71, 77, 83, 89, 95, 101, 113, 119,
};
static uint8_t endorfy_map[EVISION_V2_MATRIX_WIDTH * EVISION_V2_MATRIX_HEIGHT] =
{
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 19 20 */
0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 80, 81, 82,
84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 97, 99, 101, 102, 103, 104,
105, 106, 107, 111, 115, 116, 117, 118, 119, 120, 121, 123, 124,
};
EVisionV2KeyboardController::EVisionV2KeyboardController(hid_device* dev_handle, const char* path, EVisionV2KeyboardLayout layout_)
{
layout = layout_;
dev = dev_handle;
location = path;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
/*---------------------------------------------------------*\
| Get capabilities and layout |
\*---------------------------------------------------------*/
uint8_t buffer[7];
if(Read(EVISION_V2_CMD_READ_CAPABILITIES, 0, sizeof(buffer), buffer) < 0)
{
return;
}
if(buffer[0] != 0xAA && buffer[1] != 0x55)
{
return;
}
map_size = buffer[5];
macros_size = buffer[6] * 0x80;
switch(layout)
{
case EVISION_V2_KEYBOARD_LAYOUT:
keyvalue_map = evisionv2_map;
led_count = 106;
break;
case ENDORFY_KEYBOARD_LAYOUT:
keyvalue_map = endorfy_map;
led_count = 104;
break;
}
}
EVisionV2KeyboardController::~EVisionV2KeyboardController()
{
hid_close(dev);
}
std::string EVisionV2KeyboardController::GetDeviceName()
{
return device_name;
}
std::string EVisionV2KeyboardController::GetSerial()
{
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 EVisionV2KeyboardController::GetLocation()
{
return("HID: " + location);
}
int EVisionV2KeyboardController::Query(uint8_t cmd, uint16_t offset, const uint8_t* idata, uint8_t size, uint8_t* odata)
{
uint8_t buffer[EVISION_V2_PACKET_SIZE];
memset(buffer, 0, sizeof(buffer));
buffer[0] = EVISION_V2_REPORT_ID;
buffer[3] = cmd;
buffer[4] = size;
buffer[5] = offset & 0xff;
buffer[6] = (offset >> 8) & 0xff;
if(idata)
{
memcpy(buffer + 8, idata, size);
}
uint16_t chksum = 0;
for(uint8_t* p = &buffer[3]; p != &buffer[EVISION_V2_PACKET_SIZE]; p++)
{
chksum += *p;
}
buffer[1] = chksum & 0xff;
buffer[2] = (chksum >> 8) & 0xff;
int bytes_read;
{
const std::lock_guard<std::mutex> lock(query_mutex);
hid_write(dev, buffer, sizeof(buffer));
do
{
bytes_read = hid_read(dev, buffer, sizeof(buffer));
} while(bytes_read != 0 && buffer[0] != EVISION_V2_REPORT_ID);
}
query_check_buffer(bytes_read == sizeof(buffer));
query_check_buffer(buffer[0] == EVISION_V2_REPORT_ID);
query_check_buffer(buffer[1] == (chksum & 0xff));
query_check_buffer(buffer[2] == ((chksum >> 8) & 0xff));
query_check_buffer(buffer[3] == cmd);
query_check_buffer(buffer[5] == (offset & 0xff));
query_check_buffer(buffer[6] == ((offset >> 8) & 0xff));
if(buffer[7] != 0)
{
return -buffer[7];
}
size = buffer[4];
if(size > EVISION_V2_PACKET_SIZE - 8)
{
return -256;
}
if(odata)
{
memcpy(odata, buffer + 8, size);
}
return size;
}
int EVisionV2KeyboardController::BeginConfigure()
{
return Query(EVISION_V2_CMD_BEGIN_CONFIGURE);
}
int EVisionV2KeyboardController::EndConfigure()
{
return Query(EVISION_V2_CMD_END_CONFIGURE);
}
int EVisionV2KeyboardController::Read(uint8_t cmd, uint16_t offset, uint16_t size, uint8_t* odata)
{
while(size > 0)
{
uint8_t pktsz = (uint8_t)std::min<size_t>(size, EVISION_V2_PACKET_SIZE - 8);
int result = Query(cmd, offset, nullptr, pktsz, odata);
if(result <= 0)
{
return result;
}
else if(result > size)
{
return -256;
}
offset += result;
odata += result;
size -= result;
}
return 0;
}
int EVisionV2KeyboardController::Write(uint8_t cmd, uint16_t offset, const uint8_t* idata, uint16_t size)
{
while(size > 0)
{
uint8_t pktsz = (uint8_t)std::min<size_t>(size, EVISION_V2_PACKET_SIZE - 8);
int result = Query(cmd, offset, idata, pktsz);
if(result <= 0)
{
return result;
}
offset += pktsz;
idata += pktsz;
size -= pktsz;
}
return 0;
}
int EVisionV2KeyboardController::GetMode(EVisionV2KeyboardPart part, EvisionV2ModeConfig& config)
{
uint8_t buffer[18];
memset(buffer, 0, sizeof(buffer));
uint8_t current_profile;
int ret = Read(EVISION_V2_CMD_READ_CONFIG, EVISION_V2_OFFSET_CURRENT_PROFILE, 1, &current_profile);
if(ret < 0)
{
return ret;
}
if(current_profile > 2)
{
current_profile = 0;
}
uint16_t offset;
uint8_t size;
offset = current_profile * 0x40 + EVISION_V2_OFFSET_FIRST_PROFILE;
switch(part)
{
case EVISION_V2_KEYBOARD_PART_KEYBOARD:
size = sizeof(buffer);
break;
case EVISION_V2_KEYBOARD_PART_LOGO:
case ENDORFY_KEYBOARD_PART_EDGE:
offset += EVISION_V2_PARAMETER_LOGO;
size = EVISION_V2_PARAMETER_LOGO_ON_OFF - EVISION_V2_PARAMETER_LOGO + 1;
break;
case EVISION_V2_KEYBOARD_PART_EDGE:
offset += EVISION_V2_PARAMETER_EDGE;
size = EVISION_V2_PARAMETER_END - EVISION_V2_PARAMETER_EDGE;
break;
default:
size = 0;
break;
}
ret = Read(EVISION_V2_CMD_READ_CONFIG, offset, size, buffer);
if(ret < 0)
{
return ret;
}
config.mode = buffer[EVISION_V2_PARAMETER_MODE];
config.brightness = buffer[EVISION_V2_PARAMETER_BRIGHTNESS];
config.speed = buffer[EVISION_V2_PARAMETER_SPEED];
config.direction = buffer[EVISION_V2_PARAMETER_DIRECTION];
config.random_colours = buffer[EVISION_V2_PARAMETER_RANDOM_COLOR_FLAG] != 0;
config.colour = ToRGBColor(buffer[EVISION_V2_PARAMETER_MODE_COLOR + 0],
buffer[EVISION_V2_PARAMETER_MODE_COLOR + 1], buffer[EVISION_V2_PARAMETER_MODE_COLOR + 2]);
if(part == EVISION_V2_KEYBOARD_PART_KEYBOARD)
{
config.ledmode = buffer[EVISION_V2_PARAMETER_LED_MODE_COLOR];
if(config.mode == EVISION_V2_MODE_CUSTOM)
{
ret = Read(EVISION_V2_CMD_READ_CONFIG, current_profile * 0x40 + EVISION_V2_OFFSET_FIRST_PROFILE + EVISION_V2_PARAMETER_CURRENT_CUSTOM_MODE, sizeof(config.ledmode), &config.ledmode);
if(ret < 0)
{
return ret;
}
}
}
else if(part == EVISION_V2_KEYBOARD_PART_LOGO || part == ENDORFY_KEYBOARD_PART_EDGE)
{
// Use ledmode for logo on/off
config.ledmode = buffer[EVISION_V2_PARAMETER_LOGO_ON_OFF - EVISION_V2_PARAMETER_LOGO];
}
return 0;
}
void EVisionV2KeyboardController::SetMode(EVisionV2KeyboardPart part, const EvisionV2ModeConfig& config)
{
uint8_t buffer[18];
memset(buffer, 0, sizeof(buffer));
buffer[EVISION_V2_PARAMETER_MODE] = config.mode;
buffer[EVISION_V2_PARAMETER_BRIGHTNESS] = config.brightness;
buffer[EVISION_V2_PARAMETER_SPEED] = config.speed;
buffer[EVISION_V2_PARAMETER_DIRECTION] = config.direction;
buffer[EVISION_V2_PARAMETER_RANDOM_COLOR_FLAG] = (config.random_colours) ? 255 : 0;
buffer[EVISION_V2_PARAMETER_MODE_COLOR + 0] = RGBGetRValue(config.colour);
buffer[EVISION_V2_PARAMETER_MODE_COLOR + 1] = RGBGetGValue(config.colour);
buffer[EVISION_V2_PARAMETER_MODE_COLOR + 2] = RGBGetBValue(config.colour);
if(part == EVISION_V2_KEYBOARD_PART_KEYBOARD)
{
buffer[EVISION_V2_PARAMETER_COLOR_OFFSET] = 0;
if(config.mode != EVISION_V2_MODE_CUSTOM)
{
buffer[EVISION_V2_PARAMETER_LED_MODE_COLOR] = config.ledmode;
}
}
else if(part == EVISION_V2_KEYBOARD_PART_LOGO || part == ENDORFY_KEYBOARD_PART_EDGE)
{
// Use ledmode for logo on/off
buffer[EVISION_V2_PARAMETER_LOGO_ON_OFF - EVISION_V2_PARAMETER_LOGO] = config.ledmode;
}
BeginConfigure();
uint8_t current_profile;
int ret = Read(EVISION_V2_CMD_READ_CONFIG, EVISION_V2_OFFSET_CURRENT_PROFILE, 1, &current_profile);
if(ret < 0)
{
return;
}
if(current_profile > 2)
{
current_profile = 0;
Write(EVISION_V2_CMD_WRITE_CONFIG, EVISION_V2_OFFSET_CURRENT_PROFILE, &current_profile, 1);
}
uint16_t offset = 0;
uint8_t size = 0;
offset = current_profile * 0x40 + EVISION_V2_OFFSET_FIRST_PROFILE;
switch(part)
{
case EVISION_V2_KEYBOARD_PART_KEYBOARD:
size = sizeof(buffer);
break;
case EVISION_V2_KEYBOARD_PART_LOGO:
case ENDORFY_KEYBOARD_PART_EDGE:
offset += EVISION_V2_PARAMETER_LOGO;
size = EVISION_V2_PARAMETER_LOGO_ON_OFF - EVISION_V2_PARAMETER_LOGO + 1;
break;
case EVISION_V2_KEYBOARD_PART_EDGE:
offset += EVISION_V2_PARAMETER_EDGE;
size = EVISION_V2_PARAMETER_END - EVISION_V2_PARAMETER_EDGE;
break;
}
Write(EVISION_V2_CMD_WRITE_CONFIG, offset, buffer, size);
if((part == EVISION_V2_KEYBOARD_PART_KEYBOARD) && (config.mode == EVISION_V2_MODE_CUSTOM))
{
Write(EVISION_V2_CMD_WRITE_CONFIG, current_profile * 0x40 + EVISION_V2_OFFSET_FIRST_PROFILE + EVISION_V2_PARAMETER_CURRENT_CUSTOM_MODE, &config.ledmode, sizeof(config.ledmode));
}
EndConfigure();
}
void EVisionV2KeyboardController::SetLedsDirect(const std::vector<RGBColor>& colours)
{
const size_t colours_num = std::min(colours.size(), led_count);
uint8_t* buffer = new uint8_t[3 * map_size];
memset(buffer, 0, 3 * map_size);
for(size_t i = 0; i < colours_num; i++)
{
size_t j = (size_t)keyvalue_map[i] * 3;
buffer[j + 0] = RGBGetRValue(colours[i]);
buffer[j + 1] = RGBGetGValue(colours[i]);
buffer[j + 2] = RGBGetBValue(colours[i]);
}
Write(EVISION_V2_CMD_SEND_DYNAMIC_COLORS, 0, buffer, (uint16_t)(3 * map_size));
delete[] buffer;
}
void EVisionV2KeyboardController::SetLedDirect(int led, RGBColor colour)
{
uint8_t buffer[3];
buffer[0] = RGBGetRValue(colour);
buffer[1] = RGBGetGValue(colour);
buffer[2] = RGBGetBValue(colour);
Write(EVISION_V2_CMD_SEND_DYNAMIC_COLORS, keyvalue_map[led] * 3, buffer, sizeof(buffer));
}
void EVisionV2KeyboardController::RefreshLedDirect()
{
// Write one zero byte in the first blank space
Query(EVISION_V2_CMD_SEND_DYNAMIC_COLORS, BLANK_SPACE * 3, nullptr, 1, nullptr);
}
void EVisionV2KeyboardController::EndLedsDirect()
{
Query(EVISION_V2_CMD_END_DYNAMIC_COLORS);
}
int EVisionV2KeyboardController::GetLedsCustom(uint8_t colorset, std::vector<RGBColor>& colours)
{
if(colorset > 9)
{
return -256;
}
const size_t colours_num = std::min(colours.size(), led_count);
uint8_t* buffer = new uint8_t[3 * map_size];
memset(buffer, 0, 3 * map_size);
int ret = Read(EVISION_V2_CMD_READ_CUSTOM_COLORS, 512 * colorset, (uint16_t)(3 * map_size), buffer);
if(ret < 0)
{
return ret;
}
for(size_t i = 0; i < colours_num; i++)
{
size_t j = (size_t)keyvalue_map[i] * 3;
colours[i] = ToRGBColor(buffer[j + 0], buffer[j + 1], buffer[j + 2]);
}
delete[] buffer;
return 0;
}
void EVisionV2KeyboardController::SetLedsCustom(uint8_t colorset, const std::vector<RGBColor>& colours)
{
if(colorset > 9)
{
return;
}
const size_t colours_num = std::min(colours.size(), led_count);
uint8_t* buffer = new uint8_t[3 * map_size];
memset(buffer, 0, 3 * map_size);
for(size_t i = 0; i < colours_num; i++)
{
size_t j = (size_t)keyvalue_map[i] * 3;
buffer[j + 0] = RGBGetRValue(colours[i]);
buffer[j + 1] = RGBGetGValue(colours[i]);
buffer[j + 2] = RGBGetBValue(colours[i]);
}
BeginConfigure();
Write(EVISION_V2_CMD_WRITE_CUSTOM_COLORS, 512 * colorset, buffer, (uint16_t)(3 * map_size));
EndConfigure();
delete[] buffer;
}