302 lines
9.8 KiB
C++
302 lines
9.8 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)
|
|
{
|
|
if (handle == nullptr) {
|
|
emit errorOccurred("No device handle.");
|
|
return false;
|
|
}
|
|
|
|
int actualLength;
|
|
int status = libusb_bulk_transfer(handle, endpoint, data, length, &actualLength, 1000);
|
|
if (status < 0) {
|
|
emit errorOccurred("Bulk transfer failed.");
|
|
return false;
|
|
}
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// 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. 提交传输
|
|
int status = libusb_submit_transfer(transfer);
|
|
if (status < 0) {
|
|
emit errorOccurred("Failed to submit async transfer.");
|
|
libusb_free_transfer(transfer);
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|