windows USB进行USB开发
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
- 获取设备信息GetDevicePath,如"\?\usb#vid_8087&pid_0aaa#5&21cd2d89&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed}";设备信息如下:
设备ID:8087
厂商ID:0aaa
设备序列号:5&21cd2d89&0 - 再将指定设备信息完整的传入初始化函数InitPort的第一个参数;
- 最后就是简单的按照对待文件的方式处理该设备;
//获取设备信息
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;
}
更多推荐
所有评论(0)