第五篇 USB设备枚举过程(4)

上一篇:https://blog.****.net/qq_40088639/article/details/109765847

六、语言ID描述符和字符串描述符的请求

这个阶段,Host会先请求语言ID字符串,然后再依次请求厂商字符串、产品字符串和***字符串。

1. 字符串描述符的结构

 主机在获得配置描述符集合之后,会下发获得语言ID的请求,以及获得字符串的请求。在USB协议中,字符串描述符是可选的。在设备描述符中,申请了三个非0的索引值:

1:是厂商字符串的索引值

2:是产品字符串的索引值

3:是产品***的索引值

主机通过索引值来获取对应的字符串数据。索引值为0则表示获取的是语言ID字符串。字符串描述符的结构很简单,如下:

                                                                                    语言ID描述符的结构

偏移量/字节

大小/字节

说明

0

bLength

1

该描述符的长度(4字节=0x04)

1

bDescriptorType

1

描述符类型(字符串类型为0x03)

2

wLANGID

2

语言ID号

                                                                                   字符串描述符的结构

偏移量/字节

大小/字节

说明

0

bLength

1

该描述符的长度(n)

1

bDescriptorType

1

描述符类型(字符串类型为0x03)

2

bString

N

UNICODE编码的字符串

说明:

(1) 语言ID,只使用美式英语的一种,即0x0409.

(2) bString字段使用的是UNICODE编码的字符串,使用两个字节来表示一个字符。

 

2. 字符串描述符在程序中的定义

首先,在定义设备描述符的时候,厂商字符串索引值、产品字符串索引值、产品***索引值都不为0。并且按照协议,分别给设备描述符的iManufacturer、iProduct、iSerialNumber赋了对应的索引值。设备描述符中,对这三个域的赋值如下:

第五篇 USB设备枚举过程(4)

因为,设备描述符之前已经传入主机,主机经过分析得知,设备这边是有定义这些字符串的(索引值不为0,就说明有定义),接下来,主机会单独请求获得这些字符串数据。

实例:Host下发的数据包(标准请求)

请求获得语言ID字符串:

bmRequestType=0x80  bRequest=0x06  wValue =0x300  wIndex=0x00 

 

请求获得产品字符串:

bmRequestType=0x80  bRequest=0x06  wValue=0x302  wIndex=0x409

 

请求获得产品***字符串:

bmRequestType=0x80  bRequest=0x06  wValue=0x303  wIndex=0x409

 

根据bRequest可知这是一个获得描述符的请求,对wValue高字节的解析可知,这是一个获得字符串描述符的请求,对wValue低字节的解析可知,这是一个获得XXX字符串的请求。

 

注意低字节表示字符串索引值。高字节表示描述符类型,都是属于字符串描述符,所以都是03。

这些字符串在程序中的定义如下:

第五篇 USB设备枚举过程(4)

第五篇 USB设备枚举过程(4)

其中

CONFIG_USB_DEVICE_MANUFACTURER

CONFIG_USB_DEVICE_PRODUCT

CONFIG_USB_DEVICE_SN

这三个宏被定义在当前工程配置文件prj.conf中,如下:

第五篇 USB设备枚举过程(4)

/******************************************************************************

(1) 配置文件prj.conf里面定义:  CONFIG_USB_DEVICE_MANUFACTURER="Actions

所以厂商字符串描述符总字节数: 

sizeof("Actions")*2 = 7 * 2 =14 Byte  + bLength(1 Byte)  +  bDescriptorType(1 Byte) = 16 Byte

(2) 配置文件prj.conf里面定义:  CONFIG_USB_DEVICE_PRODUCT="USB Dongle"

所以产品字符串描述符总字节数: 

sizeof("USB Dongle")*2 = 10 * 2 = 20 Byte + bLength(1 Byte) +  bDescriptorType(1 Byte) = 22 Byte

(3) 配置文件prj.conf里面定义:  CONFIG_USB_DEVICE_SN="0123456789AB"

所以产品***描述符总字节数: 

sizeof("0123456789AB") * 2 = 12 * 2 = 24 Byte + bLength(1 Byte) + bDescriptorType(1 Byte) = 26 Byte

******************************************************************************/

对照协议分析仪进行分析:

第五篇 USB设备枚举过程(4)

串口打印跟踪:

第五篇 USB设备枚举过程(4)

 

七、又再一次获取设备描述符

协议分析仪:

第五篇 USB设备枚举过程(4)

串口跟踪打印:

第五篇 USB设备枚举过程(4)

 

八、又再一次获取配置描述符

这次和第一次获取描述符有所不同,第一次获取配置描述符,请求的长度是255(0xFF)字节。我们可以认为这是不合理的,正确的请求应该是:第一次先获取9字节长度的配置描述符,然后根据配置描述符中配置集合的长度,再次获取配置描述符集合。第二次获取的时候,设备会将配置描述符、接口描述符、类特殊描述符、端点描述符等一并返回。这里分两次获取,也就是有两个事务(或者说有两次数据传输)。这一次获取配置描述符,是比较合理的请求。

协议分析仪:

第五篇 USB设备枚举过程(4)

 

串口跟踪打印:

第五篇 USB设备枚举过程(4)

 

下一篇: