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 /*!< endpoint address */
10 #define CDC_IN_EP  0x81
11 #define CDC_OUT_EP 0x02
12 #define CDC_INT_EP 0x83
13 
14 #define USBD_VID           0xFFFF
15 #define USBD_PID           0xFFFF
16 #define USBD_MAX_POWER     100
17 #define USBD_LANGID_STRING 1033
18 
19 /*!< config descriptor size */
20 #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
21 
22 #ifdef CONFIG_USB_HS
23 #define CDC_MAX_MPS 512
24 #else
25 #define CDC_MAX_MPS 64
26 #endif
27 
28 #ifdef CONFIG_USBDEV_ADVANCE_DESC
29 static const uint8_t device_descriptor[] = {
30     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
31 };
32 
33 static const uint8_t config_descriptor[] = {
34     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
35     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
36 };
37 
38 static const uint8_t device_quality_descriptor[] = {
39     ///////////////////////////////////////
40     /// device qualifier descriptor
41     ///////////////////////////////////////
42     0x0a,
43     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
44     0x00,
45     0x02,
46     0x00,
47     0x00,
48     0x00,
49     0x40,
50     0x00,
51     0x00,
52 };
53 
54 static const char *string_descriptors[] = {
55     (const char[]){ 0x09, 0x04 }, /* Langid */
56     "CherryUSB",                  /* Manufacturer */
57     "CherryUSB CDC DEMO",         /* Product */
58     "2022123456",                 /* Serial Number */
59 };
60 
device_descriptor_callback(uint8_t speed)61 static const uint8_t *device_descriptor_callback(uint8_t speed)
62 {
63     return device_descriptor;
64 }
65 
config_descriptor_callback(uint8_t speed)66 static const uint8_t *config_descriptor_callback(uint8_t speed)
67 {
68     return config_descriptor;
69 }
70 
device_quality_descriptor_callback(uint8_t speed)71 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
72 {
73     return device_quality_descriptor;
74 }
75 
string_descriptor_callback(uint8_t speed,uint8_t index)76 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
77 {
78     if (index > 3) {
79         return NULL;
80     }
81     return string_descriptors[index];
82 }
83 
84 const struct usb_descriptor cdc_descriptor = {
85     .device_descriptor_callback = device_descriptor_callback,
86     .config_descriptor_callback = config_descriptor_callback,
87     .device_quality_descriptor_callback = device_quality_descriptor_callback,
88     .string_descriptor_callback = string_descriptor_callback
89 };
90 #else
91 /*!< global descriptor */
92 static const uint8_t cdc_descriptor[] = {
93     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
94     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
95     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
96     ///////////////////////////////////////
97     /// string0 descriptor
98     ///////////////////////////////////////
99     USB_LANGID_INIT(USBD_LANGID_STRING),
100     ///////////////////////////////////////
101     /// string1 descriptor
102     ///////////////////////////////////////
103     0x14,                       /* bLength */
104     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
105     'C', 0x00,                  /* wcChar0 */
106     'h', 0x00,                  /* wcChar1 */
107     'e', 0x00,                  /* wcChar2 */
108     'r', 0x00,                  /* wcChar3 */
109     'r', 0x00,                  /* wcChar4 */
110     'y', 0x00,                  /* wcChar5 */
111     'U', 0x00,                  /* wcChar6 */
112     'S', 0x00,                  /* wcChar7 */
113     'B', 0x00,                  /* wcChar8 */
114     ///////////////////////////////////////
115     /// string2 descriptor
116     ///////////////////////////////////////
117     0x26,                       /* bLength */
118     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
119     'C', 0x00,                  /* wcChar0 */
120     'h', 0x00,                  /* wcChar1 */
121     'e', 0x00,                  /* wcChar2 */
122     'r', 0x00,                  /* wcChar3 */
123     'r', 0x00,                  /* wcChar4 */
124     'y', 0x00,                  /* wcChar5 */
125     'U', 0x00,                  /* wcChar6 */
126     'S', 0x00,                  /* wcChar7 */
127     'B', 0x00,                  /* wcChar8 */
128     ' ', 0x00,                  /* wcChar9 */
129     'C', 0x00,                  /* wcChar10 */
130     'D', 0x00,                  /* wcChar11 */
131     'C', 0x00,                  /* wcChar12 */
132     ' ', 0x00,                  /* wcChar13 */
133     'D', 0x00,                  /* wcChar14 */
134     'E', 0x00,                  /* wcChar15 */
135     'M', 0x00,                  /* wcChar16 */
136     'O', 0x00,                  /* wcChar17 */
137     ///////////////////////////////////////
138     /// string3 descriptor
139     ///////////////////////////////////////
140     0x16,                       /* bLength */
141     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
142     '2', 0x00,                  /* wcChar0 */
143     '0', 0x00,                  /* wcChar1 */
144     '2', 0x00,                  /* wcChar2 */
145     '2', 0x00,                  /* wcChar3 */
146     '1', 0x00,                  /* wcChar4 */
147     '2', 0x00,                  /* wcChar5 */
148     '3', 0x00,                  /* wcChar6 */
149     '4', 0x00,                  /* wcChar7 */
150     '5', 0x00,                  /* wcChar8 */
151     '6', 0x00,                  /* wcChar9 */
152 #ifdef CONFIG_USB_HS
153     ///////////////////////////////////////
154     /// device qualifier descriptor
155     ///////////////////////////////////////
156     0x0a,
157     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
158     0x00,
159     0x02,
160     0x00,
161     0x00,
162     0x00,
163     0x40,
164     0x00,
165     0x00,
166 #endif
167     0x00
168 };
169 #endif
170 
171 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
172 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
173 
174 volatile bool ep_tx_busy_flag = false;
175 
usbd_event_handler(uint8_t busid,uint8_t event)176 static void usbd_event_handler(uint8_t busid, uint8_t event)
177 {
178     switch (event) {
179         case USBD_EVENT_RESET:
180             break;
181         case USBD_EVENT_CONNECTED:
182             break;
183         case USBD_EVENT_DISCONNECTED:
184             break;
185         case USBD_EVENT_RESUME:
186             break;
187         case USBD_EVENT_SUSPEND:
188             break;
189         case USBD_EVENT_CONFIGURED:
190             ep_tx_busy_flag = false;
191             /* setup first out ep read transfer */
192             usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
193             break;
194         case USBD_EVENT_SET_REMOTE_WAKEUP:
195             break;
196         case USBD_EVENT_CLR_REMOTE_WAKEUP:
197             break;
198 
199         default:
200             break;
201     }
202 }
203 
usbd_cdc_acm_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)204 void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
205 {
206     USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
207     // for (int i = 0; i < 100; i++) {
208     //     printf("%02x ", read_buffer[i]);
209     // }
210     // printf("\r\n");
211     /* setup next out ep read transfer */
212     usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
213 }
214 
usbd_cdc_acm_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)215 void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
216 {
217     USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
218 
219     if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
220         /* send zlp */
221         usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
222     } else {
223         ep_tx_busy_flag = false;
224     }
225 }
226 
227 /*!< endpoint call back */
228 struct usbd_endpoint cdc_out_ep = {
229     .ep_addr = CDC_OUT_EP,
230     .ep_cb = usbd_cdc_acm_bulk_out
231 };
232 
233 struct usbd_endpoint cdc_in_ep = {
234     .ep_addr = CDC_IN_EP,
235     .ep_cb = usbd_cdc_acm_bulk_in
236 };
237 
238 static struct usbd_interface intf0;
239 static struct usbd_interface intf1;
240 
cdc_acm_init(uint8_t busid,uintptr_t reg_base)241 void cdc_acm_init(uint8_t busid, uintptr_t reg_base)
242 {
243     const uint8_t data[10] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 };
244 
245     memcpy(&write_buffer[0], data, 10);
246     memset(&write_buffer[10], 'a', 2038);
247 
248 #ifdef CONFIG_USBDEV_ADVANCE_DESC
249     usbd_desc_register(busid, &cdc_descriptor);
250 #else
251     usbd_desc_register(busid, cdc_descriptor);
252 #endif
253     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
254     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
255     usbd_add_endpoint(busid, &cdc_out_ep);
256     usbd_add_endpoint(busid, &cdc_in_ep);
257     usbd_initialize(busid, reg_base, usbd_event_handler);
258 }
259 
260 volatile uint8_t dtr_enable = 0;
261 
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)262 void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
263 {
264     if (dtr) {
265         dtr_enable = 1;
266     } else {
267         dtr_enable = 0;
268     }
269 }
270 
cdc_acm_data_send_with_dtr_test(uint8_t busid)271 void cdc_acm_data_send_with_dtr_test(uint8_t busid)
272 {
273     if (dtr_enable) {
274         ep_tx_busy_flag = true;
275         usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
276         while (ep_tx_busy_flag) {
277         }
278     }
279 }