mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-09-13 13:47:02 -04:00
182 lines
5.1 KiB
C++
182 lines
5.1 KiB
C++
/*---------------------------------------------------------*\
|
|
| TurtleBeachKP7Controller.cpp |
|
|
| |
|
|
| Driver for Turtle Beach Command Series KP7 keypad |
|
|
| |
|
|
| Joe Peterson (joevpeterson@gmail.com) 05 Aug 2026 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include "StringUtils.h"
|
|
#include "TurtleBeachKP7Controller.h"
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
TurtleBeachKP7Controller::TurtleBeachKP7Controller(hid_device* dev_handle, const char* path)
|
|
{
|
|
dev = dev_handle;
|
|
location = path;
|
|
last_led_data_size = 0;
|
|
|
|
memset(last_led_data, 0x00, sizeof(last_led_data));
|
|
|
|
EnterDirectMode();
|
|
|
|
keepalive_running = true;
|
|
keepalive_thread = std::thread(&TurtleBeachKP7Controller::KeepAliveThreadFunction, this);
|
|
}
|
|
|
|
TurtleBeachKP7Controller::~TurtleBeachKP7Controller()
|
|
{
|
|
keepalive_running = false;
|
|
|
|
if(keepalive_thread.joinable())
|
|
{
|
|
keepalive_thread.join();
|
|
}
|
|
|
|
hid_close(dev);
|
|
}
|
|
|
|
std::string TurtleBeachKP7Controller::GetLocation()
|
|
{
|
|
return("HID: " + location);
|
|
}
|
|
|
|
std::string TurtleBeachKP7Controller::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));
|
|
}
|
|
|
|
void TurtleBeachKP7Controller::EnterDirectMode()
|
|
{
|
|
unsigned char buf[5];
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Flip the device out of its onboard preset effects and |
|
|
| into host controlled mode. Until this is sent the |
|
|
| keypad ignores everything written to EP 0x06. |
|
|
\*-----------------------------------------------------*/
|
|
buf[0] = TURTLE_BEACH_KP7_ENTER_DIRECT_REPORT_ID;
|
|
buf[1] = 0x00;
|
|
buf[2] = 0x01;
|
|
buf[3] = 0x00;
|
|
buf[4] = 0x00;
|
|
|
|
hid_send_feature_report(dev, buf, sizeof(buf));
|
|
}
|
|
|
|
void TurtleBeachKP7Controller::SendDirect(unsigned char* led_data, unsigned int led_data_size)
|
|
{
|
|
unsigned int copy_size = led_data_size;
|
|
|
|
if(copy_size > sizeof(last_led_data))
|
|
{
|
|
copy_size = sizeof(last_led_data);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Cache the frame so the keep alive thread has |
|
|
| something to re-send while the host is idle |
|
|
\*-----------------------------------------------------*/
|
|
{
|
|
std::lock_guard<std::mutex> lock(led_data_mutex);
|
|
|
|
memcpy(last_led_data, led_data, copy_size);
|
|
last_led_data_size = copy_size;
|
|
}
|
|
|
|
SendFrame(led_data, led_data_size);
|
|
}
|
|
|
|
void TurtleBeachKP7Controller::SendFrame(unsigned char* led_data, unsigned int led_data_size)
|
|
{
|
|
unsigned char buf[TURTLE_BEACH_KP7_REPORT_SIZE];
|
|
unsigned int page0_bytes = led_data_size;
|
|
unsigned int page1_bytes = 0;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Page 0 holds the first TURTLE_BEACH_KP7_PAGE0_LED_ |
|
|
| BYTES bytes of the concatenated [R, G, B] LED buffer |
|
|
\*-----------------------------------------------------*/
|
|
memset(buf, 0x00, sizeof(buf));
|
|
|
|
buf[0] = TURTLE_BEACH_KP7_REPORT_ID;
|
|
buf[1] = 0x00;
|
|
|
|
if(page0_bytes > TURTLE_BEACH_KP7_PAGE0_LED_BYTES)
|
|
{
|
|
page0_bytes = TURTLE_BEACH_KP7_PAGE0_LED_BYTES;
|
|
}
|
|
|
|
memcpy(&buf[2], led_data, page0_bytes);
|
|
|
|
hid_write(dev, buf, TURTLE_BEACH_KP7_REPORT_SIZE);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Page 1 holds the remaining bytes, zero padded |
|
|
\*-----------------------------------------------------*/
|
|
memset(buf, 0x00, sizeof(buf));
|
|
|
|
buf[0] = TURTLE_BEACH_KP7_REPORT_ID;
|
|
buf[1] = 0x01;
|
|
|
|
if(led_data_size > TURTLE_BEACH_KP7_PAGE0_LED_BYTES)
|
|
{
|
|
page1_bytes = led_data_size - TURTLE_BEACH_KP7_PAGE0_LED_BYTES;
|
|
|
|
if(page1_bytes > TURTLE_BEACH_KP7_PAGE1_LED_BYTES)
|
|
{
|
|
page1_bytes = TURTLE_BEACH_KP7_PAGE1_LED_BYTES;
|
|
}
|
|
|
|
memcpy(&buf[2], &led_data[TURTLE_BEACH_KP7_PAGE0_LED_BYTES], page1_bytes);
|
|
}
|
|
|
|
hid_write(dev, buf, TURTLE_BEACH_KP7_REPORT_SIZE);
|
|
}
|
|
|
|
void TurtleBeachKP7Controller::KeepAliveThreadFunction()
|
|
{
|
|
while(keepalive_running)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(TURTLE_BEACH_KP7_KEEPALIVE_DELAY_MS));
|
|
|
|
if(!keepalive_running)
|
|
{
|
|
break;
|
|
}
|
|
|
|
unsigned char frame[TURTLE_BEACH_KP7_LED_COUNT * 3];
|
|
unsigned int frame_size;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(led_data_mutex);
|
|
|
|
frame_size = last_led_data_size;
|
|
|
|
if(frame_size > 0)
|
|
{
|
|
memcpy(frame, last_led_data, frame_size);
|
|
}
|
|
}
|
|
|
|
if(frame_size > 0)
|
|
{
|
|
SendFrame(frame, frame_size);
|
|
}
|
|
}
|
|
}
|