Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
USBCDC.cpp
00001 /* 00002 * Copyright (c) 2018-2019, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "stdint.h" 00019 #include "USBCDC.h" 00020 #include "EndpointResolver.h" 00021 #include "AsyncOp.h" 00022 #include "usb_phy_api.h" 00023 00024 static const uint8_t cdc_line_coding_default[7] = {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; 00025 00026 #define DEFAULT_CONFIGURATION (1) 00027 00028 #define CDC_SET_LINE_CODING 0x20 00029 #define CDC_GET_LINE_CODING 0x21 00030 #define CDC_SET_CONTROL_LINE_STATE 0x22 00031 00032 // Control Line State bits 00033 #define CLS_DTR (1 << 0) 00034 #define CLS_RTS (1 << 1) 00035 00036 #define CDC_MAX_PACKET_SIZE 64 00037 00038 class USBCDC::AsyncWrite: public AsyncOp { 00039 public: 00040 AsyncWrite(USBCDC *serial, uint8_t *buf, uint32_t size): 00041 serial(serial), tx_buf(buf), tx_size(size), result(false) 00042 { 00043 00044 } 00045 00046 virtual ~AsyncWrite() 00047 { 00048 00049 } 00050 00051 virtual bool process() 00052 { 00053 if (!serial->_terminal_connected) { 00054 result = false; 00055 return true; 00056 } 00057 00058 uint32_t actual_size = 0; 00059 serial->send_nb(tx_buf, tx_size, &actual_size, true); 00060 tx_size -= actual_size; 00061 tx_buf += actual_size; 00062 if (tx_size == 0) { 00063 result = true; 00064 return true; 00065 } 00066 00067 // Start transfer if it hasn't been 00068 serial->_send_isr_start(); 00069 return false; 00070 } 00071 00072 USBCDC *serial; 00073 uint8_t *tx_buf; 00074 uint32_t tx_size; 00075 bool result; 00076 }; 00077 00078 class USBCDC::AsyncRead: public AsyncOp { 00079 public: 00080 AsyncRead(USBCDC *serial, uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all) 00081 : serial(serial), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false) 00082 { 00083 00084 } 00085 00086 virtual ~AsyncRead() 00087 { 00088 00089 } 00090 00091 virtual bool process() 00092 { 00093 if (!serial->_terminal_connected) { 00094 result = false; 00095 return true; 00096 } 00097 00098 uint32_t actual_size = 0; 00099 serial->receive_nb(rx_buf, rx_size, &actual_size); 00100 rx_buf += actual_size; 00101 *rx_actual += actual_size; 00102 rx_size -= actual_size; 00103 if ((!all && *rx_actual > 0) || (rx_size == 0)) { 00104 // Wake thread if request is done 00105 result = true; 00106 return true; 00107 } 00108 00109 serial->_receive_isr_start(); 00110 return false; 00111 } 00112 00113 USBCDC *serial; 00114 uint8_t *rx_buf; 00115 uint32_t rx_size; 00116 uint32_t *rx_actual; 00117 bool all; 00118 bool result; 00119 }; 00120 00121 class USBCDC::AsyncWait: public AsyncOp { 00122 public: 00123 AsyncWait(USBCDC *serial) 00124 : serial(serial) 00125 { 00126 00127 } 00128 00129 virtual ~AsyncWait() 00130 { 00131 00132 } 00133 00134 virtual bool process() 00135 { 00136 if (serial->_terminal_connected) { 00137 return true; 00138 } 00139 00140 return false; 00141 } 00142 00143 USBCDC *serial; 00144 }; 00145 00146 USBCDC::USBCDC(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) 00147 : USBDevice(get_usb_phy(), vendor_id, product_id, product_release) 00148 00149 { 00150 _init(); 00151 if (connect_blocking) { 00152 connect(); 00153 wait_ready(); 00154 } else { 00155 init(); 00156 } 00157 } 00158 00159 USBCDC::USBCDC(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) 00160 : USBDevice(phy, vendor_id, product_id, product_release) 00161 { 00162 _init(); 00163 } 00164 00165 USBCDC::~USBCDC() 00166 { 00167 deinit(); 00168 } 00169 00170 void USBCDC::_init() 00171 { 00172 memcpy(_cdc_line_coding, cdc_line_coding_default, sizeof(_cdc_line_coding)); 00173 00174 EndpointResolver resolver(endpoint_table()); 00175 resolver.endpoint_ctrl(CDC_MAX_PACKET_SIZE); 00176 _bulk_in = resolver.endpoint_in(USB_EP_TYPE_BULK, CDC_MAX_PACKET_SIZE); 00177 _bulk_out = resolver.endpoint_out(USB_EP_TYPE_BULK, CDC_MAX_PACKET_SIZE); 00178 _int_in = resolver.endpoint_in(USB_EP_TYPE_INT, CDC_MAX_PACKET_SIZE); 00179 MBED_ASSERT(resolver.valid()); 00180 00181 _terminal_connected = false; 00182 00183 _tx_in_progress = false; 00184 _tx_buf = _tx_buffer; 00185 _tx_size = 0; 00186 00187 _rx_in_progress = false; 00188 _rx_buf = _rx_buffer; 00189 _rx_size = 0; 00190 } 00191 00192 void USBCDC::callback_reset() 00193 { 00194 assert_locked(); 00195 /* Called in ISR context */ 00196 00197 _change_terminal_connected(false); 00198 }; 00199 00200 void USBCDC::callback_state_change(DeviceState new_state) 00201 { 00202 assert_locked(); 00203 /* Called in ISR context */ 00204 00205 if (new_state != Configured) { 00206 _change_terminal_connected(false); 00207 } 00208 } 00209 00210 void USBCDC::callback_request(const setup_packet_t *setup) 00211 { 00212 assert_locked(); 00213 /* Called in ISR context */ 00214 00215 RequestResult result = PassThrough; 00216 uint8_t *data = NULL; 00217 uint32_t size = 0; 00218 00219 /* Only process class-specific requests */ 00220 if (setup->bmRequestType.Type == CLASS_TYPE) { 00221 switch (setup->bRequest) { 00222 case CDC_GET_LINE_CODING: 00223 result = Send; 00224 data = _cdc_line_coding; 00225 size = 7; 00226 break; 00227 case CDC_SET_LINE_CODING: 00228 result = Receive; 00229 data = _cdc_new_line_coding; 00230 size = 7; 00231 break; 00232 case CDC_SET_CONTROL_LINE_STATE: 00233 if (setup->wValue & CLS_DTR) { 00234 _change_terminal_connected(true); 00235 } else { 00236 _change_terminal_connected(false); 00237 } 00238 result = Success; 00239 break; 00240 default: 00241 result = Failure; 00242 break; 00243 } 00244 } 00245 complete_request(result, data, size); 00246 } 00247 00248 00249 void USBCDC::callback_request_xfer_done(const setup_packet_t *setup, bool aborted) 00250 { 00251 assert_locked(); 00252 /* Called in ISR context */ 00253 00254 if (aborted) { 00255 complete_request_xfer_done(false); 00256 return; 00257 } 00258 00259 bool success = false; 00260 00261 /* Process class-specific requests */ 00262 if (setup->bmRequestType.Type == CLASS_TYPE) { 00263 if ((setup->bRequest == CDC_SET_LINE_CODING) && (setup->wLength == 7)) { 00264 if (memcmp(_cdc_line_coding, _cdc_new_line_coding, 7)) { 00265 memcpy(_cdc_line_coding, _cdc_new_line_coding, 7); 00266 00267 const uint8_t *buf = _cdc_line_coding; 00268 int baud = buf[0] + (buf[1] << 8) 00269 + (buf[2] << 16) + (buf[3] << 24); 00270 int stop = buf[4]; 00271 int bits = buf[6]; 00272 int parity = buf[5]; 00273 00274 line_coding_changed(baud, bits, parity, stop); 00275 } 00276 success = true; 00277 } 00278 if (setup->bRequest == CDC_GET_LINE_CODING) { 00279 success = true; 00280 } 00281 } 00282 00283 complete_request_xfer_done(success); 00284 } 00285 00286 void USBCDC::callback_set_configuration(uint8_t configuration) 00287 { 00288 assert_locked(); 00289 /* Called in ISR context */ 00290 00291 bool ret = false; 00292 if (configuration == DEFAULT_CONFIGURATION) { 00293 // Configure endpoints > 0 00294 endpoint_add(_int_in, CDC_MAX_PACKET_SIZE, USB_EP_TYPE_INT); 00295 endpoint_add(_bulk_in, CDC_MAX_PACKET_SIZE, USB_EP_TYPE_BULK, &USBCDC::_send_isr); 00296 endpoint_add(_bulk_out, CDC_MAX_PACKET_SIZE, USB_EP_TYPE_BULK, &USBCDC::_receive_isr); 00297 00298 read_start(_bulk_out, _rx_buf, sizeof(_rx_buffer)); 00299 _rx_in_progress = true; 00300 00301 ret = true; 00302 } 00303 00304 complete_set_configuration(ret); 00305 } 00306 00307 void USBCDC::callback_set_interface(uint16_t interface, uint8_t alternate) 00308 { 00309 assert_locked(); 00310 complete_set_interface(true); 00311 } 00312 00313 void USBCDC::_change_terminal_connected(bool connected) 00314 { 00315 assert_locked(); 00316 00317 _terminal_connected = connected; 00318 if (!_terminal_connected) { 00319 // Abort TX 00320 if (_tx_in_progress) { 00321 endpoint_abort(_bulk_in); 00322 _tx_in_progress = false; 00323 } 00324 _tx_buf = _tx_buffer; 00325 _tx_size = 0; 00326 _tx_list.process(); 00327 MBED_ASSERT(_tx_list.empty()); 00328 00329 // Abort RX 00330 if (_rx_in_progress) { 00331 endpoint_abort(_bulk_in); 00332 _rx_in_progress = false; 00333 } 00334 _rx_buf = _rx_buffer; 00335 _rx_size = 0; 00336 _rx_list.process(); 00337 MBED_ASSERT(_rx_list.empty()); 00338 00339 } 00340 _connected_list.process(); 00341 } 00342 00343 bool USBCDC::ready() 00344 { 00345 lock(); 00346 00347 bool ready = _terminal_connected; 00348 00349 unlock(); 00350 return ready; 00351 } 00352 00353 void USBCDC::wait_ready() 00354 { 00355 lock(); 00356 00357 AsyncWait wait_op(this); 00358 _connected_list.add(&wait_op); 00359 00360 unlock(); 00361 00362 wait_op.wait(NULL); 00363 } 00364 00365 bool USBCDC::send(uint8_t *buffer, uint32_t size) 00366 { 00367 lock(); 00368 00369 AsyncWrite write_op(this, buffer, size); 00370 _tx_list.add(&write_op); 00371 00372 unlock(); 00373 00374 write_op.wait(NULL); 00375 return write_op.result; 00376 } 00377 00378 void USBCDC::send_nb(uint8_t *buffer, uint32_t size, uint32_t *actual, bool now) 00379 { 00380 lock(); 00381 00382 *actual = 0; 00383 if (_terminal_connected && !_tx_in_progress) { 00384 uint32_t free = sizeof(_tx_buffer) - _tx_size; 00385 uint32_t write_size = free > size ? size : free; 00386 if (size > 0) { 00387 memcpy(_tx_buf, buffer, write_size); 00388 } 00389 _tx_size += write_size; 00390 *actual = write_size; 00391 if (now) { 00392 _send_isr_start(); 00393 } 00394 } 00395 00396 unlock(); 00397 } 00398 00399 void USBCDC::_send_isr_start() 00400 { 00401 assert_locked(); 00402 00403 if (!_tx_in_progress && _tx_size) { 00404 if (USBDevice::write_start(_bulk_in, _tx_buffer, _tx_size)) { 00405 _tx_in_progress = true; 00406 } 00407 } 00408 } 00409 00410 /* 00411 * Called by when CDC data is sent 00412 * Warning: Called in ISR 00413 */ 00414 void USBCDC::_send_isr() 00415 { 00416 assert_locked(); 00417 00418 write_finish(_bulk_in); 00419 _tx_buf = _tx_buffer; 00420 _tx_size = 0; 00421 _tx_in_progress = false; 00422 00423 _tx_list.process(); 00424 if (!_tx_in_progress) { 00425 data_tx(); 00426 } 00427 } 00428 00429 bool USBCDC::receive(uint8_t *buffer, uint32_t size, uint32_t *size_read) 00430 { 00431 lock(); 00432 00433 bool read_all = size_read == NULL; 00434 uint32_t size_read_dummy; 00435 uint32_t *size_read_ptr = read_all ? &size_read_dummy : size_read; 00436 *size_read_ptr = 0; 00437 AsyncRead read_op(this, buffer, size, size_read_ptr, read_all); 00438 _rx_list.add(&read_op); 00439 00440 unlock(); 00441 00442 read_op.wait(NULL); 00443 return read_op.result; 00444 } 00445 00446 void USBCDC::receive_nb(uint8_t *buffer, uint32_t size, uint32_t *size_read) 00447 { 00448 00449 *size_read = 0; 00450 if (_terminal_connected && !_rx_in_progress) { 00451 // Copy data over 00452 uint32_t copy_size = _rx_size > size ? size : _rx_size; 00453 memcpy(buffer, _rx_buf, copy_size); 00454 *size_read = copy_size; 00455 _rx_buf += copy_size; 00456 _rx_size -= copy_size; 00457 if (_rx_size == 0) { 00458 _receive_isr_start(); 00459 } 00460 } 00461 } 00462 00463 void USBCDC::_receive_isr_start() 00464 { 00465 if ((_rx_size == 0) && !_rx_in_progress) { 00466 // Refill the buffer 00467 read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); 00468 _rx_in_progress = true; 00469 } 00470 } 00471 00472 /* 00473 * Called by when CDC data is received 00474 * Warning: Called in ISR 00475 */ 00476 void USBCDC::_receive_isr() 00477 { 00478 assert_locked(); 00479 00480 MBED_ASSERT(_rx_size == 0); 00481 _rx_buf = _rx_buffer; 00482 _rx_size = read_finish(_bulk_out); 00483 _rx_in_progress = false; 00484 _rx_list.process(); 00485 if (!_rx_in_progress) { 00486 data_rx(); 00487 } 00488 00489 } 00490 00491 const uint8_t *USBCDC::device_desc() 00492 { 00493 uint8_t ep0_size = endpoint_max_packet_size(0x00); 00494 uint8_t device_descriptor_temp[] = { 00495 18, // bLength 00496 1, // bDescriptorType 00497 0x10, 0x01, // bcdUSB 00498 2, // bDeviceClass 00499 0, // bDeviceSubClass 00500 0, // bDeviceProtocol 00501 ep0_size, // bMaxPacketSize0 00502 (uint8_t)(LSB(vendor_id)), (uint8_t)(MSB(vendor_id)), // idVendor 00503 (uint8_t)(LSB(product_id)), (uint8_t)(MSB(product_id)),// idProduct 00504 0x00, 0x01, // bcdDevice 00505 1, // iManufacturer 00506 2, // iProduct 00507 3, // iSerialNumber 00508 1 // bNumConfigurations 00509 }; 00510 MBED_ASSERT(sizeof(device_descriptor_temp) == sizeof(device_descriptor)); 00511 memcpy(device_descriptor, device_descriptor_temp, sizeof(device_descriptor)); 00512 return device_descriptor; 00513 } 00514 00515 const uint8_t *USBCDC::string_iinterface_desc() 00516 { 00517 static const uint8_t stringIinterfaceDescriptor[] = { 00518 0x08, 00519 STRING_DESCRIPTOR, 00520 'C', 0, 'D', 0, 'C', 0, 00521 }; 00522 return stringIinterfaceDescriptor; 00523 } 00524 00525 const uint8_t *USBCDC::string_iproduct_desc() 00526 { 00527 static const uint8_t stringIproductDescriptor[] = { 00528 0x16, 00529 STRING_DESCRIPTOR, 00530 'C', 0, 'D', 0, 'C', 0, ' ', 0, 'D', 0, 'E', 0, 'V', 0, 'I', 0, 'C', 0, 'E', 0 00531 }; 00532 return stringIproductDescriptor; 00533 } 00534 00535 00536 #define CONFIG1_DESC_SIZE (9+8+9+5+5+4+5+7+9+7+7) 00537 00538 const uint8_t *USBCDC::configuration_desc(uint8_t index) 00539 { 00540 uint8_t config_descriptor_temp[] = { 00541 // configuration descriptor 00542 9, // bLength 00543 2, // bDescriptorType 00544 LSB(CONFIG1_DESC_SIZE), // wTotalLength 00545 MSB(CONFIG1_DESC_SIZE), 00546 2, // bNumInterfaces 00547 1, // bConfigurationValue 00548 0, // iConfiguration 00549 0x80, // bmAttributes 00550 50, // bMaxPower 00551 00552 // IAD to associate the two CDC interfaces 00553 0x08, // bLength 00554 0x0b, // bDescriptorType 00555 0x00, // bFirstInterface 00556 0x02, // bInterfaceCount 00557 0x02, // bFunctionClass 00558 0x02, // bFunctionSubClass 00559 0, // bFunctionProtocol 00560 0, // iFunction 00561 00562 // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 00563 9, // bLength 00564 4, // bDescriptorType 00565 0, // bInterfaceNumber 00566 0, // bAlternateSetting 00567 1, // bNumEndpoints 00568 0x02, // bInterfaceClass 00569 0x02, // bInterfaceSubClass 00570 0x01, // bInterfaceProtocol 00571 0, // iInterface 00572 00573 // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 00574 5, // bFunctionLength 00575 0x24, // bDescriptorType 00576 0x00, // bDescriptorSubtype 00577 0x10, 0x01, // bcdCDC 00578 00579 // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 00580 5, // bFunctionLength 00581 0x24, // bDescriptorType 00582 0x01, // bDescriptorSubtype 00583 0x03, // bmCapabilities 00584 1, // bDataInterface 00585 00586 // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 00587 4, // bFunctionLength 00588 0x24, // bDescriptorType 00589 0x02, // bDescriptorSubtype 00590 0x06, // bmCapabilities 00591 00592 // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 00593 5, // bFunctionLength 00594 0x24, // bDescriptorType 00595 0x06, // bDescriptorSubtype 00596 0, // bMasterInterface 00597 1, // bSlaveInterface0 00598 00599 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 00600 ENDPOINT_DESCRIPTOR_LENGTH, // bLength 00601 ENDPOINT_DESCRIPTOR, // bDescriptorType 00602 _int_in, // bEndpointAddress 00603 E_INTERRUPT, // bmAttributes (0x03=intr) 00604 LSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) 00605 MSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) 00606 16, // bInterval 00607 00608 // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 00609 9, // bLength 00610 4, // bDescriptorType 00611 1, // bInterfaceNumber 00612 0, // bAlternateSetting 00613 2, // bNumEndpoints 00614 0x0A, // bInterfaceClass 00615 0x00, // bInterfaceSubClass 00616 0x00, // bInterfaceProtocol 00617 0, // iInterface 00618 00619 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 00620 ENDPOINT_DESCRIPTOR_LENGTH, // bLength 00621 ENDPOINT_DESCRIPTOR, // bDescriptorType 00622 _bulk_in, // bEndpointAddress 00623 E_BULK, // bmAttributes (0x02=bulk) 00624 LSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) 00625 MSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) 00626 0, // bInterval 00627 00628 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 00629 ENDPOINT_DESCRIPTOR_LENGTH, // bLength 00630 ENDPOINT_DESCRIPTOR, // bDescriptorType 00631 _bulk_out, // bEndpointAddress 00632 E_BULK, // bmAttributes (0x02=bulk) 00633 LSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) 00634 MSB(CDC_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) 00635 0 // bInterval 00636 }; 00637 00638 if (index == 0) { 00639 MBED_ASSERT(sizeof(config_descriptor_temp) == sizeof(_config_descriptor)); 00640 memcpy(_config_descriptor, config_descriptor_temp, sizeof(_config_descriptor)); 00641 return _config_descriptor; 00642 } else { 00643 return NULL; 00644 } 00645 }
Generated on Tue Jul 12 2022 13:55:02 by
