备注:
//主要是三步,调用三个函数BeginDataXfer,WaitForXfer,FinishDataXfer。
//按照手册上说的,BeginDataXfer发起异步传输,并且立即返回。
//也就是说,发起此次的length后,并不会等length传输完,而是立即开始下一次length字节传输
上位机与下位机双向传输通信,亲测可用
CyUSBComm.h
#ifndef CYUSBCOMM_H
#define CYUSBCOMM_H
#include "cyusbcomm_global.h"
#include <QByteArray>
#include <QMutex>
#include <QThread>
typedef void (*RecvCallback)(unsigned char* buffer, long length);
class CCyUSBDevice;
class CYUSBCOMM_EXPORT CyUSBComm: public QThread
{
public:
CyUSBComm();
~CyUSBComm();
public:
bool initUsb();
void uninitUsb();
bool resetUsb();
bool sendData(const QByteArray& byteArray);
bool recvData(unsigned char* buffer, long& length);
/*the asynchronous BeginDataXfer / WaitForXfer / FinishDataXfer methods
allow queuing of multiple data transfer requests on a single endpoint,
thus enabling data streaming from the application level.
异步BeginDataXfer / WaitForXfer / FinishDataXfer方法
允许在单个端点上排队进行多个数据传输请求;
从而支持来自应用程序级别的数据流
*/
void startDataStream();
void stopDataStream();
void setRecvCallback(RecvCallback callback) { m_recvCallback = callback; }
void GetUSBDeviceInfo(QString& info);
private:
void run();
private:
CCyUSBDevice* m_USBDevice; //定义usb设备
bool m_isUsbInit;
QMutex m_sendMutex;
RecvCallback m_recvCallback;
bool m_isRun;
};
#endif // CYUSBCOMM_H
CyUSBComm.cpp
#include "cyusbcomm.h"
#include <Windows.h>
#include <time.h>
#include "CyAPI.h"
#include "qslog.h"
static const int TIMEOUT_TRANSFER_MILLI_SEC = 1500;
static const int QUEUE_SIZE = 16;
static const int PACKETS_PER_XFER = 6;
#pragma comment(lib,"setupapi.lib") //hidapi所需的lib环境,没有此文件会导致链接错误
#pragma comment(lib,"legacy_stdio_definitions.lib") // error LNK2019: 无法解析的外部符号 sprintf,用vs2013就没事
#pragma comment(lib,"../Lib/CyAPI.lib")
// #ifdef _DEBUG
// #pragma comment(lib,"../Lib/QsLog_d.lib")
// #else
#pragma comment(lib,"../Lib/QsLog.lib")
//#endif
CyUSBComm::CyUSBComm()
: m_isUsbInit(false)
, m_USBDevice(nullptr)
{
}
CyUSBComm::~CyUSBComm()
{
}
bool CyUSBComm::initUsb()
{
if (m_isUsbInit)
{
return true;
}
m_USBDevice = new CCyUSBDevice();
//打开0号设备
if (!(m_USBDevice->Open(0)))
{
return false;
}
m_isUsbInit = true;
return true;
}
void CyUSBComm::uninitUsb()
{
if (!m_isUsbInit)
{
return;
}
if (m_USBDevice->IsOpen())
{
m_USBDevice->Close();
}
m_isUsbInit = false;
}
bool bulkTransfer(CCyBulkEndPoint* pBulkEp, OVERLAPPED& overlapped, unsigned char* buffer, long& length)
{
//主要是三步,调用三个函数BeginDataXfer,WaitForXfer,FinishDataXfer。
//按照手册上说的,BeginDataXfer发起异步传输,并且立即返回。
//也就是说,发起此次的length后,并不会等length传输完,而是立即开始下一次length字节传输
BYTE* pContext = pBulkEp->BeginDataXfer(buffer, length, &overlapped); //开始下一次传输
//异步传输最大等待时间
if (!pBulkEp->WaitForXfer(&overlapped, TIMEOUT_TRANSFER_MILLI_SEC))
{
TRACEINFO << QString("WaitForXfer error %1").arg(pBulkEp->LastError);
return false;
}
//到这里才开始真正的写内存,将读到的数写到缓冲区buffer中
if (pBulkEp)
{
if (pContext)
{
if (pBulkEp->FinishDataXfer(buffer, length, &overlapped, pContext)) //关闭软件该函数造成崩溃
{
return true;
}
}
}
TRACEINFO << QString("FinishDataXfer error %1").arg(pBulkEp->LastError);
return false;
}
bool CyUSBComm::recvData(unsigned char* buffer, long& length)
{
if (!m_isUsbInit)
return false;
CCyBulkEndPoint* pBulkEpIn = m_USBDevice->BulkInEndPt;
if (pBulkEpIn == NULL)
return false;
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, L"CYUSB_IN");
bool ret = bulkTransfer(pBulkEpIn, overlapped, buffer, length);
CloseHandle(overlapped.hEvent);
return ret;
}
void CyUSBComm::startDataStream()
{
m_isRun = true;
QThread::start();
}
void CyUSBComm::stopDataStream()
{
m_isRun = false;
quit();
wait();
}
void CyUSBComm::run()
{
CCyBulkEndPoint* pBulkEpIn = m_USBDevice->BulkInEndPt;
if (pBulkEpIn == NULL)
return;
long xferSize = pBulkEpIn->MaxPktSize * PACKETS_PER_XFER;
pBulkEpIn->SetXferSize(xferSize);
PBYTE* buffersIn = new PBYTE[QUEUE_SIZE];
PBYTE* contextIn = new PBYTE[QUEUE_SIZE];
OVERLAPPED overlapped[QUEUE_SIZE];
for (int i = 0; i < QUEUE_SIZE; i++)
{
buffersIn[i] = new BYTE[xferSize];
memset(buffersIn[i], 0, xferSize);
overlapped[i].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
for (int i = 0; i < QUEUE_SIZE; i++)
{
contextIn[i] = pBulkEpIn->BeginDataXfer(buffersIn[i], xferSize, &overlapped[i]);
}
int index = 0;
long readLength = xferSize;
while (m_isRun)
{
if (!pBulkEpIn->WaitForXfer(&overlapped[index], TIMEOUT_TRANSFER_MILLI_SEC))
{
pBulkEpIn->Abort();
if (pBulkEpIn->LastError == ERROR_IO_PENDING)
WaitForSingleObject(overlapped[index].hEvent, TIMEOUT_TRANSFER_MILLI_SEC);
}
if (pBulkEpIn->FinishDataXfer(buffersIn[index], readLength, &overlapped[index], contextIn[index]))
{
m_recvCallback(buffersIn[index], readLength);
}
// else
// TRACEINFO << QString("CyUSBComm::run FinishDataXfer error %1").arg(pBulkEpIn->LastError);
contextIn[index] = pBulkEpIn->BeginDataXfer(buffersIn[index], xferSize, &overlapped[index]);
++index;
if (index >= QUEUE_SIZE)
{
index = 0;
}
}
pBulkEpIn->Abort();
for (int i = 0; i < QUEUE_SIZE; i++)
{
CloseHandle(overlapped[i].hEvent);
delete[] buffersIn[i];
}
delete[] buffersIn;
delete[] contextIn;
}
bool CyUSBComm::sendData(const QByteArray& byteArray)
{
QMutexLocker locker(&m_sendMutex);
if (!m_isUsbInit)
return false;
CCyBulkEndPoint* pBulkEpOut = m_USBDevice->BulkOutEndPt;
if (pBulkEpOut == NULL)
return false;
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, L"CYUSB_OUT");
long length = byteArray.size();
PBYTE buffer = (PBYTE)byteArray.data();
bool ret = bulkTransfer(pBulkEpOut, overlapped, buffer, length);
CloseHandle(overlapped.hEvent);
if (ret)
TRACEINFO << "sendData: " + QString::fromLocal8Bit(byteArray.toHex());
else
TRACEINFO << "sendData failed: " + QString::fromLocal8Bit(byteArray.toHex());
return ret;
}
bool CyUSBComm::resetUsb()
{
//可以清空usb芯片中缓存数据
return m_USBDevice->Reset();
}
void CyUSBComm::GetUSBDeviceInfo(QString& info)
{
if (!m_USBDevice)
return;
int devices = m_USBDevice->DeviceCount();
if (!(m_USBDevice->IsOpen()))
return;
int venID = m_USBDevice->VendorID;
int proID = m_USBDevice->ProductID;
QString name = QString(m_USBDevice->DeviceName);
auto is_high_speed = m_USBDevice->bHighSpeed;
auto is_super_speed = m_USBDevice->bSuperSpeed;
int usb_bcd = m_USBDevice->BcdUSB;
QString usb_type;
switch (usb_bcd)
{
case 0x0200:
usb_type = "usb 2.0";
break;
case 0x0210:
usb_type = "usb 2.1";
break;
case 0x0250:
usb_type = "usb 2.5";
break;
case 0x0300:
usb_type = "usb 3.0";
break;
case 0x0310:
usb_type = "usb 3.1";
break;
case 0x0320:
usb_type = "usb 3.2";
break;
default:
break;
}
info = name + "/" + usb_type;
QString usb_info;
usb_info += QString("DeviceName:%1 ").arg(name);
usb_info += QString("VendorID:%1 ").arg(venID);
usb_info += QString("ProductID:%1 ").arg(proID);
usb_info += QString("UsbType:%1 ").arg(usb_type);
usb_info += QString("bHighSpeed:%1 ").arg(is_high_speed?"true":"false");
usb_info += QString("bSuperSpeed:%1 ").arg(is_super_speed ? "true" : "false");
OUTPUTDEBUG << usb_info;
}