Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465355
  • 博文数量: 191
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 172
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-31 14:35
个人简介

没有时间把一件事情做好,却有时间把一件事情反复做!

文章分类

全部博文(191)

文章存档

2016年(2)

2015年(74)

2014年(111)

2013年(4)

我的朋友

分类: 嵌入式

2015-05-12 23:10:29

原文地址:usblib使用【转】 作者:LYZC11

转载地址:http://blog.chinaunix.net/space.php?uid=22159897&do=blog&cuid=2461859

作者:thyman126

首先声明,这是看到国外论坛上的学习文章后,独立翻译过来作为笔记用,加入部分自我理解,并且全部原创。
介绍:
libusb是一个开源库,可以帮助开发者在用户空间的层面上与UBS设备进行通讯。如果想了解更多,可以查看他们的主页:
在其文档中,建议首先阅读USB2的规格说明:http://www.usb.org/developers/docs/,这可以帮助真正地了解USB是如何工作的。
libusb的安装:
你可以从官方的主页上获取源代码,并且编译安装。或者使用的发行版已经包含了软件包,可以很方便地安装。
如果已经安装完毕,请继续往下
通讯:
设备和客户端之间的通讯是个清楚的概念叫做使用管道。每个管道都是一个主机上的一个软件和设备上一个端点的通道。每个端点对于设备来说完成一部分特殊的目标,比如接受命令或者传输数据。一个全速设备最高可以拥有16个端点,然后低速的设备只拥有三个端点。
所有的USB设备当供电时都支持端口0。这个端口是默认的目标管道。当设备连接被检测到后,USBD软件会使用端口0来初始化设备,执行普通的(非特殊)配置,并且获得有设备提供的其他端点的信息。端点是以他们的端点数目(取决于设计的时间),总线宽带,访问频率,延迟和处理错误要求为特征区分的。
一旦设备里的端点识别并且配置完毕,管道就产生允许客户端软件与设备进行通讯。跟一个管道产生联系是以对总线的访问和带宽,传输的类型,传输的方向和最大数据负载大小为描述特征的。
USB定义了四种传输方式:控制传输,通常用来传输命令和状态操作;中断传输,通过设备初始化一些来自主机的请求;同步传输,用来传输投递关键事件的数据(比如视频和对话);批量传输,使用全部可以用的带宽但不是特定时间的。所有的数传使用相同格式的包装,包括控制信息,数据和错误效验区域。
这里有两种管道:消息管道和流管道。控制传输是使用消息管道。在消息管道中,在每个包中的数据部分对于USB系统软件是有意义的。
流管道被中断传输,同步传输和批量传输使用。在流管道中,在每个包中的数据部分对于USB是没有意义,仅仅在客户端软件和设备间传输。
同步接口:
同步接口允许你使用单独一个函数调用一个USB传输。当这个函数调用返回时,这个传输也已经完成并且返回结果供解析用。这种方式的优点是十分清晰的:你可以通过一个简单的函数调用做任何事。
尽管如此,这个接口还是有它的局限性。你的程序会进入休眠当在libusb_bulk_transfer()(当进行批量传输),直到传输完成。假如这需要花费三个小时,你的程序同样需要休眠同样的时间。实现将会在库里面结束,整体线程这期间是无用的。另一个问题是,当一个单独的传输线程结束,这里不存在可能多个端点和多个设备同时地进行I/O操作,除非你借助创造新的线程处理。另外的,当请求被提交后,这里没有机会可能取消传输。
设备和接口:
在libusb中,每个USB设备通过libusb_device和libusb_device_handle对象操作。libusb API 连接一个打开的设备至特定的接口。这意味着如果你在设备上请求多个接口,你必须同样多次打开设备来接受一个libusb_dev_handle,对应每个你想进行通讯的接口。不要忘记调用libusb_dev_handle。
这些意味着什么?这意味你在设备上操作以前,可以完成请求接口,同样,你可以在完成设备操作前,先释放接口。
每个设备都有自己独属的配置,比如vendor id,product id等。我们使用这些设置去发现需求的设备,并且通过这些配置来工作。首先我们写一个函数来查明这些配置并且打印出来,以便我们找到正确的一个;我们基本的操作如下:
1.通过调用libusb_init来初始化库,同时创建一个对话;
2.调用libusb_get_device_list来获得已经连接的设备的队列。这会创建一个libusb_device的数组,包含了所有连接到系统上的usb设备;
3.循环遍历所有的设备来检查他们的选项;
4.发现其中需要的一个,使用libusb_open或者libusb_open_device_with_vid_pid(当你知道这个设备vendor id和product id)来打开设备;
5.使用libusb_free_device_list清除使用libusb_get_device_list获得的队列;
6.通过libusb_claim_interface请求接口(需要你知道设备的接口数值);
7.操作想得到的I/O;
8.通过libusb_release_interface释放设备;
9.通过libusb_close将你之前打开的设备关闭;
10.通过libusb_exit来关闭对话;
PS:英文需要苦练啊,一篇短的教程文章看的结结巴巴的

接学习一,学习二主要是看例程
ok,现在最简单的想法看看有多少信息包含在你的设备里,程序代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include
#include
usingnamespace std;
 
void printdev(libusb_device *dev);//prototype of the function
 
int main(){
libusb_device **devs;//pointer to pointer of device, used to retrieve a list of devices
libusb_context *ctx =NULL;//a libusb session
int r;//for return values
ssize_t cnt;//holding number of devices in list
r = libusb_init(&ctx);//initialize a library session
if(r <0){
cout<<"Init Error "<<r<<endl;//there was an error
return1;
}
libusb_set_debug(ctx, 3);//set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs);//get the list of devices
 
if(cnt <0){
cout<<"Get Device Error"<<endl;//there was an error
}
cout<<cnt<<" Devices in list."<<endl;//print total number of usb device
ssize_t i;//for iterating through the list
 
for(i =0; i < cnt; i++){
printdev(devs[i]);//print specs of this device
}
libusb_free_device_list(devs, 1);//free the list, unref the devices in it
libusb_exit(ctx);//close the session
return0;
}
 
void printdev(libusb_device *dev){
libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if(r <0){
cout<<"failed to get device descriptor"<<endl;
return;
}
 
cout<<"Number of possible configurations: "<<(int)desc.bNumConfigurations<<" ";
cout<<"Device Class: "<<(int)desc.bDeviceClass<<" ";
cout<<"VendorID: "<<desc.idVendor<<" ";
cout<<"ProductID: "<<desc.idProduct<<endl;
libusb_config_descriptor *config;
libusb_get_config_descriptor(dev, 0, &config);
cout<<"Interfaces: "<<(int)config->bNumInterfaces<<" ||| ";
const libusb_interface *inter;
const libusb_interface_descriptor *interdesc;
const libusb_endpoint_descriptor *epdesc;
 
for(int i=0; i<(int)config->bNumInterfaces; i++){
inter =&config->interface[i];
cout<<"Number of alternate settings: "<<inter->num_altsetting<<" | ";
for(int j=0; j<inter->num_altsetting; j++){
interdesc =&inter->altsetting[j];
cout<<"Interface Number: "<<(int)interdesc->bInterfaceNumber<<" | ";
cout<<"Number of endpoints: "<<(int)interdesc->bNumEndpoints<<" | ";
 
for(int k=0; k<(int)interdesc->bNumEndpoints; k++){
epdesc =&interdesc->endpoint[k];
cout<<"Descriptor Type: "<<(int)epdesc->bDescriptorType<<" | ";
cout<<"EP Address: "<<(int)epdesc->bEndpointAddress<<" | ";
}
}
}
cout<<endl<<endl<<endl;
libusb_free_config_descriptor(config);
}

