1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_cdc_acm.h"
8 
9 #define WINUSB_IN_EP  0x81
10 #define WINUSB_OUT_EP 0x02
11 
12 #define CDC_IN_EP  0x83
13 #define CDC_OUT_EP 0x04
14 #define CDC_INT_EP 0x85
15 
16 #define USBD_VID           0xFFFE
17 #define USBD_PID           0xFFFF
18 #define USBD_MAX_POWER     500
19 #define USBD_LANGID_STRING 1033
20 
21 #define USB_CONFIG_SIZE (9 + 9 + 7 + 7 + CDC_ACM_DESCRIPTOR_LEN)
22 #define INTF_NUM        3
23 
24 #ifdef CONFIG_USB_HS
25 #define WINUSB_EP_MPS 512
26 #else
27 #define WINUSB_EP_MPS 64
28 #endif
29 
30 #define USBD_WINUSB_VENDOR_CODE 0x20
31 
32 #define USBD_WEBUSB_ENABLE 0
33 #define USBD_BULK_ENABLE   1
34 #define USBD_WINUSB_ENABLE 1
35 
36 /* WinUSB Microsoft OS 2.0 descriptor sizes */
37 #define WINUSB_DESCRIPTOR_SET_HEADER_SIZE  10
38 #define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
39 #define WINUSB_FEATURE_COMPATIBLE_ID_SIZE  20
40 
41 #define FUNCTION_SUBSET_LEN                160
42 #define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132
43 
44 #define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN)
45 
46 __ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[] = {
47     WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */
48     WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */
49     0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */  /* dwWindowsVersion*/
50     WBVAL(USBD_WINUSB_DESC_SET_LEN),          /* wDescriptorSetTotalLength */
51 #if (USBD_WEBUSB_ENABLE)
52     WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength
53     WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType
54     0,                                         // bFirstInterface USBD_WINUSB_IF_NUM
55     0,                                         // bReserved
56     WBVAL(FUNCTION_SUBSET_LEN),                // wSubsetLength
57     WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE),  // wLength
58     WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE),  // wDescriptorType
59     'W', 'I', 'N', 'U', 'S', 'B', 0, 0,        // CompatibleId
60     0, 0, 0, 0, 0, 0, 0, 0,                    // SubCompatibleId
61     WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength
62     WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE),   // wDescriptorType
63     WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType
64     WBVAL(42),                                 // wPropertyNameLength
65     'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
66     'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
67     'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
68     WBVAL(80), // wPropertyDataLength
69     '{', 0,
70     '9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0,
71     '9', 0, 'C', 0, '7', 0, '7', 0, '-', 0,
72     '4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0,
73     '9', 0, '3', 0, '3', 0, 'B', 0, '-',
74     0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0,
75     '}', 0, 0, 0, 0, 0
76 #endif
77 #if USBD_BULK_ENABLE
78     WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */
79     WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */
80     0,                                         /* bFirstInterface USBD_BULK_IF_NUM*/
81     0,                                         /* bReserved */
82     WBVAL(FUNCTION_SUBSET_LEN),                /* wSubsetLength */
83     WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE),  /* wLength */
84     WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE),  /* wDescriptorType */
85     'W', 'I', 'N', 'U', 'S', 'B', 0, 0,        /* CompatibleId*/
86     0, 0, 0, 0, 0, 0, 0, 0,                    /* SubCompatibleId*/
87     WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */
88     WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE),   /* wDescriptorType */
89     WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */
90     WBVAL(42),                                 /* wPropertyNameLength */
91     'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
92     'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
93     'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
94     WBVAL(80), /* wPropertyDataLength */
95     '{', 0,
96     'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0,
97     '2', 0, '9', 0, '3', 0, 'B', 0, '-', 0,
98     '4', 0, '6', 0, '6', 0, '3', 0, '-', 0,
99     'A', 0, 'A', 0, '3', 0, '6', 0, '-',
100     0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0,
101     '}', 0, 0, 0, 0, 0
102 #endif
103 };
104 
105 #define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE)
106 
107 #define USBD_WEBUSB_DESC_LEN 24
108 #define USBD_WINUSB_DESC_LEN 28
109 
110 #define USBD_BOS_WTOTALLENGTH (0x05 +                                      \
111                                USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \
112                                USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE)
113 
114 __ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = {
115     0x05,                         /* bLength */
116     0x0f,                         /* bDescriptorType */
117     WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */
118     USBD_NUM_DEV_CAPABILITIES,    /* bNumDeviceCaps */
119 #if (USBD_WEBUSB_ENABLE)
120     USBD_WEBUSB_DESC_LEN,           /* bLength */
121     0x10,                           /* bDescriptorType */
122     USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
123     0x00,                           /* bReserved */
124     0x38, 0xB6, 0x08, 0x34,         /* PlatformCapabilityUUID */
125     0xA9, 0x09, 0xA0, 0x47,
126     0x8B, 0xFD, 0xA0, 0x76,
127     0x88, 0x15, 0xB6, 0x65,
128     WBVAL(0x0100), /* 1.00 */ /* bcdVersion */
129     USBD_WINUSB_VENDOR_CODE,  /* bVendorCode */
130     0,                        /* iLandingPage */
131 #endif
132 #if (USBD_WINUSB_ENABLE)
133     USBD_WINUSB_DESC_LEN,           /* bLength */
134     0x10,                           /* bDescriptorType */
135     USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
136     0x00,                           /* bReserved */
137     0xDF, 0x60, 0xDD, 0xD8,         /* PlatformCapabilityUUID */
138     0x89, 0x45, 0xC7, 0x4C,
139     0x9C, 0xD2, 0x65, 0x9D,
140     0x9E, 0x64, 0x8A, 0x9F,
141     0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
142     WBVAL(USBD_WINUSB_DESC_SET_LEN),         /* wDescriptorSetTotalLength */
143     USBD_WINUSB_VENDOR_CODE,                 /* bVendorCode */
144     0,                                       /* bAltEnumCode */
145 #endif
146 };
147 
148 struct usb_msosv2_descriptor msosv2_desc = {
149     .vendor_code = USBD_WINUSB_VENDOR_CODE,
150     .compat_id = USBD_WinUSBDescriptorSetDescriptor,
151     .compat_id_len = USBD_WINUSB_DESC_SET_LEN,
152 };
153 
154 struct usb_bos_descriptor bos_desc = {
155     .string = USBD_BinaryObjectStoreDescriptor,
156     .string_len = USBD_BOS_WTOTALLENGTH
157 };
158 
159 #ifdef CONFIG_USBDEV_ADVANCE_DESC
160 static const uint8_t device_descriptor[] = {
161     USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
162 };
163 
164 static const uint8_t config_descriptor[] = {
165     /* Configuration 0 */
166     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
167     /* Interface 0 */
168     USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
169     /* Endpoint OUT 2 */
170     USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
171     /* Endpoint IN 1 */
172     USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
173     CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00)
174 };
175 
176 static const uint8_t device_quality_descriptor[] = {
177     ///////////////////////////////////////
178     /// device qualifier descriptor
179     ///////////////////////////////////////
180     0x0a,
181     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
182     0x10,
183     0x02,
184     0x00,
185     0x00,
186     0x00,
187     0x40,
188     0x00,
189     0x00,
190 };
191 
192 static const char *string_descriptors[] = {
193     (const char[]){ 0x09, 0x04 }, /* Langid */
194     "CherryUSB",                  /* Manufacturer */
195     "CherryUSB WINUSB DEMO",      /* Product */
196     "2022123456",                 /* Serial Number */
197 };
198 
device_descriptor_callback(uint8_t speed)199 static const uint8_t *device_descriptor_callback(uint8_t speed)
200 {
201     return device_descriptor;
202 }
203 
config_descriptor_callback(uint8_t speed)204 static const uint8_t *config_descriptor_callback(uint8_t speed)
205 {
206     return config_descriptor;
207 }
208 
device_quality_descriptor_callback(uint8_t speed)209 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
210 {
211     return device_quality_descriptor;
212 }
213 
string_descriptor_callback(uint8_t speed,uint8_t index)214 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
215 {
216     if (index > 3) {
217         return NULL;
218     }
219     return string_descriptors[index];
220 }
221 
222 const struct usb_descriptor winusbv2_descriptor = {
223     .device_descriptor_callback = device_descriptor_callback,
224     .config_descriptor_callback = config_descriptor_callback,
225     .device_quality_descriptor_callback = device_quality_descriptor_callback,
226     .string_descriptor_callback = string_descriptor_callback,
227     .msosv2_descriptor = &msosv2_desc,
228     .bos_descriptor = &bos_desc
229 };
230 #else
231 const uint8_t winusbv2_descriptor[] = {
232     USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
233     /* Configuration 0 */
234     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
235     /* Interface 0 */
236     USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
237     /* Endpoint OUT 2 */
238     USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
239     /* Endpoint IN 1 */
240     USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
241     CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00),
242     /* String 0 (LANGID) */
243     USB_LANGID_INIT(USBD_LANGID_STRING),
244     /* String 1 (Manufacturer) */
245     0x14,                       /* bLength */
246     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
247     'C', 0x00,                  /* wcChar0 */
248     'h', 0x00,                  /* wcChar1 */
249     'e', 0x00,                  /* wcChar2 */
250     'r', 0x00,                  /* wcChar3 */
251     'r', 0x00,                  /* wcChar4 */
252     'y', 0x00,                  /* wcChar5 */
253     'U', 0x00,                  /* wcChar6 */
254     'S', 0x00,                  /* wcChar7 */
255     'B', 0x00,                  /* wcChar8 */
256     ///////////////////////////////////////
257     /// string2 descriptor
258     ///////////////////////////////////////
259     0x2C,                       /* bLength */
260     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
261     'C', 0x00,                  /* wcChar0 */
262     'h', 0x00,                  /* wcChar1 */
263     'e', 0x00,                  /* wcChar2 */
264     'r', 0x00,                  /* wcChar3 */
265     'r', 0x00,                  /* wcChar4 */
266     'y', 0x00,                  /* wcChar5 */
267     'U', 0x00,                  /* wcChar6 */
268     'S', 0x00,                  /* wcChar7 */
269     'B', 0x00,                  /* wcChar8 */
270     ' ', 0x00,                  /* wcChar9 */
271     'W', 0x00,                  /* wcChar10 */
272     'I', 0x00,                  /* wcChar11 */
273     'N', 0x00,                  /* wcChar12 */
274     'U', 0x00,                  /* wcChar13 */
275     'S', 0x00,                  /* wcChar14 */
276     'B', 0x00,                  /* wcChar15 */
277     ' ', 0x00,                  /* wcChar16 */
278     'D', 0x00,                  /* wcChar17 */
279     'E', 0x00,                  /* wcChar18 */
280     'M', 0x00,                  /* wcChar19 */
281     'O', 0x00,                  /* wcChar20 */
282     ///////////////////////////////////////
283     /// string3 descriptor
284     ///////////////////////////////////////
285     0x16,                       /* bLength */
286     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
287     '2', 0x00,                  /* wcChar0 */
288     '0', 0x00,                  /* wcChar1 */
289     '2', 0x00,                  /* wcChar2 */
290     '2', 0x00,                  /* wcChar3 */
291     '1', 0x00,                  /* wcChar4 */
292     '2', 0x00,                  /* wcChar5 */
293     '3', 0x00,                  /* wcChar6 */
294     '4', 0x00,                  /* wcChar7 */
295     '5', 0x00,                  /* wcChar8 */
296     '6', 0x00,                  /* wcChar9 */
297 #ifdef CONFIG_USB_HS
298     /* Device Qualifier */
299     0x0a,
300     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
301     0x10,
302     0x02,
303     0x00,
304     0x00,
305     0x00,
306     0x40,
307     0x00,
308     0x00,
309 #endif
310     /* End */
311     0x00
312 };
313 #endif
314 
315 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
316 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
317 
318 volatile bool ep_tx_busy_flag = false;
319 
usbd_event_handler(uint8_t busid,uint8_t event)320 static void usbd_event_handler(uint8_t busid, uint8_t event)
321 {
322     switch (event) {
323         case USBD_EVENT_RESET:
324             break;
325         case USBD_EVENT_CONNECTED:
326             break;
327         case USBD_EVENT_DISCONNECTED:
328             break;
329         case USBD_EVENT_RESUME:
330             break;
331         case USBD_EVENT_SUSPEND:
332             break;
333         case USBD_EVENT_CONFIGURED:
334             ep_tx_busy_flag = false;
335             /* setup first out ep read transfer */
336             usbd_ep_start_read(busid, WINUSB_OUT_EP, read_buffer, 2048);
337             usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
338             break;
339         case USBD_EVENT_SET_REMOTE_WAKEUP:
340             break;
341         case USBD_EVENT_CLR_REMOTE_WAKEUP:
342             break;
343 
344         default:
345             break;
346     }
347 }
348 
usbd_winusb_out(uint8_t busid,uint8_t ep,uint32_t nbytes)349 void usbd_winusb_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
350 {
351     USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
352     // for (int i = 0; i < 100; i++) {
353     //     printf("%02x ", read_buffer[i]);
354     // }
355     // printf("\r\n");
356     usbd_ep_start_write(busid, WINUSB_IN_EP, read_buffer, nbytes);
357     /* setup next out ep read transfer */
358     usbd_ep_start_read(busid, WINUSB_OUT_EP, read_buffer, 2048);
359 }
360 
usbd_winusb_in(uint8_t busid,uint8_t ep,uint32_t nbytes)361 void usbd_winusb_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
362 {
363     USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
364 
365     if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
366         /* send zlp */
367         usbd_ep_start_write(busid, WINUSB_IN_EP, NULL, 0);
368     } else {
369         ep_tx_busy_flag = false;
370     }
371 }
372 
usbd_cdc_acm_out(uint8_t busid,uint8_t ep,uint32_t nbytes)373 void usbd_cdc_acm_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
374 {
375     USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
376     // for (int i = 0; i < 100; i++) {
377     //     printf("%02x ", read_buffer[i]);
378     // }
379     // printf("\r\n");
380     usbd_ep_start_write(busid, CDC_IN_EP, read_buffer, nbytes);
381     /* setup next out ep read transfer */
382     usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
383 }
384 
usbd_cdc_acm_in(uint8_t busid,uint8_t ep,uint32_t nbytes)385 void usbd_cdc_acm_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
386 {
387     USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
388 
389     if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
390         /* send zlp */
391         usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
392     } else {
393         ep_tx_busy_flag = false;
394     }
395 }
396 
397 struct usbd_endpoint winusb_out_ep1 = {
398     .ep_addr = WINUSB_OUT_EP,
399     .ep_cb = usbd_winusb_out
400 };
401 
402 struct usbd_endpoint winusb_in_ep1 = {
403     .ep_addr = WINUSB_IN_EP,
404     .ep_cb = usbd_winusb_in
405 };
406 
407 static struct usbd_endpoint cdc_out_ep = {
408     .ep_addr = CDC_OUT_EP,
409     .ep_cb = usbd_cdc_acm_out
410 };
411 
412 static struct usbd_endpoint cdc_in_ep = {
413     .ep_addr = CDC_IN_EP,
414     .ep_cb = usbd_cdc_acm_in
415 };
416 
417 struct usbd_interface winusb_intf;
418 struct usbd_interface intf1;
419 struct usbd_interface intf2;
420 
winusbv2_init(uint8_t busid,uintptr_t reg_base)421 void winusbv2_init(uint8_t busid, uintptr_t reg_base)
422 {
423 #ifdef CONFIG_USBDEV_ADVANCE_DESC
424     usbd_desc_register(busid, &winusbv2_descriptor);
425 #else
426     usbd_desc_register(busid, winusbv2_descriptor);
427 #endif
428 #ifndef CONFIG_USBDEV_ADVANCE_DESC
429     usbd_bos_desc_register(busid, &bos_desc);
430     usbd_msosv2_desc_register(busid, &msosv2_desc);
431 #endif
432     /*!< winusb */
433     usbd_add_interface(busid, &winusb_intf);
434     usbd_add_endpoint(busid, &winusb_out_ep1);
435     usbd_add_endpoint(busid, &winusb_in_ep1);
436 
437     /*!< cdc acm */
438     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
439     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf2));
440     usbd_add_endpoint(busid, &cdc_out_ep);
441     usbd_add_endpoint(busid, &cdc_in_ep);
442 
443     usbd_initialize(busid, reg_base, usbd_event_handler);
444 }
445 
446 volatile uint8_t dtr_enable = 0;
447 
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)448 void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
449 {
450     if (dtr) {
451         dtr_enable = 1;
452     } else {
453         dtr_enable = 0;
454     }
455 }
456 
cdc_acm_data_send_with_dtr_test(uint8_t busid)457 void cdc_acm_data_send_with_dtr_test(uint8_t busid)
458 {
459     if (dtr_enable) {
460         memset(&write_buffer[10], 'a', 2038);
461         ep_tx_busy_flag = true;
462         usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
463         while (ep_tx_busy_flag) {
464         }
465     }
466 }