XINPUT协议模拟前序2-USB协议栈之设备新手入门
本文介绍了如何通过修改USB设备描述符和配置描述符,使STM32单片机模拟Xbox 360手柄被系统识别。主要内容包括:1) USB设备端的描述符结构解析,重点说明设备描述符、配置描述符和接口描述符的定义与作用;2) 详细的操作步骤,包括在STM32CubeMX创建Custom HID工程,修改usbd_desc.c和usbd_customhid.c文件中的描述符数据;3) 指出仅需正确实现设备描
上一章提了以下USB设备描述符和USB配置描述符,都是USB Device端的定义。
USB协议简化来说就三部分Host部分,Device部分,中间的传输部分,这次讲Device部分。

Device这边需要结合上一章讲的协议里面传输的内容和STM32 USB协议栈来看更加直观一些。
所以前序最好下载主页的xbox协议数据和STM32CubeMX生成一个Custom Hid设备比较容易看懂,使用单片机为STM32F103C8T6。
USB手柄设备简单来说需要实现几个功能,上传自己的描述符信息和特定字符串定义信息,上传按键和轴的状态,接收Host对Device的控制信息来控制外设,其中上传描述符信息和特定字符串定义信息与xbox 360手柄一致就会被系统认定为正版手柄并驱动(新版手柄不行,因为微软加入了加密芯片,硬件加密无法破解)
我直接套用第一章链接里面大佬的话:
脑袋里面可以想象一下这个是一个树状结构,看起来很抽象,但是通过实例对比其实还好。
设备描述符里面的数据就是微软xbox360手柄的产品定义和厂商定义,这个是USB协会定义的固定长度和结构,这个定义在usbd_desc.c里面,如果需要模拟手柄,这部分直接把设备描述符抄进去就好了,想理解的话,可以看注释,大概解释一下就是第一行是描述符长度,第二行是描述符类型,第三四个是设备版本号,第五个是设备的类,第六个是子类,后面可以自己结合注释理解。
通过协议可以直观看到传输内容,逆向的时候可以直接抄:
配置描述符只有一个(一般也只有一个),配置描述符里面定义的是接口数量,配置描述符大小,供电方式和供电电流。
配置描述符为什么需要定义长度?因为配置描述符传输的时候跟接口描述符和端点描述符打包到一起发送的,它是一整包一起发送的,配置描述符里面定义的是整包大小。以下是配置描述符的定义,在usbd_customhid.c里面可以找到,以下的其他描述符也在这
抓到的USB协议长成这样,有153Byte,很夸张的长度,因为它是超多描述符打包到一起发送的。
接口描述符(Interface Descriptor)里面定义的是设备的逻辑功能,比如Xbox手柄支持音频传输,HID数据传输,这两个明显不是同一个东西,所以分到不同的Interface。
Interface相关的有一个类的概念,类就是USB设备的功能分类,比如HID设备,音频设备,跟上面接口描述符描述的有相通的地方了吧?但是一个类可以对应多个Interface,比如一个设备支持好几个功能,但是每个功能只能对应一个类。XBOX手柄不是传统定义的HID类,它包含好几个功能,所以有好几个Interface,比如Interface0是手柄数据控制,Interface1是音频,还有其他的功能,它是一个定制的类(ID为0xFF,不是通用的定义),需要用定制的驱动,我们只需要用到Custom HID的功能,所以直接用Custom HID的例程只实现手柄的类HID Interface就好了,不需要实现音频等其他Interface。
以下是用到的手柄控制接口描述符定义,它里面定义了它需要用到2个Endpoint,同时定义了每个Endpoint的地址和功能,还有很多不知道的定义,因为是逆向工程,很多定义都是靠猜来的。
后面需要代码来实现功能的只有这两个Endpoint,Endpoint 1是IN端点,用来发送设备按键和摇杆状态数据(也有发送当前LED和电机状态的作用,但是可以不用实现),Endpoint 2是OUT端点,主要用来接收Host传过来的LED和电机控制状态。
Endpoint的实现放到下一章。
上面这张图只有一个比较重要需要讲的,就是最后的bInterval,可以理解为设备发送数据给主机的时间周期,4就是4帧,一帧1ms,所以是4ms上报一次状态,需要的话可以自己改这个参数,做到上报频率更高。
上面啰嗦讲了很多,其实就三个地方需要改,设备描述符和配置描述符发送正确,Host就会正常枚举为xbox手柄。
具体步骤:
1.参考结尾图创建工程
2.在usbd_desc.c里面修改Device descriptor,直接从协议分析仪复制数组:0x12, 0x01, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x08, 0x5E, 0x04, 0x8E, 0x02, 0x14, 0x01, 0x01, 0x02, 0x03, 0x01
这里面有一个关联以下宏定义需要修改(usbd_def.h):
#define USB_MAX_EP0_SIZE 8U
3.在usbd_customhid.c里面修改配置描述符,直接从抓的协议里面复制数组:
0x09, 0x02, 0x99, 0x00, 0x04, 0x01, 0x00, 0xA0,
0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0x5D,
0x01, 0x00, 0x11, 0x21, 0x00, 0x01, 0x01, 0x25,
0x81, 0x14, 0x00, 0x00, 0x00, 0x00, 0x13, 0x02,
0x08, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x20,
0x00, 0x04, 0x07, 0x05, 0x02, 0x03, 0x20, 0x00,
0x08, 0x09, 0x04, 0x01, 0x00, 0x04, 0xFF, 0x5D,
0x03, 0x00, 0x1B, 0x21, 0x00, 0x01, 0x01, 0x01,
0x83, 0x40, 0x01, 0x04, 0x20, 0x16, 0x85, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x83,
0x03, 0x20, 0x00, 0x02, 0x07, 0x05, 0x04, 0x03,
0x20, 0x00, 0x04, 0x07, 0x05, 0x85, 0x03, 0x20,
0x00, 0x40, 0x07, 0x05, 0x05, 0x03, 0x20, 0x00,
0x10, 0x09, 0x04, 0x02, 0x00, 0x01, 0xFF, 0x5D,
0x02, 0x00, 0x09, 0x21, 0x00, 0x01, 0x01, 0x22,
0x86, 0x07, 0x00, 0x07, 0x05, 0x86, 0x03, 0x20,
0x00, 0x10, 0x09, 0x04, 0x03, 0x00, 0x00, 0xFF,
0xFD, 0x13, 0x04, 0x06, 0x41, 0x00, 0x01, 0x01,
0x03
4.此时会报错,因为原数组长度不匹配,选择数组长度宏定义USB_CUSTOM_HID_CONFIG_DESC_SIZ,修改为153,排除报错
5.还有一些字符串描述符没有介绍,基本上就是直接照抄微软设定就好了,
#define USBD_VID 1118
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "@Microsoft"
#define USBD_PID_FS 654
#define USBD_PRODUCT_STRING_FS "Controller"
#define USBD_CONFIGURATION_STRING_FS "Custom HID Config"
#define USBD_INTERFACE_STRING_FS "\xB2\x03\x58\x00\x62\x00\x6F\x00\x78\x00\x20\x00\x53\x00\x65\x00\x63\x00\x75\x00\x72\x00\x69\x00\x74\x00\x79\x00\x20\x00\x4D\x00\x65\x00\x74\x00\x68\x00\x6F\x00\x64\x00\x20\x00\x33\x00\x2C\x00\x20\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6F\x00\x6E\x00\x20\x00\x31\x00\x2E\x00\x30\x00\x30\x00\x2C\x00\x20\x00\xA9\x00\x20\x00\x32\x00\x30\x00\x30\x00\x35\x00\x20\x00\x4D\x00\x69\x00\x63\x00\x72\x00\x6F\x00\x73\x00\x6F\x00\x66\x00\x74\x00\x20\x00\x43\x00\x6F\x00\x72\x00\x70\x00\x6F\x00\x72\x00\x61\x00\x74\x00\x69\x00\x6F\x00\x6E\x00\x2E\x00\x20\x00\x41\x00\x6C\x00\x6C\x00\x20\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x73\x00\x20\x00\x72\x00\x65\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00\x64\x00\x2E\x00"
编译烧录,此时就设备插到电脑上就可以识别为手柄了
以下为STM32CubeMX创建Custom HID设备参考配置(填入部分内容参考上面的字符描述符定义):

更多推荐



所有评论(0)