#include "hal.h" #include "hal_usb_cdc.h" #include "hal_serial_usb.h" #include "usbcfg.h" SerialUSBDriver SDU1; volatile bool cdc_dtr = false; #define HID_EP 1 #define CDC_INT_EP 2 #define CDC_DATA_EP 3 #define HID_EP_SIZE 0x0020U #define CDC_INT_SIZE 0x0010U #define CDC_DATA_SIZE 0x0040U #define HID_IF_DESC_SIZE \ (USB_DESC_INTERFACE_SIZE + 9U + (USB_DESC_ENDPOINT_SIZE * 2U)) #define CDC_FUNC_DESC_SIZE (5U + 5U + 4U + 5U) #define CDC_IF_DESC_SIZE \ (USB_DESC_INTERFACE_SIZE + CDC_FUNC_DESC_SIZE + \ USB_DESC_ENDPOINT_SIZE + \ USB_DESC_INTERFACE_SIZE + (USB_DESC_ENDPOINT_SIZE * 2U)) #define IAD_CDC_SIZE \ (USB_DESC_INTERFACE_ASSOCIATION_SIZE + CDC_IF_DESC_SIZE) #define CONFIG_TOTAL_SIZE \ (USB_DESC_CONFIGURATION_SIZE + HID_IF_DESC_SIZE + IAD_CDC_SIZE) /* * USB Device Descriptor. */ static const uint8_t device_descriptor_data[18] = { USB_DESC_DEVICE (0x0200, 0xEF, /* bDeviceClass (Miscellaneous). */ 0x02, /* bDeviceSubClass (Common). */ 0x01, /* bDeviceProtocol (IAD). */ 0x40, /* bMaxPacketSize. */ 0xEDDE, /* idVendor. */ 0x2025, /* idProduct. */ 0x0200, /* bcdDevice. */ 1, /* iManufacturer. */ 2, /* iProduct. */ 3, /* iSerialNumber. */ 1) /* bNumConfigurations. */ }; static const USBDescriptor device_descriptor = { sizeof device_descriptor_data, device_descriptor_data }; /* * Configuration Descriptor tree for HID LampArray + CDC ACM. */ static const uint8_t configuration_descriptor_data[] = { /* Configuration Descriptor */ USB_DESC_CONFIGURATION(CONFIG_TOTAL_SIZE, 3, /* bNumInterfaces (HID + CDC ctrl + CDC data). */ 0x01, /* bConfigurationValue. */ 0, /* iConfiguration. */ 0xC0, /* bmAttributes (self powered). */ 50), /* bMaxPower (100mA). */ /* HID Interface (0) */ USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ 0x00, /* bAlternateSetting. */ 0x02, /* bNumEndpoints. */ 0x03, /* bInterfaceClass (HID). */ 0x00, /* bInterfaceSubClass. */ 0x00, /* bInterfaceProtocol. */ 0), /* iInterface. */ /* HID Class Descriptor */ USB_DESC_BYTE (0x09), /* bLength. */ USB_DESC_BYTE (0x21), /* bDescriptorType (HID). */ USB_DESC_BCD (0x111), /* bcdHID (1.1). */ USB_DESC_BYTE (0x00), /* bCountryCode (None). */ USB_DESC_BYTE (0x01), /* bNumDescriptors. */ USB_DESC_BYTE (0x22), /* bDescriptorType (Report). */ USB_DESC_WORD (292), /* wDescriptorLength. */ /* HID EP1 IN */ USB_DESC_ENDPOINT (USB_ENDPOINT_IN(HID_EP), USB_EP_MODE_TYPE_INTR, HID_EP_SIZE, 0xFF), /* HID EP1 OUT */ USB_DESC_ENDPOINT (USB_ENDPOINT_OUT(HID_EP), USB_EP_MODE_TYPE_INTR, HID_EP_SIZE, 0xFF), /* IAD grouping the two CDC interfaces */ USB_DESC_INTERFACE_ASSOCIATION( 0x01, /* bFirstInterface. */ 2, /* bInterfaceCount. */ CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0x01, /* bFunctionProtocol (AT commands). */ 0), /* iFunction. */ /* CDC Control Interface (1) */ USB_DESC_INTERFACE (0x01, 0x00, 0x01, /* bNumEndpoints (interrupt IN). */ CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0x01, 0), /* Header Functional Descriptor */ USB_DESC_BYTE(5), USB_DESC_BYTE(CDC_CS_INTERFACE), USB_DESC_BYTE(CDC_HEADER), USB_DESC_BCD(0x0110), /* Call Management Functional Descriptor */ USB_DESC_BYTE(5), USB_DESC_BYTE(CDC_CS_INTERFACE), USB_DESC_BYTE(CDC_CALL_MANAGEMENT), USB_DESC_BYTE(0x03), /* bmCapabilities. */ USB_DESC_BYTE(0x02), /* bDataInterface. */ /* Abstract Control Management Functional Descriptor */ USB_DESC_BYTE(4), USB_DESC_BYTE(CDC_CS_INTERFACE), USB_DESC_BYTE(CDC_ABSTRACT_CONTROL_MANAGEMENT), USB_DESC_BYTE(0x02), /* bmCapabilities. */ /* Union Functional Descriptor */ USB_DESC_BYTE(5), USB_DESC_BYTE(CDC_CS_INTERFACE), USB_DESC_BYTE(CDC_UNION), USB_DESC_BYTE(0x01), /* bMasterInterface. */ USB_DESC_BYTE(0x02), /* bSlaveInterface. */ /* CDC Interrupt IN EP2 */ USB_DESC_ENDPOINT (USB_ENDPOINT_IN(CDC_INT_EP), USB_EP_MODE_TYPE_INTR, CDC_INT_SIZE, 0x01), /* CDC Data Interface (2) */ USB_DESC_INTERFACE (0x02, 0x00, 0x02, /* bNumEndpoints (bulk IN + OUT). */ CDC_DATA_INTERFACE_CLASS, 0x00, 0x00, 0), /* CDC Bulk OUT EP3 */ USB_DESC_ENDPOINT (USB_ENDPOINT_OUT(CDC_DATA_EP), USB_EP_MODE_TYPE_BULK, CDC_DATA_SIZE, 0x00), /* CDC Bulk IN EP3 */ USB_DESC_ENDPOINT (USB_ENDPOINT_IN(CDC_DATA_EP), USB_EP_MODE_TYPE_BULK, CDC_DATA_SIZE, 0x00), }; static const USBDescriptor configuration_descriptor = { sizeof configuration_descriptor_data, configuration_descriptor_data }; /* Generated by WaratahCmd.exe from lampArray sample */ static const uint8_t hid_report_descriptor_data[292] = { 0x05, 0x59, // UsagePage(Lighting And Illumination[0x0059]) 0x09, 0x01, // UsageId(LampArray[0x0001]) 0xA1, 0x01, // Collection(Application) 0x85, 0x01, // ReportId(1) 0x09, 0x02, // UsageId(LampArrayAttributesReport[0x0002]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x03, // UsageId(LampCount[0x0003]) 0x15, 0x00, // LogicalMinimum(0) 0x27, 0xFF, 0xFF, 0x00, 0x00, // LogicalMaximum(65,535) 0x95, 0x01, // ReportCount(1) 0x75, 0x10, // ReportSize(16) 0xB1, 0x03, // Feature(Constant, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x04, // UsageId(BoundingBoxWidthInMicrometers[0x0004]) 0x09, 0x05, // UsageId(BoundingBoxHeightInMicrometers[0x0005]) 0x09, 0x06, // UsageId(BoundingBoxDepthInMicrometers[0x0006]) 0x09, 0x07, // UsageId(LampArrayKind[0x0007]) 0x09, 0x08, // UsageId(MinUpdateIntervalInMicroseconds[0x0008]) 0x27, 0xFF, 0xFF, 0xFF, 0x7F, // LogicalMaximum(2,147,483,647) 0x95, 0x05, // ReportCount(5) 0x75, 0x20, // ReportSize(32) 0xB1, 0x03, // Feature(Constant, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0x85, 0x02, // ReportId(2) 0x09, 0x20, // UsageId(LampAttributesRequestReport[0x0020]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x21, // UsageId(LampId[0x0021]) 0x27, 0xFF, 0xFF, 0x00, 0x00, // LogicalMaximum(65,535) 0x95, 0x01, // ReportCount(1) 0x75, 0x10, // ReportSize(16) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0x85, 0x03, // ReportId(3) 0x09, 0x22, // UsageId(LampAttributesResponseReport[0x0022]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x21, // UsageId(LampId[0x0021]) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x23, // UsageId(PositionXInMicrometers[0x0023]) 0x09, 0x24, // UsageId(PositionYInMicrometers[0x0024]) 0x09, 0x25, // UsageId(PositionZInMicrometers[0x0025]) 0x09, 0x27, // UsageId(UpdateLatencyInMicroseconds[0x0027]) 0x09, 0x26, // UsageId(LampPurposes[0x0026]) 0x27, 0xFF, 0xFF, 0xFF, 0x7F, // LogicalMaximum(2,147,483,647) 0x95, 0x05, // ReportCount(5) 0x75, 0x20, // ReportSize(32) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x28, // UsageId(RedLevelCount[0x0028]) 0x09, 0x29, // UsageId(GreenLevelCount[0x0029]) 0x09, 0x2A, // UsageId(BlueLevelCount[0x002A]) 0x09, 0x2B, // UsageId(IntensityLevelCount[0x002B]) 0x09, 0x2C, // UsageId(IsProgrammable[0x002C]) 0x09, 0x2D, // UsageId(InputBinding[0x002D]) 0x26, 0xFF, 0x00, // LogicalMaximum(255) 0x95, 0x06, // ReportCount(6) 0x75, 0x08, // ReportSize(8) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0x85, 0x04, // ReportId(4) 0x09, 0x50, // UsageId(LampMultiUpdateReport[0x0050]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x03, // UsageId(LampCount[0x0003]) 0x25, 0x08, // LogicalMaximum(8) 0x95, 0x01, // ReportCount(1) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x55, // UsageId(LampUpdateFlags[0x0055]) 0x25, 0x01, // LogicalMaximum(1) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x21, // UsageId(LampId[0x0021]) 0x27, 0xFF, 0xFF, 0x00, 0x00, // LogicalMaximum(65,535) 0x95, 0x08, // ReportCount(8) 0x75, 0x10, // ReportSize(16) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x26, 0xFF, 0x00, // LogicalMaximum(255) 0x95, 0x20, // ReportCount(32) 0x75, 0x08, // ReportSize(8) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0x85, 0x05, // ReportId(5) 0x09, 0x60, // UsageId(LampRangeUpdateReport[0x0060]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x55, // UsageId(LampUpdateFlags[0x0055]) 0x25, 0x01, // LogicalMaximum(1) 0x95, 0x01, // ReportCount(1) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x61, // UsageId(LampIdStart[0x0061]) 0x09, 0x62, // UsageId(LampIdEnd[0x0062]) 0x27, 0xFF, 0xFF, 0x00, 0x00, // LogicalMaximum(65,535) 0x95, 0x02, // ReportCount(2) 0x75, 0x10, // ReportSize(16) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0x09, 0x51, // UsageId(RedUpdateChannel[0x0051]) 0x09, 0x52, // UsageId(GreenUpdateChannel[0x0052]) 0x09, 0x53, // UsageId(BlueUpdateChannel[0x0053]) 0x09, 0x54, // UsageId(IntensityUpdateChannel[0x0054]) 0x26, 0xFF, 0x00, // LogicalMaximum(255) 0x95, 0x04, // ReportCount(4) 0x75, 0x08, // ReportSize(8) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0x85, 0x06, // ReportId(6) 0x09, 0x70, // UsageId(LampArrayControlReport[0x0070]) 0xA1, 0x02, // Collection(Logical) 0x09, 0x71, // UsageId(AutonomousMode[0x0071]) 0x25, 0x01, // LogicalMaximum(1) 0x95, 0x01, // ReportCount(1) 0xB1, 0x02, // Feature(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField) 0xC0, // EndCollection() 0xC0, // EndCollection() }; static const USBDescriptor hid_report_descriptor = { sizeof hid_report_descriptor_data, hid_report_descriptor_data }; static const uint8_t usb_string0[] = { USB_DESC_BYTE(4), USB_DESC_BYTE(USB_DESCRIPTOR_STRING), USB_DESC_WORD(0x0409) }; static const uint8_t usb_string1[] = { USB_DESC_BYTE(16), USB_DESC_BYTE(USB_DESCRIPTOR_STRING), 'M', 0, 'e', 0, 't', 0, 'z', 0, 'N', 0, 'e', 0, 't', 0 }; static const uint8_t usb_string2[] = { USB_DESC_BYTE(30), USB_DESC_BYTE(USB_DESCRIPTOR_STRING), 'T', 0, 'w', 0, 'i', 0, 'n', 0, 'k', 0, 'l', 0, 'e', 0, 'S', 0, 't', 0, 'i', 0, 'c', 0, 'k', 0, 'V', 0, '2', 0 }; static const uint8_t usb_string3[] = { USB_DESC_BYTE(2 + 12*2), /* bLength */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), 'T', 0, 'w', 0, 'i', 0, 'n', 0, 'k', 0, 'l', 0, 'e', 0, 'S', 0, 't', 0, 'i', 0, 'c', 0, 'k', 0 }; static const USBDescriptor usb_strings[] = { {sizeof usb_string0, usb_string0}, {sizeof usb_string1, usb_string1}, {sizeof usb_string2, usb_string2}, {sizeof usb_string3, usb_string3} }; static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) { (void)usbp; (void)lang; switch (dtype) { case USB_DESCRIPTOR_DEVICE: return &device_descriptor; case USB_DESCRIPTOR_CONFIGURATION: return &configuration_descriptor; case USB_DESCRIPTOR_STRING: if (dindex < 4) return &usb_strings[dindex]; break; case 0x22: return &hid_report_descriptor; } return NULL; } #define HID_GET_REPORT 0x01U #define HID_SET_REPORT 0x09U #define HID_SET_IDLE 0x0AU #define HID_REPORT_BUF_SIZE 64U static uint8_t hid_get_buf[HID_REPORT_BUF_SIZE]; static uint8_t hid_set_buf[HID_REPORT_BUF_SIZE]; static struct { uint8_t id; uint16_t len; } hid_set_ctx; static void hid_set_cb(USBDriver *usbp) { (void)usbp; isr_hid_set_report(hid_set_ctx.id, hid_set_buf, hid_set_ctx.len); } /* EP1: HID interrupt IN/OUT */ static USBInEndpointState ep1instate; static USBOutEndpointState ep1outstate; static const USBEndpointConfig ep1config = { USB_EP_MODE_TYPE_INTR, NULL, NULL, NULL, HID_EP_SIZE, HID_EP_SIZE, &ep1instate, &ep1outstate, 1, NULL }; /* EP2: CDC interrupt IN (notifications) */ static USBInEndpointState ep2instate; static const USBEndpointConfig ep2config = { USB_EP_MODE_TYPE_INTR, NULL, sduInterruptTransmitted, NULL, CDC_INT_SIZE, 0x0000, &ep2instate, NULL, 1, NULL }; /* EP3: CDC bulk IN/OUT (data) */ static USBInEndpointState ep3instate; static USBOutEndpointState ep3outstate; static const USBEndpointConfig ep3config = { USB_EP_MODE_TYPE_BULK, NULL, sduDataTransmitted, sduDataReceived, CDC_DATA_SIZE, CDC_DATA_SIZE, &ep3instate, &ep3outstate, 1, NULL }; static bool usb_request(USBDriver *usbp) { uint8_t rtype = usbp->setup[0]; uint8_t req = usbp->setup[1]; if ((rtype & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE && req == USB_REQ_SET_INTERFACE) { usbSetupTransfer(usbp, NULL, 0, NULL); return true; } /* HID class requests targeted at interface 0 */ if ((rtype & (USB_RTYPE_TYPE_MASK | USB_RTYPE_RECIPIENT_MASK)) == (USB_RTYPE_TYPE_CLASS | USB_RTYPE_RECIPIENT_INTERFACE) && usbp->setup[4] == 0x00U) { uint8_t report_id = usbp->setup[2]; uint16_t wlength = (uint16_t)usbp->setup[6] | ((uint16_t)usbp->setup[7] << 8); switch (req) { case HID_GET_REPORT: { size_t len = HID_REPORT_BUF_SIZE; if (!isr_hid_get_report(report_id, hid_get_buf, &len)) return false; usbSetupTransfer(usbp, hid_get_buf, len < wlength ? len : wlength, NULL); return true; } case HID_SET_REPORT: hid_set_ctx.id = report_id; hid_set_ctx.len = wlength < HID_REPORT_BUF_SIZE ? wlength : HID_REPORT_BUF_SIZE; usbSetupTransfer(usbp, hid_set_buf, hid_set_ctx.len, hid_set_cb); return true; case HID_SET_IDLE: usbSetupTransfer(usbp, NULL, 0, NULL); return true; default: return false; } } if ((rtype & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS && req == CDC_SET_CONTROL_LINE_STATE) cdc_dtr = (usbp->setup[2] & 0x01U) != 0U; return sduRequestsHook(usbp); } static void usb_event(USBDriver *usbp, usbevent_t event) { switch (event) { case USB_EVENT_ADDRESS: return; case USB_EVENT_CONFIGURED: chSysLockFromISR(); if (usbp->state == USB_ACTIVE) { usbInitEndpointI(usbp, HID_EP, &ep1config); usbInitEndpointI(usbp, CDC_INT_EP, &ep2config); usbInitEndpointI(usbp, CDC_DATA_EP, &ep3config); sduConfigureHookI(&SDU1); } else if (usbp->state == USB_SELECTED) { usbDisableEndpointsI(usbp); } chSysUnlockFromISR(); return; case USB_EVENT_RESET: case USB_EVENT_UNCONFIGURED: case USB_EVENT_SUSPEND: cdc_dtr = false; chSysLockFromISR(); sduSuspendHookI(&SDU1); chSysUnlockFromISR(); return; case USB_EVENT_WAKEUP: chSysLockFromISR(); sduWakeupHookI(&SDU1); chSysUnlockFromISR(); return; case USB_EVENT_STALLED: return; } } static void sof_handler(USBDriver *usbp) { (void)usbp; osalSysLockFromISR(); sduSOFHookI(&SDU1); osalSysUnlockFromISR(); } const USBConfig usbcfg = { usb_event, get_descriptor, usb_request, sof_handler }; const SerialUSBConfig serusbcfg = { &USBD1, CDC_DATA_EP, /* bulk_in */ CDC_DATA_EP, /* bulk_out */ CDC_INT_EP /* int_in */ };