Prechádzať zdrojové kódy

add HID mouse as interface to the CDC device

Dmitry 7 rokov pred
rodič
commit
c280f0649e
1 zmenil súbory, kde vykonal 175 pridanie a 18 odobranie
  1. 175 18
      demo/cdc_loop.c

+ 175 - 18
demo/cdc_loop.c

@@ -19,17 +19,25 @@
 #include "stm32.h"
 #include "usb.h"
 #include "usb_cdc.h"
+#include "usb_hid.h"
+#include "hid_usage_desktop.h"
+#include "hid_usage_button.h"
 
 #define CDC_EP0_SIZE    0x08
 #define CDC_RXD_EP      0x01
-#define CDC_TXD_EP      0x82
+#define CDC_TXD_EP      0x81
 #define CDC_DATA_SZ     0x40
-#define CDC_NTF_EP      0x83
+#define CDC_NTF_EP      0x82
 #define CDC_NTF_SZ      0x08
+#define HID_RIN_EP      0x83
+#define HID_RIN_SZ      0x10
+
 #define CDC_LOOPBACK
+#define ENABLE_HID_COMBO
 
 //#define CDC_USE_IRQ   /* uncomment to build interrupt-based demo */
 
+/* Declaration of the report descriptor */
 struct cdc_config {
     struct usb_config_descriptor        config;
     struct usb_interface_descriptor     comm;
@@ -41,13 +49,45 @@ struct cdc_config {
     struct usb_interface_descriptor     data;
     struct usb_endpoint_descriptor      data_eprx;
     struct usb_endpoint_descriptor      data_eptx;
+#ifdef ENABLE_HID_COMBO
+    struct usb_interface_descriptor     hid;
+    struct usb_hid_descriptor           hid_desc;
+    struct usb_endpoint_descriptor      hid_ep;
+#endif //ENABLE_HID_COMBO
 } __attribute__((packed));
 
+/* HID mouse report desscriptor. 2 axis 5 buttons */
+static const uint8_t hid_report_desc[] = {
+    HID_USAGE_PAGE(HID_PAGE_DESKTOP),
+    HID_USAGE(HID_DESKTOP_MOUSE),
+    HID_COLLECTION(HID_APPLICATION_COLLECTION),
+        HID_USAGE(HID_DESKTOP_POINTER),
+        HID_COLLECTION(HID_PHYSICAL_COLLECTION),
+            HID_USAGE(HID_DESKTOP_X),
+            HID_USAGE(HID_DESKTOP_Y),
+            HID_LOGICAL_MINIMUM(-127),
+            HID_LOGICAL_MAXIMUM(127),
+            HID_REPORT_SIZE(8),
+            HID_REPORT_COUNT(2),
+            HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE ),
+            HID_USAGE_PAGE(HID_PAGE_BUTTON),
+            HID_USAGE_MINIMUM(1),
+            HID_USAGE_MAXIMUM(5),
+            HID_LOGICAL_MINIMUM(0),
+            HID_LOGICAL_MAXIMUM(1),
+            HID_REPORT_SIZE(1),
+            HID_REPORT_COUNT(5),
+            HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE ),
+        HID_END_COLLECTION,
+    HID_END_COLLECTION,
+};
+
+/* Device descriptor */
 static const struct usb_device_descriptor device_desc = {
     .bLength            = sizeof(struct usb_device_descriptor),
     .bDescriptorType    = USB_DTYPE_DEVICE,
     .bcdUSB             = VERSION_BCD(2,0,0),
-    .bDeviceClass       = USB_CLASS_CDC,
+    .bDeviceClass       = USB_CLASS_PER_INTERFACE,
     .bDeviceSubClass    = USB_SUBCLASS_NONE,
     .bDeviceProtocol    = USB_PROTO_NONE,
     .bMaxPacketSize0    = CDC_EP0_SIZE,
@@ -60,12 +100,17 @@ static const struct usb_device_descriptor device_desc = {
     .bNumConfigurations = 1,
 };
 
+/* Device configuration descriptor */
 static const struct cdc_config config_desc = {
     .config = {
         .bLength                = sizeof(struct usb_config_descriptor),
         .bDescriptorType        = USB_DTYPE_CONFIGURATION,
         .wTotalLength           = sizeof(struct cdc_config),
+#ifdef ENABLE_HID_COMBO
+        .bNumInterfaces         = 3,
+#else
         .bNumInterfaces         = 2,
+#endif //ENABLE_HID_COMBO
         .bConfigurationValue    = 1,
         .iConfiguration         = NO_DESCRIPTOR,
         .bmAttributes           = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
@@ -144,6 +189,36 @@ static const struct cdc_config config_desc = {
         .wMaxPacketSize         = CDC_DATA_SZ,
         .bInterval              = 0x01,
     },
+#ifdef ENABLE_HID_COMBO
+    .hid = {
+        .bLength                = sizeof(struct usb_interface_descriptor),
+        .bDescriptorType        = USB_DTYPE_INTERFACE,
+        .bInterfaceNumber       = 2,
+        .bAlternateSetting      = 0,
+        .bNumEndpoints          = 1,
+        .bInterfaceClass        = USB_CLASS_HID,
+        .bInterfaceSubClass     = USB_HID_SUBCLASS_NONBOOT,
+        .bInterfaceProtocol     = USB_HID_PROTO_NONBOOT,
+        .iInterface             = NO_DESCRIPTOR,
+    },
+    .hid_desc = {
+        .bLength                = sizeof(struct usb_hid_descriptor),
+        .bDescriptorType        = USB_DTYPE_HID,
+        .bcdHID                 = VERSION_BCD(1,0,0),
+        .bCountryCode           = USB_HID_COUNTRY_NONE,
+        .bNumDescriptors        = 1,
+        .bDescriptorType0       = USB_DTYPE_HID_REPORT,
+        .wDescriptorLength0     = sizeof(hid_report_desc),
+    },
+    .hid_ep = {
+        .bLength                = sizeof(struct usb_endpoint_descriptor),
+        .bDescriptorType        = USB_DTYPE_ENDPOINT,
+        .bEndpointAddress       = HID_RIN_EP,
+        .bmAttributes           = USB_EPTYPE_INTERRUPT,
+        .wMaxPacketSize         = HID_RIN_SZ,
+        .bInterval              = 50,
+    },
+#endif // ENABLE_HID_COMBO
 };
 
 static const struct usb_string_descriptor lang_desc     = USB_ARRAY_DESC(USB_LANGID_ENG_US);
@@ -167,6 +242,12 @@ static struct usb_cdc_line_coding cdc_line = {
     .bDataBits          = 8,
 };
 
+static struct {
+    int8_t      x;
+    int8_t      y;
+    uint8_t     buttons;
+} __attribute__((packed)) hid_report_data;
+
 static usbd_respond cdc_getdesc (usbd_ctlreq *req, void **address, uint16_t *length) {
     const uint8_t dtype = req->wValue >> 8;
     const uint8_t dnumber = req->wValue & 0xFF;
@@ -200,20 +281,54 @@ static usbd_respond cdc_getdesc (usbd_ctlreq *req, void **address, uint16_t *len
 
 
 static usbd_respond cdc_control(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) {
-    if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) != (USB_REQ_INTERFACE | USB_REQ_CLASS)) return usbd_fail;
-    switch (req->bRequest) {
-    case USB_CDC_SET_CONTROL_LINE_STATE:
-        return usbd_ack;
-    case USB_CDC_SET_LINE_CODING:
-        memmove( req->data, &cdc_line, sizeof(cdc_line));
-        return usbd_ack;
-    case USB_CDC_GET_LINE_CODING:
-        dev->status.data_ptr = &cdc_line;
-        dev->status.data_count = sizeof(cdc_line);
-        return usbd_ack;
-    default:
-        return usbd_fail;
+    if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
+        && req->wIndex == 0 ) {
+        switch (req->bRequest) {
+        case USB_CDC_SET_CONTROL_LINE_STATE:
+            return usbd_ack;
+        case USB_CDC_SET_LINE_CODING:
+            memcpy( req->data, &cdc_line, sizeof(cdc_line));
+            return usbd_ack;
+        case USB_CDC_GET_LINE_CODING:
+            dev->status.data_ptr = &cdc_line;
+            dev->status.data_count = sizeof(cdc_line);
+            return usbd_ack;
+        default:
+            return usbd_fail;
+        }
+    }
+#ifdef ENABLE_HID_COMBO
+    if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
+        && req->wIndex == 2 ) {
+        switch (req->bRequest) {
+        case USB_HID_SETIDLE:
+            return usbd_ack;
+        case USB_HID_GETREPORT:
+            dev->status.data_ptr = &hid_report_data;
+            dev->status.data_count = sizeof(hid_report_data);
+            return usbd_ack;
+        default:
+            return usbd_fail;
+        }
+    }
+    if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_STANDARD)
+        && req->wIndex == 2
+        && req->bRequest == USB_STD_GET_DESCRIPTOR) {
+        switch (req->wValue >> 8) {
+        case USB_DTYPE_HID:
+            dev->status.data_ptr = (uint8_t*)&(config_desc.hid_desc);
+            dev->status.data_count = sizeof(config_desc.hid_desc);
+            return usbd_ack;
+        case USB_DTYPE_HID_REPORT:
+            dev->status.data_ptr = (uint8_t*)hid_report_desc;
+            dev->status.data_count = sizeof(hid_report_desc);
+            return usbd_ack;
+        default:
+            return usbd_fail;
+        }
     }
+#endif // ENABLE_HID_COMBO
+    return usbd_fail;
 }
 
 
@@ -227,6 +342,39 @@ static void cdc_txonly(usbd_device *dev, uint8_t event, uint8_t ep) {
     usbd_ep_write(dev, ep, fifo, CDC_DATA_SZ);
 }
 
+/* HID mouse IN endpoint callback */
+static void hid_mouse_move(usbd_device *dev, uint8_t event, uint8_t ep) {
+    static uint8_t t = 0;
+    if (t < 0x10) {
+        hid_report_data.x = 1;
+        hid_report_data.y = 0;
+    } else if (t < 0x20) {
+        hid_report_data.x = 1;
+        hid_report_data.y = 1;
+    } else if (t < 0x30) {
+        hid_report_data.x = 0;
+        hid_report_data.y = 1;
+    } else if (t < 0x40) {
+        hid_report_data.x = -1;
+        hid_report_data.y = 1;
+    } else if (t < 0x50) {
+        hid_report_data.x = -1;
+        hid_report_data.y = 0;
+    } else if (t < 0x60) {
+        hid_report_data.x = -1;
+        hid_report_data.y = -1;
+    } else if (t < 0x70) {
+        hid_report_data.x = 0;
+        hid_report_data.y = -1;
+    } else  {
+        hid_report_data.x = 1;
+        hid_report_data.y = -1;
+    }
+    t = (t + 1) & 0x7F;
+    usbd_ep_write(dev, ep, &hid_report_data, sizeof(hid_report_data));
+}
+
+/* CDC loop callback. Both for the Data IN and Data OUT endpoint */
 static void cdc_loopback(usbd_device *dev, uint8_t event, uint8_t ep) {
     int _t;
     switch (event) {
@@ -252,6 +400,10 @@ static usbd_respond cdc_setconf (usbd_device *dev, uint8_t cfg) {
     switch (cfg) {
     case 0:
         /* deconfiguring device */
+#ifdef ENABLE_HID_COMBO
+        usbd_ep_deconfig(dev, HID_RIN_EP);
+        usbd_reg_endpoint(dev, HID_RIN_EP, 0);
+#endif // ENABLE_HID_COMBO
         usbd_ep_deconfig(dev, CDC_NTF_EP);
         usbd_ep_deconfig(dev, CDC_TXD_EP);
         usbd_ep_deconfig(dev, CDC_RXD_EP);
@@ -260,8 +412,8 @@ static usbd_respond cdc_setconf (usbd_device *dev, uint8_t cfg) {
         return usbd_ack;
     case 1:
         /* configuring device */
-        usbd_ep_config(dev, CDC_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
-        usbd_ep_config(dev, CDC_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
+        usbd_ep_config(dev, CDC_RXD_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, CDC_DATA_SZ);
+        usbd_ep_config(dev, CDC_TXD_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, CDC_DATA_SZ);
         usbd_ep_config(dev, CDC_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
 #if defined(CDC_LOOPBACK)
         usbd_reg_endpoint(dev, CDC_RXD_EP, cdc_loopback);
@@ -270,6 +422,11 @@ static usbd_respond cdc_setconf (usbd_device *dev, uint8_t cfg) {
         usbd_reg_endpoint(dev, CDC_RXD_EP, cdc_rxonly);
         usbd_reg_endpoint(dev, CDC_TXD_EP, cdc_txonly);
 #endif
+#ifdef ENABLE_HID_COMBO
+        usbd_ep_config(dev, HID_RIN_EP, USB_EPTYPE_INTERRUPT, HID_RIN_SZ);
+        usbd_reg_endpoint(dev, HID_RIN_EP, hid_mouse_move);
+        usbd_ep_write(dev, HID_RIN_EP, 0, 0);
+#endif // ENABLE_HID_COMBO
         usbd_ep_write(dev, CDC_TXD_EP, 0, 0);
         return usbd_ack;
     default: