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 }