写完之后,编译看看会出现什么。首先运行程序并检查设备,然后连上我自己的设备在执行程序。会发现有新的内容出现,可以根据vendor id和product id发现这正是我自己连上打开的设备。
注意:发现设备(调用libusb_get_device_list())会返回新的内存分配的设备队列。当你完成这个队列的使用后必须释放他。
Libusb同样需要知道当一切完成时清除队列的内容;设备的本身。
为处理这些问题,libusb提供了两个单独的条目:
一个释放队列本身的函数
一个针对设备内部的参考计数系统
新的设备由libusb_get_device_list()函数展示,都拥有一个参考计数1。你可以使用libubs_ref_device()和libusb_unref_device()增加或减少参考计数。当一个设备的参考计数为0时,该设备就被销毁
通过以上的信息,打开设备的基本流程可以视为如下步骤:
1. 使用libusb_get_device_list()发现设备;
2. 选择你想操作的设备,调用libusb_open();
3. 在设备队列中unref所有的设备;
4. 释放已经发现的设备队列;
这个次序是十分重要的,在尝试打开设备之前,你不能够unreference设备,因此unreference操作有可能导致设备的销毁。
为了方便起见,libusb_free_device_list()函数包含一个参数,在释放队列本身前,该参数能够选择性地在队列中unreference所有设备。这包含了以上的步骤3和步骤4。
如果还有需要,可以去libusb1’s API()文档参考你需要的函数。
好了,现在你可以找到你需要的设备了。现在是打开设备,请求并且执行一个简单的I/O。如果你知道vendor ID和prouct ID,使用libusb_open_device_with_vid_pid。
另外需要注意的,如果内核(你的OS)已经连接到这个设备,你将无法请求到它。在这种情况下,你需要调用 libusb_detach_kernel_drive来从内核中检测设备。如果你想知道内核是否可用的,使用 libusb_kernel_drive_active,如果返回值为1,对于你的设备内核可以加载驱动。
批量传输
为了在你的设备上使用批量传输,你应该获得为你的USB设备获得一个设备句柄,并且你应该知道使用哪个端点(从之前设备说明获得)。
关于语法上的信息参考这里()
这里有个简单的例子包含所有我提到的相关部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include
#include
 
usingnamespace std;
 
int main(){
libusb_device **devs;//pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle;//a device handle
libusb_context *ctx =NULL;//a libusb session
int r;//for return values
ssize_t cnt;//holding number of devices in list
r = libusb_init(&ctx);//initialize the library for the session we just declared
 
if(r <0){
cout<<"Init Error "<<r<<endl;//there was an error
return1;
}
libusb_set_debug(ctx, 3);//set verbosity level to 3, as suggested in the documentation
 
cnt = libusb_get_device_list(ctx, &devs);//get the list of devices
if(cnt <0){
cout<<"Get Device Error"<<endl;//there was an error
return1;
}
cout<<cnt<<" Devices in list."<<endl;
 
dev_handle = libusb_open_device_with_vid_pid(ctx, 5118, 7424);//these are vendorID and productID I found for my usb device
if(dev_handle ==NULL)
cout<<"Cannot open device"<<endl;
else
cout<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1);//free the list, unref the devices in it
 
unsignedchar*data =newunsignedchar[4];//data to write
data[0]='a';data[1]='b';data[2]='c';data[3]='d';//some dummy values
 
int actual;//used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, 0)==1){//find out if kernel driver is attached
cout<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, 0)==0)//detach it
cout<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, 0);//claim interface 0 (the first) of device (mine had jsut 1)
if(r <0){
cout<<"Cannot Claim Interface"<<endl;
return1;
}
cout<<"Claimed Interface"<<endl;
 
cout<<"Data->"<<data<<"<-"<<endl;//just to see the data we want to write : abcd
cout<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (2| LIBUSB_ENDPOINT_OUT), data, 4, &actual, 0);//my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129
if(r ==0&& actual ==4)//we wrote the 4 bytes successfully
cout<<"Writing Successful!"<<endl;
else
cout<<"Write Error"<<endl;
 
r = libusb_release_interface(dev_handle, 0);//release the claimed interface
if(r!=0){
cout<<"Cannot Release Interface"<<endl;
return1;
}
cout<<"Released Interface"<<endl;
 
libusb_close(dev_handle);//close the device we opened
libusb_exit(ctx);//needs to be called to end the
 
delete[] data;//delete the allocated memory for data
return0;
}

结尾:这个教程对于这个话题来说是十分简单的介绍,需要时间需联系同步传输,然后移动是异步的,这还有很多需要学习。
希望这些对你的初学有帮助。



版权声明: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
阅读(838) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~