libusb开源库简单用法

官网:https://libusb.info
github:https://github.com/libusb/libusb

基于libusb,我们可以不用关心操作系统平台的差异化,编写统一的usb设备通讯代码。
鉴于网上搜索到的很多资料都偏旧,大多都是基于libusb0.x版本,其API与官方最新的libusb1.x差异较大,不方便学习和理解,所以这里我本着简单实用不发散的原则,重点围绕如何使用libusb打开和读写设备,简单地过一下相关的函数用法。

一个例子

代码如下:

#include 
#include 

// 此入头文件
#include 

int main(int argc, char *argv[])
{
    // 初使化上下文
    int nRet = libusb_init(NULL);
    if (nRet < 0)
    {
        printf("libusb_init(NULL) failed:[%s] \n", libusb_strerror(nRet));
        return -1;
    }

    printf("libusb_init(NULL) ok \n");

    // 打开指定厂商的某类产品
    libusb_device_handle* pHandle = libusb_open_device_with_vid_pid(NULL, 0x0483, 0x5750);
    if (pHandle == NULL)
    {
        printf("libusb_open_device_with_vid_pid(0x0483, 0x5750) failed \n");
        libusb_exit(NULL);
        return -1;
    }

    printf("libusb_open_device_with_vid_pid(0x0483, 0x5750) ok \n");

    // 声明使用第1个接口
    nRet = libusb_claim_interface(pHandle, 0);
    if (nRet < 0)
    {
        printf("libusb_claim_interface(0) failed:[%s] \n", libusb_strerror(nRet));
        libusb_close(pHandle);
        libusb_exit(NULL);
        return -1;
    }

    printf("libusb_claim_interface(0) ok \n");

    // 向指定端点发送数据
    char sBuf[] = "1234567890";
    int nActualBytes = 0;
    nRet = libusb_bulk_transfer(pHandle, 0x01, (unsigned char *)sBuf, strlen(sBuf), &nActualBytes, 1000);
    if (nRet < 0)
    {
        printf("libusb_bulk_transfer(0x01) write failed:[%s] \n", libusb_strerror(nRet));
        libusb_release_interface(pHandle, 0);
        libusb_close(pHandle);
        libusb_exit(NULL);
        return -1;
    }

    printf("libusb_bulk_transfer(0x01) write size:[%d] \n", nActualBytes);

    // 从指定端点接收数据
    char sBuf2[128] = {0};
    nActualBytes = 0;
    nRet = libusb_bulk_transfer(pHandle, 0x81, (unsigned char *)sBuf2, sizeof(sBuf2), &nActualBytes, 1000);
    if (nRet < 0)
    {
        printf("libusb_bulk_transfer(0x81) read failed:[%s] \n", libusb_strerror(nRet));
        libusb_release_interface(pHandle, 0);
        libusb_close(pHandle);
        libusb_exit(NULL);
        return -1;
    }

    printf("libusb_bulk_transfer(0x81) read size:[%d] \n", nActualBytes);

    // 释放第1个接口
    libusb_release_interface(pHandle, 0);

    // 关闭设备
    libusb_close(pHandle);

    // 释放上下文
    libusb_exit(NULL);

    return 0;
}

基本上只需要用到上面的这几个接口,就能完成对USB设备的简单读写操作,考虑到实际项目中大多会使用专门的线程来负责读写,虽然那样代码组织结构上会变得更加复杂,但是对于基本USB读写来说,本质并没有改变。

涉及的主要接口:

初使化上下文:

int LIBUSB_CALL libusb_init(libusb_context **ctx);

上下文是在1.x版本出现的,它将一个完整的使用环境隔离起来,使用环境包含了很多复杂的结构,比如日志级别、回调、工作线程、定时器、互斥锁等等,多个上下文允许多个使用环境在互不干绕的情况下同时工作。一般情况下,我们不需要显示指定上下文参数,默认传NULL即可,它表示我们只使用默认的全局上下文。

释放上下文:

void LIBUSB_CALL libusb_exit(libusb_context *ctx);

在程序退出时,或者明确不需要再使用libusb的接口了,调用本函数完成内部资源释放。同样的,如果存在多个上下文,请传入具体的参数表示要释放哪个上下文,否则传入NULL即可。

解释错误字符串:

const char * LIBUSB_CALL libusb_strerror(int errcode);

编译具体的错误码,返回静态的错误描述指针。

根据厂商ID和产品ID打开指定设备:

libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);

对每个USB设备来说,有两个重要的参数:厂商ID和产品ID,这是两个16位的整数,通过它们可以找到指定的设备,返回设备的操作句柄。

关闭指定设备:

void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);

在使用完设备后,调用本接口关闭它,并且释放对应的资源。

对指定设备声明使用哪个接口:

int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev_handle,
int interface_number);

打开设备成功后,在向设备发起操作前,需要申明使用哪个设备接口,这里的接口指的是USB架构中的一个概念,因为收发数据是对应端点的,而端点又附属于某个接口,所以必须要声明设备接口,才能在收发时定位到端点。

对指定设备释放哪个接口:

int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev_handle,
int interface_number);

在完成收发操作后,或者需要切换设备的其它接口时,调用本函数关闭已经打开的设备接口。

对指定设备发起同步传输操作:

int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *data, int length,
int *actual_length, unsigned int timeout);

这里是批量传输,使用它可以同时支持收发操作。那么怎么区分接收和发送呢?根据endpoint这个参数!
按照USB的体系结构,在设备的每个接口上,至少存在两个端点,每个端点只能支持单向操作,具体端点的地址随设备而定,在本例中,接收端点是0x81,发送端点是0x01。

你可能感兴趣的:(libusb开源库简单用法)