WinUSB是Windows操作系统提供的一种通用USB驱动程序,用于简化USB设备的开发和使用。它是一个用户模式驱动程序,可以在Windows XP及更高版本的操作系统上使用。WinUSB提供了一组API和工具,使开发人员能够与USB设备进行通信,包括数据传输和设备控制。

使用WinUSB进行批量传输(Bulk Transfer)的示例代码

#include <Windows.h>
#include <SetupAPI.h>
#include <winusb.h>
#include <iostream>

// USB设备的Vendor ID和Product ID
#define VENDOR_ID 0x1234
#define PRODUCT_ID 0x5678

// 批量传输管道的端点地址
#define BULK_IN_ENDPOINT 0x81
#define BULK_OUT_ENDPOINT 0x02

int main()
{
    // 初始化WinUSB库
    BOOL result = WinUsb_Initialize(NULL, NULL, NULL, NULL);
    if (!result)
    {
        std::cout << "Failed to initialize WinUSB." << std::endl;
        return 1;
    }

    // 枚举USB设备
    HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
    if (deviceInfoSet == INVALID_HANDLE_VALUE)
    {
        std::cout << "Failed to enumerate USB devices." << std::endl;
        WinUsb_Free(NULL);
        return 1;
    }

    // 遍历设备列表,查找指定的USB设备
    SP_DEVINFO_DATA deviceInfoData = { 0 };
    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    for (DWORD index = 0; SetupDiEnumDeviceInfo(deviceInfoSet, index, &deviceInfoData); ++index)
    {
        // 获取设备的USB描述符
        SP_DEVICE_INTERFACE_DATA interfaceData = { 0 };
        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfoData, &GUID_DEVINTERFACE_USB_DEVICE, 0, &interfaceData))
        {
            continue;
        }

        // 获取设备路径
        DWORD requiredSize = 0;
        SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL);
        PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);
        interfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
        if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &interfaceData, interfaceDetailData, requiredSize, NULL, NULL))
        {
            free(interfaceDetailData);
            continue;
        }

        // 打开设备
        HANDLE deviceHandle = CreateFile(interfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if (deviceHandle == INVALID_HANDLE_VALUE)
        {
            free(interfaceDetailData);
            continue;
        }

        // 获取WinUSB接口句柄
        WINUSB_INTERFACE_HANDLE winusbHandle = NULL;
        result = WinUsb_Initialize(deviceHandle, &winusbHandle);
        if (result)
        {
            // 获取USB设备的描述符
            USB_DEVICE_DESCRIPTOR deviceDescriptor;
            result = WinUsb_GetDescriptor(winusbHandle, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (PUCHAR)&deviceDescriptor, sizeof(deviceDescriptor), NULL);
            if (result)
            {
                // 检查Vendor ID和Product ID是否匹配
                if (deviceDescriptor.idVendor == VENDOR_ID && deviceDescriptor.idProduct == PRODUCT_ID)
                {
                    // 发送数据
                    UCHAR outBuffer[64] = { 0 }; // 要发送的数据
                    DWORD bytesTransferred = 0;
                    result = WinUsb_WritePipe(winusbHandle, BULK_OUT_ENDPOINT, outBuffer, sizeof(outBuffer), &bytesTransferred, NULL);
                    if (result)
                    {
                        std::cout << "Data sent successfully." << std::endl;
                    }
                    else
                    {
                        std::cout << "Failed to send data." << std::endl;
                    }

                    // 接收数据
                    UCHAR inBuffer[64] = { 0 }; // 用于接收数据
                    result = WinUsb_ReadPipe(winusbHandle, BULK_IN_ENDPOINT, inBuffer, sizeof(inBuffer), &bytesTransferred, NULL);
                    if (result)
                    {
                        std::cout << "Data received successfully." << std::endl;
                    }
                    else
                    {
                        std::cout << "Failed to receive data." << std::endl;
                    }
                }
            }

            // 关闭WinUSB接口
            WinUsb_Free(winusbHandle);
        }

        // 关闭设备句柄
        CloseHandle(deviceHandle);
        free(interfaceDetailData);
    }

    // 释放资源
    SetupDiDestroyDeviceInfoList(deviceInfoSet);
    WinUsb_Free(NULL);

    return ;
    }

示例代码展示了如何使用WinUSB进行批量传输(Bulk Transfer)。在示例代码中,我们首先初始化WinUSB库,然后通过SetupAPI枚举连接到计算机的USB设备,并查找与指定的Vendor ID和Product ID匹配的设备。

如果设备匹配成功,我们可以使用WinUsb_WritePipe函数发送数据,以及使用WinUsb_ReadPipe函数接收数据。在示例代码中,我们使用了BULK_OUT_ENDPOINT和BULK_IN_ENDPOINT来指定批量传输的输入和输出端点地址
根据自己的需求修改示例代码,例如更改发送和接收的数据缓冲区大小、使用异步传输等

winUSB应用程序的编写:

winUSB设备的初始化

   初始化时跟基他设备类型,find,open,注意除了注册接收回调函数外还要注册发送回调函数。最后必须先调用一下rt_device_read()给winUSB设备接收数据时传入接收数据使用的缓冲区,同时启动USB设备接收
   /* find and open command device */
    dev_name = “winUSB”
    client->device = rt_device_find(dev_name);
    
    if (client->device)
    {
        /* using the tx interrupt when uart is RS485 */
        open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR);
        
        RT_ASSERT(open_result == RT_EOK);
 
        rt_device_set_tx_complete(client->device, utc_d_tx_ind);
        rt_device_set_rx_indicate(client->device, utc_d_rx_ind);
        client->putc_package = client->utcA_package;
 
        /*wait read the winusb device success */
        while(rt_device_read(client->device, 0, client->putc_package, sizeof(client->utcA_package)) == 0)
        {
            rt_thread_mdelay(10);
        }
    }
    else
    {
        LOG_E("Not find the device(%s).", dev_name);
        result = -RT_ERROR;
    }

接收回调函数

USB设备接收到数据后,发送一个信号量给接收数据的线程通知数据处理。这个接收回调函数中使用双缓冲区,让接收数据与处理数据互不干扰

static rt_err_t utc_d_rx_ind(rt_device_t dev, rt_size_t size)
{
    utc_d_client_t client = &utc_d_client;
 
    if(client->package_len)
    {
        LOG_W("utc package overwrite!");
    }
    client->package_len = size;
 
    if(client->putc_package == client->utcA_package)
    {
        client->putc_package = client->utcB_package;
    }
    else
    {
        client->putc_package = client->utcA_package;
    }
    /*read the usb data next */
    rt_device_read(dev, 0, client->putc_package, sizeof(client->utcA_package));
 
    if(size)
    {
        
        /*release the sem */
        rt_sem_release(client->rx_notice);
    }
 
    return RT_EOK;
}
发送回调函数,usb设备发送成功后会调用发送回调函数,发送一个信号量,通知发送函数已经成功完成发送,这个功能非常重要,否则,USB设备无法正常工作。
static rt_err_t utc_d_tx_ind(rt_device_t dev, void *buffer)
{
    utc_d_client_t client = &utc_d_client;
 
    rt_sem_release(client->tx_notice);
    return RT_EOK;
}
usb设备发送函数通过rt_device_write函数把数据发送给usb设备驱动后,一定要等待发送完成才行。
static int utc_d_send(utc_d_client_t client, rt_uint8_t *send_data, rt_uint32_t send_len)
{
 
    /*send the packet counter    */
    client->send_packet_counter++;
 
    if(rt_device_write(client->device, 0, send_data, send_len) == send_len)
    {
        /*Must wait the usb send data finish */
        return rt_sem_take(client->tx_notice, RT_WAITING_FOREVER);
    }    
    else
    {
        return -RT_ERROR;
    }
    
}

