162 lines
5.0 KiB
C++
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);
|
||
|
}
|