From bab18473aacc71cac6892ca77e4ceaf6b7b3d072 Mon Sep 17 00:00:00 2001 From: denk_mal Date: Fri, 22 Jan 2021 10:33:26 +0100 Subject: [PATCH] Add support for Das Keyboard 4Q Commit amended for code style by Adam Honse --- .../DasKeyboardController.cpp | 204 +++++++++++ .../DasKeyboardController.h | 45 +++ .../DasKeyboardControllerDetect.cpp | 60 ++++ .../RGBController_DasKeyboard.cpp | 328 ++++++++++++++++++ .../RGBController_DasKeyboard.h | 51 +++ OpenRGB.pro | 6 + 6 files changed, 694 insertions(+) create mode 100644 Controllers/DasKeyboardController/DasKeyboardController.cpp create mode 100644 Controllers/DasKeyboardController/DasKeyboardController.h create mode 100644 Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp create mode 100644 Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp create mode 100644 Controllers/DasKeyboardController/RGBController_DasKeyboard.h diff --git a/Controllers/DasKeyboardController/DasKeyboardController.cpp b/Controllers/DasKeyboardController/DasKeyboardController.cpp new file mode 100644 index 00000000..31ebc01d --- /dev/null +++ b/Controllers/DasKeyboardController/DasKeyboardController.cpp @@ -0,0 +1,204 @@ +/*-----------------------------------------*\ +| DasKeyboardController.cpp | +| | +| Driver for Das Keyboard RGB keyboard | +| lighting controller | +| | +| Frank Niessen (denk_mal) 12/16/2020 | +\*-----------------------------------------*/ + +#include +#include "DasKeyboardController.h" + +DasKeyboardController::DasKeyboardController(hid_device *dev_handle, const char *path) +{ + dev = dev_handle; + location = path; + + SendInitialize(); +} + +DasKeyboardController::~DasKeyboardController() +{ + +} + +std::string DasKeyboardController::GetDeviceLocation() +{ + return "HID: " + location; +} + +std::string DasKeyboardController::GetSerialString() +{ + wchar_t serial_string[128]; + hid_get_serial_number_string(dev, serial_string, 128); + + std::wstring return_wstring = serial_string; + std::string return_string(return_wstring.begin(), return_wstring.end()); + + return return_string; +} + +std::string DasKeyboardController::GetVersionString() +{ + return version; +} + +void DasKeyboardController::SendColors(unsigned char key_id, unsigned char mode, + unsigned char red, unsigned char green, unsigned char blue) +{ + if (key_id < 130) + { + unsigned char usb_buf[] = {0xEA, + 0x08, + 0x78, + 0x08, + static_cast(key_id), + mode, + red, + green, + blue}; + + SendData(usb_buf, sizeof(usb_buf)); + } + else + { + /*-----------------------------------------------------*\ + | Special handling for the Q-Button; only color, no mode| + \*-----------------------------------------------------*/ + unsigned char usb_buf[] = {0xEA, + 0x06, + 0x78, + 0x06, + red, + green, + blue}; + + SendData(usb_buf, sizeof(usb_buf)); + } +} + + +void DasKeyboardController::SendInitialize() +{ + unsigned char usb_buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Set up Initialize connection | + \*-----------------------------------------------------*/ + unsigned char usb_init[] = {0xEA, 0x02, 0xB0}; + SendData(usb_init, sizeof(usb_init)); + + /*-----------------------------------------------------*\ + | Get Version String | + \*-----------------------------------------------------*/ + ReceiveData(usb_buf); + + std::string fw_version(reinterpret_cast(&usb_buf[2])); + version = fw_version; +} + +void DasKeyboardController::SendApply() +{ + /*-----------------------------------------------------*\ + | Set up Terminate Color packet | + \*-----------------------------------------------------*/ + unsigned char usb_buf2[] = {0xEA, 0x03, 0x78, 0x0a}; + SendData(usb_buf2, sizeof(usb_buf2)); + + unsigned char usb_buf[256] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + ReceiveData(usb_buf); +} + +void DasKeyboardController::SendData(const unsigned char *data, int length) +{ + unsigned char usb_buf[65]; + + /*-----------------------------------------------------*\ + | Fill data into send buffer | + \*-----------------------------------------------------*/ + unsigned int chk_sum = 0; + usb_buf[0] = 1; + + for(unsigned int idx = 0; idx < length; idx++) + { + usb_buf[idx + 1] = data[idx]; + chk_sum ^= data[idx]; + } + + usb_buf[++length] = chk_sum; + length++; + + hid_send_feature_report(dev, usb_buf, length); +} + +int DasKeyboardController::ReceiveData(unsigned char *data) +{ + int idx = 0; + unsigned char usb_buf[9]; + + /*-----------------------------------------------------*\ + | Fill data from receive buffer | + \*-----------------------------------------------------*/ + unsigned int chk_sum = 0; + + do + { + memset(usb_buf, 0x00, sizeof(usb_buf)); + usb_buf[0x00] = 0x01; + + hid_get_feature_report(dev, usb_buf, 8); + + if(usb_buf[0]) + { + for(unsigned int ii = 0; ii < 8; ii++) + { + data[idx++] = usb_buf[ii]; + chk_sum ^= usb_buf[ii]; + } + } + } while (usb_buf[0]); + + /*-----------------------------------------------------*\ + | If checksum is not correct, clean up data buffer | + \*-----------------------------------------------------*/ + if(chk_sum) + { + for (unsigned int ii = 0; ii < idx; ii++) + { + data[ii] = 0; + } + return -1; + } + + if(idx) + { + idx = data[1]; + + /*-----------------------------------------------------*\ + | Remove first two bytes (signature?) and content length| + \*-----------------------------------------------------*/ + for(unsigned int ii = 0; ii < idx - 1; ii++) + { + data[ii] = data[ii + 2]; + } + + /*-----------------------------------------------------*\ + | Remove checksum | + \*-----------------------------------------------------*/ + data[idx + 1] = 0; + + /*-----------------------------------------------------*\ + | Remove duplicate bytes at the end | + \*-----------------------------------------------------*/ + data[idx--] = 0; + data[idx] = 0; + } + + return idx; +} diff --git a/Controllers/DasKeyboardController/DasKeyboardController.h b/Controllers/DasKeyboardController/DasKeyboardController.h new file mode 100644 index 00000000..1855b52e --- /dev/null +++ b/Controllers/DasKeyboardController/DasKeyboardController.h @@ -0,0 +1,45 @@ +/*-----------------------------------------*\ +| DasKeyboardController.h | +| | +| Definitions and types for Das Keyboard | +| RGB keyboard lighting controller | +| | +| Frank Niessen (denk_mal) 12/16/2020 | +\*-----------------------------------------*/ + +#include "RGBController.h" + +#include +#include + +#pragma once + +class DasKeyboardController +{ +public: + DasKeyboardController(hid_device *dev_handle, const char *path); + + ~DasKeyboardController(); + + std::string GetDeviceLocation(); + + std::string GetSerialString(); + + std::string GetVersionString(); + + void SendColors(unsigned char key_id, unsigned char mode, + unsigned char red, unsigned char green, unsigned char blue); + + void SendApply(); + +private: + hid_device *dev; + std::string location; + std::string version; + + void SendInitialize(); + + void SendData(const unsigned char *data, int length); + + int ReceiveData(unsigned char *data); +}; diff --git a/Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp b/Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp new file mode 100644 index 00000000..13d2aa12 --- /dev/null +++ b/Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp @@ -0,0 +1,60 @@ +#include "Detector.h" +#include "DasKeyboardController.h" +#include "RGBController.h" +#include "RGBController_DasKeyboard.h" +#include + +/*-----------------------------------------------------*\ +| Das Keyboard vendor ID | +\*-----------------------------------------------------*/ +#define DAS_KEYBOARD_VID 0x24F0 + +/*-----------------------------------------------------*\ +| Keyboard product IDs | +\*-----------------------------------------------------*/ +#define DAS_KEYBOARD_Q4_PID 0x2037 +#define DAS_KEYBOARD_Q5_PID 0x202B + +/******************************************************************************************\ +* * +* DetectDasKeyboardControllers * +* * +* Tests the USB address to see if a Das Keyboard RGB controller exists there. * +* We need the second interface to communicate with the keyboard * +* * +\******************************************************************************************/ + +void DetectDasKeyboardControllers(hid_device_info *info_in, const std::string &name) +{ + hid_device_info *info = info_in; + + while(info) + { + if(info->vendor_id == DAS_KEYBOARD_VID && + info->product_id == DAS_KEYBOARD_Q4_PID && + info->interface_number == 1) + { + break; + } + info = info->next; + } + + if(!info) + { + return; + } + + hid_device *dev = hid_open_path(info->path); + + if(dev) + { + DasKeyboardController* controller = new DasKeyboardController(dev, info->path); + RGBController_DasKeyboard* rgb_controller = new RGBController_DasKeyboard(controller); + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} /* DetectDasKeyboardControllers() */ + +REGISTER_HID_DETECTOR_I("Das Keyboard Q4 RGB", DetectDasKeyboardControllers, DAS_KEYBOARD_VID, DAS_KEYBOARD_Q4_PID, 0); +REGISTER_HID_DETECTOR_I("Das Keyboard Q5 RGB", DetectDasKeyboardControllers, DAS_KEYBOARD_VID, DAS_KEYBOARD_Q5_PID, 0); diff --git a/Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp b/Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp new file mode 100644 index 00000000..29ed0ad8 --- /dev/null +++ b/Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp @@ -0,0 +1,328 @@ +/*-----------------------------------------*\ +| RGBController_DasKeyboard.cpp | +| | +| Generic RGB Interface for Das Keyboard | +| RGB keyboard devices | +| | +| Frank Niessen (denk_mal) 12/16/2020 | +\*-----------------------------------------*/ + +#include "RGBController_DasKeyboard.h" + +using namespace std::chrono_literals; + +//0xFFFFFFFF indicates an unused entry in matrix +#define NA 0xFFFFFFFF + +static unsigned int matrix_map[7][21] = + { + {NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 126, NA, NA, NA}, + { 5, NA, 17, 23, 29, 35, 41, 47, 53, 59, 65, 71, 77, 83, 89, 95, 101, 127, 128, 129, 130}, + { 4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 100, 106, 112, 118, 124}, + { 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 80, 87, 93, 99, 105, 111, 117, 123}, + { 2, 8, 14, 20, 26, 32, 38, 44, 50, 56, 62, 68, 81, NA, NA, NA, NA, 104, 110, 116, NA}, + { 1, 7, 13, 19, 25, 31, 37, 43, 49, 55, 61, 67, 79, NA, NA, 91, NA, 103, 109, 115, 122}, + { 0, 6, 12, NA, NA, NA, 36, NA, NA, NA, 60, 66, 72, 78, 84, 90, 96, 102, NA, 114, NA} + }; + +static const char *zone_names[] = + { + "Keyboard" + }; + +static zone_type zone_types[] = + { + ZONE_TYPE_MATRIX, + }; + +static const unsigned int zone_sizes[] = + { + 131 + }; + +static const char *led_names[] = + { + "Key: Left Control", + "Key: Left Shift", + "Key: Caps Lock", + "Key: Tab", + "Key: ^", + "Key: Escape", + "Key: Left Windows", + "Key: <", + "Key: A", + "Key: Q", + "Key: 1", + "Undefined", + "Key: Left Alt", + "Key: Y", + "Key: S", + "Key: W", + "Key: 2", + "Key: F1", + "Undefined", + "Key: X", + "Key: D", + "Key: E", + "Key: 3", + "Key: F2", + "Undefined", + "Key: C", + "Key: F", + "Key: R", + "Key: 4", + "Key: F3", + "Undefined", + "Key: V", + "Key: G", + "Key: T", + "Key: 5", + "Key: F4", + "Key: Space", + "Key: B", + "Key: H", + "Key: Z", + "Key: 6", + "Key: F5", + "Undefined", + "Key: N", + "Key: J", + "Key: U", + "Key: 7", + "Key: F6", + "Undefined", + "Key: M", + "Key: K", + "Key: I", + "Key: 8", + "Key: F7", + "Undefined", + "Key: ,", + "Key: L", + "Key: O", + "Key: 9", + "Key: F8", + "Key: Right Alt", + "Key: .", + "Key: O-Uml", + "Key: P", + "Key: 0", + "Key: F9", + "Key: Right Windows", + "Key: -", + "Key: A-Uml", + "Key: U-Uml", + "Key: SZ", + "Key: F10", + "Key: Menu", + "Undefined", + "Undefined", + "Key: +", + "Key: `", + "Key: F11", + "Key: Right Control", + "Key: Right Shift", + "Key: Enter", + "Key: #", + "Key: Backspace", + "Key: F12", + "Key: Left Arrow", + "Undefined", + "Undefined", + "Key: Delete", + "Key: Insert", + "Key: Print Screen", + "Key: Down Arrow", + "Key: Up Arrow", + "Undefined", + "Key: End", + "Key: Home", + "Key: Scroll Lock", + "Key: Right Arrow", + "Undefined", + "Undefined", + "Key: Page Down", + "Key: Page Up", + "Key: Pause/Break", + "Key: Number Pad 0", + "Key: Number Pad 1", + "Key: Number Pad 4", + "Key: Number Pad 7", + "Key: Num Lock", + "Undefined", + "Undefined", + "Key: Number Pad 2", + "Key: Number Pad 5", + "Key: Number Pad 8", + "Key: Number Pad /", + "Undefined", + "Key: Number Pad .", + "Key: Number Pad 3", + "Key: Number Pad 6", + "Key: Number Pad 9", + "Key: Number Pad *", + "Undefined", + "Undefined", + "Undefined", + "Key: Number Pad Enter", + "Key: Number Pad +", + "Key: Number Pad -", + "Undefined", + "Key: Sleep", + "Key: Brightness", + "Key: Media Play/Pause", + "Key: Media Next", + "Key: Q-Button" + }; + +RGBController_DasKeyboard::RGBController_DasKeyboard(DasKeyboardController *das_ptr) +{ + das = das_ptr; + + for(unsigned int ii=0; ii < zone_sizes[0]; ii++) + { + double_buffer.push_back(-1); + } + + updateDevice = true; + + name = "Das Keyboard Device"; + vendor = "Das Keyboard"; + type = DEVICE_TYPE_KEYBOARD; + description = "Das Keyboard Device"; + location = das->GetDeviceLocation(); + serial = das->GetSerialString(); + version = das->GetVersionString(); + + modes.resize(4); + modes[0].name = "Static"; + modes[0].value = DAS_KEYBOARD_MODE_STATIC; + modes[0].flags = MODE_FLAG_HAS_PER_LED_COLOR; + modes[0].color_mode = MODE_COLORS_PER_LED; + + modes[1].name = "Blink"; + modes[1].value = DAS_KEYBOARD_MODE_BLINKING; + modes[1].flags = MODE_FLAG_HAS_PER_LED_COLOR; + modes[1].color_mode = MODE_COLORS_PER_LED; + + modes[2].name = "Breathing"; + modes[2].value = DAS_KEYBOARD_MODE_BREATHING; + modes[2].flags = MODE_FLAG_HAS_PER_LED_COLOR; + modes[2].color_mode = MODE_COLORS_PER_LED; + + modes[3].name = "Color Cycle"; + modes[3].value = DAS_KEYBOARD_MODE_COLOR_CYCLE; + modes[3].flags = MODE_FLAG_HAS_PER_LED_COLOR; + modes[3].color_mode = MODE_COLORS_PER_LED; + + SetupZones(); +} + +RGBController_DasKeyboard::~RGBController_DasKeyboard() +{ + /*---------------------------------------------------------*\ + | Delete the matrix map | + \*---------------------------------------------------------*/ + unsigned int zone_size = zones.size(); + + for(unsigned int zone_index = 0; zone_index < zone_size; zone_index++) + { + delete zones[zone_index].matrix_map; + } +} + +void RGBController_DasKeyboard::SetupZones() +{ + /*---------------------------------------------------------*\ + | Set up zones | + \*---------------------------------------------------------*/ + unsigned int total_led_count = 0; + + for(unsigned int zone_idx = 0; zone_idx < 1; zone_idx++) + { + zone new_zone; + new_zone.name = zone_names[zone_idx]; + new_zone.type = zone_types[zone_idx]; + new_zone.leds_min = zone_sizes[zone_idx]; + new_zone.leds_max = zone_sizes[zone_idx]; + new_zone.leds_count = zone_sizes[zone_idx]; + new_zone.matrix_map = new matrix_map_type; + new_zone.matrix_map->height = 7; + new_zone.matrix_map->width = 21; + new_zone.matrix_map->map = (unsigned int *) &matrix_map; + zones.push_back(new_zone); + + total_led_count += zone_sizes[zone_idx]; + } + + for(unsigned int led_idx = 0; led_idx < total_led_count; led_idx++) + { + led new_led; + new_led.name = led_names[led_idx]; + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_DasKeyboard::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_DasKeyboard::DeviceUpdateLEDs() +{ + UpdateZoneLEDs(0); +} + +void RGBController_DasKeyboard::UpdateZoneLEDs(int /*zone*/) +{ + updateDevice = false; + + for(unsigned int led_idx = 0; led_idx < leds.size(); led_idx++) + { + UpdateSingleLED(static_cast(led_idx)); + + /*---------------------------------------------------------*\ + | Hack to work around a firmware bug in v21.27.0 | + \*---------------------------------------------------------*/ + std::this_thread::sleep_for(0.3ms); + } + + updateDevice = true; + + das->SendApply(); +} + +void RGBController_DasKeyboard::UpdateSingleLED(int led) +{ + mode selected_mode = modes[active_mode]; + + if(double_buffer[led] == colors[led]) + { + return; + } + + das->SendColors(led, selected_mode.value, + RGBGetRValue(colors[led]), + RGBGetGValue(colors[led]), + RGBGetBValue(colors[led])); + + double_buffer[led] = colors[led]; + + if(updateDevice) + { + das->SendApply(); + } +} + +void RGBController_DasKeyboard::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_DasKeyboard::DeviceUpdateMode() +{ +} diff --git a/Controllers/DasKeyboardController/RGBController_DasKeyboard.h b/Controllers/DasKeyboardController/RGBController_DasKeyboard.h new file mode 100644 index 00000000..c7e5c256 --- /dev/null +++ b/Controllers/DasKeyboardController/RGBController_DasKeyboard.h @@ -0,0 +1,51 @@ +/*-----------------------------------------*\ +| RGBController_DasKeyboard.h | +| | +| Generic RGB Interface for Das Keyboard | +| RGB keyboard devices | +| | +| Frank Niessen (denk_mal) 12/16/2020 | +\*-----------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "DasKeyboardController.h" + +enum +{ + DAS_KEYBOARD_MODE_STATIC = 0x01, + DAS_KEYBOARD_MODE_BLINKING = 0x1F, + DAS_KEYBOARD_MODE_BREATHING = 0x08, + DAS_KEYBOARD_MODE_COLOR_CYCLE = 0x14 +}; + + +class RGBController_DasKeyboard : public RGBController +{ +public: + RGBController_DasKeyboard(DasKeyboardController *das_ptr); + + ~RGBController_DasKeyboard(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + + void UpdateZoneLEDs(int zone); + + void UpdateSingleLED(int led); + + void SetCustomMode(); + + void DeviceUpdateMode(); + +private: + DasKeyboardController* das; + + std::vector mode_index; + std::vector double_buffer; + bool updateDevice; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index dd3edaa2..4f79eee3 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -64,6 +64,7 @@ INCLUDEPATH += Controllers/CorsairVengeanceController/ \ Controllers/CorsairVengeanceProController/ \ Controllers/CrucialController/ \ + Controllers/DasKeyboardController/ \ Controllers/DebugController/ \ Controllers/DuckyKeyboardController/ \ Controllers/E131Controller/ \ @@ -175,6 +176,8 @@ HEADERS += Controllers/CorsairVengeanceProController/RGBController_CorsairVengeancePro.h \ Controllers/CrucialController/CrucialController.h \ Controllers/CrucialController/RGBController_Crucial.h \ + Controllers/DasKeyboardController/DasKeyboardController.h \ + Controllers/DasKeyboardController/RGBController_DasKeyboard.h \ Controllers/DuckyKeyboardController/DuckyKeyboardController.h \ Controllers/DuckyKeyboardController/RGBController_DuckyKeyboard.h \ Controllers/DebugController/RGBController_Debug.h \ @@ -373,6 +376,9 @@ SOURCES += Controllers/CrucialController/CrucialControllerDetect.cpp \ Controllers/CrucialController/RGBController_Crucial.cpp \ Controllers/DebugController/DebugControllerDetect.cpp \ + Controllers/DasKeyboardController/DasKeyboardController.cpp \ + Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp \ + Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp \ Controllers/DuckyKeyboardController/DuckyKeyboardController.cpp \ Controllers/DuckyKeyboardController/DuckyKeyboardControllerDetect.cpp \ Controllers/DuckyKeyboardController/RGBController_DuckyKeyboard.cpp \