windows上,在c++/qt中使用CyAPI操作USB设备驱动,多线程使用CCyUSBDevice,异步传输

备注
//主要是三步,调用三个函数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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用 CyAPI 库在 Linux 上编写一个使用 Cypress USB 设备驱动程序时,您可以按照以下步骤进行: 步骤 1: 安装 CyAPI 库和驱动程序 首先,从 Cypress 官方网站下载适用于 Linux 的 CyAPI 库和驱动程序。然后,按照提供的安装说明进行安装。 步骤 2: 创建 C++ 项目 在 Linux 上创建一个新的 C++ 项目,可以使用您喜欢的集成开发环境(如 Eclipse、Code::Blocks 等)或者使用命令行工具。 步骤 3: 包含头文件和链接库 在您的 C++ 代码,包含适当的 CyAPI 头文件,并在编译时链接 CyAPI 库。例如: ```cpp #include <cyapi.h> // 在编译时链接 CyAPI 库 // g++ -o your_program your_program.cpp -lcyusb ``` 步骤 4: 初始化和打开设备 使用 CyAPI 的函数来初始化和打开 Cypress USB 设备。例如: ```cpp CCyUSBDevice usbDevice; // 初始化库 CyUSB_Init(); // 打开设备 if (!usbDevice.IsOpen()) { if (!usbDevice.Open(0)) { // 打开设备失败,处理错误 // ... } } ``` 步骤 5: 与设备进行通信 使用 CyAPI 的函数来与 Cypress USB 设备进行数据的读写和控制操作。例如: ```cpp unsigned char buffer[64]; long bytesRead = 0; // 读取数据 if (!usbDevice.BulkInEndPt->XferData(buffer, sizeof(buffer), bytesRead)) { // 读取数据失败,处理错误 // ... } // 写入数据 if (!usbDevice.BulkOutEndPt->XferData(buffer, sizeof(buffer), bytesRead)) { // 写入数据失败,处理错误 // ... } ``` 步骤 6: 清理和关闭设备 在程序结束时,确保清理和关闭 Cypress USB 设备。例如: ```cpp // 关闭设备 usbDevice.Close(); // 清理库 CyUSB_Exit(); ``` 这是一个简单的示例,您可以根据您的具体需求和 Cypress USB 设备的功能进行进一步的开发和扩展。请确保按照 CyAPI 文档提供的函数和方法来正确地使用库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空上的鲸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值