334 lines
11 KiB
C++
334 lines
11 KiB
C++
#include "usbhandler.h"
|
||
|
||
UsbHandler::UsbHandler(QObject *parent) : QObject(parent), context(nullptr), deviceList(nullptr), deviceCount(0), handle(nullptr)
|
||
{
|
||
// Initialize libusb context
|
||
if (libusb_init(&context) < 0) {
|
||
emit errorOccurred("Failed to initialize libusb.");
|
||
}
|
||
}
|
||
|
||
UsbHandler::~UsbHandler()
|
||
{
|
||
if (handle) {
|
||
libusb_close(handle);
|
||
}
|
||
if (deviceList) {
|
||
libusb_free_device_list(deviceList, 1);
|
||
}
|
||
libusb_exit(context);
|
||
}
|
||
|
||
bool UsbHandler::initialize()
|
||
{
|
||
// Initialize the libusb context and check for errors
|
||
if (libusb_init(&context) < 0) {
|
||
emit errorOccurred("Failed to initialize libusb.");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void UsbHandler::listDevices()
|
||
{
|
||
// Retrieve the list of connected USB devices
|
||
deviceCount = libusb_get_device_list(context, &deviceList);
|
||
if (deviceCount < 0) {
|
||
emit errorOccurred("Failed to get USB device list.");
|
||
return;
|
||
}else{
|
||
productList = new QMap<int,QString>[deviceCount];
|
||
}
|
||
|
||
|
||
for (ssize_t i = 0; i < deviceCount; ++i) {
|
||
productList->insert(i,printDeviceInfo(deviceList[i]));
|
||
// Optionally add more detailed device information here
|
||
}
|
||
emit productListUpdate(productList);
|
||
}
|
||
|
||
bool UsbHandler::openDevice(int deviceIndex)
|
||
{
|
||
if (deviceIndex < 0 || deviceIndex >= deviceCount) {
|
||
emit errorOccurred("Invalid device index.");
|
||
return false;
|
||
}
|
||
|
||
// Open the selected device
|
||
libusb_device_handle *devHandle;
|
||
int status = libusb_open(deviceList[deviceIndex], &devHandle);
|
||
LOG_DEBUG("status is %d",status);
|
||
if (status < 0) {
|
||
emit errorOccurred("Failed to open USB device.");
|
||
return false;
|
||
}
|
||
|
||
// Store the device handle for further operations
|
||
handle = devHandle;
|
||
LOG_DEBUG("open deviceindex %d success",deviceIndex);
|
||
return true;
|
||
}
|
||
|
||
bool UsbHandler::sendControlTransfer(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t length)
|
||
{
|
||
if (handle == nullptr) {
|
||
emit errorOccurred("No device handle.");
|
||
return false;
|
||
}
|
||
|
||
|
||
int status = libusb_control_transfer(handle, bmRequestType, bRequest, wValue, wIndex, data, length, 1000);
|
||
if (status < 0) {
|
||
emit errorOccurred("Control transfer failed.");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool UsbHandler::sendBulkTransfer(uint8_t endpoint, uint8_t *data, int length,int interfaceNum)
|
||
{
|
||
int status;
|
||
if (handle == nullptr) {
|
||
emit errorOccurred("No device handle.");
|
||
return false;
|
||
}
|
||
|
||
// 获取接口权限(可选,部分系统如Linux必须)
|
||
if (libusb_kernel_driver_active(handle, interfaceNum)) {
|
||
libusb_detach_kernel_driver(handle, interfaceNum);
|
||
}
|
||
|
||
status = libusb_claim_interface(handle, interfaceNum);
|
||
if (status < 0) {
|
||
LOG_ERROR("Failed to claim interface: %d",interfaceNum);
|
||
return false;
|
||
}
|
||
|
||
int actualLength;
|
||
status = libusb_bulk_transfer(handle, endpoint, data, length, &actualLength, 1000);
|
||
if (status < 0) {
|
||
emit errorOccurred("Bulk transfer failed.");
|
||
libusb_release_interface(handle, interfaceNum);
|
||
return false;
|
||
}
|
||
|
||
libusb_release_interface(handle, interfaceNum);
|
||
return true;
|
||
}
|
||
|
||
//主要用在数据读,从设备到主机
|
||
// bool UsbHandler::sendInterruptTransfer(uint8_t endpoint, uint8_t *data, int length)
|
||
// {
|
||
// if (handle == nullptr) {
|
||
// emit errorOccurred("No device handle.");
|
||
// return false;
|
||
// }
|
||
|
||
// int actualLength;
|
||
// int status = libusb_interrupt_transfer(handle, endpoint, data, length, &actualLength, 1000);
|
||
// if (status < 0) {
|
||
// emit errorOccurred("Interrupt transfer failed.");
|
||
// return false;
|
||
// }
|
||
// return true;
|
||
// }
|
||
|
||
|
||
bool UsbHandler::sendAsyncTransfer(uint8_t endpoint, uint8_t *data, int length,int interfaceNum)
|
||
{
|
||
int status;
|
||
if (handle == nullptr) {
|
||
emit errorOccurred("No device handle.");
|
||
return false;
|
||
}
|
||
|
||
// 1. 创建 libusb_transfer 对象
|
||
libusb_transfer *transfer = libusb_alloc_transfer(0); // 0 表示默认的最大传输包大小
|
||
if (transfer == nullptr) {
|
||
emit errorOccurred("Failed to allocate transfer.");
|
||
return false;
|
||
}
|
||
|
||
// 获取接口权限(可选,部分系统如Linux必须)
|
||
if (libusb_kernel_driver_active(handle, interfaceNum)) {
|
||
libusb_detach_kernel_driver(handle, interfaceNum);
|
||
}
|
||
|
||
status = libusb_claim_interface(handle, interfaceNum);
|
||
if (status < 0) {
|
||
LOG_ERROR("Failed to claim interface: %d",interfaceNum);
|
||
return false;
|
||
}
|
||
|
||
|
||
// 2. 设置传输类型和参数
|
||
if (endpoint & LIBUSB_ENDPOINT_IN) { // 如果是输入端点 (IN)
|
||
libusb_fill_bulk_transfer(transfer, handle, endpoint, data, length,
|
||
[](libusb_transfer *transfer) {
|
||
// 回调函数,当传输完成时调用
|
||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||
LOG_DEBUG("Async Transfer completed successfully.");
|
||
} else {
|
||
LOG_ERROR("Async Transfer failed with status:0x%x",transfer->status);
|
||
}
|
||
libusb_free_transfer(transfer); // 释放传输资源
|
||
}, nullptr, 0);
|
||
} else { // 如果是输出端点 (OUT)
|
||
libusb_fill_bulk_transfer(transfer, handle, endpoint, data, length,
|
||
[](libusb_transfer *transfer) {
|
||
// 回调函数,当传输完成时调用
|
||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||
LOG_DEBUG("Async Transfer completed successfully.");
|
||
} else {
|
||
LOG_ERROR("Async Transfer failed with status:0x%x",transfer->status);
|
||
}
|
||
libusb_free_transfer(transfer); // 释放传输资源
|
||
}, nullptr, 0);
|
||
}
|
||
|
||
// 3. 提交传输
|
||
status = libusb_submit_transfer(transfer);
|
||
if (status < 0) {
|
||
emit errorOccurred("Failed to submit async transfer.");
|
||
libusb_free_transfer(transfer);
|
||
libusb_release_interface(handle, interfaceNum);
|
||
return false;
|
||
}
|
||
|
||
libusb_release_interface(handle, interfaceNum);
|
||
// libusb_handle_events(context); // 确保事件循环能处理异步传输
|
||
|
||
return true;
|
||
}
|
||
|
||
QString UsbHandler::printDeviceInfo(libusb_device *device)
|
||
{
|
||
libusb_device_descriptor desc;
|
||
QString tmp={};
|
||
if (libusb_get_device_descriptor(device, &desc) == 0) {
|
||
tmp= "Vendor ID: 0x"+QString::number(desc.idVendor,16)+",Product ID: 0x"+QString::number(desc.idProduct,16);
|
||
LOG_DEBUG("Vendor ID: 0x%x, Product ID: 0x%x", desc.idVendor, desc.idProduct);
|
||
} else {
|
||
LOG_ERROR("Failed to retrieve device descriptor.");
|
||
}
|
||
return tmp;
|
||
}
|
||
|
||
|
||
void UsbHandler::listInterfaces(int deviceIndex) {
|
||
if (deviceIndex < 0 || deviceIndex >= deviceCount) {
|
||
emit errorOccurred("无效的设备索引");
|
||
return;
|
||
}
|
||
|
||
libusb_device *device = deviceList[deviceIndex];
|
||
|
||
libusb_config_descriptor *config = nullptr;
|
||
if (libusb_get_active_config_descriptor(device, &config) != 0) {
|
||
emit errorOccurred("获取配置描述符失败");
|
||
return;
|
||
}
|
||
|
||
LOG_DEBUG("接口总数: %d",config->bNumInterfaces);
|
||
|
||
interfaceList = new QMap<int,QString>[config->bNumInterfaces];
|
||
|
||
|
||
for (int i = 0; i < config->bNumInterfaces; ++i) {
|
||
const libusb_interface &interface = config->interface[i];
|
||
QString tmp;
|
||
|
||
for (int j = 0; j < interface.num_altsetting; ++j) {
|
||
const libusb_interface_descriptor &alt = interface.altsetting[j];
|
||
|
||
tmp += QString("Interface #[%1]: %2, Class: %3, SubClass: %4, Protocol: %5")
|
||
.arg(i)
|
||
.arg(alt.bInterfaceNumber)
|
||
.arg(alt.bInterfaceClass)
|
||
.arg(alt.bInterfaceSubClass)
|
||
.arg(alt.bInterfaceProtocol);
|
||
}
|
||
|
||
interfaceList->insert(i, tmp);
|
||
}
|
||
|
||
|
||
libusb_free_config_descriptor(config);
|
||
emit interfaceListUpdate(interfaceList);
|
||
}
|
||
|
||
|
||
void UsbHandler::listInterfaceEndpoints(int deviceIndex, int interfaceNumber) {
|
||
LOG_DEBUG("devivceIdx is %d,interfaceiIdx is %d",deviceIndex,interfaceNumber);
|
||
if (deviceIndex < 0 || deviceIndex >= deviceCount) {
|
||
qDebug() << "无效的设备索引";
|
||
return;
|
||
}
|
||
|
||
libusb_device *device = deviceList[deviceIndex];
|
||
libusb_config_descriptor *config = nullptr;
|
||
|
||
if (libusb_get_active_config_descriptor(device, &config) != 0) {
|
||
qDebug() << "获取配置描述符失败";
|
||
return;
|
||
}
|
||
|
||
if (interfaceNumber < 0 || interfaceNumber >= config->bNumInterfaces) {
|
||
qDebug() << "无效的接口编号";
|
||
libusb_free_config_descriptor(config);
|
||
return;
|
||
}
|
||
|
||
const libusb_interface &interface = config->interface[interfaceNumber];
|
||
|
||
if (interface.num_altsetting < 1) {
|
||
qDebug() << "接口无 altsetting";
|
||
libusb_free_config_descriptor(config);
|
||
return;
|
||
}
|
||
|
||
endPointList = new QMap<int, QString>;
|
||
for(int j=0;j<interface.num_altsetting;j++){
|
||
const libusb_interface_descriptor &alt = interface.altsetting[j];
|
||
|
||
for (int k = 0; k < alt.bNumEndpoints; ++k) {
|
||
const libusb_endpoint_descriptor &ep = alt.endpoint[k];
|
||
|
||
QString epTypeStr;
|
||
switch (ep.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
|
||
case LIBUSB_TRANSFER_TYPE_CONTROL: epTypeStr = "Control"; break;
|
||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: epTypeStr = "Isochronous"; break;
|
||
case LIBUSB_TRANSFER_TYPE_BULK: epTypeStr = "Bulk"; break;
|
||
case LIBUSB_TRANSFER_TYPE_INTERRUPT: epTypeStr = "Interrupt"; break;
|
||
default: epTypeStr = "Unknown"; break;
|
||
}
|
||
|
||
QString direction = (ep.bEndpointAddress & LIBUSB_ENDPOINT_IN) ? "IN" : "OUT";
|
||
|
||
QString info= QString("Endpoint 0x%1 (%2, %3), MaxPacketSize: %4")
|
||
.arg(ep.bEndpointAddress, 2, 16, QChar('0'))
|
||
.arg(direction)
|
||
.arg(epTypeStr)
|
||
.arg(ep.wMaxPacketSize);
|
||
endPointList->insert(k, info);
|
||
}
|
||
}
|
||
|
||
libusb_free_config_descriptor(config);
|
||
|
||
emit endPointListUpdate(endPointList);
|
||
}
|
||
|
||
bool UsbHandler::closeDevice() {
|
||
if (handle) {
|
||
libusb_close(handle);
|
||
handle = nullptr;
|
||
LOG_DEBUG("设备关闭成功");
|
||
return true;
|
||
} else {
|
||
LOG_DEBUG("无打开的设备");
|
||
return false;
|
||
}
|
||
}
|