USB-HID/UsbHidDevEx/hiddev.cpp

162 lines
5.0 KiB
C++

#include <unistd.h>
#include "hiddev.h"
#include <iostream>
HIDDev::HIDDev() : dev_handle(nullptr), ctx(nullptr), connected(false) {
libusb_init(&ctx);
#if USB_HOT_PLUG_SUPPORT
libusb_hotplug_callback_handle handle_attach;
int rc = libusb_hotplug_register_callback(ctx, static_cast<libusb_hotplug_event>(
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
LIBUSB_HOTPLUG_NO_FLAGS,
LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback,
this,
&handle_attach);
if (rc != LIBUSB_SUCCESS) {
std::cout << "Error registering callback for attach event." << std::endl;
libusb_exit(ctx);
}
std::cout << "[INFO] HIDDev using hot plug driver." << std::endl;
#endif
// 启动事件处理线程
usbThread = std::thread(&HIDDev::usbEventHandling, this);
}
HIDDev::~HIDDev() {
// 通知线程结束
stopThread = true;
if (usbThread.joinable()) {
usbThread.join();
}
closeDevice();
libusb_exit(ctx);
}
bool HIDDev::openDevice(int vendor_id, int product_id) {
vendorId = vendor_id;
productId = product_id;
dev_handle = libusb_open_device_with_vid_pid(ctx, vendor_id, product_id);
if (!dev_handle) {
std::cerr << "Cannot open device\n";
connected = false;
return false;
}
if (libusb_kernel_driver_active(dev_handle, 0) == 1)
{ // find out if kernel driver is attached
printf("Kernel Driver Active\n");
if (libusb_detach_kernel_driver(dev_handle, 0) == 0) // detach it
printf("Kernel Driver Detached!\n");
}
if (libusb_claim_interface(dev_handle, 0) < 0) {
std::cerr << "Cannot claim interface\n";
closeDevice();
return false;
}
connected = true;
return true;
}
#if USB_HOT_PLUG_SUPPORT
int LIBUSB_CALL HIDDev::hotplug_callback(libusb_context *ctx, libusb_device *device,
libusb_hotplug_event event, void *user_data) {
HIDDev *self = static_cast<HIDDev *>(user_data);
libusb_device_descriptor desc;
if (libusb_get_device_descriptor(device, &desc) == 0) {
if(self->vendorId != desc.idVendor || self->productId != desc.iProduct){
return 0;
}
std::cout << "Device Event: VendorID=" << desc.idVendor << ", ProductID=" << desc.idProduct << std::endl;
}
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
self->devArrived = true;
std::cout << "Device arrived." << std::endl;
} else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
self->connected = false;
std::cout << "Device disconnected." << std::endl;
}
std::cout << "Device event." << std::endl;
return 0;
}
#endif
void HIDDev::closeDevice() {
if (dev_handle) {
libusb_release_interface(dev_handle, 0);
libusb_close(dev_handle);
dev_handle = nullptr;
}
connected = false;
}
int HIDDev::read(unsigned char *data, int length) {
if (!connected) {
return -1;
}
int actual_length;
int res = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_IN | 1, data, length, &actual_length, 0);
if (res == 0) {
return actual_length;
} else {
if (res == LIBUSB_ERROR_NO_DEVICE) {
std::cout << "Device not connected error...\n";
connected = false;
reconnectFlag = true;
}
return -1;
}
}
int HIDDev::write(const unsigned char *data, int length) {
if (!connected) {
return -1;
}
int actual_length;
int res = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | 1,
const_cast<unsigned char *>(data), length, &actual_length, 0);
if (res == 0) {
return actual_length;
} else {
if (res == LIBUSB_ERROR_NO_DEVICE) {
connected = false;
reconnectFlag = true;
}
return -1;
}
}
void HIDDev::usbEventHandling() {
int completed = 0;
while (!stopThread) {
#if USB_HOT_PLUG_SUPPORT
libusb_handle_events_completed(ctx, &completed);
// 也可以加入一些线程休眠来减少CPU使用率
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if(devArrived == true){
std::cout << "[INFO] Hotplug mode, Device reconnected ...\n";
tryReconnect();
devArrived = false;
}
#else
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// 如果设备未连接,定期尝试连接设备
if(reconnectFlag && !connected){
std::cout << "[INFO] Query mode,Device disconnected, try to connect.\n";
reconnectFlag = !tryReconnect();
}
#endif
}
std::cout << "[INFO] HIDDev event thread exit...\n";
}
bool HIDDev::isConnected() {
return connected;
}
bool HIDDev::tryReconnect() {
return openDevice(this->vendorId, this->productId);
}