Implement find_usb_serial_port for MacOS, switch HYTE CNVS implementation to serial-based

This commit is contained in:
Adam Honse 2025-07-14 12:39:15 -05:00
parent 75bf674537
commit f03e4fd049
9 changed files with 164 additions and 248 deletions

View file

@ -1,89 +0,0 @@
/*---------------------------------------------------------*\
| HYTEMousematControllerDetect_MacOS.cpp |
| |
| Detector for HYTE mousemat (libusb implementation for |
| MacOS) |
| |
| Adam Honse (calcprogrammer1@gmail.com) 05 Aug 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <libusb.h>
#include "Detector.h"
#include "RGBController_HYTEMousemat.h"
/*-----------------------------------------------------*\
| HYTE vendor ID |
\*-----------------------------------------------------*/
#define HYTE_VID 0x3402
/*-----------------------------------------------------*\
| HYTE CNVS product IDs |
\*-----------------------------------------------------*/
#define HYTE_CNVS_HW_VER_1_PID 0x0B00
#define HYTE_CNVS_HW_VER_2_PID 0x0B01
typedef struct
{
unsigned short usb_vid;
unsigned short usb_pid;
unsigned char usb_interface;
const char * name;
} hyte_mousemat_device;
#define HYTE_MOUSEMAT_NUM_DEVICES (sizeof(device_list) / sizeof(device_list[ 0 ]))
static const hyte_mousemat_device device_list[] =
{
/*-----------------------------------------------------------------------------------------------------*\
| Mousemats |
\*-----------------------------------------------------------------------------------------------------*/
{ HYTE_VID, HYTE_CNVS_HW_VER_1_PID, 0, "HYTE CNVS" },
{ HYTE_VID, HYTE_CNVS_HW_VER_2_PID, 0, "HYTE CNVS" },
};
/******************************************************************************************\
* *
* DetectHYTEMousematControllers *
* *
* Detect devices supported by the HyteMousemat driver *
* *
\******************************************************************************************/
void DetectHYTEMousematControllers()
{
libusb_init(NULL);
#ifdef _WIN32
libusb_set_option(NULL, LIBUSB_OPTION_USE_USBDK);
#endif
for(std::size_t device_idx = 0; device_idx < HYTE_MOUSEMAT_NUM_DEVICES; device_idx++)
{
libusb_device_handle * dev = libusb_open_device_with_vid_pid(NULL, device_list[device_idx].usb_vid, device_list[device_idx].usb_pid);
//Look for HYTE CNVS
if(dev)
{
libusb_detach_kernel_driver(dev, 0);
libusb_claim_interface(dev, 0);
HYTEMousematController * controller = new HYTEMousematController(dev);
RGBController_HYTEMousemat * rgb_controller = new RGBController_HYTEMousemat(controller);
rgb_controller->name = device_list[device_idx].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 ) |
\*---------------------------------------------------------------------------------------------------------*/

View file

@ -1,101 +0,0 @@
/*---------------------------------------------------------*\
| HYTEMousematController_MacOS.cpp |
| |
| Driver for HYTE mousemat (libusb implementation for |
| MacOS) |
| |
| Adam Honse (calcprogrammer1@gmail.com) 05 Aug 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <cstring>
#include <iomanip>
#include <sstream>
#include "HYTEMousematController_MacOS.h"
HYTEMousematController::HYTEMousematController(libusb_device_handle* dev_handle)
{
dev = dev_handle;
/*-----------------------------------------------------*\
| Fill in location string with USB ID |
\*-----------------------------------------------------*/
libusb_device_descriptor descriptor;
libusb_get_device_descriptor(libusb_get_device(dev_handle), &descriptor);
std::stringstream location_stream;
location_stream << std::hex << std::setfill('0') << std::setw(4) << descriptor.idVendor << ":" << std::hex << std::setfill('0') << std::setw(4) << descriptor.idProduct;
location = location_stream.str();
}
HYTEMousematController::~HYTEMousematController()
{
}
std::string HYTEMousematController::GetLocation()
{
return(location);
}
void HYTEMousematController::FirmwareAnimationControl(bool enabled)
{
unsigned char serial_buf[4];
/*-----------------------------------------------------*\
| Zero out buffer |
\*-----------------------------------------------------*/
memset(serial_buf, 0, sizeof(serial_buf));
/*-----------------------------------------------------*\
| Set up Firmware Animation Control packet |
\*-----------------------------------------------------*/
serial_buf[0] = 0xFF;
serial_buf[1] = 0xDC;
serial_buf[2] = 0x05;
serial_buf[3] = enabled;
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
libusb_bulk_transfer(dev, HYTE_CNVS_EP_OUT, serial_buf, sizeof(serial_buf), NULL, 1000);
}
void HYTEMousematController::StreamingCommand(RGBColor* colors)
{
unsigned char serial_buf[157];
unsigned int max_brightness = 72;
/*-----------------------------------------------------*\
| Zero out buffer |
\*-----------------------------------------------------*/
memset(serial_buf, 0, sizeof(serial_buf));
/*-----------------------------------------------------*\
| Set up Streaming packet |
\*-----------------------------------------------------*/
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;
/*-----------------------------------------------------*\
| Copy in colors |
\*-----------------------------------------------------*/
for(unsigned int color_idx = 0; color_idx < 50; color_idx++)
{
serial_buf[7 + (color_idx * 3)] = ( max_brightness * RGBGetGValue(colors[color_idx]) ) / 100;
serial_buf[8 + (color_idx * 3)] = ( max_brightness * RGBGetRValue(colors[color_idx]) ) / 100;
serial_buf[9 + (color_idx * 3)] = ( max_brightness * RGBGetBValue(colors[color_idx]) ) / 100;
}
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
libusb_bulk_transfer(dev, HYTE_CNVS_EP_OUT, serial_buf, sizeof(serial_buf), NULL, 1000);
}

View file

@ -1,39 +0,0 @@
/*---------------------------------------------------------*\
| HYTEMousematController_MacOS.h |
| |
| Driver for HYTE mousemat (libusb implementation for |
| MacOS) |
| |
| Adam Honse (calcprogrammer1@gmail.com) 05 Aug 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include <libusb.h>
#include "RGBController.h"
/*---------------------------------------------------------*\
| HYTE CNVS endpoint values |
\*---------------------------------------------------------*/
#define HYTE_CNVS_EP_IN 0x81
#define HYTE_CNVS_EP_OUT 0x01
class HYTEMousematController
{
public:
HYTEMousematController(libusb_device_handle* dev_handle);
~HYTEMousematController();
std::string GetLocation();
void FirmwareAnimationControl(bool enabled);
void StreamingCommand(RGBColor* colors);
private:
libusb_device_handle* dev;
std::string location;
};

View file

@ -1,8 +1,8 @@
/*---------------------------------------------------------*\ /*---------------------------------------------------------*\
| HYTEMousematControllerDetect_Windows.cpp | | HYTEMousematControllerDetect_Windows_MacOS.cpp |
| | | |
| Detector for HYTE mousemat (Serial implementation for | | Detector for HYTE mousemat (Serial implementation for |
| Windows) | | Windows and MacOS) |
| | | |
| Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 | | Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 |
| | | |
@ -12,7 +12,7 @@
#include <vector> #include <vector>
#include "Detector.h" #include "Detector.h"
#include "HYTEMousematController_Windows.h" #include "HYTEMousematController_Windows_MacOS.h"
#include "RGBController_HYTEMousemat.h" #include "RGBController_HYTEMousemat.h"
#include "find_usb_serial_port.h" #include "find_usb_serial_port.h"

View file

@ -1,8 +1,8 @@
/*---------------------------------------------------------*\ /*---------------------------------------------------------*\
| HYTEMousematController_Windows.cpp | | HYTEMousematController_Windows_MacOS.cpp |
| | | |
| Driver for HYTE mousemat (Serial implementation for | | Driver for HYTE mousemat (Serial implementation for |
| Windows) | | Windows and MacOS) |
| | | |
| Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 | | Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 |
| | | |
@ -10,7 +10,7 @@
| SPDX-License-Identifier: GPL-2.0-only | | SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/ \*---------------------------------------------------------*/
#include "HYTEMousematController_Windows.h" #include "HYTEMousematController_Windows_MacOS.h"
HYTEMousematController::HYTEMousematController(char* port) HYTEMousematController::HYTEMousematController(char* port)
{ {

View file

@ -1,8 +1,8 @@
/*---------------------------------------------------------*\ /*---------------------------------------------------------*\
| HYTEMousematController_Windows.h | | HYTEMousematController_Windows_MacOS.h |
| | | |
| Driver for HYTE mousemat (Serial implementation for | | Driver for HYTE mousemat (Serial implementation for |
| Windows) | | Windows and MacOS) |
| | | |
| Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 | | Adam Honse (calcprogrammer1@gmail.com) 18 Jul 2023 |
| | | |

View file

@ -12,12 +12,16 @@
#pragma once #pragma once
#include "RGBController.h" #include "RGBController.h"
#ifdef _WIN32
#include "HYTEMousematController_Windows.h" #if defined(_WIN32) || defined(__APPLE__)
#else #include "HYTEMousematController_Windows_MacOS.h"
#endif
#ifdef __linux__
#include "HYTEMousematController_Linux.h" #include "HYTEMousematController_Linux.h"
#endif #endif
enum enum
{ {
HYTE_CNVS_MODE_DIRECT = 0, /* Direct (streaming) mode */ HYTE_CNVS_MODE_DIRECT = 0, /* Direct (streaming) mode */

View file

@ -10,6 +10,35 @@
#include "find_usb_serial_port.h" #include "find_usb_serial_port.h"
std::string exec(const char* cmd)
{
char buffer[128];
std::string result = "";
FILE* pipe = popen(cmd, "r");
if(!pipe)
{
throw std::runtime_error("popen() failed!");
}
try
{
while(fgets(buffer, sizeof(buffer), pipe) != NULL)
{
result += buffer;
}
}
catch(...)
{
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}
/*---------------------------------------------------------------------*\ /*---------------------------------------------------------------------*\
| | | |
| find_usb_serial_port | | find_usb_serial_port |
@ -24,12 +53,121 @@
| | | |
\*---------------------------------------------------------------------*/ \*---------------------------------------------------------------------*/
std::vector<std::string *> find_usb_serial_port(unsigned short /*vid*/, unsigned short /*pid*/) std::vector<std::string *> find_usb_serial_port(unsigned short vid, unsigned short pid)
{ {
std::vector<std::string *> ret_vector; /*-----------------------------------------------------*\
| Strings to search for in ioreg output |
\*-----------------------------------------------------*/
#define IO_CALLOUT_STR "\"IOCalloutDevice\" ="
#define ID_VENDOR_STR "\"idVendor\" = "
#define ID_PRODUCT_STR "\"idProduct\" = "
/*-----------------------------------------------------------------*\ /*-----------------------------------------------------*\
| TODO: Implement for MacOS | | Return variables |
\*-----------------------------------------------------------------*/ \*-----------------------------------------------------*/
std::vector<std::string *> ret_vector;
std::string * tmp_string;
/*-----------------------------------------------------*\
| Execute command to list USB devices |
| |
| Top level entry lines in ioreg output start with |
| "+-o". Start the string with an extra newline so |
| that we can search for "\n+-0" to identify only hits |
| at the beginning of a line. |
\*-----------------------------------------------------*/
std::string out_string = "\n" + exec("ioreg -r -c IOUSBHostDevice -l");
/*-----------------------------------------------------*\
| Append desired VID and PID to search strings |
\*-----------------------------------------------------*/
std::string vid_string = ID_VENDOR_STR + std::to_string(vid);
std::string pid_string = ID_PRODUCT_STR + std::to_string(pid);
/*-----------------------------------------------------*\
| Start position counter at 0 |
\*-----------------------------------------------------*/
std::size_t pos = 0;
/*-----------------------------------------------------*\
| Loop through ioreg output, loop exits when "\n+-o" |
| string cannot be found. |
\*-----------------------------------------------------*/
while(1)
{
/*-------------------------------------------------*\
| Variables to store positions in string |
\*-------------------------------------------------*/
std::size_t next_pos;
std::size_t vid_pos;
std::size_t pid_pos;
/*-------------------------------------------------*\
| Search for the next 2 iterations of "\n+-o" so |
| that we can check if hits are in between them |
\*-------------------------------------------------*/
pos = out_string.find("\n+-o", pos);
next_pos = out_string.find("\n+-o", pos + 1);
/*-------------------------------------------------*\
| Search for the vendor and product ID strings in |
| and verify that they are between pos and next_pos |
\*-------------------------------------------------*/
vid_pos = out_string.find(vid_string, pos);
pid_pos = out_string.find(pid_string, pos);
/*-------------------------------------------------*\
| Verify that VID/PID matches are within this |
| device block by checking that their positions are |
| less than next_pos. If next_pos is invalid, |
| this is the last block, in which case check if |
| VID/PID positions are valid. |
\*-------------------------------------------------*/
if(((vid_pos < next_pos) && (pid_pos < next_pos)) || ((pos == std::string::npos) && (vid_pos != std::string::npos) && (pid_pos != std::string::npos)))
{
/*---------------------------------------------*\
| Variables to store positions in string |
\*---------------------------------------------*/
std::size_t dev_pos;
std::size_t start_pos;
std::size_t end_pos;
/*---------------------------------------------*\
| Look for the IO callout device tag and then |
| get the start and end positions of its value |
\*---------------------------------------------*/
dev_pos = out_string.find(IO_CALLOUT_STR, pos + 1);
start_pos = out_string.find("\"", dev_pos + sizeof(IO_CALLOUT_STR)) + 1;
end_pos = out_string.find("\"\n", start_pos);
/*---------------------------------------------*\
| Ensure the IO callout device tag is within |
| this device's section |
\*---------------------------------------------*/
if(dev_pos < next_pos)
{
tmp_string = new std::string(out_string.substr(start_pos, end_pos-start_pos));
ret_vector.push_back(tmp_string);
}
}
/*-------------------------------------------------*\
| If we've reached the end of the string, break out |
| of the loop |
\*-------------------------------------------------*/
if(pos == std::string::npos)
{
break;
}
/*-------------------------------------------------*\
| Increment position |
\*-------------------------------------------------*/
pos++;
}
/*-----------------------------------------------------*\
| Return vector of detected strings |
\*-----------------------------------------------------*/
return(ret_vector); return(ret_vector);
} }

View file

@ -460,6 +460,8 @@ bool serial_port::serial_open()
| Configure baud rate | | Configure baud rate |
\*-----------------------------------------*/ \*-----------------------------------------*/
ioctl(file_descriptor, IOSSIOSPEED, &baud_rate); ioctl(file_descriptor, IOSSIOSPEED, &baud_rate);
printf("Port opened fd %d", file_descriptor);
#endif #endif
/*-----------------------------------------------------*\ /*-----------------------------------------------------*\
@ -595,9 +597,10 @@ int serial_port::serial_write(char * buffer, int length)
\*-----------------------------------------------------*/ \*-----------------------------------------------------*/
#ifdef __APPLE__ #ifdef __APPLE__
int byteswritten; int byteswritten;
tcdrain(file_descriptor); printf("serial write fd %d", file_descriptor);
byteswritten = write(file_descriptor, buffer, length); printf("tcdrain %d\r\n",tcdrain(file_descriptor));
tcdrain(file_descriptor); printf("write %d\r\n", byteswritten = write(file_descriptor, buffer, length));
printf("tcdrain %d\r\n", tcdrain(file_descriptor));
return byteswritten; return byteswritten;
#endif #endif