From 6473a22e89d95d04240345f395e603693603b1e8 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 19 Jul 2023 22:45:18 -0500 Subject: [PATCH] Initial HYTE CNVS controller implementation using serial port --- .../HYTEMousematController.cpp | 71 +++++++ .../HYTEMousematController.h | 29 +++ .../HYTEMousematControllerDetect.cpp | 62 ++++++ .../RGBController_HYTEMousemat.cpp | 85 ++++++++ .../RGBController_HYTEMousemat.h | 32 +++ OpenRGB.pro | 6 + serial_port/find_usb_serial_port_linux.cpp | 191 ++++++++++++++---- serial_port/serial_port.cpp | 6 +- 8 files changed, 440 insertions(+), 42 deletions(-) create mode 100644 Controllers/HYTEMousematController/HYTEMousematController.cpp create mode 100644 Controllers/HYTEMousematController/HYTEMousematController.h create mode 100644 Controllers/HYTEMousematController/HYTEMousematControllerDetect.cpp create mode 100644 Controllers/HYTEMousematController/RGBController_HYTEMousemat.cpp create mode 100644 Controllers/HYTEMousematController/RGBController_HYTEMousemat.h diff --git a/Controllers/HYTEMousematController/HYTEMousematController.cpp b/Controllers/HYTEMousematController/HYTEMousematController.cpp new file mode 100644 index 000000000..ff0ddb551 --- /dev/null +++ b/Controllers/HYTEMousematController/HYTEMousematController.cpp @@ -0,0 +1,71 @@ +/*---------------------------------------------------------*\ +| HYTEMousematController.cpp | +| | +| Driver for HYTE CNVS RGB mousemat controller | +| | +| Adam Honse (calcprogrammer1@gmail.com), 7/18/2023 | +\*---------------------------------------------------------*/ + +#include "HYTEMousematController.h" + +HYTEMousematController::HYTEMousematController(char* port) +{ + port_name = port; + + /*-----------------------------------------------------*\ + | Open the port | + | Baud rate doesn't matter for ACM device | + \*-----------------------------------------------------*/ + serialport = new serial_port(port_name.c_str(), 2000000); + + FirmwareAnimationControl(false); +} + +HYTEMousematController::~HYTEMousematController() +{ + +} + +std::string HYTEMousematController::GetLocation() +{ + return(port_name); +} + +void HYTEMousematController::FirmwareAnimationControl(bool enabled) +{ + unsigned char serial_buf[4]; + + memset(serial_buf, 0, sizeof(serial_buf)); + + serial_buf[0] = 0xFF; + serial_buf[1] = 0xDC; + serial_buf[2] = 0x05; + serial_buf[3] = enabled; + + serialport->serial_write((char *)serial_buf, sizeof(serial_buf)); +} + +void HYTEMousematController::StreamingCommand(RGBColor* colors) +{ + unsigned char serial_buf[157]; + + memset(serial_buf, 0, sizeof(serial_buf)); + + serial_buf[0] = 0xFF; + serial_buf[1] = 0xEE; + serial_buf[2] = 0x02; + serial_buf[3] = 0x01; + serial_buf[4] = 0x00; + serial_buf[5] = 0x32; + serial_buf[6] = 0x00; + + for(unsigned int color_idx = 0; color_idx < 50; color_idx++) + { + serial_buf[7 + (color_idx * 3)] = RGBGetGValue(colors[color_idx]); + serial_buf[8 + (color_idx * 3)] = RGBGetRValue(colors[color_idx]); + serial_buf[9 + (color_idx * 3)] = RGBGetBValue(colors[color_idx]); + } + + serialport->serial_write((char *)serial_buf, sizeof(serial_buf)); + serialport->serial_flush_tx(); +} diff --git a/Controllers/HYTEMousematController/HYTEMousematController.h b/Controllers/HYTEMousematController/HYTEMousematController.h new file mode 100644 index 000000000..d767bc2f3 --- /dev/null +++ b/Controllers/HYTEMousematController/HYTEMousematController.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------*\ +| HYTEMousematController.h | +| | +| Definitions for HYTE CNVS RGB mousemat controller | +| | +| Adam Honse (calcprogrammer1@gmail.com), 7/18/2023 | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "serial_port.h" +#include + +class HYTEMousematController +{ +public: + HYTEMousematController(char* port); + ~HYTEMousematController(); + + std::string GetLocation(); + + void FirmwareAnimationControl(bool enabled); + void StreamingCommand(RGBColor* colors); + +private: + std::string port_name; + serial_port * serialport = nullptr; +}; diff --git a/Controllers/HYTEMousematController/HYTEMousematControllerDetect.cpp b/Controllers/HYTEMousematController/HYTEMousematControllerDetect.cpp new file mode 100644 index 000000000..f2d08e676 --- /dev/null +++ b/Controllers/HYTEMousematController/HYTEMousematControllerDetect.cpp @@ -0,0 +1,62 @@ +#include "Detector.h" +#include "HYTEMousematController.h" +#include "RGBController.h" +#include "RGBController_HYTEMousemat.h" +#include "find_usb_serial_port.h" +#include + +#define HYTE_VID 0x3402 + +#define HYTE_CNVS_HW_VER_1_PID 0x0B00 +#define HYTE_CNVS_HW_VER_2_PID 0x0B01 + +struct hyte_mousemat_type +{ + unsigned short vid; + unsigned short pid; + const char * name; +}; + +#define HYTE_MOUSEMAT_NUM_DEVICES 2 + +static const hyte_mousemat_type hyte_mousemat_devices[] = +{ + { HYTE_VID, HYTE_CNVS_HW_VER_1_PID, "HYTE CNVS" }, + { HYTE_VID, HYTE_CNVS_HW_VER_2_PID, "HYTE CNVS" }, +}; + +/******************************************************************************************\ +* * +* DetectHYTEMousematControllers * +* * +* Detect devices supported by the HyteMousemat driver * +* * +\******************************************************************************************/ + +void DetectHYTEMousematControllers() +{ + for(unsigned int device_id = 0; device_id < HYTE_MOUSEMAT_NUM_DEVICES; device_id++) + { + std::vector ports = find_usb_serial_port(hyte_mousemat_devices[device_id].vid, hyte_mousemat_devices[device_id].pid); + + for(unsigned int i = 0; i < ports.size(); i++) + { + if(*ports[i] != "") + { + HYTEMousematController * controller = new HYTEMousematController((char *)ports[i]->c_str()); + RGBController_HYTEMousemat * rgb_controller = new RGBController_HYTEMousemat(controller); + rgb_controller->name = hyte_mousemat_devices[device_id].name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + } + } +} /* DetectHYTEMousematControllers() */ + +REGISTER_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers); +/*---------------------------------------------------------------------------------------------------------*\ +| Entries for dynamic UDEV rules | +| | +| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B00 ) | +| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B01 ) | +\*---------------------------------------------------------------------------------------------------------*/ diff --git a/Controllers/HYTEMousematController/RGBController_HYTEMousemat.cpp b/Controllers/HYTEMousematController/RGBController_HYTEMousemat.cpp new file mode 100644 index 000000000..639e4e7cd --- /dev/null +++ b/Controllers/HYTEMousematController/RGBController_HYTEMousemat.cpp @@ -0,0 +1,85 @@ +/*-----------------------------------------*\ +| RGBController_HYTEMousemat.cpp | +| | +| Generic RGB Interface for HYTE CNVS RGB | +| mousemat | +| | +| Adam Honse (CalcProgrammer1) 7/18/2023 | +\*-----------------------------------------*/ + +#include "RGBController_HYTEMousemat.h" + +RGBController_HYTEMousemat::RGBController_HYTEMousemat(HYTEMousematController* controller_ptr) +{ + controller = controller_ptr; + + name = "HYTE Mousemat"; + description = "HYTE Mousemat Device"; + type = DEVICE_TYPE_MOUSEMAT; + location = controller->GetLocation(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_HYTEMousemat::~RGBController_HYTEMousemat() +{ + +} + +void RGBController_HYTEMousemat::SetupZones() +{ + zone mousemat_zone; + + mousemat_zone.name = "Mousemat"; + mousemat_zone.type = ZONE_TYPE_LINEAR; + mousemat_zone.leds_min = 50; + mousemat_zone.leds_max = 50; + mousemat_zone.leds_count = 50; + mousemat_zone.matrix_map = NULL; + + zones.push_back(mousemat_zone); + + for(unsigned int led_idx = 0; led_idx < zones[0].leds_count; led_idx++) + { + led mousemat_led; + + mousemat_led.name = "Mousemat LED"; + + leds.push_back(mousemat_led); + } + + SetupColors(); +} + +void RGBController_HYTEMousemat::ResizeZone(int /*zone*/, int /*new_size*/) +{ + +} + +void RGBController_HYTEMousemat::DeviceUpdateLEDs() +{ + printf("DeviceUpdateLEDs called\r\n"); + controller->StreamingCommand(&colors[0]); +} + +void RGBController_HYTEMousemat::UpdateZoneLEDs(int /*zone*/) +{ + +} + +void RGBController_HYTEMousemat::UpdateSingleLED(int /*led*/) +{ + +} + +void RGBController_HYTEMousemat::DeviceUpdateMode() +{ + +} diff --git a/Controllers/HYTEMousematController/RGBController_HYTEMousemat.h b/Controllers/HYTEMousematController/RGBController_HYTEMousemat.h new file mode 100644 index 000000000..313ca15b7 --- /dev/null +++ b/Controllers/HYTEMousematController/RGBController_HYTEMousemat.h @@ -0,0 +1,32 @@ +/*-----------------------------------------*\ +| RGBController_HYTEMousemat.h | +| | +| Generic RGB Interface for HYTE CNVS RGB | +| mousemat | +| | +| Adam Honse (CalcProgrammer1) 7/18/2023 | +\*-----------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "HYTEMousematController.h" + +class RGBController_HYTEMousemat : public RGBController +{ +public: + RGBController_HYTEMousemat(HYTEMousematController* controller_ptr); + ~RGBController_HYTEMousemat(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + HYTEMousematController* controller; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index 4d3d69548..03c27156e 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -172,6 +172,7 @@ INCLUDEPATH += Controllers/HyperXMicrophoneController/ \ Controllers/HyperXMouseController/ \ Controllers/HyperXMousematController/ \ + Controllers/HYTEMousematController/ \ Controllers/IntelArcA770LEController/ \ Controllers/IonicoController/ \ Controllers/LEDStripController/ \ @@ -533,6 +534,8 @@ HEADERS += Controllers/HyperXMouseController/RGBController_HyperXPulsefireRaid.h \ Controllers/HyperXMousematController/HyperXMousematController.h \ Controllers/HyperXMousematController/RGBController_HyperXMousemat.h \ + Controllers/HYTEMousematController/HYTEMousematController.h \ + Controllers/HYTEMousematController/RGBController_HYTEMousemat.h \ Controllers/IntelArcA770LEController/IntelArcA770LEController.h \ Controllers/IntelArcA770LEController/RGBController_IntelArcA770LE.h \ Controllers/IonicoController/IonicoController.h \ @@ -1181,6 +1184,9 @@ SOURCES += Controllers/HyperXMousematController/HyperXMousematController.cpp \ Controllers/HyperXMousematController/HyperXMousematControllerDetect.cpp \ Controllers/HyperXMousematController/RGBController_HyperXMousemat.cpp \ + Controllers/HYTEMousematController/HYTEMousematController.cpp \ + Controllers/HYTEMousematController/HYTEMousematControllerDetect.cpp \ + Controllers/HYTEMousematController/RGBController_HYTEMousemat.cpp \ Controllers/IntelArcA770LEController/IntelArcA770LEController.cpp \ Controllers/IntelArcA770LEController/IntelArcA770LEControllerDetect.cpp \ Controllers/IonicoController/IonicoController.cpp \ diff --git a/serial_port/find_usb_serial_port_linux.cpp b/serial_port/find_usb_serial_port_linux.cpp index 2e9a22b24..3d9a24c57 100644 --- a/serial_port/find_usb_serial_port_linux.cpp +++ b/serial_port/find_usb_serial_port_linux.cpp @@ -24,12 +24,20 @@ std::vector find_usb_serial_port(unsigned short vid, unsigned sho DIR* dir; char symlink_path[1024] = {0}; struct dirent* ent; - char vid_pid[10] = {0}; //Store VID/PID + char target_vid[10] = {0}; + char target_pid[10] = {0}; + + /*-----------------------------------------------------------------*\ + | Target VID/PID strings | + \*-----------------------------------------------------------------*/ + snprintf(target_vid, 10, "%04x", vid); + snprintf(target_pid, 10, "%04x", pid); /*-----------------------------------------------------------------*\ | Open /sys/class/tty | \*-----------------------------------------------------------------*/ - dir = opendir("/sys/class/tty"); + //dir = opendir("/sys/class/tty"); + dir = opendir("/sys/bus/usb/devices"); if(dir == NULL) { @@ -47,33 +55,18 @@ std::vector find_usb_serial_port(unsigned short vid, unsigned sho { if(ent->d_type == DT_LNK) { - char tty_path[1024]; - strcpy(tty_path, "/sys/class/tty/"); - strcat(tty_path, ent->d_name); + char usb_path[1024]; + strcpy(usb_path, "/sys/bus/usb/devices/"); + strcat(usb_path, ent->d_name); /*-----------------------------------------------------------------*\ | readlink() does not null-terminate, so manually terminate it | \*-----------------------------------------------------------------*/ - ssize_t link_path_size = readlink(tty_path, symlink_path, 1024); + ssize_t link_path_size = readlink(usb_path, symlink_path, 1024); symlink_path[link_path_size] = '\0'; - char * usb_string = strstr(symlink_path, "usb"); - - if(usb_string != NULL) + if(1) { - char * usb_dev = strstr(usb_string, "/"); - usb_dev++; - char * usb_end = strstr(usb_dev, "/tty"); - *usb_end = '\0'; - - usb_end = strrchr(usb_dev, '/'); - *usb_end = '\0'; - - char usb_path[1024]; - - strcpy(usb_path, "/sys/bus/usb/devices/"); - strcat(usb_path, usb_dev); - char vendor_path[1024]; char product_path[1024]; @@ -94,26 +87,57 @@ std::vector find_usb_serial_port(unsigned short vid, unsigned sho std::getline(vendor_file, vendor_string); std::getline(product_file, product_string); - snprintf(vid_pid, 10, "%04x", vid); - - if(strcmp(vid_pid, vendor_string.c_str()) == 0) + if(strcmp(target_vid, vendor_string.c_str()) == 0) { - snprintf(vid_pid, 10, "%04x", pid); - if(strcmp(vid_pid, product_string.c_str()) == 0) + if(strcmp(target_pid, product_string.c_str()) == 0) { - char* port_string = NULL; - for(int i = strlen(tty_path); i > 0; i--) - { - if(tty_path[i] == '/') - { - port_string = &tty_path[i + 1]; - break; - } - } - tmp_string = new std::string("/dev/"); - tmp_string->append(port_string); + DIR* usb_dev_dir; + struct dirent* usb_dev_ent; - ret_vector.push_back(tmp_string); + usb_dev_dir = opendir(usb_path); + + usb_dev_ent = readdir(usb_dev_dir); + + while(usb_dev_ent != NULL) + { + if(usb_dev_ent->d_type == DT_DIR) + { + char tty_path[1024]; + + strcpy(tty_path, usb_path); + strcat(tty_path, "/"); + strcat(tty_path, usb_dev_ent->d_name); + strcat(tty_path, "/tty"); + + DIR* tty_dir; + + tty_dir = opendir(tty_path); + + if(tty_dir != NULL) + { + struct dirent* tty_ent; + + tty_ent = readdir(tty_dir); + + while(tty_ent != NULL) + { + if(tty_ent->d_type == DT_DIR) + { + if(strncmp(tty_ent->d_name, "tty", 3) == 0) + { + tmp_string = new std::string("/dev/" + std::string(tty_ent->d_name)); + + ret_vector.push_back(tmp_string); + } + } + + tty_ent = readdir(tty_dir); + } + } + } + + usb_dev_ent = readdir(usb_dev_dir); + } } } } @@ -122,6 +146,95 @@ std::vector find_usb_serial_port(unsigned short vid, unsigned sho ent = readdir(dir); } + closedir(dir); + return ret_vector; + + // /*-----------------------------------------------------------------*\ + // | Loop through all symlinks in /sys/class/tty directory to find | + // | paths with "usb" in them. These links should have the USB device | + // | index which can be used to find the VID/PID | + // \*-----------------------------------------------------------------*/ + // ent = readdir(dir); + + // while(ent != NULL) + // { + // if(ent->d_type == DT_LNK) + // { + // char tty_path[1024]; + // strcpy(tty_path, "/sys/class/tty/"); + // strcat(tty_path, ent->d_name); + + // /*-----------------------------------------------------------------*\ + // | readlink() does not null-terminate, so manually terminate it | + // \*-----------------------------------------------------------------*/ + // ssize_t link_path_size = readlink(tty_path, symlink_path, 1024); + // symlink_path[link_path_size] = '\0'; + + // char * usb_string = strstr(symlink_path, "usb"); + + // if(usb_string != NULL) + // { + // char * usb_dev = strstr(usb_string, "/"); + // usb_dev++; + // char * usb_end = strstr(usb_dev, "/tty"); + // *usb_end = '\0'; + + // usb_end = strrchr(usb_dev, '/'); + // *usb_end = '\0'; + + // char usb_path[1024]; + + // strcpy(usb_path, "/sys/bus/usb/devices/"); + // strcat(usb_path, usb_dev); + + // char vendor_path[1024]; + // char product_path[1024]; + + // strcpy(vendor_path, usb_path); + // strcat(vendor_path, "/idVendor"); + + // strcpy(product_path, usb_path); + // strcat(product_path, "/idProduct"); + + // std::ifstream vendor_file; + // std::ifstream product_file; + // std::string vendor_string; + // std::string product_string; + + // vendor_file.open(vendor_path); + // product_file.open(product_path); + + // std::getline(vendor_file, vendor_string); + // std::getline(product_file, product_string); + + // snprintf(vid_pid, 10, "%04x", vid); + + // if(strcmp(vid_pid, vendor_string.c_str()) == 0) + // { + // snprintf(vid_pid, 10, "%04x", pid); + // if(strcmp(vid_pid, product_string.c_str()) == 0) + // { + // char* port_string = NULL; + // for(int i = strlen(tty_path); i > 0; i--) + // { + // if(tty_path[i] == '/') + // { + // port_string = &tty_path[i + 1]; + // break; + // } + // } + // tmp_string = new std::string("/dev/"); + // tmp_string->append(port_string); + + // ret_vector.push_back(tmp_string); + // } + // } + // } + // } + + // ent = readdir(dir); + // } + closedir(dir); return ret_vector; diff --git a/serial_port/serial_port.cpp b/serial_port/serial_port.cpp index b8d603102..f673ea739 100644 --- a/serial_port/serial_port.cpp +++ b/serial_port/serial_port.cpp @@ -219,7 +219,7 @@ bool serial_port::serial_open() /*-----------------------------------------*\ | Open the port read/write with no delay | \*-----------------------------------------*/ - file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY); + file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_DSYNC); if(file_descriptor < 0) { @@ -566,9 +566,9 @@ int serial_port::serial_write(char * buffer, int length) \*-----------------------------------------------------*/ #ifdef __linux__ int byteswritten; - tcdrain(file_descriptor); + //tcdrain(file_descriptor); byteswritten = write(file_descriptor, buffer, length); - tcdrain(file_descriptor); + //tcdrain(file_descriptor); return byteswritten; #endif