3636 */
3737
3838/* Includes ------------------------------------------------------------------*/
39- #include <pbio/protocol.h>
40- #include <pbio/version.h>
41-
4239#include "usbd_ctlreq.h"
4340#include "usbd_pybricks.h"
4441
4542#include "../usb_ch9.h"
46- #include "../usb_common_desc.h"
4743
4844
4945/** @addtogroup STM32_USB_DEVICE_LIBRARY
@@ -116,7 +112,14 @@ USBD_ClassTypeDef USBD_Pybricks_ClassDriver =
116112/* USB Pybricks device Configuration Descriptor */
117113typedef struct PBDRV_PACKED {
118114 pbdrv_usb_conf_desc_t conf_desc ;
119- pbdrv_usb_iface_desc_t iface_desc ;
115+ pbdrv_usb_iad_desc_t iad ;
116+ pbdrv_usb_iface_desc_t comm_iface ;
117+ pbdrv_usb_cdc_header_desc_t cdc_header ;
118+ pbdrv_usb_cdc_call_mgmt_desc_t cdc_call_mgmt ;
119+ pbdrv_usb_cdc_acm_desc_t cdc_acm ;
120+ pbdrv_usb_cdc_union_desc_t cdc_union ;
121+ pbdrv_usb_ep_desc_t cmd_ep ;
122+ pbdrv_usb_iface_desc_t data_iface ;
120123 pbdrv_usb_ep_desc_t ep_out ;
121124 pbdrv_usb_ep_desc_t ep_in ;
122125} pbdrv_usb_stm32_conf_t ;
@@ -128,21 +131,80 @@ static pbdrv_usb_stm32_conf_union_t USBD_Pybricks_CfgDesc = {
128131 .bLength = sizeof (pbdrv_usb_conf_desc_t ),
129132 .bDescriptorType = DESC_TYPE_CONFIGURATION ,
130133 .wTotalLength = sizeof (pbdrv_usb_stm32_conf_t ),
131- .bNumInterfaces = 1 ,
134+ .bNumInterfaces = 2 ,
132135 .bConfigurationValue = 1 ,
133136 .iConfiguration = 0 ,
134137 .bmAttributes = USB_CONF_DESC_BM_ATTR_MUST_BE_SET ,
135138 .bMaxPower = 250 , /* 500mA (number of 2mA units) */
136139 },
137- .iface_desc = {
140+ /* Interface Association: groups the comm and data interfaces into one
141+ * CDC ACM function. */
142+ .iad = {
143+ .bLength = sizeof (pbdrv_usb_iad_desc_t ),
144+ .bDescriptorType = DESC_TYPE_INTERFACE_ASSOCIATION ,
145+ .bFirstInterface = 0 ,
146+ .bInterfaceCount = 2 ,
147+ .bFunctionClass = USB_CLASS_CDC ,
148+ .bFunctionSubClass = USB_CDC_SUBCLASS_ACM ,
149+ .bFunctionProtocol = USB_CDC_PROTOCOL_AT ,
150+ .iFunction = 0 ,
151+ },
152+ /* Communication interface */
153+ .comm_iface = {
138154 .bLength = sizeof (pbdrv_usb_iface_desc_t ),
139155 .bDescriptorType = DESC_TYPE_INTERFACE ,
140156 .bInterfaceNumber = 0 ,
141157 .bAlternateSetting = 0 ,
158+ .bNumEndpoints = 1 ,
159+ .bInterfaceClass = USB_CLASS_CDC ,
160+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM ,
161+ .bInterfaceProtocol = USB_CDC_PROTOCOL_AT ,
162+ .iInterface = 0 ,
163+ },
164+ .cdc_header = {
165+ .bFunctionLength = sizeof (pbdrv_usb_cdc_header_desc_t ),
166+ .bDescriptorType = USB_CDC_CS_INTERFACE ,
167+ .bDescriptorSubtype = USB_CDC_FUNC_SUBTYPE_HEADER ,
168+ .bcdCDC = 0x0110 ,
169+ },
170+ .cdc_call_mgmt = {
171+ .bFunctionLength = sizeof (pbdrv_usb_cdc_call_mgmt_desc_t ),
172+ .bDescriptorType = USB_CDC_CS_INTERFACE ,
173+ .bDescriptorSubtype = USB_CDC_FUNC_SUBTYPE_CALL_MGMT ,
174+ .bmCapabilities = 0x00 ,
175+ .bDataInterface = 1 ,
176+ },
177+ .cdc_acm = {
178+ .bFunctionLength = sizeof (pbdrv_usb_cdc_acm_desc_t ),
179+ .bDescriptorType = USB_CDC_CS_INTERFACE ,
180+ .bDescriptorSubtype = USB_CDC_FUNC_SUBTYPE_ACM ,
181+ .bmCapabilities = 0x02 ,
182+ },
183+ .cdc_union = {
184+ .bFunctionLength = sizeof (pbdrv_usb_cdc_union_desc_t ),
185+ .bDescriptorType = USB_CDC_CS_INTERFACE ,
186+ .bDescriptorSubtype = USB_CDC_FUNC_SUBTYPE_UNION ,
187+ .bControlInterface = 0 ,
188+ .bSubordinateInterface0 = 1 ,
189+ },
190+ .cmd_ep = {
191+ .bLength = sizeof (pbdrv_usb_ep_desc_t ),
192+ .bDescriptorType = DESC_TYPE_ENDPOINT ,
193+ .bEndpointAddress = USBD_PYBRICKS_CMD_EP ,
194+ .bmAttributes = PBDRV_USB_EP_TYPE_INTR ,
195+ .wMaxPacketSize = USBD_PYBRICKS_CMD_PACKET_SIZE ,
196+ .bInterval = 16 ,
197+ },
198+ /* Data interface */
199+ .data_iface = {
200+ .bLength = sizeof (pbdrv_usb_iface_desc_t ),
201+ .bDescriptorType = DESC_TYPE_INTERFACE ,
202+ .bInterfaceNumber = 1 ,
203+ .bAlternateSetting = 0 ,
142204 .bNumEndpoints = 2 ,
143- .bInterfaceClass = PBIO_PYBRICKS_USB_DEVICE_CLASS ,
144- .bInterfaceSubClass = PBIO_PYBRICKS_USB_DEVICE_SUBCLASS ,
145- .bInterfaceProtocol = PBIO_PYBRICKS_USB_DEVICE_PROTOCOL ,
205+ .bInterfaceClass = USB_CLASS_CDC_DATA ,
206+ .bInterfaceSubClass = 0 ,
207+ .bInterfaceProtocol = 0 ,
146208 .iInterface = 0 ,
147209 },
148210 .ep_out = {
@@ -185,12 +247,28 @@ static USBD_StatusTypeDef USBD_Pybricks_Init(USBD_HandleTypeDef *pdev, uint8_t c
185247
186248 pdev -> pClassData = & hPybricks ;
187249
250+ /* Default line coding reported to the host: 115200 baud, 1 stop bit, no
251+ * parity, 8 data bits. This is inert: USB does not transfer data at this
252+ * rate (it is not a real UART). CDC ACM just requires valid line coding to
253+ * be stored and echoed back on GET_LINE_CODING. */
254+ hPybricks .LineCoding [0 ] = 0x00 ;
255+ hPybricks .LineCoding [1 ] = 0xC2 ;
256+ hPybricks .LineCoding [2 ] = 0x01 ;
257+ hPybricks .LineCoding [3 ] = 0x00 ;
258+ hPybricks .LineCoding [4 ] = 0x00 ;
259+ hPybricks .LineCoding [5 ] = 0x00 ;
260+ hPybricks .LineCoding [6 ] = 0x08 ;
261+ hPybricks .CmdOpCode = 0xFFU ;
262+
188263 (void )USBD_LL_OpenEP (pdev , USBD_PYBRICKS_IN_EP , USBD_EP_TYPE_BULK , USBD_PYBRICKS_MAX_PACKET_SIZE );
189264 pdev -> ep_in [USBD_PYBRICKS_IN_EP & 0xFU ].is_used = 1U ;
190265
191266 (void )USBD_LL_OpenEP (pdev , USBD_PYBRICKS_OUT_EP , USBD_EP_TYPE_BULK , USBD_PYBRICKS_MAX_PACKET_SIZE );
192267 pdev -> ep_out [USBD_PYBRICKS_OUT_EP & 0xFU ].is_used = 1U ;
193268
269+ (void )USBD_LL_OpenEP (pdev , USBD_PYBRICKS_CMD_EP , USBD_EP_TYPE_INTR , USBD_PYBRICKS_CMD_PACKET_SIZE );
270+ pdev -> ep_in [USBD_PYBRICKS_CMD_EP & 0xFU ].is_used = 1U ;
271+
194272 /* Init physical Interface components */
195273 ((USBD_Pybricks_ItfTypeDef * )pdev -> pUserData [pdev -> classId ])-> Init ();
196274
@@ -217,6 +295,10 @@ static USBD_StatusTypeDef USBD_Pybricks_DeInit(USBD_HandleTypeDef *pdev, uint8_t
217295 (void )USBD_LL_CloseEP (pdev , USBD_PYBRICKS_OUT_EP );
218296 pdev -> ep_out [USBD_PYBRICKS_OUT_EP & 0xFU ].is_used = 0U ;
219297
298+ /* Close command EP */
299+ (void )USBD_LL_CloseEP (pdev , USBD_PYBRICKS_CMD_EP );
300+ pdev -> ep_in [USBD_PYBRICKS_CMD_EP & 0xFU ].is_used = 0U ;
301+
220302 /* DeInit physical Interface components */
221303 if (pdev -> pClassData != NULL ) {
222304 ((USBD_Pybricks_ItfTypeDef * )pdev -> pUserData [pdev -> classId ])-> DeInit ();
@@ -235,31 +317,45 @@ static USBD_StatusTypeDef USBD_Pybricks_DeInit(USBD_HandleTypeDef *pdev, uint8_t
235317 */
236318static USBD_StatusTypeDef USBD_Pybricks_Setup (USBD_HandleTypeDef * pdev ,
237319 USBD_SetupReqTypedef * req ) {
320+ USBD_Pybricks_HandleTypeDef * hPybricks = pdev -> pClassData ;
238321 uint8_t ifalt = 0U ;
239322 uint16_t status_info = 0U ;
240323 USBD_StatusTypeDef ret = USBD_OK ;
241324
242325 switch (req -> bmRequest & USB_REQ_TYPE_MASK )
243326 {
244327 case USB_REQ_TYPE_CLASS :
245- ret = ((USBD_Pybricks_ItfTypeDef * )pdev -> pUserData [pdev -> classId ])-> ReadCharacteristic (pdev , req );
246- break ;
247-
248- case USB_REQ_TYPE_VENDOR :
328+ if (hPybricks == NULL ) {
329+ USBD_CtlError (pdev , req );
330+ ret = USBD_FAIL ;
331+ break ;
332+ }
249333 switch (req -> bRequest )
250334 {
251- case PBDRV_USB_VENDOR_REQ_MS_20 :
252- (void )USBD_CtlSendData (pdev ,
253- (uint8_t * )& pbdrv_usb_ms_20_desc_set ,
254- MIN (sizeof (pbdrv_usb_ms_20_desc_set .s ), req -> wLength ));
335+ case USB_CDC_REQ_SET_LINE_CODING :
336+ /* Receive the line coding into the handle. The value is
337+ * accepted but not acted on (the link is not a real UART). */
338+ if (req -> wLength == USB_CDC_LINE_CODING_SIZE ) {
339+ hPybricks -> CmdOpCode = (uint8_t )req -> bRequest ;
340+ hPybricks -> CmdLength = USB_CDC_LINE_CODING_SIZE ;
341+ (void )USBD_CtlPrepareRx (pdev , hPybricks -> LineCoding , USB_CDC_LINE_CODING_SIZE );
342+ } else {
343+ USBD_CtlError (pdev , req );
344+ ret = USBD_FAIL ;
345+ }
255346 break ;
256347
257- case PBDRV_USB_VENDOR_REQ_WEBUSB :
258- if ((req -> wValue == PBDRV_USB_WEBUSB_LANDING_PAGE_URL_IDX ) && (req -> wIndex == WEBUSB_REQ_GET_URL )) {
259- (void )USBD_CtlSendData (pdev ,
260- (uint8_t * )& pbdrv_usb_webusb_landing_page ,
261- MIN (pbdrv_usb_webusb_landing_page .s .bLength , req -> wLength ));
262- }
348+ case USB_CDC_REQ_GET_LINE_CODING :
349+ (void )USBD_CtlSendData (pdev , hPybricks -> LineCoding ,
350+ MIN (USB_CDC_LINE_CODING_SIZE , req -> wLength ));
351+ break ;
352+
353+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE :
354+ /* The DTR bit indicates whether a host application has
355+ * opened the port. This is the USB analog of a BLE host
356+ * subscribing to notifications. */
357+ ((USBD_Pybricks_ItfTypeDef * )pdev -> pUserData [pdev -> classId ])-> SetControlLineState (
358+ (req -> wValue & USB_CDC_CONTROL_LINE_STATE_DTR ) != 0U );
263359 break ;
264360
265361 default :
@@ -388,6 +484,14 @@ static USBD_StatusTypeDef USBD_Pybricks_DataOut(USBD_HandleTypeDef *pdev, uint8_
388484 * @retval status
389485 */
390486static USBD_StatusTypeDef USBD_Pybricks_EP0_RxReady (USBD_HandleTypeDef * pdev ) {
487+ USBD_Pybricks_HandleTypeDef * hPybricks = pdev -> pClassData ;
488+
489+ if (hPybricks != NULL && hPybricks -> CmdOpCode != 0xFFU ) {
490+ /* SET_LINE_CODING data has been received into hPybricks->LineCoding.
491+ * Nothing to do; the value is stored for GET_LINE_CODING. */
492+ hPybricks -> CmdOpCode = 0xFFU ;
493+ }
494+
391495 return USBD_OK ;
392496}
393497
0 commit comments