STM32F103 USB固件开发-移植JoyStickMouse-(3)(USB描述符详解)
目录
1.USB设备描述符简介
USB描述符结构如下(图片引用自USB中文网):
设备描述符:主要向主机说明设备类型、USB版本号、PID、VID等,是主机读取的第一个配置,一个设备能有有一个。
配置描述符:一个设备可以有一个或多个,描述设备的供电方式、最大功耗、接口数量。配置描述符在USB设备的枚举过程中,需要获取两次:第一次只获取配置描述符的基本长度9字节,获取后从wTotalLength字节中解析出配置描述符的总长度,然后再次获取全部的描述符。
接口描述符:具体功能的体现,接口的编号、接口的端点数量、接口所使用的类、子类、协议等。
**端点描述符:**端点号及方向、端点的传输类型(控制、同步、批量、中断等),最大包长度、查寻时间间隔等。
字符串描述符:不是必须的,采用unicode编码,主要是提供一些方便人们阅读的厂商或设备名称等文字信息。
HID描述符:HID描述符的主要作用是用来识别HID通信所使用的额外描述符。
2.常用描述符详解
USB 设备描述符
struct _DEVICE_DESCRIPTOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型
//0x00不是在设备描述符中定义的,如HID
BYTE bDeviceSubClass; //usb分配的子类代码,同上,值由USB规定和分配的
BYTE bDeviceProtocol; //USB分配的设备协议代码,同上
BYTE bMaxPacketSize0; //端点0的最大包的大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //描述厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfiguration; //可能的配置数量
}
配置描述符
struct _CONFIGURATION_DESCRIPTOR_STRUCT
{
BYTE bLength; //配置描述符的字节数大小,固定为9字节
BYTE bDescriptorType; //描述符类型编号,为0x02
WORD wTotalLength; //配置所返回的所有数量的大小
BYTE bNumInterface; //此配置所支持的接口数量
BYTE bConfigurationVale; //Set_Configuration命令需要的参数值
BYTE iConfiguration; //描述该配置的字符串的索引值
BYTE bmAttribute; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流
}CONFIGURATION_DESCRIPTOR_STRUCT
接口描述符
struct _INTERFACE_DESCRIPTOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x09
BYTE bDescriptorType; //描述符类型编号,为0x04
BYTE bInterfaceNumber; //接口的编号
BYTE bAlternateSetting;//备用的接口描述符编号
BYTE bNumEndpoints; //该接口使用端点数,不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass;//接口子类型
BYTE bInterfaceProtocol;//接口所遵循的协议
BYTE iInterface; //描述该接口的字符串索引值
}INTERFACE_DESCRIPTOR_STRUCT
端点描述符
struct _ENDPOIN_DESCRIPTOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x7
BYTE bDescriptorType; //描述符类型编号,为0x05
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttribute; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包的大小
BYTE bInterval; //主机查询端点的时间间隔
} ENDPOIN_DESCRIPTOR_STRUCT
字符串描述符
typedef struct _USB_STRING_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
HID描述符(图片来自USB中文网)
3.JoyStickMouse 例程各段描述符解析
/* USB Standard Device Descriptor 设备描述符
*/
const uint8_t Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =
{
0x12, //bLength:设备描述符的字节数大小,为0x12
USB_DEVICE_DESCRIPTOR_TYPE, //bDescriptorType:描述符类型编号,为0x01表示设备描述符
0x00, //bcdUSB:USB版本号,二个字节表示,USB 2.0 设备拥有 0x0200 值, USB 1.1 设备拥有0x0110 值
0x02,
0x00, //bDeviceClass:USB所属设备类 [USB设备类型定义](https://www.usbzh.com/article/detail-221.html)
0x00, //bDeviceSubClass:USB设备所属设备子类
0x00, //bDeviceProtocol:USB设备所用的设备类协议
0x40, //bMaxPacketSize:端点0的最大包的大小
0x83, //idVendor (0x0483):厂商编号
0x04,
0x10, //idProduct = 0x5710:产品编号
0x57,
0x00, //bcdDevice rel. 2.00:设备出厂编号
0x02,
1, //iManufacturer:描述厂商字符串的索引
2, //iProduct:描述产品字符串的索引
3, //iSerialNumber:描述设备序列号字符串的索引
0x01 //bNumConfigurations:可能的配置数量
};
/* USB Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =
{
// Configuration
0x09, //bLength: 配置描述符的字节数大小,固定为9字节
USB_CONFIGURATION_DESCRIPTOR_TYPE, //bDescriptorType: 描述符类型编号,为0x02表示配置描述符
JOYSTICK_SIZ_CONFIG_DESC, //wTotalLength 2个字节: 配置所返回的所有数量的大小
0x00,
0x01, //bNumInterfaces: 此配置所支持的接口数量
0x01, //bConfigurationValue: Set_Configuration命令需要的参数值
0x00, //iConfiguration: 描述该配置的字符串的索引值
0xE0, //bmAttributes: 供电模式的选择
0x32, //MaxPower 100 mA: 设备从总线提取的最大电流
// Interface
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, //bLength: 设备描述符的字节数大小,为0x09
USB_INTERFACE_DESCRIPTOR_TYPE,//bDescriptorType: 描述符类型编号,为0x04表示接口描述符类型
0x00, //bInterfaceNumber: 接口的编号
0x00, //bAlternateSetting: 备用的接口描述符编号
0x01, //bNumEndpoints:该接口使用端点数,不包括端点0
0x03, //bInterfaceClass: 接口类型,参考[Windows定义的USB设备类型bInterfaceClass](https://www.usbzh.com/article/detail-864.html)
0x01, //bInterfaceSubClass : 接口子类型,对于HID接口,bInterfaceSubClass仅用于设备是否支持启动接口
0x02, //nInterfaceProtocol : 接口所遵循的协议,对于HID接口:0=none, 1=keyboard, 2=mouse*/
0, //iInterface: 描述该接口的字符串索引值
// HID描述符
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, //bLength: 描述符字节数
HID_DESCRIPTOR_TYPE, //bDescriptorType: 0x21 = HID描述符
0x00, //bcdHID 2个字节: HID规范版本号(BCD)
0x01,
0x00, //bCountryCode: 硬件设备所在国家的国家代码
0x01, //bNumDescriptors: 类别描述符数目(至少有一个报表描述符)
0x22, //bDescriptorType:该类别描述符的类型
JOYSTICK_SIZ_REPORT_DESC,//wItemLength 2个字节: 该类别描述符的总长度
0x00,
/******************** Descriptor of Joystick Mouse endpoint ********************/
/* 27 */
0x07, //bLength:设备描述符的字节数大小,为0x7
USB_ENDPOINT_DESCRIPTOR_TYPE, //bDescriptorType:描述符类型编号,0x05表示端点描述符类型
0x81, //bEndpointAddress: 端点地址及输入输出属性
0x03, //bmAttributes: 端点的传输类型属性,0x3表示中断类型
0x04, //wMaxPacketSize 2个字节: 端点收、发的最大包的大小
0x00,
0x20, //bInterval: 主机查询端点的时间间隔
/* 34 */
}
; /* MOUSE_ConfigDescriptor */
4.JoyStickMouse HID报告描述符分析
const uint8_t Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] ={
0x05,0x01, /* Usage Page(Generic Desktop) */
0x09,0x02, /* Usage(Mouse) */
0xA1,0x01, /* Collection(Application) */
0x09,0x01, /* Usage(Pointer) */
0xA1,0x00, /* Collection(Physical) 8 */
0x05,0x09, /* Usage Page(Buttons) */
0x19,0x01, /* Usage Minimum(1) */
0x29,0x03, /* Usage Maximum(3) */
0x15,0x00, /* Logical Minimum(0) 16 */
0x25,0x01, /* Logical Maximum(1) */
0x95,0x03, /* Report Count(3) */
0x75,0x01, /* Report Size(1) */
0x81,0x02, /* Input(Variable) 24 */
0x95,0x01, /* Report Count(1) */
0x75,0x05, /* Report Size(5) */
0x81,0x01, /* Input(Constant,Array) */
0x05,0x01, /* Usage Page(Generic Desktop) 32 */
0x09,0x30, /* Usage(X axis) */
0x09,0x31, /* Usage(Y axis) */
0x09,0x38, /* Usage(Wheel) */
0x15,0x81, /* Logical Minimum(-127) 40 */
0x25,0x7F, /* Logical Maximum(127) */
0x75,0x08, /* Report Size(8) */
0x95,0x03, /* Report Count(3) */
0x81,0x06, /* Input(Variable, Relative) 48 */
0xC0, /* END_COLLECTION */
0x09,0x3c, /* USAGE (Motion Wakeup) */
0x05,0xff, /* USAGE_PAGE(Reserved or Other) */
0x09,0x01, /* Usage(Pointer) */
0x15,0x00, /* Logical Minimum(0) */
0x25,0x01, /* Logical Maximum(1) */
0x75,0x01, /* Report Size(1) */
0x95,0x02, /* Report Count(2) */
0xb1,0x22, /* FEATURE (Data,Var,Abs,NPrf) */
0x75,0x06, /* Report Size(6) */
0x95,0x01, /* Report Count(1) */
0xb1,0x01, /* FEATURE (Cnst,Ary,Abs) */
0xc0, /* END_COLLECTION 74 */
}; /* Joystick_ReportDescriptor */
Collection:表示集合,有四种类型Collection Physical(实体,CP)、Collection Application(应用,CA)、Collection Logical(逻辑,CL)、Vendor Defined(自定义,VD)。
这里只所以使用CA和CP是USB HID规范规定的,在HID Usage Tables1.22的30页有规定,如下:
关于这个HID的数据结构,我的解析如下(如果有错误欢迎指出,我是才开始学习HSB HID协议):
解析如下:
- 报告描述符有三段,第一段Buttos,1个BYTE表示,BIT0-BIT2分别表示三个按键,BI3-BI5表示填充位,报告的类型是INPUT。第2段用3字节表示(不包括REPORT ID)。第一个BYTE表示X轴移植,第2个BYTE表示Y轴偏移,第3个BYTE表示中间的滚轮的偏移,报告的类型是INPUT。第3段表示鼠标移动后的唤醒功能,只使用了BIT0-BIT1,BIT2-BIT7是填充位,报告类型是FEATURE.
- 如何查看是填充字段?INUPT/OUTPUT/FEATURE的第一人字段是Constant则表示是一个常量,不可变,用作填充。
- HID 报告中是以多少位的?我看了许多报告,目前都是以8BIT对齐,也就是一个BYTE。
- 代码中发送的报告是第二个报告,也就是X轴、Y轴偏移,ID默认为0,不带滚轮,所以BIT3默认是0。代码如下:
4.备注
现在的代码里面只使用的第二段的HID报告,向主机报告了鼠标的位移。