360 lines
14 KiB
C++
360 lines
14 KiB
C++
#include <cstring>
|
|
#include <execution>
|
|
#include <VulcanoLE/Keyboards/Vulcan121.h>
|
|
#include <VUtils/Logging.h>
|
|
#include <VUtils/Math.h>
|
|
#include <cmath>
|
|
|
|
Vulcan121::Vulcan121(HIDHelper *helper)
|
|
: m_helper(helper) {
|
|
for (auto &item: keyMapRow) {
|
|
item = new keys;
|
|
}
|
|
for (auto &item: keyMapCol) {
|
|
item = new keys;
|
|
}
|
|
|
|
setupMap();
|
|
}
|
|
|
|
Vulcan121::~Vulcan121() {
|
|
for (auto &item: keyMapRow) {
|
|
delete[] item->index;
|
|
delete item;
|
|
}
|
|
for (auto &item: keyMapCol) {
|
|
delete[] item->index;
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
// Colors are in blocks of 12 keys (2 columns). Color parts are sorted by color e.g. the red
|
|
// values for all 12 keys are first then come the green values etc.
|
|
int Vulcan121::sendLedMap(led_map &src) {
|
|
int i, k;
|
|
rgba rgb;
|
|
unsigned char ledBuffer[448]{};
|
|
memset(ledBuffer, 0, sizeof(ledBuffer));
|
|
ledBuffer[0] = 0xa1;
|
|
ledBuffer[1] = 0x01;
|
|
ledBuffer[2] = 0x01;
|
|
ledBuffer[3] = 0xb4;
|
|
for (k = 0; k < NUM_KEYS; k++) {
|
|
// Prepare Color
|
|
auto use = m_fixed[k] ? *(m_fixed[k]) : src.key[k];
|
|
rgb.a = (int16_t) VUtils::Math::clamp(use.a, 0, 255);
|
|
double factor = rgb.a / 255.0;
|
|
rgb.r = (int16_t) VUtils::Math::clamp(std::round(use.r * factor), 0, 255);
|
|
rgb.g = (int16_t) VUtils::Math::clamp(std::round(use.g * factor), 0, 255);
|
|
rgb.b = (int16_t) VUtils::Math::clamp(std::round(use.b * factor), 0, 255);
|
|
|
|
int offset = ((k / 12) * 36) + (k % 12);
|
|
ledBuffer[offset + 4] = (unsigned char) rgb.r;
|
|
ledBuffer[offset + 16] = (unsigned char) rgb.g;
|
|
ledBuffer[offset + 28] = (unsigned char) rgb.b;
|
|
}
|
|
|
|
unsigned char buffer[65];
|
|
buffer[0] = 0x00;
|
|
for (i = 0; i < 7; i++) {
|
|
int index = i * 64;
|
|
memcpy(&buffer[1], &ledBuffer[index], 64);
|
|
if (hid_write(m_helper->m_ledDevice, buffer, 65) != 65) {
|
|
ERR("Write failed")
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
int Vulcan121::sendToLEDs(rgba rgb) {
|
|
auto map = led_map();
|
|
for (auto &i: map.key) {
|
|
i = rgb;
|
|
}
|
|
int st = sendLedMap(map);
|
|
return st;
|
|
}
|
|
|
|
bool Vulcan121::sendInitSequence() {
|
|
LOG("Sending device init sequence...")
|
|
unsigned char a[9] = { 0x15, 0x05, 0x07, 0x0a, 0x0b, 0x06, 0x09, 0x0d, 0x13 };
|
|
if (!queryCtrlReport(0x0f))
|
|
return false;
|
|
for (auto i: a) {
|
|
if (!sendCtrlReport(i) || !waitForCtrlDev()) {
|
|
return false;
|
|
}
|
|
}
|
|
m_helper->closeCtrlDevice();
|
|
return true;
|
|
}
|
|
|
|
bool Vulcan121::queryCtrlReport(unsigned char id) {
|
|
if (id != 0x0f) return false;
|
|
unsigned char buffer[8] = {};
|
|
int length = 8;
|
|
buffer[0] = id;
|
|
int res = m_helper->getFeatureReport(buffer, length);
|
|
if (res) {
|
|
return true;
|
|
}
|
|
ERR("queryCtrlReport(%02hhx) failed", id);
|
|
return false;
|
|
}
|
|
|
|
bool Vulcan121::sendCtrlReport(unsigned char id) {
|
|
unsigned char *buffer;
|
|
int length;
|
|
|
|
switch (id) {
|
|
case 0x15:
|
|
buffer = (unsigned char *) "\x15\x00\x01";
|
|
length = 3;
|
|
break;
|
|
case 0x05:
|
|
buffer = (unsigned char *) "\x05\x04\x00\x04";
|
|
length = 4;
|
|
break;
|
|
case 0x07:
|
|
buffer = (unsigned char *) "\x07\x5f\x00\x3a\x00\x00\x3b\x00\x00\x3c\x00\x00\x3d\x00\x00\x3e" \
|
|
"\x00\x00\x3f\x00\x00\x40\x00\x00\x41\x00\x00\x42\x00\x00\x43\x00" \
|
|
"\x00\x44\x00\x00\x45\x00\x00\x46\x00\x00\x47\x00\x00\x48\x00\x00" \
|
|
"\xb3\x00\x00\xb4\x00\x00\xb5\x00\x00\xb6\x00\x00\xc2\x00\x00\xc3" \
|
|
"\x00\x00\xc0\x00\x00\xc1\x00\x00\xce\x00\x00\xcf\x00\x00\xcc\x00" \
|
|
"\x00\xcd\x00\x00\x46\x00\x00\xfc\x00\x00\x48\x00\x00\xcd\x0e";
|
|
length = 95;
|
|
break;
|
|
case 0x0a:
|
|
buffer = (unsigned char *) "\x0a\x08\x00\xff\xf1\x00\x02\x02";
|
|
length = 8;
|
|
break;
|
|
case 0x0b:
|
|
buffer = (unsigned char *) "\x0b\x41\x00\x1e\x00\x00\x1f\x00\x00\x20\x00\x00\x21\x00\x00\x22" \
|
|
"\x00\x00\x14\x00\x00\x1a\x00\x00\x08\x00\x00\x15\x00\x00\x17\x00" \
|
|
"\x00\x04\x00\x00\x16\x00\x00\x07\x00\x00\x09\x00\x00\x0a\x00\x00" \
|
|
"\x1d\x00\x00\x1b\x00\x00\x06\x00\x00\x19\x00\x00\x05\x00\x00\xde\x01";
|
|
length = 65;
|
|
break;
|
|
case 0x06:
|
|
buffer = (unsigned char *) "\x06\x85\x00\x3a\x29\x35\x1e\x2b\x39\xe1\xe0\x3b\x1f\x14\x1a\x04" \
|
|
"\x64\x00\x00\x3d\x3c\x20\x21\x08\x16\x1d\xe2\x3e\x23\x22\x15\x07" \
|
|
"\x1b\x06\x8b\x3f\x24\x00\x17\x0a\x09\x19\x91\x40\x41\x00\x1c\x18" \
|
|
"\x0b\x05\x2c\x42\x26\x25\x0c\x0d\x0e\x10\x11\x43\x2a\x27\x2d\x12" \
|
|
"\x0f\x36\x8a\x44\x45\x89\x2e\x13\x33\x37\x90\x46\x49\x4c\x2f\x30" \
|
|
"\x34\x38\x88\x47\x4a\x4d\x31\x32\x00\x87\xe6\x48\x4b\x4e\x28\x52" \
|
|
"\x50\xe5\xe7\xd2\x53\x5f\x5c\x59\x51\x00\xf1\xd1\x54\x60\x5d\x5a" \
|
|
"\x4f\x8e\x65\xd0\x55\x61\x5e\x5b\x62\xa4\xe4\xfc\x56\x57\x85\x58" \
|
|
"\x63\x00\x00\xc2\x24";
|
|
length = 133;
|
|
break;
|
|
case 0x09:
|
|
buffer = (unsigned char *) "\x09\x2b\x00\x49\x00\x00\x4a\x00\x00\x4b\x00\x00\x4c\x00\x00\x4d" \
|
|
"\x00\x00\x4e\x00\x00\xa4\x00\x00\x8e\x00\x00\xd0\x00\x00\xd1\x00" \
|
|
"\x00\x00\x00\x00\x01\x00\x00\x00\x00\xcd\x04";
|
|
length = 43;
|
|
break;
|
|
case 0x0d:
|
|
length = 443;
|
|
buffer = (unsigned char *) "\x0d\xbb\x01\x00\x06\x0b\x05\x45\x83\xca\xca\xca\xca\xca\xca\xce" \
|
|
"\xce\xd2\xce\xce\xd2\x19\x19\x19\x19\x19\x19\x23\x23\x2d\x23\x23" \
|
|
"\x2d\xe0\xe0\xe0\xe0\xe0\xe0\xe3\xe3\xe6\xe3\xe3\xe6\xd2\xd2\xd5" \
|
|
"\xd2\xd2\xd5\xd5\xd5\xd9\xd5\x00\xd9\x2d\x2d\x36\x2d\x2d\x36\x36" \
|
|
"\x36\x40\x36\x00\x40\xe6\xe6\xe9\xe6\xe6\xe9\xe9\xe9\xec\xe9\x00" \
|
|
"\xec\xd9\xd9\xdd\xd9\xdd\xdd\xe0\xe0\xdd\xe0\xe4\xe4\x40\x40\x4a" \
|
|
"\x40\x4a\x4a\x53\x53\x4a\x53\x5d\x5d\xec\xec\xef\xec\xef\xef\xf2" \
|
|
"\xf2\xef\xf2\xf5\xf5\xe4\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x5d\x5d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5\xf5\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\xe4\xe8\xe8\xe8\xe8\xe8" \
|
|
"\xeb\xeb\xeb\x00\xeb\x5d\x5d\x67\x67\x67\x67\x67\x70\x70\x70\x00" \
|
|
"\x70\xf5\xf5\xf8\xf8\xf8\xf8\xf8\xfb\xfb\xfb\x00\xfb\xeb\xef\xef" \
|
|
"\xef\x00\xef\xf0\xf0\xed\xf0\xf0\x00\x70\x7a\x7a\x7a\x00\x7a\x7a" \
|
|
"\x7a\x6f\x7a\x7a\x00\xfb\xfd\xfd\xfd\x00\xfd\xf8\xf8\xea\xf8\xf8" \
|
|
"\x00\xed\xed\xea\xed\xed\x00\xed\xea\xea\xf6\xe7\xea\x6f\x6f\x65" \
|
|
"\x6f\x6f\x00\x6f\x65\x65\x66\x5a\x65\xea\xea\xdc\xea\xea\x00\xea" \
|
|
"\xdc\xdc\x00\xce\xdc\xea\xe7\xe5\xe7\xe5\xe5\x00\x00\x00\x00\x00" \
|
|
"\x00\x65\x5a\x50\x5a\x50\x50\x00\x00\x00\x00\x00\x00\xdc\xce\xc0" \
|
|
"\xce\xc0\xc0\x00\x00\x00\x00\x00\x00\xe7\x00\x00\xe2\xe2\xe2\xe2" \
|
|
"\xdf\xdf\xdf\xdf\xdf\x5a\x00\x00\x45\x45\x45\x45\x3b\x3b\x3b\x3b" \
|
|
"\x3b\xce\x00\x00\xb2\xb2\xb2\xb2\xa4\xa4\xa4\xa4\xa4\xdc\xdc\xdc" \
|
|
"\xdc\x00\xda\xda\xda\xda\xda\x00\xd7\x30\x30\x30\x30\x00\x26\x26" \
|
|
"\x26\x26\x26\x00\x1c\x96\x96\x96\x96\x00\x88\x88\x88\x88\x88\x00" \
|
|
"\x7a\xd7\xd7\xd7\x00\xd4\xd4\xd4\xd4\xd4\xd1\xd1\xd1\x1c\x1c\x1c" \
|
|
"\x00\x11\x11\x11\x11\x11\x06\x06\x06\x7a\x7a\x7a\x00\x6c\x6c\x6c" \
|
|
"\x6c\x6c\x5e\x5e\x5e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\xcf";
|
|
break;
|
|
case 0x13:
|
|
buffer = (unsigned char *) "\x13\x08\x01\x00\x00\x00\x00\x00";
|
|
length = 8;
|
|
break;
|
|
default: ERR("UNKNOWN BUFFER OPTION")
|
|
return false;
|
|
}
|
|
int res = m_helper->sendFeatureReport(buffer, length);
|
|
if (res == length) return true;
|
|
ERR("sendCtrlReport(%02hhx) failed", id)
|
|
return false;
|
|
}
|
|
|
|
bool Vulcan121::waitForCtrlDev() {
|
|
unsigned char buffer[] = { 0x04, 0x00, 0x00, 0x00 };
|
|
int res;
|
|
while (true) {
|
|
// 150ms is the magic number here, should suffice on first try.
|
|
usleep(10000);
|
|
res = m_helper->getFeatureReport(buffer, sizeof(buffer));
|
|
if (res) {
|
|
if (buffer[1] == 0x01) break;
|
|
} else {
|
|
ERR("rv_wait_for_ctrl_device() failed");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int Vulcan121::getColumnsForRow(int row) {
|
|
if (row > NUM_ROWS - 1) {
|
|
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS - 1)
|
|
return 0;
|
|
}
|
|
return keyMapRow[row]->count;
|
|
}
|
|
|
|
|
|
int Vulcan121::getRowsForColumns(int col) {
|
|
if (col > NUM_COLS - 1) {
|
|
WARN("Try to Access out of Bound %d max %d", col, NUM_COLS - 1)
|
|
return 0;
|
|
}
|
|
return keyMapCol[col]->count;
|
|
}
|
|
|
|
int Vulcan121::getIndex(int row, int col) {
|
|
if (row > NUM_ROWS - 1) {
|
|
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS - 1)
|
|
return 0;
|
|
}
|
|
if (col > keyMapRow[row]->count) {
|
|
WARN("Try to Access out of Bound %d max %d", col, keyMapRow[row]->count)
|
|
return 0;
|
|
}
|
|
return keyMapRow[row]->index[col];
|
|
}
|
|
|
|
/**
|
|
* Setup Mapping
|
|
* They are not magic! look in the layout.md
|
|
* @Fixme: Mapping is broken and not 100% correct for columns!
|
|
*/
|
|
void Vulcan121::setupMap() {
|
|
// Row Init
|
|
keyMapRow[0]->count = 16;
|
|
keyMapRow[0]->index = new int[16]{ 0, 11, 17, 23, 28, 48, 53, 59, 65, 78, 84, 85, 86, 99, 103, 108 };
|
|
keyMapRow[1]->count = 21;
|
|
keyMapRow[1]->index = new int[21]{ 1, 6, 12, 18, 24, 29, 33, 49, 54, 60, 66, 72,
|
|
79, 87, 100, 104, 109, 113, 119, 124, 129 };
|
|
keyMapRow[2]->count = 19;
|
|
keyMapRow[2]->index = new int[19]{ 2, 7, 13, 19, 25, 30, 34, 50, 55, 61, 67, 73, 80, 101, 105, 110, 114, 120, 125 };
|
|
keyMapRow[3]->count = 18;
|
|
keyMapRow[3]->index = new int[18]{ 3, 8, 14, 20, 26, 31, 35, 51, 56, 62, 68, 74, 96, 88, 115, 121, 126, 130 };
|
|
keyMapRow[4]->count = 17;
|
|
keyMapRow[4]->index = new int[17]{ 4, 9, 15, 21, 27, 32, 36, 52, 57, 63, 69, 75, 82, 106, 116, 122, 127 };
|
|
keyMapRow[5]->count = 14;
|
|
keyMapRow[5]->index = new int[14]{ 5, 10, 16, 37, 70, 76, 83, 89, 102, 107, 111, 117, 128, 131 };
|
|
// Col init
|
|
keyMapCol[0]->count = 6;
|
|
keyMapCol[0]->index = new int[6]{ 0, 1, 2, 3, 4, 5 };
|
|
keyMapCol[1]->count = 5;
|
|
keyMapCol[1]->index = new int[5]{ 6, 7, 8, 9, 10 };
|
|
keyMapCol[2]->count = 6;
|
|
keyMapCol[2]->index = new int[6]{ 11, 12, 13, 14, 15, 16 };
|
|
keyMapCol[3]->count = 5;
|
|
keyMapCol[3]->index = new int[5]{ 17, 18, 19, 20, 21 };
|
|
keyMapCol[4]->count = 5;
|
|
keyMapCol[4]->index = new int[5]{ 23, 24, 25, 26, 27 };
|
|
keyMapCol[5]->count = 7;
|
|
keyMapCol[5]->index = new int[7]{ 28, 29, 30, 31, 36, 32, 37 };
|
|
keyMapCol[6]->count = 5;
|
|
keyMapCol[6]->index = new int[5]{ 48, 33, 34, 35, 52 };
|
|
keyMapCol[7]->count = 5;
|
|
keyMapCol[7]->index = new int[5]{ 53, 49, 50, 51, 57 };
|
|
keyMapCol[8]->count = 5;
|
|
keyMapCol[8]->index = new int[5]{ 59, 54, 55, 56, 63 };
|
|
keyMapCol[9]->count = 6;
|
|
keyMapCol[9]->index = new int[6]{ 65, 60, 61, 62, 69, 70 };
|
|
keyMapCol[10]->count = 6;
|
|
keyMapCol[10]->index = new int[6]{ 78, 66, 67, 68, 75, 76 };
|
|
keyMapCol[11]->count = 5;
|
|
keyMapCol[11]->index = new int[5]{ 84, 72, 73, 74, 83 };
|
|
keyMapCol[12]->count = 5;
|
|
keyMapCol[12]->index = new int[5]{ 85, 79, 80, 96, 82 };
|
|
keyMapCol[13]->count = 4;
|
|
keyMapCol[13]->index = new int[4]{ 86, 87, 88, 89 };
|
|
keyMapCol[14]->count = 4;
|
|
keyMapCol[14]->index = new int[4]{ 99, 100, 101, 102 };
|
|
keyMapCol[15]->count = 5;
|
|
keyMapCol[15]->index = new int[5]{ 103, 104, 105, 106, 107 };
|
|
keyMapCol[16]->count = 4;
|
|
keyMapCol[16]->index = new int[4]{ 108, 109, 110, 111 };
|
|
keyMapCol[17]->count = 5;
|
|
keyMapCol[17]->index = new int[5]{ 113, 114, 115, 116, 117 };
|
|
keyMapCol[18]->count = 4;
|
|
keyMapCol[18]->index = new int[4]{ 119, 120, 121, 122 };
|
|
keyMapCol[19]->count = 5;
|
|
keyMapCol[19]->index = new int[5]{ 124, 125, 126, 127, 128 };
|
|
keyMapCol[20]->count = 3;
|
|
keyMapCol[20]->index = new int[3]{ 129, 130, 131 };
|
|
}
|
|
|
|
int Vulcan121::getIndexNoCheck(int row, int col) {
|
|
return keyMapRow[row]->index[col];
|
|
}
|
|
|
|
const keys *Vulcan121::getColumn(int col) {
|
|
return keyMapCol[col];
|
|
}
|
|
const keys *Vulcan121::getRow(int row) {
|
|
return keyMapRow[row];
|
|
}
|
|
|
|
void Vulcan121::fadeOutMap(led_map &map, double factor = 0.3) {
|
|
for (auto &i: map.key) {
|
|
i.a *= factor;
|
|
}
|
|
}
|
|
|
|
// Column FadeOut! Check if previous Col is brighter!
|
|
void Vulcan121::fadeOutMapColumn(led_map &map, double factor) {
|
|
for (int i = 0; i < NUM_COLS; ++i) {
|
|
// prev check if not 0
|
|
auto *columnA = getColumn(i);
|
|
int16_t colorB = 0;
|
|
if (i > 0 && map.key[columnA->index[0]].a > 0.1) {
|
|
auto columnB = getColumn(i - 1);
|
|
colorB = map.key[columnB->index[0]].a;
|
|
}
|
|
for (int j = 0; j < columnA->count; ++j) {
|
|
auto &colorA = map.key[columnA->index[j]];
|
|
colorA.a = colorB != 0 && colorB > colorA.a ? colorB * 1.3 : colorA.a * factor;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Vulcan121::setColor(led_map &map, rgba color) {
|
|
for (auto &i: map.key) {
|
|
i.r = color.r;
|
|
i.g = color.g;
|
|
i.b = color.b;
|
|
i.a = color.a;
|
|
}
|
|
}
|
|
void Vulcan121::setColorNoBrightness(led_map &map, rgba color) {
|
|
for (auto &i: map.key) {
|
|
i.r = color.r;
|
|
i.g = color.g;
|
|
i.b = color.b;
|
|
}
|
|
}
|