本文将从多个方面对Bulk-In, Interface驱动进行详细的阐述和解答,包含代码示例。
一、USB传输模式介绍
USB(Universal Serial Bus)是一种通用的数字式通信接口标准,让不同设备可以通过单一的USB接口连接,并实现不同的数字通信需求。USB 接口有四种传输方式:Control、Bulk、Interrupt、Isochronous。
Bulk-In,Interface驱动是一种通过Bulk传输方式的USB设备驱动。Bulk-In指从设备到主机的数据传输,Interface则是该传输模式的一种。
二、Bulk-In, Interface驱动开发前提条件
开始开发之前,我们需要了解基本的开发环境和软件:Linux操作系统、libusb-1.0库、C语言开发工具。
三、Bulk-In, Interface驱动数据传输
Bulk-In, Interface驱动的数据传输可以分为两个步骤:端点准备和传输数据。
1. 端点准备
首先,我们需要找到USB设备的接口和端点地址。可以使用lsusb
命令查看设备的厂商ID、产品ID、接口和端点信息:
$ lsusb -d 1234:5678 -v Bus 003 Device 017: ID 1234:5678 Device Descriptor: ... idVendor 0x1234 idProduct 0x5678 ... iInterface 2 ... Interface Descriptor: bInterfaceNumber 2 bAlternateSetting 1 bNumEndpoints 2 bInterfaceClass 0xff bInterfaceSubClass 0xff bInterfaceProtocol 0xff iInterface 3 Endpoint Descriptor: bEndpointAddress 0x01 EP 1 IN bmAttributes 0x02 wMaxPacketSize 0x0040 // 最大包长度为64 ... Endpoint Descriptor: bEndpointAddress 0x82 EP 2 OUT bmAttributes 0x02 wMaxPacketSize 0x0040 // 最大包长度为64 ...
从上述输出中,我们可以得到接口编号为2,IN端点地址为1,OUT端点地址为2。
在使用libusb_bulk_transfer()
传输数据之前,还需要进行端点参数的设置:
libusb_claim_interface(devh, interface_number); // 申请接口 libusb_set_interface_alt_setting(devh, interface_number, alternate_setting); // 设置接口备用状态 libusb_get_endpoint_descriptor(devh, endpoint_address_bulk, &endpoint); // 获取端点描述符 libusb_set_interface_alt_setting(devh, interface_number, alternate_setting); // 选择接口状态
2. 传输数据
设置端点参数完成后,我们就可以进行Bulk-In, Interface数据传输了。以下是简单的示例代码:
int transferred; unsigned char data[64]; // 缓存区大小需等于wMaxPacketSize int r = libusb_bulk_transfer(devh, endpoint->bEndpointAddress, data, sizeof(data), &transferred, 1000); if (r == 0) { printf("%d bytes readn", transferred); } else { printf("Bulk-In transfer error %dn", r); }
四、Bulk-In, Interface驱动数据解析
在进行Bulk-In传输数据之后,需要解析USB设备传输的数据。这里我们以设备传输字符串为例进行说明。
1. 字符串解析
如果设备传输的数据是字符串,我们可以使用以下的方式进行解析:
if (transferred > 0) { // 构造字符串 char str[transferred + 1]; memset(str, 0, transferred + 1); memcpy(str, data, transferred); printf("Received %d bytes: %sn", transferred, str); }
2. 结构体解析
如果设备传输的数据是结构体,我们可以使用以下的方式进行解析:
struct my_struct { uint16_t val1; uint8_t val2; uint32_t val3; } __attribute__((packed)); struct my_struct *ptr; if (transferred == sizeof(struct my_struct)) { ptr = (struct my_struct *)data; printf("Received val1=%d val2=%d val3=%dn", ptr->val1, ptr->val2, ptr->val3); }
五、Bulk-In, Interface驱动常见问题解答
1. 为什么读取的数据不正确?
可能是数据传输时,缓存区大小不够,应确保缓存区大小等于端点的最大包长度。
2. 如何确定设备的接口和端点地址?
可以使用lsusb
命令查看设备的厂商ID、产品ID、接口和端点信息。
六、Bulk-In, Interface驱动代码示例
#include <stdio.h> #include <stdint.h> #include <string.h> #include <usb.h> int main(void) { int r = 1; struct usb_device *dev; struct usb_dev_handle *devh = NULL; unsigned char data[64]; int transferred; // 初始化USB库 usb_init(); usb_find_busses(); usb_find_devices(); // 查找设备 dev = usb_find_device(0x1234, 0x5678); if (dev) { // 打开设备 devh = usb_open(dev); if (devh) { // 申请接口 int interface_number = 2; usb_detach_kernel_driver_np(devh, interface_number - 1); r = usb_set_configuration(devh, 1); r = usb_claim_interface(devh, interface_number); int alternate_setting = 1; r = usb_set_altinterface(devh, alternate_setting); struct usb_endpoint_descriptor *endpoint; // 获取IN端点的描述符 uint8_t endpoint_address_bulk = 0x81; endpoint = (struct usb_endpoint_descriptor *)dev->config-> interface[interface_number - 1].altsetting[alternate_setting].endpoint; for (int i = 0; i < dev->config->interface[interface_number - 1]. altsetting[alternate_setting].bNumEndpoints; i++) { if ((endpoint + i)->bEndpointAddress == endpoint_address_bulk) { endpoint = endpoint + i; break; } } // 读取数据 r = usb_bulk_read(devh, endpoint->bEndpointAddress, data, sizeof(data), 1000); if (r >= 0) { printf("Bulk-In data: "); for (int i = 0; i < r; i++) { printf("%02x ", data[i]); } printf("n"); } else { printf("Bulk-In transfer errorn"); } // 释放接口 r = usb_release_interface(devh, interface_number); // 关闭设备 usb_close(devh); } } return 0; }