- __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
- {
- 0x12, /*bLength */
- USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
- 0x00, /*bcdUSB */
- 0x02,
- 0x00, /*bDeviceClass*/
- 0x00, /*bDeviceSubClass*/
- 0x00, /*bDeviceProtocol*/
- USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
- LOBYTE(USBD_VID), /*idVendor*/
- HIBYTE(USBD_VID), /*idVendor*/
- LOBYTE(USBD_PID_FS), /*idProduct*/
- HIBYTE(USBD_PID_FS), /*idProduct*/
- 0x00, /*bcdDevice rel. 2.00*/
- 0x02,
- USBD_IDX_MFC_STR, /*Index of manufacturer string*/
- USBD_IDX_PRODUCT_STR, /*Index of product string*/
- USBD_IDX_SERIAL_STR, /*Index of serial number string*/
- USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
- };
需要修改的设备描述符中的USBD_VID和USBD_PID_FS,这两个分别是厂商ID和产品ID,厂商ID是USB IF组织分配的,以下是微软的VID以及Xinput的PID
- #define USBD_VID 0x045E
- #define USBD_PID_FS 0x028E
2.修改配置/接口/HID/端点/厂商描述符:
- /* USB CUSTOM_HID device FS Configuration Descriptor */
- __ALIGN_BEGIN static uint8_t USBD_CUSTOM_HID_CfgFSDesc[USB_CUSTOM_HID_CONFIG_DESC_SIZ] __ALIGN_END =
- {
- /************** Configuration Descriptor 1 Bus Powered, 500 mA ****************/
- 0x09, /* bLength: Configuration Descriptor size */
- USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
- USB_CUSTOM_HID_CONFIG_DESC_SIZ,
- /* wTotalLength: Bytes returned */
- 0x00,
- 0x04, /*bNumInterfaces: 1 interface*/
- 0x01, /*bConfigurationValue: Configuration value*/
- 0x00, /*iConfiguration: Index of string descriptor describing
- the configuration*/
- 0xA0, /*bmAttributes: Bus Powered, Remote Wakeup*/
- 0xFA, /*MaxPower 500 mA: this current is used for detecting Vbus*/
- /**************Interface Descriptor 0/0 Vendor-Specific, 2 Endpoints****************/
- /* 09 */
- 0x09, /*bLength: Interface Descriptor size*/
- USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
- 0x00, /*bInterfaceNumber: Number of Interface*/
- 0x00, /*bAlternateSetting: Alternate setting*/
- 0x02, /*bNumEndpoints*/
- 0xFF, /*Vendor-Specific*/
- 0x5D, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
- 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
- 0x00, /*iInterface: Index of string descriptor*/
- /**************Unrecognized Class-Specific Descriptor***********************/
- /* 18 */
- 0x11, /*bLength: CUSTOM_HID Descriptor size*/
- 0x21, /*bDescriptorType: CUSTOM_HID*/
- 0x10,0x01,0x01,0x25,0x81,0x14,0x03,0x03,
- 0x03,0x04,0x13,0x02,0x08,0x03,0x03,
- /**************Endpoint Descriptor 81 1 In, Interrupt, 4 ms******************/
- /* 27 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
- CUSTOM_HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- CUSTOM_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- CUSTOM_HID_FS_BINTERVAL, /*bInterval: Polling Interval */
- /**************Endpoint Descriptor 02 2 Out, Interrupt, 8 ms******************/
- /* 34 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
- 0x02, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- 0x20, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- 0x08, /*bInterval: Polling Interval */
- /**************Interface Descriptor 1/0 Vendor-Specific, 2 Endpoints****************/
- /* 09 */
- 0x09, /*bLength: Interface Descriptor size*/
- USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
- 0x01, /*bInterfaceNumber: Number of Interface*/
- 0x00, /*bAlternateSetting: Alternate setting*/
- 0x02, /*bNumEndpoints*/
- 0xFF, /*Vendor-Specific*/
- 0x5D, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
- 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
- 0x00, /*iInterface: Index of string descriptor*/
- /**************Unrecognized Class-Specific Descriptor***********************/
- /* 18 */
- 0x1B, /*bLength: CUSTOM_HID Descriptor size*/
- 0x21, /*bDescriptorType: CUSTOM_HID*/
- 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,
- /**************Endpoint Descriptor 81 1 In, Interrupt, 4 ms******************/
- /* 27 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
- 0x83, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- 0x20, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- 0x02, /*bInterval: Polling Interval */
- /**************Endpoint Descriptor 02 2 Out, Interrupt, 8 ms******************/
- /* 34 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
- 0x04, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- 0x20, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- 0x04, /*bInterval: Polling Interval */
- /**************Interface Descriptor 2/0 Vendor-Specific, 2 Endpoints****************/
- /* 09 */
- 0x09, /*bLength: Interface Descriptor size*/
- USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
- 0x02, /*bInterfaceNumber: Number of Interface*/
- 0x00, /*bAlternateSetting: Alternate setting*/
- 0x01, /*bNumEndpoints*/
- 0xFF, /*Vendor-Specific*/
- 0x5D, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
- 0x02, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
- 0x00, /*iInterface: Index of string descriptor*/
- /**************Unrecognized Class-Specific Descriptor***********************/
- /* 18 */
- 0x09, /*bLength: CUSTOM_HID Descriptor size*/
- 0x21, /*bDescriptorType: CUSTOM_HID*/
- 0x00,0x01,0x01,0x22,0x86,0x07,0x00,
- /**************Endpoint Descriptor 81 1 In, Interrupt, 4 ms******************/
- /* 27 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
- 0x86, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- 0x20, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- 0x10, /*bInterval: Polling Interval */
- /**************nterface Descriptor 3/0 Vendor-Specific, 0 Endpoints****************/
- /* 09 */
- 0x09, /*bLength: Interface Descriptor size*/
- USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
- 0x03, /*bInterfaceNumber: Number of Interface*/
- 0x00, /*bAlternateSetting: Alternate setting*/
- 0x00, /*bNumEndpoints*/
- 0xFF, /*Vendor-Specific*/
- 0xFD, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
- 0x13, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
- 0x04, /*iInterface: Index of string descriptor*/
- /**************Unrecognized Class-Specific Descriptor***********************/
- /* 18 */
- 0x06, /*bLength: CUSTOM_HID Descriptor size*/
- 0x41, /*bDescriptorType: CUSTOM_HID*/
- 0x00,0x01,0x01,0x03
- };
这个配置描述符即可比较长,不过也比较统一,大家可以直接复制参考代码中的也可以,不过要注意以下接口索引号,端点地址之类的,比如我们定义的
- #define CUSTOM_HID_EPIN_ADDR 0x81U
- #define CUSTOM_HID_EPIN_SIZE 20U
这个端点1地址以及端点大小正是我们自己定义的,大小一定不能小于20,因为微软XBOX360手柄定义的报表描述符正是20个字节。
大家可能比较好奇,XBOX360手柄为什么没有报表没舒服,我们在代码中也没有实现,直接给它初始化为0,这是为何?
其实我也不清楚,是不是系统自己只要认对应的VID和PID以及配置描述符正确,应该就可以正确枚举了?其实我们Usb主机好像也确实没有问我们设备要报表描述符。
3. 添加厂商请求的处理。在USBD_CUSTOM_HID_Setup函数值,除了类请求USB_REQ_TYPE_CLASS、标准请求USB_REQ_TYPE_STANDARD,还需要增加一个厂商请求USB_REQ_TYPE_VENDOR,如下:
- static uint8_t USBD_CUSTOM_HID_Setup(USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req)
- {
- USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
- uint16_t len = 0U;
- uint8_t *pbuf = NULL;
- uint16_t status_info = 0U;
- uint8_t ret = USBD_OK;
- switch (req->bmRequest & USB_REQ_TYPE_MASK)
- {
- case USB_REQ_TYPE_VENDOR:
- switch (req->bRequest)
- {
- case 0x01:
- {
- /* code */
- if(req->wLength == 0x14)
- {
- len = MIN(0x14, req->wLength);
- pbuf = vendor_request_content;
- }
- else if(req->wLength == 0x08)
- {
- len = MIN(0x8, req->wLength);
- pbuf = vendor_re2;
- }
- else if(req->wLength == 0x04)
- {
- len = MIN(0x04, req->wLength);
- pbuf = vendor_re2;
- }
- break;
- }
- default:
- break;
- }
- USBD_CtlSendData(pdev, pbuf, len);
- break;
- default:
- USBD_CtlError(pdev, req);
- ret = USBD_FAIL;
- break;
- }
- return ret;
- }
实现上面这些,基本在电脑端可以枚举成功一个Xbox 360 Controller for Windows 手柄设备。但是我们并不能满足一次。
4. 解析摇杆电位器和按键数据。
- void Xinput_Handle(void)
- {
- int16_t X=0,Y=0;
- //X-Y
- for(u8 i=0; i<AD_DATA_SIZE;)
- {
- AdXSum += AD_DATA[i];
- i++;
- AdYSum += AD_DATA[i];
- i++;
- }
- Xtemp=AdXSum/10;
- AdXSum=0;
- Ytemp=AdYSum/10;
- AdYSum=0;
- if(Xtemp>Xmax)
- Xtemp=Xmax;
- if(Xtemp<Xmin)
- Xtemp=Xmin;
- if(Ytemp>Ymax)
- Ytemp=Ymax;
- if(Ytemp<Ymin)
- Ytemp=Ymin;
- X=(int16_t)map( Xtemp, Xmin, Xmax, INT16_MAX, INT16_MIN );
- Y=(int16_t)map( Ytemp, Ymin, Ymax, INT16_MIN, INT16_MAX );
-
-
- //Button
- if((UPKEY)==0)//Y
- {
- TXData[BUTTON_PACKET_2] |= Y_MASK_ON;
- }else{
- TXData[BUTTON_PACKET_2] &= Y_MASK_OFF;
- }
- if((DNKEY)==0)//A
- {
- TXData[BUTTON_PACKET_2] |= A_MASK_ON;
- }else{
- TXData[BUTTON_PACKET_2] &= A_MASK_OFF;
-
- }
-
- if(LFKEY==0)
- {
- TXData[BUTTON_PACKET_2] |= X_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_2] &= X_MASK_OFF;
- }
- if(RGKEY==0)
- {
- TXData[BUTTON_PACKET_2] |= B_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_2] &= B_MASK_OFF;
- }
-
- if(BKKEY==0)//BUTTON_BACK
- {
- TXData[BUTTON_PACKET_1] |= BACK_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_1] &= BACK_MASK_OFF;
- }
- if(MDKEY==0)//BUTTON_LB
- {
- TXData[BUTTON_PACKET_2] |= LB_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_2] &= LB_MASK_OFF;
- }
- if(STKEY==0)//BUTTON_START
- {
- TXData[BUTTON_PACKET_1] |= START_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_1] &= START_MASK_OFF;
- }
- if(TBKEY==0)//BUTTON_RB
- {
- TXData[BUTTON_PACKET_2] |= RB_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_2] &= RB_MASK_OFF;
- }
- if(SW1!=0)
- {
- TXData[BUTTON_PACKET_2] |= **_MASK_ON;
- } else {
- TXData[BUTTON_PACKET_2] &= **_MASK_OFF;
- }
- TXData[LEFT_STICK_X_PACKET_LSB] = LOBYTE(Y); // (CONFERIR)
- TXData[LEFT_STICK_X_PACKET_MSB] = HIBYTE(Y);
- //Left Stick Y Axis
- TXData[LEFT_STICK_Y_PACKET_LSB] = LOBYTE(X);
- TXData[LEFT_STICK_Y_PACKET_MSB] = HIBYTE(X);
- //Clear DPAD
- TXData[BUTTON_PACKET_1] &= DPAD_MASK_OFF;
- USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,(u8*)&TXData, 20);
- }
这里我们直接参考了GitHub上大佬的。其中map函数的作用把12位AD值0~4095转成16位的0~65535。然后扫描一下按键,按要求赋值即可。我们这里实现了左摇杆,以及A、B、X、Y、LB、RB、START、BACK等按键。
下载验证:
请大家查看我们的视频: