diff --git a/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.cpp b/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.cpp new file mode 100644 index 00000000..4e3f9eed --- /dev/null +++ b/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.cpp @@ -0,0 +1,247 @@ +/*-----------------------------------------*\ +| RGBController_WootingKeyboard.cpp | +| | +| Generic RGB Interface for Wooting RGB | +| keyboard devices | +| | +| Diogo Trindade (diogotr7) 3/4/2021 | +\*-----------------------------------------*/ + +#include "RGBController_WootingKeyboard.h" + +//0xFFFFFFFF indicates an unused entry in matrix +#define NA 0xFFFFFFFF +#define RGB_RAW_BUFFER_SIZE 96 + +static unsigned int matrix_map[6][17] = +{ + {0, NA, 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}, + {2, 8, 14, 20, 26, 32, 38, 44, 50, 56, 62, 68, 74, 80, 86, 92, 98}, + {3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, NA, NA, NA}, + {4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, NA, 82, NA, 94, NA}, + {5, 11, 17, NA, NA, NA, 41, NA, NA, NA, 65, 71, 77, 83, 89, 95, 101} +}; + +static const char *zone_names[] = +{ + "Keyboard" +}; + +static zone_type zone_types[] = +{ + ZONE_TYPE_MATRIX, +}; + +static const unsigned int zone_sizes[] = +{ + 102 +}; + +static const char *led_names[] = +{ + "Key: Escape", + "Key: `", + "Key: Tab", + "Key: Caps Lock", + "Key: Left Shift", + "Key: Left Control", + "Unused", + "Key: 1", + "Key: Q", + "Key: A", + "Key: \\ (ISO)", //iso key - 10 + "Key: Left Windows", + "Key: F1", + "Key: 2", + "Key: W", + "Key: S", + "Key: Z", + "Key: Left Alt", + "Key: F2", + "Key: 3", + "Key: E", //20 + "Key: D", + "Key: X", + "Unused", //space + "Key: F3", + "Key: 4", + "Key: R", + "Key: F", + "Key: C", + "Unused", //space + "Key: F4", //30 + "Key: 5", + "Key: T", + "Key: G", + "Key: V", + "Unused", //space + "Key: F5", + "Key: 6", + "Key: Y", + "Key: H", + "Key: B", //40 + "Key: Space", + "Key: F6", + "Key: 7", + "Key: U", + "Key: J", + "Key: N", + "Unused", //space + "Key: F7", + "Key: 8", + "Key: I", + "Key: K", + "Key: M", + "Unused", //space + "Key: F8", + "Key: 9", + "Key: O", + "Key: L", + "Key: ,", + "Unused", //space + "Key: F9", + "Key: 0", + "Key: P", + "Key: ;", + "Key: .", + "Key: Right Alt", + "Key: F10", + "Key: -", + "Key: [", + "Key: '", + "Key: /", + "Key: Right Windows", + "Key: F11", + "Key: =", + "Key: ]", + "Key: #", //iso only + "Unused", + "Key: Right Fn", + "Key: F12", + "Key: Backspace", + "Key: \\ (ANSI)", + "Key: Enter", + "Key: Right Shift", + "Key: Right Control", + "Key: Print Screen", + "Key: Insert", + "Key: Delete", + "Unused", + "Unused", + "Key: Left Arrow", + "Key: Scroll Lock", + "Key: Pause/Break", + "Key: Home", + "Key: End", + "Unused", + "Key: Up Arrow", + "Key: Down Arrow", + "Key: Mode", + "Key: Page Up", + "Key: Page Down", + "Unused", + "Unused", + "Key: Right Arrow" +}; + +RGBController_WootingKeyboard::RGBController_WootingKeyboard(WootingKeyboardController *wooting_ptr) +{ + wooting = wooting_ptr; + + name = "Wooting keyboard Device"; + type = DEVICE_TYPE_KEYBOARD; + description = "Wooting Keyboard Device"; + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_WootingKeyboard::~RGBController_WootingKeyboard() +{ + /*---------------------------------------------------------*\ + | Delete the matrix map | + \*---------------------------------------------------------*/ + for (unsigned int zone_index = 0; zone_index < zones.size(); zone_index++) + { + if (zones[zone_index].matrix_map != NULL) + { + delete zones[zone_index].matrix_map; + } + } +} + +void RGBController_WootingKeyboard::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 = 6; + new_zone.matrix_map->width = 17; + 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_WootingKeyboard::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_WootingKeyboard::DeviceUpdateLEDs() +{ + wooting->SendDirect(&colors[0], colors.size()); +} + +void RGBController_WootingKeyboard::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_WootingKeyboard::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_WootingKeyboard::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_WootingKeyboard::DeviceUpdateMode() +{ +} diff --git a/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.h b/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.h new file mode 100644 index 00000000..1d36cdcf --- /dev/null +++ b/Controllers/WootingKeyboardController/RGBController_WootingKeyboard.h @@ -0,0 +1,33 @@ +/*-----------------------------------------*\ +| RGBController_WootingKeyboard.h | +| | +| Generic RGB Interface for Wooting RGB | +| keyboard devices | +| | +| Diogo Trindade (diogotr7) 3/4/2021 | +\*-----------------------------------------*/ + +#pragma once +#include "RGBController.h" +#include "WootingKeyboardController.h" + +class RGBController_WootingKeyboard : public RGBController +{ +public: + RGBController_WootingKeyboard(WootingKeyboardController* wooting_ptr); + ~RGBController_WootingKeyboard(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void DeviceUpdateMode(); + +private: + WootingKeyboardController* wooting; +}; diff --git a/Controllers/WootingKeyboardController/WootingKeyboardController.cpp b/Controllers/WootingKeyboardController/WootingKeyboardController.cpp new file mode 100644 index 00000000..9c24657e --- /dev/null +++ b/Controllers/WootingKeyboardController/WootingKeyboardController.cpp @@ -0,0 +1,228 @@ +/*-----------------------------------------*\ +| WootingKeyboardController.cpp | +| | +| Driver for Wooting RGB keyboardlighting | +| controller | +| | +| Diogo Trindade (diogotr7) 3/4/2021 | +\*-----------------------------------------*/ + +#include +#include "WootingKeyboardController.h" + +#define WOOTING_COMMAND_SIZE 8 +#define WOOTING_REPORT_SIZE 129 +#define WOOTING_RAW_COLORS_REPORT 11 +#define WOOTING_SINGLE_COLOR_COMMAND 30 +#define WOOTING_SINGLE_RESET_COMMAND 31 +#define WOOTING_RESET_ALL_COMMAND 32 +#define WOOTING_COLOR_INIT_COMMAND 33 +#define WOOTING_ONE_KEY_CODE_LIMIT 95 +#define WOOTING_TWO_KEY_CODE_LIMIT 116 +#define RGB_RAW_BUFFER_SIZE 96 + +//0xFFFFFFFF indicates an unused entry in matrix +#define NA 0xFFFFFFFF + +static const unsigned int rgb_led_index[6][17] = +{ + {0, NA, 11, 12, 23, 24, 36, 47, 85, 84, 49, 48, 59, 61, 73, 81, 80}, + {2, 1, 14, 13, 26, 25, 35, 38, 37, 87, 86, 95, 51, 63, 75, 72, 74}, + {3, 4, 15, 16, 27, 28, 39, 42, 40, 88, 89, 52, 53, 71, 76, 83, 77}, + {5, 6, 17, 18, 29, 30, 41, 46, 44, 90, 93, 54, 57, 65, NA, NA, NA}, + {9, 8, 19, 20, 31, 34, 32, 45, 43, 91, 92, 55, NA, 66, NA, 78, NA}, + {10, 22, 21, NA, NA, NA, 33, NA, NA, NA, 94, 58, 67, 68, 70, 79, 82} +}; + +static uint16_t getCrc16ccitt(const uint8_t* buffer, uint16_t size) +{ + uint16_t crc = 0; + + while(size--) + { + crc ^= (*buffer++ << 8); + + for(uint8_t i = 0; i < 8; ++i) + { + if(crc & 0x8000) + { + crc = (crc << 1) ^ 0x1021; + } + else + { + crc = crc << 1; + } + } + } + + return crc; +} + +WootingKeyboardController::WootingKeyboardController(hid_device* dev_handle) +{ + dev = dev_handle; + + SendInitialize(); +} + +WootingKeyboardController::~WootingKeyboardController() +{ + +} + +void WootingKeyboardController::SendDirect(RGBColor* colors, unsigned int num_colors) +{ + const uint8_t pwm_mem_map[48] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D + }; + + unsigned char buffer0[RGB_RAW_BUFFER_SIZE] = {0}; + unsigned char buffer1[RGB_RAW_BUFFER_SIZE] = {0}; + unsigned char buffer2[RGB_RAW_BUFFER_SIZE] = {0}; + unsigned char buffer3[RGB_RAW_BUFFER_SIZE] = {0}; + + for(std::size_t color_idx = 0; color_idx < num_colors; color_idx++) + { + unsigned char led_index = rgb_led_index[color_idx % 6][color_idx / 6]; + + if(led_index > 95) + { + continue; + } + + unsigned char *buffer_pointer = buffer0; + + if(led_index >= 72) + { + buffer_pointer = buffer3; + } + else if(led_index >= 48) + { + buffer_pointer = buffer2; + } + else if(led_index >= 24) + { + buffer_pointer = buffer1; + } + else + { + buffer_pointer = buffer0; + } + + unsigned char buffer_index = pwm_mem_map[led_index % 24]; + buffer_pointer[buffer_index + 0x00] = RGBGetRValue(colors[color_idx]); + buffer_pointer[buffer_index + 0x10] = RGBGetGValue(colors[color_idx]); + buffer_pointer[buffer_index + 0x20] = RGBGetBValue(colors[color_idx]); + } + + wooting_usb_send_buffer(RGB_PARTS::PART0, buffer0); + wooting_usb_send_buffer(RGB_PARTS::PART1, buffer1); + wooting_usb_send_buffer(RGB_PARTS::PART2, buffer2); + wooting_usb_send_buffer(RGB_PARTS::PART3, buffer3); +} + +void WootingKeyboardController::SendInitialize() +{ + wooting_usb_send_feature(WOOTING_COLOR_INIT_COMMAND, 0,0,0,0); + unsigned char stub = 0; + hid_read(dev, &stub, 0); + hid_read_timeout(dev, &stub, 0, 50); +} + +bool WootingKeyboardController::wooting_usb_send_feature(uint8_t commandId, uint8_t parameter0, uint8_t parameter1, uint8_t parameter2, uint8_t parameter3) +{ + /*---------------------------------------------------------*\ + | Prevent sending unnecessary data to the Wootings if the | + | index exceedes it's capabilities | + \*---------------------------------------------------------*/ + if ((commandId == WOOTING_SINGLE_COLOR_COMMAND && parameter0 > WOOTING_ONE_KEY_CODE_LIMIT) + || (commandId == WOOTING_SINGLE_RESET_COMMAND && parameter3 > WOOTING_ONE_KEY_CODE_LIMIT)) + { + /*-----------------------------------------------------*\ + | This is not a USB error so let's return true. | + | wooting_rgb_direct_set_key would also behave | + | differently otherwise. | + \*-----------------------------------------------------*/ + return true; + } + + unsigned char report_buffer[WOOTING_COMMAND_SIZE] = {0}; + + /*---------------------------------------------------------*\ + | Set up the Send Feature packet | + \*---------------------------------------------------------*/ + report_buffer[0] = 0; // HID report index (unused) + report_buffer[1] = 0xD0; // Magic word + report_buffer[2] = 0xDA; // Magic word + report_buffer[3] = commandId; + report_buffer[4] = parameter3; + report_buffer[5] = parameter2; + report_buffer[6] = parameter1; + report_buffer[7] = parameter0; + + /*---------------------------------------------------------*\ + | Send packet | + \*---------------------------------------------------------*/ + hid_send_feature_report(dev, report_buffer, WOOTING_COMMAND_SIZE); +} + +bool WootingKeyboardController::wooting_usb_send_buffer(RGB_PARTS part_number, uint8_t rgb_buffer[]) +{ + unsigned char report_buffer[WOOTING_REPORT_SIZE] = {0}; + + /*---------------------------------------------------------*\ + | Set up the Send Buffer packet | + \*---------------------------------------------------------*/ + report_buffer[0] = 0; // HID report index (unused) + report_buffer[1] = 0xD0; // Magic word + report_buffer[2] = 0xDA; // Magic word + report_buffer[3] = WOOTING_RAW_COLORS_REPORT; // Report ID + + switch(part_number) + { + case PART0: + report_buffer[4] = 0; // Slave nr + report_buffer[5] = 0; // Reg start address + break; + + case PART1: + report_buffer[4] = 0; // Slave nr + report_buffer[5] = RGB_RAW_BUFFER_SIZE; // Reg start address + break; + + case PART2: + report_buffer[4] = 1; // Slave nr + report_buffer[5] = 0; // Reg start address + break; + + case PART3: + report_buffer[4] = 1; // Slave nr + report_buffer[5] = RGB_RAW_BUFFER_SIZE; // Reg start address + break; + + default: + return false; + break; + } + + /*---------------------------------------------------------*\ + | Copy in the buffer data | + \*---------------------------------------------------------*/ + memcpy(&report_buffer[6], rgb_buffer, RGB_RAW_BUFFER_SIZE); + + /*---------------------------------------------------------*\ + | Calculate the CRC and append it to the packet | + \*---------------------------------------------------------*/ + unsigned short crc = getCrc16ccitt((unsigned char*)&report_buffer, WOOTING_REPORT_SIZE - 2); + report_buffer[127] = (unsigned char)crc; + report_buffer[128] = crc >> 8; + + /*---------------------------------------------------------*\ + | Send packet | + \*---------------------------------------------------------*/ + hid_write(dev, report_buffer, WOOTING_REPORT_SIZE); +} diff --git a/Controllers/WootingKeyboardController/WootingKeyboardController.h b/Controllers/WootingKeyboardController/WootingKeyboardController.h new file mode 100644 index 00000000..3cba008c --- /dev/null +++ b/Controllers/WootingKeyboardController/WootingKeyboardController.h @@ -0,0 +1,53 @@ +/*-----------------------------------------*\ +| WootingKeyboardController.h | +| | +| Definitions and types for Wooting RGB | +| keyboard lighting controller | +| | +| Diogo Trindade (diogotr7) 3/4/2021 | +\*-----------------------------------------*/ + +#include "RGBController.h" + +#include +#include + +#pragma once + +enum RGB_PARTS +{ + PART0, + PART1, + PART2, + PART3, + PART4 +}; + +class WootingKeyboardController +{ +public: + WootingKeyboardController(hid_device* dev_handle); + ~WootingKeyboardController(); + + void SendDirect(RGBColor* colors, unsigned int num_colors); + +private: + hid_device* dev; + + void SendInitialize(); + + bool wooting_usb_send_feature + ( + unsigned char command, + unsigned char param0, + unsigned char param1, + unsigned char param2, + unsigned char param3 + ); + + bool wooting_usb_send_buffer + ( + RGB_PARTS part_number, + unsigned char rgb_buffer[] + ); +}; diff --git a/Controllers/WootingKeyboardController/WootingKeyboardControllerDetect.cpp b/Controllers/WootingKeyboardController/WootingKeyboardControllerDetect.cpp new file mode 100644 index 00000000..f357fc50 --- /dev/null +++ b/Controllers/WootingKeyboardController/WootingKeyboardControllerDetect.cpp @@ -0,0 +1,104 @@ +#include "Detector.h" +#include "WootingKeyboardController.h" +#include "RGBController.h" +#include "RGBController_WootingKeyboard.h" +#include +#include + +/*-----------------------------------------------------*\ +| Wooting vendor ID | +\*-----------------------------------------------------*/ +#define WOOTING_VID 0x03EB + +/*-----------------------------------------------------*\ +| Keyboard product IDs | +\*-----------------------------------------------------*/ +#define WOOTING_ONE_PID 0xFF01 +#define WOOTING_TWO_PID 0xFF02 + +typedef struct +{ + unsigned short usb_vid; + unsigned short usb_pid; + const char * name; +} wooting_device; + +#define WOOTING_NUM_DEVICES (sizeof(device_list) / sizeof(device_list[0])) + +static const wooting_device device_list[] = +{ + /*-----------------------------------------------------------------------*\ + | Keyboards | + \*-----------------------------------------------------------------------*/ + { WOOTING_VID, WOOTING_ONE_PID, "Wooting One" }, +// { WOOTING_VID, WOOTING_TWO_PID, "Wooting Two" }, +}; + +/******************************************************************************************\ +* * +* DetectWootingKeyboardControllers * +* * +* Tests the USB address to see if a Wooting RGB Keyboard controller exists there. * +* * +\******************************************************************************************/ + +void DetectWootingKeyboardControllers(std::vector& rgb_controllers) +{ + hid_device_info* info; + hid_device* dev; + + hid_init(); + + for(std::size_t device_idx = 0; device_idx < WOOTING_NUM_DEVICES; device_idx++) + { + dev = NULL; + + info = hid_enumerate(device_list[device_idx].usb_vid, device_list[device_idx].usb_pid); + + /*-------------------------------------------------------------*\ + | The amount of interfaces is variable, so we need to look for | + | the configuration interface. In the Wooting one keyboard the | + | configuration interface is always 4 lower than the highest | + | number | + \*-------------------------------------------------------------*/ + hid_device_info* hid_info_walker = info; + + unsigned char highestInterfaceNr = 0; + while(hid_info_walker) + { + if(hid_info_walker->interface_number > highestInterfaceNr) + { + highestInterfaceNr = hid_info_walker->interface_number; + } + + hid_info_walker = hid_info_walker->next; + } + + unsigned char interfaceNr = highestInterfaceNr - 4; + + /*-------------------------------------------------------------*\ + | Look for Wooting keyboard | + \*-------------------------------------------------------------*/ + while(info) + { + if(info->interface_number == interfaceNr) + { + dev = hid_open_path(info->path); + + if(dev) + { + WootingKeyboardController* controller = new WootingKeyboardController(dev); + + RGBController_WootingKeyboard* rgb_controller = new RGBController_WootingKeyboard(controller); + + rgb_controller->name = device_list[device_idx].name; + + rgb_controllers.push_back(rgb_controller); + } + } + info = info->next; + } + } +} /* DetectWootingKeyboardControllers() */ + +REGISTER_DETECTOR("Wooting Keyboard", DetectWootingKeyboardControllers); diff --git a/OpenRGB.pro b/OpenRGB.pro index 2bd92380..4b89c26c 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -112,6 +112,7 @@ INCLUDEPATH += Controllers/TecknetController/ \ Controllers/ThermaltakePoseidonZRGBController/ \ Controllers/ThermaltakeRiingController/ \ + Controllers/WootingKeyboardController/ \ Controllers/YeelightController/ \ Controllers/ZalmanZSyncController/ \ RGBController/ \ @@ -337,6 +338,8 @@ HEADERS += Controllers/ThermaltakeRiingController/ThermaltakeRiingController.h \ Controllers/ThermaltakeRiingController/ThermaltakeRiingQuadController.h \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiing.h \ + Controllers/WootingKeyboardController/WootingKeyboardController.h \ + Controllers/WootingKeyboardController/RGBController_WootingKeyboard.h \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiingQuad.h \ Controllers/YeelightController/YeelightController.h \ Controllers/YeelightController/RGBController_Yeelight.h \ @@ -617,6 +620,9 @@ SOURCES += Controllers/ThermaltakeRiingController/ThermaltakeRiingQuadController.cpp \ Controllers/ThermaltakeRiingController/ThermaltakeRiingControllerDetect.cpp \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiing.cpp \ + Controllers/WootingKeyboardController/WootingKeyboardController.cpp \ + Controllers/WootingKeyboardController/WootingKeyboardControllerDetect.cpp \ + Controllers/WootingKeyboardController/RGBController_WootingKeyboard.cpp \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiingQuad.cpp \ Controllers/YeelightController/YeelightController.cpp \ Controllers/YeelightController/YeelightControllerDetect.cpp \