基于libusb的通信实例

2020-11-23

关键字:libusb收发


 

1、开发前的准备工作

 

在据笔者的另一篇博文  libusb库在嵌入式Linux平台上的移植流程   准备好环境并编译完成后即可以基于libusb库来开发快速USB通信程序了。

 
我们需要用到的编译产物文件有二:
1、libusb.h
2、libusb-1.0.so.0.2.0
它们都可以在libusb源码编译目录下找到。
 
准备好上面两个文件后即可以开始写自己的程序代码了。

 

 

2、使用libusb库功能的步骤

 

应用libusb库的功能之前要先对其初始化。

 

初始化的步骤主要分为五步:
1、配置用户信息;
2、初始化库;
3、寻找设备;
4、注册并占用设备;
5、通信。

 

第一步是配置你要通信的USB设备的PID/VID以及类别信息。

第二步直接调用接口等待结果即可。

第三步则是寻找匹配的设备与端点。

第四步是调用接口建立通信信道。这里要注意的是libusb库在同一时刻只允许创建一个通信信道,当一个USB设备成功与一个应用程序透过libusb绑定通信后即无法二次绑定通信,直至当前绑定注销。

第五步则是自行编写的代码。

 

 

3、关键函数

 

使用libusb库通信的核心接口就是IO函数了。在 libusb.h 中提供了三个同步的通信接口分别用于传输控制、中断与块数据:

1、libusb_control_transfer
2、libusb_interrupt_transfer
3、libusb_bulk_transfer
这三个函数均可用于读写,靠参数来控制数据的流动方向。
 
控制数据同步传送接口原型如下:
int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
    uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
    unsigned char *data, uint16_t wLength, unsigned int timeout);

 

中断数据同步传送接口原型如下:

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

 

块数据同步传送接口原型如下:

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 即是用于区分数据流动方向的,它们的数值如下:

块数据接收    0x83
块数据发送    0x02
中断数据接收     0x81
中断数据发送     0x01

 

另外,这两个函数中的 actual_length 是用于保存执行结果数据长度的。例如在发送时用于保存实际发送了多少字节,接收时保存实际接收到的字节数。

 

两个函数的最后一个参数 timeout 的值为0时表示持续阻塞直到有结果发生。正整数值则表示函数要阻塞多少毫秒。

 

 

4、实例

 

以下直接贴出一个最基本的示例程序的源码,希望可以给有需要的同学一个参考:

#include "libusb.h"

#define BULK_RECV_EP    0x83
#define BULK_SEND_EP    0x02
#define INT_RECV_EP     0x81
#define INT_SEND_EP     0x01

#define TRANSFER_TIMEOUT 0

#define PID 0x2710
#define VID 0x2766

typedef struct {
    unsigned int pid;
    unsigned int vid;
    unsigned char bInterfaceClass;
    unsigned char bInterfaceSubClass;
    unsigned char bmAttributes;
    unsigned char bInEndpointAddress;
    unsigned char bOutEndpointAddress;
    unsigned char bInterfaceNumber;
    libusb_device *dev;
    libusb_device **devs;
} usb_dev;

static libusb_device_handle* usb_handle;
static usb_dev udev;



/*
    根据PID与VID检查指定设备是否挂载。
*/
static int get_device_descriptor(struct libusb_device_descriptor *dev_desc, usb_dev* user_device)
{
    int rv = -2;
    int i = 0;

    libusb_device **devs;
    libusb_device *dev;

    rv = libusb_get_device_list(NULL, &devs);
    if (rv < 0)
        return rv;

    //遍历USB设备
    while ((dev = devs[i++]) != NULL) {
        rv = libusb_get_device_descriptor(dev, dev_desc);
        if(rv == 0) {
        }
    }

    i = 0;
    while ((dev = devs[i++]) != NULL) {
        rv = libusb_get_device_descriptor(dev,dev_desc);
        if(rv < 0) {
            return -1;
        }

        if(dev_desc->idProduct == user_device->pid && dev_desc->idVendor == user_device->vid)
        {
            user_device->dev = dev;
            user_device->devs = devs;

            return 0;
        }
    }
    
    return -2;
}

int match_with_endpoint(const struct libusb_interface_descriptor * interface, struct userDevice *user_device)
{
    int i;
    int ret=0;
    printf("bNumEndpoints:%d\n", interface->bNumEndpoints);
    for(i=0; i<interface->bNumEndpoints; i++)
    {
        if((interface->endpoint[i].bmAttributes&0x03)==user_device->bmAttributes) //transfer type :bulk ,control, interrupt
        {
            if(interface->endpoint[i].bEndpointAddress&0x80) //out endpoint & in endpoint
            {
               ret|=1;
               user_device->bInEndpointAddress = interface->endpoint[i].bEndpointAddress;
            }
            else
            {
               ret|=2;
               user_device->bOutEndpointAddress = interface->endpoint[i].bEndpointAddress;
            }
        }

     }

     if(ret==3)
     {
       return 1;
     }
     else
     {
         return 0;
      }
}

static int get_device_endpoint(struct libusb_device_descriptor *dev_desc, usb_dev* user_device)
{
    int rv = -2;
    int i,j,k;
    struct libusb_config_descriptor *conf_desc;
    unsigned char isFind = 0;
    
    for (i = 0; i < dev_desc->bNumConfigurations; i++)
    {
        if(user_device->dev != NULL)
            rv = libusb_get_config_descriptor(user_device->dev, i, &conf_desc);
        
        if(rv < 0) {
            return -1;
        }
        
        for (j = 0; j < conf_desc->bNumInterfaces; j++)
        {
            for (k=0; k < conf_desc->interface[j].num_altsetting; k++)
            {
                if(conf_desc->interface[j].altsetting[k].bInterfaceClass == user_device->bInterfaceClass)
                {
                    if(match_with_endpoint(&(conf_desc->interface[j].altsetting[k] ), user_device))
                    {
                        user_device->bInterfaceNumber = conf_desc->interface[j].altsetting[k].bInterfaceNumber;
                        libusb_free_config_descriptor(conf_desc);
                        rv = 0;
                        return rv;
                    }
                }
            }
        }
    }
    
    return -2;  //don't find user device
}


int main()
{
    usb_handle = NULL;

    struct libusb_device_descriptor udev_desc;

    //1. load user data.
    udev.pid = PID;
    udev.vid = VID;
    udev.bInterfaceClass = LIBUSB_CLASS_HID;
    udev.bInterfaceSubClass = LIBUSB_CLASS_HID;
    udev.bmAttributes = LIBUSB_TRANSFER_TYPE_INTERRUPT;
    udev.dev = NULL;

    //2. init libusb.
    int ret = libusb_init(NULL);
    if(ret < 0)
    {
        return -1;
    }

    //3. search for specified usb device.
    ret = get_device_descriptor(&udev_desc, &udev);
    if(ret < 0) {
        return -2;
    }

    ret = get_device_endpoint(&udev_desc, &udev);
    if(ret < 0) {
        return -3;
    }

    /*4.open device and start communication by usb*/
    //open the usb device
    usb_handle = libusb_open_device_with_vid_pid(NULL, udev.vid, udev.pid);
    if(usb_handle == NULL) {
        return -4;
    }

    ret = libusb_claim_interface(usb_handle, udev.bInterfaceNumber);
    if(ret < 0) {
        ret = libusb_detach_kernel_driver(usb_handle, udev.bInterfaceNumber);
        if(ret < 0) {
            return -5;
        }
        ret = libusb_claim_interface(usb_handle, udev.bInterfaceNumber);
        if(ret < 0)
        {
            return -6;
        }
    }

    //5,通信。
    //接收
    int rlen;
    unsigned char buf[64];
    int len = libusb_bulk_transfer(usb_handle, INT_RECV_EP, buf, len, &rlen, TRANSFER_TIMEOUT);
    //发送
    int wlen;
    unsigned char data[64];
    len = libusb_bulk_transfer(usb_handle, INT_SEND_EP, data, len, &wlen, TRANSFER_TIMEOUT);
    
    
    //6,注销
    libusb_close(usb_handle);
    libusb_release_interface(usb_handle, udev.bInterfaceNumber);
    libusb_free_device_list(udev.devs, 1);
    libusb_exit(NULL);
    usb_handle = NULL;
    
    return 0;
}

 

这份示例程序及依赖文件的目录结构如下图所示:

 

其编译命令如下:

gcc ddemo.c libusb-1.0.so.0.2.0

 

以上即是一个笔者实践过程中提炼出来的libusb应用示例,希望能够帮助到有需要的同学。 

 


 

posted @ 2020-11-23 19:15  大窟窿  阅读(8058)  评论(4编辑  收藏  举报