(USB HID) In/Out Report 收發 Function

Posted ollie-lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(USB HID) In/Out Report 收發 Function相关的知识,希望对你有一定的参考价值。

在紀錄 In/Out Report 收發之前先來看一下一個struct

 1 typedef struct _Device_cb
 2 {
 3   uint8_t  (*Init)         (void *pdev , uint8_t cfgidx);
 4   uint8_t  (*DeInit)       (void *pdev , uint8_t cfgidx);
 5  /* Control Endpoints*/
 6   uint8_t  (*Setup)        (void *pdev , USB_SETUP_REQ  *req);  
 7   uint8_t  (*EP0_TxSent)   (void *pdev );    
 8   uint8_t  (*EP0_RxReady)  (void *pdev );  
 9   /* Class Specific Endpoints*/
10   uint8_t  (*DataIn)       (void *pdev , uint8_t epnum);   
11   uint8_t  (*DataOut)      (void *pdev , uint8_t epnum); 
12   uint8_t  (*SOF)          (void *pdev); 
13   uint8_t  (*IsoINIncomplete)  (void *pdev); 
14   uint8_t  (*IsoOUTIncomplete)  (void *pdev);   
15 
16   uint8_t  *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length); 
17 #ifdef USB_OTG_HS_CORE 
18   uint8_t  *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);   
19 #endif
20 
21 #ifdef USB_SUPPORT_USER_STRING_DESC 
22   uint8_t  *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index,  uint16_t *length);   
23 #endif  
24   
25 } USBD_Class_cb_TypeDef;

這邊有特別註解 Control Endpoint, Class Specific Endpoint,理解翻譯就是Control Endpoint 即是所謂的Endpoint 0

在USB協定中,一定是透過Endpoint 0,而且一個裝置只能有一個,而且一定要支援。

它一次最大能傳的資料大小為64 bytes,並且是雙向傳輸。基本上一個USB裝置一插上電腦,電腦就會透過Endpoint 0來問一些資料。

根據USB2.0規格,Host必須保留10%的頻寬給Control傳輸。

 

而Class Specific Endpoint則是我定義 In/Out Report 需要使用的Function,在USB HID Init 時我會初始化我的Endpoint

 1 static uint8_t  USBD_HID_Init (void  *pdev, 
 2                                uint8_t cfgidx)
 3 {
 4   
 5   /* Open EP IN */
 6   DCD_EP_Open(pdev,
 7               HID_IN_EP,
 8               HID_IN_PACKET,
 9               USB_OTG_EP_INT);
10   
11   /* Open EP OUT */
12   DCD_EP_Open(pdev,
13               HID_OUT_EP,
14               HID_OUT_PACKET,
15               USB_OTG_EP_INT);
16     
17   DCD_EP_PrepareRx(pdev, HID_OUT_EP, WRReport_buf, USB_HID_RECEIVE_FRAME_SIZE);
18   
19   return USBD_OK;
20 }

在Window API理頭,主要是利用 WriteFile/ReadFile 跟 HidD_GetInputReport / HidD_SetOutputReport 來收發資料。

在Firmware裡頭對應 WriteFile/ReadFile 的是 Class Specific Endpoint

而對應 HidD_GetInputReport / HidD_SetOutputReport 則是透過 Endpoint 0去對Firmware 做控制。

