zoukankan      html  css  js  c++  java
  • libusb 批传输的使用方法

    概述

    libusb是开发与USB外围设备通讯应用程序的好帮手,其API精益且功能强大,完备内容可以查看接口文档和库提供的examples示例程序。

    自己使用较多的是USB批量传输类型,在此记录下有关批量传输通讯需要的一些步骤。代码适用于存在批量传输端点的USB设备。

    数据结构

    1. 查找设备的标识
    struct bulkusbid 
    {
    	unsigned short vid;
    	unsigned short pid;
    };
    
    1. 一些必须参数
    struct bulkusbdev
    {
    	libusb_device_handle* handle;
    	uint8_t endpoint_in;
    	uint8_t endpoint_out;
    	uint8_t bus;
    	uint8_t addr;
    	int nb_ifaces;
    };
    

    初始化和退出

    int bulkusb_init()
    {
    	return libusb_init(NULL);
    }
    
    void bulkusb_exit()
    {
    	libusb_exit(NULL);
    }
    

    查找设备

    同一产品多个设备它们的pid、vid都是一样的,这里获取这个id下的所有设备以备选择。

    int bulkusb_get_list(struct bulkusbdev dev_list[], int dev_max_cnt, struct bulkusbid id_list[], unsigned int id_cnt)
    {
    	int dev_cnt = 0;
    	struct libusb_device_descriptor desc;
    	libusb_device** devs;
    	ssize_t cnt;
    	int r, i;
    	unsigned int j;
    
    	cnt = libusb_get_device_list(NULL, &devs);
    	if (cnt < 0)
    		return (int)cnt;
    
    	for (i = 0; devs[i]; ++i)
    	{
    		if (dev_cnt >= dev_max_cnt)
    		{
    			break;
    		}
    
    		r = libusb_get_device_descriptor(devs[i], &desc);
    		if (r < 0)
    		{
    			fprintf(stderr, "failed to get device descriptor");
    			return r;
    		}
    
    		for (j = 0; j < id_cnt; j++)
    		{
    			if (id_list[j].vid == desc.idVendor &&
    				id_list[j].pid == desc.idProduct)
    			{
    				dev_list[dev_cnt].bus = libusb_get_bus_number(devs[i]);
    				dev_list[dev_cnt].addr = libusb_get_device_address(devs[i]);
    				dev_cnt++;
    			}
    		}
    	}
    
    	libusb_free_device_list(devs, 1);
    
    	return dev_cnt;
    }
    

    打开设备

    这部分代码主要有以下作用:

    1. 获取批量读写所需的必须参数 句柄输入端点输出端点
    2. 清除端点的暂停标志并重新;
    3. 声明接口,这些接口关闭时要释放;
    4. 重新初始化设备;

    这里获取端点需要注意的几点是:

    1. 只查找第一个设备配置描述符;
    2. 只查找厂商自定义类型接口或者CDC类型接口;
    3. 只使用找到的第一个输入输出端点;
    4. 如果已知输入输出端点,也可以直接写定它们的值,不使用查找的方法;
    int bulkusb_open(struct bulkusbdev* bdev)
    {
    	libusb_device** devs;
    	ssize_t cnt;
    	int r, i;
    
    	cnt = libusb_get_device_list(NULL, &devs);
    	if (cnt < 0)
    	{
    		printf("
    
    libusb error: %s
    ", libusb_strerror((enum libusb_error)cnt));
    		return (int)cnt;
    	}
    
    	libusb_device* dev = NULL;
    	libusb_device_handle* handle = NULL;
    
    	for (i = 0; devs[i]; ++i)
    	{
    		dev = devs[i];
    		if (bdev->bus == libusb_get_bus_number(devs[i])
    			&& bdev->addr == libusb_get_device_address(devs[i]))
    		{
    			//获得句柄
    			if (1)
    			{
    				r = libusb_open(dev, &handle);
    				if (LIBUSB_SUCCESS != r)
    				{
    					libusb_free_device_list(devs, 1);
    					printf("
    
    libusb error: %s
    ", libusb_strerror((enum libusb_error)r));
    					return r;
    				}
    				bdev->handle = handle;//赋值
    			}
    
    			//获得通讯端点并声明内核接口
    			if (1)
    			{
    				int i, j, k;
    				struct libusb_config_descriptor* conf_desc;
    				const struct libusb_endpoint_descriptor* endpoint;
    				uint8_t endpoint_in = 0, endpoint_out = 0;	// default IN and OUT endpoints
    				int iface, nb_ifaces;
    				uint8_t interfaceClass;
    
    				libusb_get_config_descriptor(dev, 0, &conf_desc);//uint8_t config_index = 0;
    				nb_ifaces = conf_desc->bNumInterfaces;
    				bdev->nb_ifaces = nb_ifaces;//赋值
    				for (i = 0; i < nb_ifaces; i++) {
    					for (j = 0; j < conf_desc->interface[i].num_altsetting; j++) {
    						//只获取接口类别为:厂商自定义类(0xFF)和CDC数据类(0xA)
    						interfaceClass = conf_desc->interface[i].altsetting[j].bInterfaceClass;
    						if (interfaceClass != 0xFF && interfaceClass != 0x0A){
    							continue;
    						}
    						for (k = 0; k < conf_desc->interface[i].altsetting[j].bNumEndpoints; k++) {
    							struct libusb_ss_endpoint_companion_descriptor* ep_comp = NULL;
    							endpoint = &conf_desc->interface[i].altsetting[j].endpoint[k];
    							// Use the first bulk IN/OUT endpoints as default for testing
    							if ((endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) & (LIBUSB_TRANSFER_TYPE_BULK)) {//只获取批量传输端点
    								if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
    									if (!endpoint_in)
    									{
    										endpoint_in = endpoint->bEndpointAddress;
    										bdev->endpoint_in = endpoint_in;//赋值
    										libusb_clear_halt(handle, bdev->endpoint_in);//清除暂停标志
    									}
    								}
    								else {
    									if (!endpoint_out)
    									{
    										endpoint_out = endpoint->bEndpointAddress;
    										bdev->endpoint_out = endpoint_out;//赋值
    										libusb_clear_halt(handle, bdev->endpoint_out);
    									}
    								}
    							}
    						}
    					}
    				}
    
    				libusb_free_config_descriptor(conf_desc);
    
    				libusb_set_auto_detach_kernel_driver(handle, 1);
    				for (iface = 0; iface < nb_ifaces; iface++)
    				{
    					r = libusb_claim_interface(handle, iface);
    					if (r != LIBUSB_SUCCESS) {
    						printf("   Failed.
    ");
    					}
    				}
    			}
    		}
    	}
    
    	libusb_free_device_list(devs, 1);
    
    	if (bdev->endpoint_in == 0 || bdev->endpoint_out == 0)
    	{
    		printf("*   Failed:endpoint_in or endpoint_out is NULL!
    ");
    		return -99;
    	}
    	//重新初始化
    	libusb_reset_device(bdev->handle);
    	return 0;
    }
    
    

    关闭设备

    int bulkusb_close(struct bulkusbdev* bdev)
    {
    	if (bdev->handle)
    	{
    		int iface;
    		for (iface = 0; iface < bdev->nb_ifaces; iface++) {
    			printf("Releasing interface %d...
    ", iface);
    			libusb_release_interface(bdev->handle, iface);
    		}
    
    		libusb_close(bdev->handle);
    	}
    
    	return 0;
    }
    

    批量写

    int bulkusb_write(struct bulkusbdev* dev, void* buffer, int len, int ms)
    {
    	int size, errcode;
    	libusb_device_handle* handle = dev->handle;
    	uint8_t endpoint_out = dev->endpoint_out;
    
    	errcode = libusb_bulk_transfer(handle, endpoint_out, buffer, len, &size, ms);
    	if (errcode<0)
    	{
    		printf("write:   %s
    ", libusb_strerror((enum libusb_error)errcode));
    		return -1;
    	}
    
    	return size;
    }
    
    

    批量读

    int bulkusb_read(struct bulkusbdev* dev, void* buffer, size_t len, int ms)
    {
    	int size, errcode;
    	libusb_device_handle* handle = dev->handle;
    	uint8_t endpoint_in = dev->endpoint_in;
    
    	errcode = libusb_bulk_transfer(handle, endpoint_in, buffer, len, &size, ms);
    	if (errcode < 0)
    	{
    		printf("read:   %s
    ", libusb_strerror((enum libusb_error)errcode));
    		return -1;
    	}
    
    	return size;
    }
    
    

    步骤执行顺序

    	char buf[8] = { 0 };
    	struct bulkusbdev* dev = NULL;
    	struct bulkusbdev devs[2] = { 0 };
    	struct bulkusbid ids[1] = {
    		{
    			.vid = 0x1234,
    			.pid = 0x1122
    		}
    	};
    
    	bulkusb_init();
    	bulkusb_get_list(devs, 2, ids, 1);
    	dev = &devs[0];
    	bulkusb_open(dev);
    	bulkusb_write(dev, buf, 8, 1000);
    	bulkusb_read(dev, buf, 8, 1000);
    	bulkusb_close(dev);
    	bulkusb_exit();
    
    
  • 相关阅读:
    【原创】今天发现CSS上的一点使用FLoat要注意的地方(FireFox+IE)
    HTTP/1.1 协议 810 持久连接( Persistent Connections)
    Javascript attachEvent传递参数的办法
    Keycode对照表
    JS正则表达式详解[收藏]
    Javascript控制剪贴板大全
    多站点整合—单点登录简单方案
    Stream 和 byte[] 之间的转换
    用CSS样式如何制作圆角的详细教程
    FireFox下为元素附加事件并传递参数-addEventListener attachEvent Pass parameters to eventfunction
  • 原文地址:https://www.cnblogs.com/llil/p/13533074.html
Copyright © 2011-2022 走看看