USB传输:控制传输、bulk传输、iso传输、中断传输

USB一个传输可以分为多个事务,而一个事务分为3个Packet:令牌包(Token)、数据包、握手包
iso传输,没有握手包;
一个packet由同步域(SOP+SYNC)、包内容、包结束符(EOP)组成;
包内容=PID(8位)+目的地址域(11位)+帧号域(11位)+数据域+CRC(5位)
目的地址=设备地址(7位)+端点地址(4位),LS设备最多3个端点,FS/HS设备最多16个端点
PID=OUT/IN/SETUP时,该包为令牌包(Token),没有帧号和数据,令牌包总是由主机发出,PID为SETUP的令牌包仅用于控制传输;

PID=DATA0/DATA1/DATA2/DATAM时,为数据包,没有地址域和帧号域;

PID=ACK/NAK/STALL/NYET/ERR时,为握手包,只有PID域;

PID=SOF时,为SOF包,没有地址域、数据域
为了防止USB总线设备挂起,需要每隔一段时间就发送SOF包,主机每发一帧,帧号就加1,当帧号达到7FFH时,帧号归零,重新计数

握手包中:

ACK:传输正确完成;

NAK:设备暂时没有准备好接收数据,或没有准备好发送数据;

STALL:设备不能进行传输;

NYET/ERR:仅用于高速传输,设备没有准备好或出错

设备描述符