GetInputReport / SetOutputReport 在 Firmeware 需要在 USBD_HID_Setup 裡頭加上 Set/Get Report的Case

 1 static uint8_t  USBD_HID_Setup (void  *pdev, USB_SETUP_REQ *req)
 2 {
 3   uint8_t USBD_HID_Report_LENGTH = 0;
 4   uint16_t len = 0;
 5   uint8_t  *pbuf = NULL;
 6   
 7   switch (req->bmRequest & USB_REQ_TYPE_MASK)
 8   {
 9   case USB_REQ_TYPE_CLASS :  
10     switch (req->bRequest)
11     {
12       
13       
14     case HID_REQ_SET_PROTOCOL:
15       USBD_HID_Protocol = (uint8_t)(req->wValue);
16       break;
17       
18     case HID_REQ_GET_PROTOCOL:
19       USBD_CtlSendData (pdev, 
20                         (uint8_t *)&USBD_HID_Protocol, 1);    
21       break;
22       
23     case HID_REQ_SET_IDLE:
24       USBD_HID_IdleState = (uint8_t)(req->wValue >> 8);
25       break;
26       
27     case HID_REQ_GET_IDLE:
28       USBD_CtlSendData (pdev, (uint8_t *)&USBD_HID_IdleState, 1);        
29       break;
30     
31     case HID_REQ_SET_REPORT:
32       /* HidD_SetOutputReport 1-byte = Report ID (IN) */
33       flag = 1;
34       USBD_HID_Report_ID = (uint8_t)(req->wValue);
35       USBD_HID_Report_LENGTH = (uint8_t)(req->wLength);
36       USBD_CtlPrepareRx (pdev, WRReport_buf, USBD_HID_Report_LENGTH); 
37       break;  
38   
39     case HID_REQ_GET_REPORT:
40       /* HidD_GetInputReport 1-byte = Report ID (OUT) */
41       flag = 1;
42       WRReport_buf[0] = 0x11;
43       WRReport_buf[1] = 0x22;
44       WRReport_buf[2] = 0x33;
45       WRReport_buf[3] = 0x44;
46       WRReport_buf[4] = 0x55;
47       WRReport_buf[5] = 0x66;
48       WRReport_buf[6] = 0x77;
49       WRReport_buf[7] = 0x88;
50       USBD_CtlSendData (pdev, (uint8_t *)&WRReport_buf, 8); // to pc
51       break; 
52       
53     default:
54       USBD_CtlError (pdev, req);
55       return USBD_FAIL; 
56     }
57     break;
58     
59   case USB_REQ_TYPE_STANDARD:
60     switch (req->bRequest)
61     {
62     case USB_REQ_GET_DESCRIPTOR: 
63       if( req->wValue >> 8 == HID_REPORT_DESC)
64       {
65             len = MIN(CUSTOMHID_SIZ_REPORT_DESC , req->wLength);
66             pbuf = CustomHID_ReportDescriptor;    
67         //pbuf = HID_MOUSE_ReportDesc;
68           
69       }
70       else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
71       {
72 //#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
73 //        pbuf = USBD_HID_Desc;   
74 //#else
75 //        pbuf = USBD_HID_CfgDesc + 0x12;
76 //#endif
77         pbuf = USBD_HID_CfgDesc + 0x12;
78         len = MIN(USB_HID_DESC_SIZ , req->wLength);
79       }
80       USBD_CtlSendData (pdev, pbuf, len);
81       break;
82     case USB_REQ_GET_INTERFACE :
83       USBD_CtlSendData (pdev, (uint8_t *)&USBD_HID_AltSet, 1);
84     
85       break;
86       
87     case USB_REQ_SET_INTERFACE :
88       USBD_HID_AltSet = (uint8_t)(req->wValue);
89       break;
90     }
91   }
92   return USBD_OK;
93 }

這邊提及一下Firmware 發送 Class Specific Endpoint In/Out Report 是利用

DCD_EP_Tx (pdev, HID_IN_EP, report, len); // In Report
DCD_EP_PrepareRx(pdev, HID_OUT_EP, WRReport_buf, HID_OUT_PACKET);

 

以上是关于(USB HID) In/Out Report 收發 Function的主要内容,如果未能解决你的问题,请参考以下文章

USB之HID类Set_Report Request[调试手记1]

STM32利用CUBEMX建立自定义HID工程,并且完成64字节的IN,OUT传输功能。

USB-HID的介绍

USB与BT HID reports描述符实践与抓包分析

usb蓝牙转hid

浅析usbhid驱动如何源源不断的获取usb鼠标