Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBCDC.cpp Source File

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 }