typedef struct _USB_DEVICE_DESCRIPTOR {
    UCHAR bLength;  //18
    UCHAR bDescriptorType;  //1
    USHORT bcdUSB;
    UCHAR bDeviceClass;
    UCHAR bDeviceSubClass;
    UCHAR bDeviceProtocol;//设备类型 音频类有控制、流,和MIDI流接口的子类代码
    UCHAR bMaxPacketSize0;//默认控制端点(端点0)上的数据包容量的最大值
    USHORT idVendor;
//    USB_DEVICE_CLASS_RESERVED 0 指出类代码存在于接口描述符中 
//USB_DEVICE_CLASS_AUDIO 1 操作模拟或数字音频、语音、和其它与声音相关的数字设备 
//USB_DEVICE_CLASS_COMMUNICATIONS 2 电讯设备,如调制解调器、电话、应答机,等等 
//USB_DEVICE_CLASS_HUMAN_INTERFACE 3 人类接口设备,如键盘、鼠标、麦克风,等等 
//USB_DEVICE_CLASS_MONITOR 4 显示器 
//USB_DEVICE_CLASS_PHYSICAL_INTERFACE 5 含有实时物理反馈的人类接口设备,如力反馈游戏杆 
//USB_DEVICE_CLASS_POWER 6 执行电源管理的人类接口设备,如电池、充电器,等等 
//USB_DEVICE_CLASS_PRINTER  7 打印机 
//USB_DEVICE_CLASS_STORAGE 8 大容量存储设备,如磁盘和CD-ROM 
//USB_DEVICE_CLASS_HUB 9 USB hubs 
//USB_DEVICE_CLASS_VENDOR_SPECIFIC 255 厂商定义的设备类
    USHORT idProduct;//厂商代码和厂商专用的产品标识
    USHORT bcdDevice;//设备的发行版本号(0x0100对应版本1.0)
    UCHAR iManufacturer;
    
    UCHAR iProduct;
    UCHAR iSerialNumber;//串描述符用人类可读的语言描述设备生产厂商、产品、和序列号
    UCHAR bNumConfigurations;  //该设备能实现多少种配置
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

DDK中的接口描述符结构定义如下:
配置描述符

typedef struct _USB_CONFIGURATION_DESCRIPTOR {
    UCHAR bLength;  //9
    UCHAR bDescriptorType;  //2
    USHORT wTotalLength;//该配置描述符长度加上该配置内所有接口和端点描述符长度的总和
    UCHAR bNumInterfaces;//配置有多少个接口
    UCHAR bConfigurationvalue;//配置的索引值
    UCHAR iConfiguration;//可选的串描述符索引
    UCHAR bmAttributes;//设备电源和其它特性的的位掩码
    UCHAR MaxPower;配置中的电源特性
  //  80h USB_CONFIG_BUS_POWERED 废弃 -- 应总为1 
//40h USB_CONFIG_SELF_POWERED 该配置为自供电 
//20h USB_CONFIG_REMOTE_WAKEUP 该配置有远程唤醒特征 
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
 
typedef struct _USB_INTERFACE_DESCRIPTOR {
    UCHAR bLength; //9
    UCHAR bDescriptorType;  //4
    UCHAR bInterfaceNumber;  //索引值 配置中的接口号从0开始
    UCHAR bAlternateSetting;  //索引值 替换设置也是从0开始的
    UCHAR bNumEndpoints;//接口有多少个端点
    UCHAR bInterfaceClass;
    UCHAR bInterfaceSubClass;
    UCHAR bInterfaceProtocol;  //接口提供的功能
    UCHAR iInterface;   //串描述符
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;

DDK中定义的端点描述符

typedef struct _USB_ENDPOINT_DESCRIPTOR {
UCHAR bLength; //7
UCHAR bDescriptorType; //5
UCHAR bEndpointAddress; //端点的方向性和端点号,如图11-11所示。//例如,地址值0x82指出该端点是一个端点号为2的IN端点,而0x02地//址指出一个端点号为2的OUT端点
UCHAR bmAttributes;//端点类型
// USB_ENDPOINT_TYPE_CONTROL 0 控制端点
//USB_ENDPOINT_TYPE_ISOCHRONOUS 1 等时端点
//USB_ENDPOINT_TYPE_BULK 2 批量端点
//USB_ENDPOINT_TYPE_INTERRUPT 3 中断端点
USHORT wMaxPacketSize; //传输的最大数据量
UCHAR bInterval; //定循检间隔时间 范围为1到255毫秒
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;

串描述符

使用Unicode编码

typedef struct _USB_STRING_DESCRIPTOR {
    UCHAR bLength;  //串数据长度
    UCHAR bDescriptorType;  //3
    WCHAR bString[1];  //串数据
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;

pyUSB的使用

import usb.core
import usb.util
 
dev =  usb.core.find(idVendor= 0x1234)
if dev is None:
    raise ValueError('Device not found')
print(dev)

USB数据的读写

import usb.core
import usb.util
import usb.backend.libusb1
import time
 
winusb = 0x1234
comusb = 0x10c4
mouseusb = 0x46d
dev = usb.core.find(idVendor=winusb)
print(dev)
 
configuration = dev.get_active_configuration()
 
dev.set_configuration()
 
cfg_ = configuration[(0, 0)]
 
# 0x2 写入节点
outPoint = usb.util.find_descriptor(
    cfg_,
    # match the first OUT endpoint
    custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
 
# 0x81 读取节点
inPoint = usb.util.find_descriptor(
    cfg_,
    # match the first IN endpoint
    custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
 
#查询版本,型号
msg = [0xa8,0x01,0x02,0x02,0x01,0x00,0x00,0x24]
msg[-1] = sum(msg[1:-1]) & 0xff
r = dev.write(outPoint.bEndpointAddress, msg, 1000)
a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
print("query ack:", end="")
for i in a:
    print("%02X "%(i),end="")
print("end")
 
#启动接收
msg = [0xa8,0x01,0x03,0x02,0x03,0x00,0x05,0x0F,0x00,0x00,0x00,0x00,0x24]
time_stamp = int(time.time()) + 8*3600
msg[-2] = time_stamp & 0xff
msg[-3] = (time_stamp >> 8) & 0xff
msg[-4] = (time_stamp >> 16) & 0xff
msg[-5] = (time_stamp >> 24)& 0xff
 
msg[-1] = sum(msg[1:-1]) & 0xff
r = dev.write(outPoint.bEndpointAddress, msg, 1000)
a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
print("start ack:", end="")
for i in a:
    print("%02X "%(i),end="")
print("end")
 
for j in range(5):
    try:
        a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
        print("read:", end="")
        for i in a:
            print("%02X "%(i),end="")
        print(" end!")
    except usb.core.USBTimeoutError:
        pass
    except usb.core.USBError:
        print("usbError")
        break
    except Exception as e:
        print("read error!",e)
                  
print("send over")

USB读写异常的处理
dev.read会返回异常,usb.core.USBTimeoutError是超时异常,即没有读到从机的数据,此时可以继续进行读取数据。 usb.core.USBError发生在从机与主机连接断开时,此异常可以识别USB设备断开

获取USB设备信息列表

Qt驱动USB设备的方法:

  • 找设备厂商要动态库和接口文档;
  • 找对应USB设备的Qt库,eg:QCamera、QPrinter等
  • USB转串口,使用QtSerialPort;
  • 使用第三方QtUSB库(Qt本身没有封装USB的库);
  • Qt + windows API
    .pro
unix|win32: LIBS += -lsetupapi

.h

#ifndef USBPRINTER_H
#define USBPRINTER_H

#include <QWidget>
#include <windows.h>
#include <string>
#include <IOSTREAM>
#include <winioctl.h>
#include <setupapi.h>
#include <stdio.h>
#include <tchar.h>
#include <QString>

#endif // USBPRINTER_H

  1. 获取设备信息GetDevicePath,如"\?\usb#vid_8087&pid_0aaa#5&21cd2d89&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed}";设备信息如下:
    设备ID:8087
    厂商ID:0aaa
    设备序列号:5&21cd2d89&0
  2. 再将指定设备信息完整的传入初始化函数InitPort的第一个参数;
  3. 最后就是简单的按照对待文件的方式处理该设备;
//获取设备信息
bool USBPrinter::GetDevicePath(QStringList &USBDeviceList, QString &p_sErrMsg)
{
    const GUID GUID_DEVINTERFACE_LIST[] =
    {
        { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }, //USB设备的GUID
        { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } }
    };
    LPGUID lpGuid = (LPGUID)&GUID_DEVINTERFACE_LIST;
    HDEVINFO hDevInfoSet;
    SP_DEVINFO_DATA spDevInfoData;
    SP_DEVICE_INTERFACE_DATA ifData;
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
    int iTotle;
    bool bResult;

    // 取得一个该GUID相关的设备信息集句柄
    hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, //class GUID
                                        NULL,   //无关键字
                                        NULL,   //不指定父窗口句柄
                                        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);//目前存在的设备

    //失败
    if(hDevInfoSet == INVALID_HANDLE_VALUE)
    {
        p_sErrMsg = "获取设备失败";
        return false;
    }

    //申请设备接口数据空间
    pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
    pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    iTotle = -1;
    bResult = true;

    //设备序号=0,1,2... 逐一测试设备接口,到失败为止
    while(bResult)
    {
        iTotle++;
        spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        // 枚举符合该GUID的设备接口
        bResult = ::SetupDiEnumDeviceInfo(
                    hDevInfoSet,     // 设备信息集句柄
                    (ULONG)iTotle,   // 设备信息集里的设备序号
                    &spDevInfoData); // 设备接口信息

        if(bResult)
        {
            DWORD DataT ;
            TCHAR buf[MAX_PATH];
            DWORD nSize = 0;
            wstring wsName=QString("Unknown").toStdWString();

            //get Friendly Name or Device Description
            if( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
                                                  SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize) )
            {

            }
            else if( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
                                                         SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize) )
            {

            }
            else
            {
                lstrcpy(buf,wsName.c_str());
            }

            QString sTemp = QString::fromWCharArray(buf);
            //是否为目标设备
            if(sTemp == "xxx")
                continue;

            ifData.cbSize = sizeof(ifData);

            //枚举符合该GUID的设备接口
            bResult = ::SetupDiEnumDeviceInterfaces(
                        hDevInfoSet,     //设备信息集句柄
                        NULL,            //不需额外的设备描述
                        lpGuid,          //GUID
                        (ULONG)iTotle,   //设备序号
                        &ifData);        //设备接口信息

            if(bResult)
            {
                //取得该设备接口的细节(设备路径)
                bResult = SetupDiGetInterfaceDeviceDetail(
                            hDevInfoSet,    // 设备信息集句柄
                            &ifData,        // 设备接口信息
                            pDetail,        // 设备接口细节(设备路径)
                            INTERFACE_DETAIL_SIZE,    // 输出缓冲区大小
                            NULL,           // 不需计算输出缓冲区大小(直接用设定值)
                            NULL);          // 不需额外的设备描述

                if(bResult)
                {
                    //复制设备路径到输出缓冲区
                    USBDeviceList.append(QString::fromWCharArray(pDetail->DevicePath));
                }
            }
        }
    }
    //释放设备接口数据空间
    ::GlobalFree(pDetail);
    //关闭设备信息集句柄
    ::SetupDiDestroyDeviceInfoList(hDevInfoSet);

    return true;
}

//初始化USB端口
bool USBPrinter::InitPort(QString p_sUSBPort, QString &p_sErrMsg)
{
    //获取句柄
    wstring wsPort = p_sUSBPort.toStdWString();
    m_hPort = CreateFile(wsPort.c_str(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

    //打开端口失败
    if(m_hPort == INVALID_HANDLE_VALUE)
    {
        p_sErrMsg = "打开端口失败";
        return false;
    }
    else
    {
        //设置端口缓冲
        SetupComm(m_hPort, 1024, 1024);

        //设定通讯端口超时参数
        COMMTIMEOUTS tmouts;
        tmouts.ReadIntervalTimeout = 100;
        tmouts.ReadTotalTimeoutMultiplier = 100;
        tmouts.ReadTotalTimeoutConstant = 100;
        tmouts.WriteTotalTimeoutConstant = 100;
        tmouts.WriteTotalTimeoutMultiplier = 100;
        SetCommTimeouts(m_hPort, &tmouts);

        //设定通讯端口通讯参数
        DCB dcb;
        bool bol = true;
        bol = GetCommState(m_hPort, &dcb);

        //配置串口
        bol = SetCommState(m_hPort, &dcb);

        // 清除通讯端口缓存
        PurgeComm(m_hPort,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);

        // 初始化重叠IO对象
        OVERLAPPED m_OverlappedRead;
        OVERLAPPED m_OverlappedWrite;
        HANDLE m_hStopCommEvent;
        HANDLE m_hDataReady;
        memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
        m_OverlappedRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
        m_OverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

        // 初始化事件对象
        m_hStopCommEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);

        //初始化
        DWORD iBytesLength;
        char chInitCode[] = "\x0D\x1B\x40";
        if(!WriteFile(m_hPort, chInitCode, (DWORD)3L, &iBytesLength, NULL))
        {
            p_sErrMsg = "初始化失败";
            return false;
        }
    }
    return true;
}

//向设备写数据
int USBPrinter::WriteData(QString p_sInput)
{
    DWORD dwWrite;
    string sInput = p_sInput.toLocal8Bit().data();

    return WriteFile(m_hPort, sInput.c_str(), (DWORD)sInput.length(), &dwWrite, NULL);
}

bool USBPrinter::ClosePort()
{
    CloseHandle(m_hPort);//关闭端口
    return true;
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