首页 > 其他分享 >Libusb测试USB device(2)

Libusb测试USB device(2)

时间:2022-11-09 18:34:30浏览次数:67  
标签:USB transfer ERROR LIBUSB libusb Libusb printf device xfer

因为测试的比较混乱,我就按照我的问题导向来描述我的过程吧

一. 提示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;但是写的时候并不需要;

    最后终于测试成功了

 

标签:USB,transfer,ERROR,LIBUSB,libusb,Libusb,printf,device,xfer
From: https://www.cnblogs.com/celesial-dancers/p/16874754.html

相关文章