Libusb测试USB device(2)
因为测试的比较混乱,我就按照我的问题导向来描述我的过程吧
一. 提示libusb_context对象为NULL的错误:
在简化的过程中,我没有加入dev_handler判断为空就进行了具体的工作;
1 if( !dev_handler )
2 libusb_open(dev_obj, &dev_handler);
3 if( dev_handler )
4 // do your job
二. 如果不知道是什么原因(比如说ioctl之类的错误,那么可能是安装错误了驱动:
我使用了zadig-2.7.exe,来安装:
如果想要测试HID设备,安装成WinUSB会比较合适;
如果想要其他的usb设备安装成libusb会比较合适
如果想要测试等时传输(isoch)则libusbk会更合适一些(虽然我用的是WinUSB好像也可以)
三. 对于Windows中USB的驱动的了解也比较重要:
1 libusb_bullk_transfer 是libusb提供的函数;
2 do_syun_bulk_transfer 执行具体的工作
3 // 在do_sync_bulk中
4 {
5 alloc_transfer();
6 fill_bulk_transfer();
7 submit_transfer();
8 sync_transfer_wait_for_completion();
9 }
10 // 其中submit又是重点:
11 submit_transfer(){
12 ref_device();
13 mutex_lock & transfer_lock;
14 set_itransfer_obj;
15 add_to_flying_list
16 usbi_backend->submit_transfer()
17 }
18 // 其中ubsi_backend表示的是具体的实现的
四. 对于device发送的Descriptor解析页非常重要:
其中我认为最重要的就是对断点endpoint descriptor属性的理解 :
关系这个断电支持什么样的传输方式,已经最多穿多少(对于Isoch来说非常重要)
1 static void print_endpoint(const struct libusb_endpoint_descriptor* endpoint)
2 {
3 int i, ret;
4 printf("\t\t\tEndpoint:\n");
5 // 可以看出endpoint是OUT(host->device)还是IN(device->host)
6 printf("\t\t\t\tbEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
7 // 可以看出支持的操作:01:中断;02:bulk;03:isoch
8 printf("\t\t\t\tbmAttributes: %02xh\n", endpoint->bmAttributes);
9 printf("\t\t\t\twMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
10 printf("\t\t\t\tTransfer Interval %u\n", endpoint->bInterval);
11 }
五. 关于等时传输isoch(困扰了我最久的一块儿)
Step1: 根据 微软的官方文档 了解等是传输断点(endpoint)中具体的信息;
获得不连续数据包大小MaximumPacketSize |
使用libusb提供的libusb_get_max_iso_packet_size方法就可以了 全速设备:这是1帧发送的数据; 对于高速设备,这个是1微帧发送的字节数; 好像已经固定了:Full是1024;High是3072;Super是45000 |
确认帧包含多少微帧 | 根据断点提供的bInterval来计算:2^(Interval-1) |
验证 |
需要连续包个数必须是每个帧数据包数的倍数; |
分配结构体 |
也就是alloc_transfer |
指定详细信息 | 也就是给transfer结构体添加缓冲区数据 |
最诡异的就是这个Interval:
根据Interval就可以计算出来轮询周期Polling Period = 2^(Interval-1); 轮询周期表示每轮询周期个总线间隔才会传输一次;
所以Interval == 4的时候就和Full Speed差不多;
Step2:实践:使用等时传输函数:
首先上代码:
int do_sync_transfer()
{
int endpoint_num;
int test_type;
int interface_num = USB_INTERFACE;
int ret;
int packet_size;
int transfer_length;
int numberOfPackets;
unsigned char* buff;
int temp;
int trans_time; printf("INFO: Enter the test type\n\t0: ISOC IN; 1: ISOC OUT\n");
scanf_s("%d", &test_type);
switch (test_type)
{
case 0:
endpoint_num = ISOC_IN_ENDPOINT;
dir = 1;
break;
case 1:
endpoint_num = ISOC_OUT_ENDPOINT;
dir = 0;
break;
default:printf("ERROR: Wrong test type\n");return;
}
if ((ret = libusb_clear_halt(g_handler, endpoint_num)) < 0)
{
printf("ERROR: clear halt failed\n\tReason: %s\n", libusb_strerror(ret));
return -1;
}
printf("INFO: clear halt succeed\n");
int number0fPacketPerFrame; // new ONE:
// 计算缓冲区大小和长度最重要的地方:
// 根据Interval 计算Polling Period
// 缓冲区大小 = 最大不连续包大小 * 8/ Polling Period
int win_interval = (ISOC_INTERVAL - 1);
int min_buffer_size = MAX_BYTES_PER_INTERVAL * 8 / win_interval; buff = (unsigned char*)malloc(sizeof(unsigned char) * 3072);
int temp_time = min_buffer_size / 16;
for (int i = 0; i < temp_time; i++)
memset(buff + (i * 16), temp_time, 16); libusb_set_debug(NULL, 4); if (endpoint_num == ISOC_OUT_ENDPOINT) {
struct libusb_transfer* xfer;
// 标识发送开始
// 也是很重要的:设置异步的检测状态函数:
// 注意使用detach分离
is_send_over = 0;
pthread_t my_thread;
pthread_create(&my_thread, NULL, handle_isoc_transfer, g_ctx);
pthread_detach(my_thread);
for (trans_time = 0; trans_time < 15; trans_time++) {
printf("TIME: %d\n", trans_time);
printf("Enter Send transfer length:\n");
scanf_s("%d", &transfer_length);
numberOfPackets = ceil(transfer_length / min_buffer_size);
printf("The number of packets is : %d\n", numberOfPackets);
if (numberOfPackets % number0fPacketPerFrame != 0) {
printf("Number of Packet should be a multiple of numberOf packet per frame\n");
return;
}
for (int i = 0; i < numberOfPackets; i++) {
int temp_translen = (transfer_length >= min_buffer_size) ? min_buffer_size : transfer_length;
transfer_length -= temp_translen;
xfer = libusb_alloc_transfer(number0fPacketPerFrame);
if (!xfer) {
printf("ERROR: no memory for transfer\n");
libusb_set_debug(NULL, 0);
return -1;
}
libusb_fill_iso_transfer(xfer, g_handler, endpoint_num,
buff,
transfer_length,
number0fPacketPerFrame,
isoc_callback_send,NULL, 200);
xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
libusb_set_iso_packet_lengths(xfer, temp_translen);
ret = libusb_submit_transfer(xfer);
if (ret < 0) {
printf("ERROR: submit\n");
libusb_free_transfer(xfer);
libusb_set_debug(NULL, 0);
return -1;
}
Sleep(500);
libusb_free_transfer(xfer);
}
}
is_send_over = 1;
}
else {
int receive_time;
is_receive_over = 0;
pthread_t my_thread;
pthread_create(&my_thread, NULL, handle_isoc_transfer, g_ctx);
pthread_detach(my_thread);
for (trans_time = 0; trans_time < 15; trans_time++) {
printf("TIME: %d\n", trans_time);
printf("Enter Receive Time:\n");
scanf_s("%d", &receive_time);
for (int i = 0; i < receive_time; i++) {
printf("Receive No.%d", i);
if ((ret = libusb_clear_halt(g_handler, endpoint_num)) < 0)
{
printf("ERROR: clear halt failed\n\tReason: %s\n", libusb_strerror(ret));
return -1;
}
printf("INFO: clear halt succeed\n");
struct libusb_transfer* xfer;
libusb_fill_iso_transfer(
xfer,
g_handler,
endpoint_num,
buff,
min_buffer_size,
number0fPacketPerFrame,
isoc_callback_receive,
NULL,
200);
xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
libusb_set_iso_packet_lengths(xfer, min_buffer_size);
ret = libusb_submit_transfer(xfer);
if (ret < 0) {
printf("ERROR: submit\n");
libusb_free_transfer(xfer);
libusb_set_debug(NULL, 0);
return -1;
}
Sleep(200);
libusb_free_transfer(xfer);
}
}
is_receive_over = 1;
}
libusb_set_debug(NULL, 0);
return 0;
}
然后对应的异步处理函数代码如下:
1 static int LIBUSB_CALL usb_arrived_callback(libusb_context*, libusb_device*, libusb_hotplug_event, void*);
2 // leave : left
3 static int LIBUSB_CALL usb_left_callback(libusb_context*, libusb_device*, libusb_hotplug_event, void*);
4 // Just get one handler (default by dev)
5 void get_handle_and_device_by_vandp(uint16_t, uint16_t, libusb_device**, libusb_device_handle**);
6 int print_all_device();
7
8 void* handle_isoc_transfer(void* param) {
9 if (param == NULL) {
10 printf("PARAM Wrong\n");
11 return;
12 }
13 libusb_context* ctx = (libusb_context*)param;
14 while (1) {
15 if (is_send_over == 1) {
16 printf("This time already done");
17 break;
18 }
19 libusb_handle_events(ctx);
20 }
21 }
22
23 static void LIBUSB_CALL isoc_callback_send(struct libusb_transfer* xfer)
24 {
25 printf("INFO : in isoc_callback send\n");
26 if (xfer == NULL)
27 return;
28 printf("INFO : the transfer status is :%d\n", xfer->status);
29 switch(xfer->status)
30 {
31 case LIBUSB_TRANSFER_COMPLETED:
32 printf("INFO: transter complete\nDatas are:\n");
33 printf("The length : %d\n", xfer->actual_length);
34 break;
35 case LIBUSB_TRANSFER_ERROR:
36 printf("ERROR: transfer error\n");
37 break;
38 case LIBUSB_TRANSFER_TIMED_OUT:
39 printf("ERROR: transfer timeout\n");
40 break;
41 case LIBUSB_TRANSFER_CANCELLED:
42 printf("ERROR: transfer is cancelled\n");
43 break;
44 case LIBUSB_TRANSFER_STALL:
45 printf("ERROR: transfer stall\n");
46 break;
47 case LIBUSB_TRANSFER_NO_DEVICE:
48 printf("ERROR: no device detected\n");
49 break;
50 case LIBUSB_TRANSFER_OVERFLOW:
51 printf("ERROR: transfer overflowed\n");
52 break;
53 default:
54 printf("ERROR: UNKNOWN status\n");
55 break;
56 }
57 }
58
59 static void LIBUSB_CALL isoc_callback_receive(struct libusb_transfer* xfer) {
60 if (xfer == NULL)
61 return;
62 printf("INFO: enter : %s and status is : %d\n", __func__, xfer->status);
63 switch (xfer->status)
64 {
65 case LIBUSB_TRANSFER_COMPLETED:
66 printf("INFO: transfer completed\n");
67 break;
68 case LIBUSB_TRANSFER_ERROR:
69 printf("ERROR: transfer error\n");
70 break;
71 case LIBUSB_TRANSFER_TIMED_OUT:
72 printf("ERROR: transfer timeout\n");
73 break;
74 case LIBUSB_TRANSFER_CANCELLED:
75 printf("ERROR: transfer is cancelled\n");
76 break;
77 case LIBUSB_TRANSFER_STALL:
78 printf("ERROR: transfer stall\n");
79 break;
80 case LIBUSB_TRANSFER_NO_DEVICE:
81 printf("ERROR: no device detected\n");
82 break;
83 case LIBUSB_TRANSFER_OVERFLOW:
84 printf("ERROR: transfer overflowed\n");
85 break;
86 default:
87 printf("ERROR: UNKNOWN status\n");
88 break;
89 }
90 }
总是不确定到底该发送多少个数据才能被接收:
终于找到了windows_winusb.c中的winusbx_submit_iso_transfer函数:
1 // For high-speed and SuperSpeed device, the interval is 2**(bInterval-1).
2 if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH)
3 interval = (1 << (pipe_info_ex.Interval - 1));
4 if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH) {// Microframes (125us)
5 printf("--------INFO: %d\n", (pipe_info_ex.MaximumBytesPerInterval * 8) / interval);
6 iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval;
7 }
8 else // Normal Frames (1ms)
9 iso_transfer_size_multiple = pipe_info_ex.MaximumBytesPerInterval / interval;
10 if (transfer->length % iso_transfer_size_multiple != 0) {
11 usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval");
12 return LIBUSB_ERROR_INVALID_PARAM;
13 }
可见:里面对interval也进行了计算:
在使用等时传输读的时候需要将buffer的长度设置为size_multiple;但是写的时候并不需要;
最后终于测试成功了
Libusb测试USB device(2)的更多相关文章
- 基于libUSB的USB设备固件更新程序(下载数据)(转)
源:基于libUSB的USB设备固件更新程序(下载数据) 本文紧接上一篇日志:基于libUSB-Win32的USB设备固件更新程序(前言),相关背景以及起因等,此处不再赘述,如感兴趣请移步. libU ...
- USB device & USB controller & USB passthrough
目录 USB device USB controller Linux 相关命令 Python 相关库 Libvirt USB passthrough 参考资料 近期往 openstack 里倒腾 US ...
- 【转载】How to Reset USB Device in Linux
USB devices are anywhere nowadays, even many embedded devices replace the traditional serial devices ...
- libusb获取usb设备的idVendor(vid),idProduct(pid),以及Serial Number
发表于2015/6/23 21:55:11 4594人阅读 最近在做关于usb设备的项目,用到了libusb,发现关于这个的函数库的介绍,讲解很少,下面仅仅是简单展示一些基本的使用方法,以备后用. ...
- 痞子衡嵌入式:可通过USB Device Path来唯一指定i.MXRT设备进行ROM/Flashloader通信
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是通过USB Device Path来唯一指定i.MXRT设备进行ROM/Flashloader通信. i.MXRT系列高性能微控制器从2 ...
- Install Slax on USB device (Slax U 盘安装)
Slax is a modern, portable, small and fast Linux operating system with a modular approach and outsta ...
- What is a Windows USB device path and how is it formatted?
http://community.silabs.com/t5/Interface-Knowledge-Base/Windows-USB-Device-Path/ta-p/114059 Windows ...
- USB Device Finder
http://www.velleman.eu/images/tmp/usbfind.c #ifdef __cplusplus extern "C" { #endif #includ ...
- Assigning Host USB device to a Guest VM
Example Assigning Host USB device to a Guest VM This example is based on qemu-kvm (0.15.0) as instal ...
- usb host和usb device
S3C2440的数据手册将USB功能分为两章--usb host和usb device.具体什么意思呢? usb host: 微处理器作为usb主设备,可以挂接U盘之类的从属设备. usb devic ...
随机推荐
- Unity屏幕永远保持为固定分辨率
Unity屏幕永远保持为固定分辨率 Unity屏幕永远保持为固定分辨率 前言 开题废话 Unity版本 正题: 打开一场景 创建脚本并且编写 挂在脚本到场景摄像机上边 以不同比的分辨率运行程序,并且观 ...
- 01 LED点灯
新建一个STM32CubeIDE 新工程 选择自己的芯片型号,我的是STM32F103RCT6 选择工程保存位置,不能有中文路径,会报错 选择下载方式.一定要选,不然下次下载有问题 选择时钟来源,我的 ...
- 记一次使用gdb诊断gc问题全过程
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 上次解决了GC长耗时问题后,系统果然平稳了许多,这是之前的文章<GC耗时高,原因竟是服务流量小?> 然 ...
- layedit 清空 编辑器
使用layedit.setContent(index,"") 即可以清除 layui.use('layedit', function(){ var layedit = layui. ...
- Linux06-常用命令 日期 日历 查找 过滤
1.date 日期 2.cal 日历 3.find 查找 4.locate 查找 5.grep 过滤 1.时间日期类 date指令-显示当前日期 1)指令: date (功能描述:显示当前时间) ...
- Java最全八股文(2023最新整理)
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
- Nacos入门
1.介绍 ①概要 官网:home (nacos.io) Nacos:Dynamic Naming and Configuration Service(动态命名和配置服务) 你可以看为:Eureka(注 ...
- echarts在移动端上tooltip弹框点击空白不能关闭的问题解决方案
1.首先新建一个mixin.js文件 export const mixinAutoHideTooltip = { mounted() { this.mAutoHideTooltip(this.$el) ...
- JZOJ 1083. 【GDOI2006】拯救亚特兰蒂斯
\(\text{Solution}\) 自己的网络流技术太拉了 连这样的题都做不出来 对于一个怪物,剑术和法术两样东西有一样就可以了 不难想到二分图中最小点覆盖,一条边只有两个端点之一被选就被覆盖了 ...
- [EULAR文摘] 新证据: NSAID对AS放射学进展的影响
新证据: NSAID对AS放射学进展的影响 Sieper J, et al. EULAR 2015. Present ID: OP0145. 背景: 既往有研究显示持续给予NSAID相较于按需给药能在 ...