mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-24 07:47:49 -05:00
475 lines
15 KiB
C++
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, ¤t_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, ¤t_profile);
|
|
if(ret < 0)
|
|
{
|
|
return;
|
|
}
|
|
if(current_profile > 2)
|
|
{
|
|
current_profile = 0;
|
|
Write(EVISION_V2_CMD_WRITE_CONFIG, EVISION_V2_OFFSET_CURRENT_PROFILE, ¤t_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;
|
|
}
|