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_ECM.cpp Source File

USBCDC_ECM.cpp

00001 /*
00002  * Copyright (c) 2018, 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_ECM.h"
00020 #include "EndpointResolver.h"
00021 #include "usb_phy_api.h"
00022 #include "mbed_interface.h"
00023 #include "mbed_assert.h"
00024 
00025 #ifndef MAX_SEGMENT_SIZE
00026 #define MAX_SEGMENT_SIZE        (1514)
00027 #endif
00028 
00029 #define FLAG_WRITE_DONE         (1 << 0)
00030 #define FLAG_DISCONNECT         (1 << 1)
00031 #define FLAG_CONNECT            (1 << 2)
00032 #define FLAG_INT_DONE           (1 << 3)
00033 
00034 #define SET_ETHERNET_MULTICAST_FILTERS                  0x40
00035 #define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER    0x41
00036 #define GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER    0x42
00037 #define SET_ETHERNET_PACKET_FILTER                      0x43
00038 #define GET_ETHERNET_STATISTIC                          0x44
00039 
00040 #define CS_INTERFACE                0x24
00041 #define NETWORK_CONNECTION          0x00
00042 #define CONNECTION_SPEED_CHANGE     0x2A
00043 #define LINK_SPEED                  (10000000)
00044 
00045 USBCDC_ECM::USBCDC_ECM(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
00046     : USBDevice(get_usb_phy(), vendor_id, product_id, product_release), _packet_filter(0), _queue(4 * EVENTS_EVENT_SIZE)
00047 {
00048     _init();
00049 
00050     if (connect_blocking) {
00051         init();
00052         USBDevice::connect();
00053         wait_ready();
00054     } else {
00055         init();
00056     }
00057 }
00058 
00059 USBCDC_ECM::USBCDC_ECM(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
00060     : USBDevice(phy, vendor_id, product_id, product_release), _packet_filter(0), _queue(4 * EVENTS_EVENT_SIZE)
00061 {
00062 
00063     _init();
00064 }
00065 
00066 USBCDC_ECM::~USBCDC_ECM()
00067 {
00068     deinit();
00069 }
00070 
00071 void USBCDC_ECM::_init()
00072 {
00073     EndpointResolver resolver(endpoint_table());
00074     resolver.endpoint_ctrl(MAX_PACKET_SIZE_EP0);
00075     _int_in = resolver.endpoint_in(USB_EP_TYPE_INT, MAX_PACKET_SIZE_INT);
00076     _bulk_in = resolver.endpoint_in(USB_EP_TYPE_BULK, MAX_PACKET_SIZE_BULK);
00077     _bulk_out = resolver.endpoint_out(USB_EP_TYPE_BULK, MAX_PACKET_SIZE_BULK);
00078 
00079     MBED_ASSERT(resolver.valid());
00080 
00081     _thread.start(callback(&_queue, &events::EventQueue::dispatch_forever));
00082     _rx_queue.resize(MAX_SEGMENT_SIZE);
00083 }
00084 
00085 void USBCDC_ECM::callback_reset()
00086 {
00087     assert_locked();
00088     /* Called in ISR context */
00089 }
00090 
00091 void USBCDC_ECM::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
00092 {
00093     assert_locked();
00094     /* Called in ISR context */
00095 
00096     complete_request_xfer_done(false);
00097 }
00098 
00099 void USBCDC_ECM::callback_set_configuration(uint8_t configuration)
00100 {
00101     assert_locked();
00102     /* Called in ISR context */
00103 
00104     bool ret = false;
00105     if (configuration == DEFAULT_CONFIGURATION) {
00106         ret = true;
00107     }
00108 
00109     complete_set_configuration(ret);
00110 }
00111 
00112 bool USBCDC_ECM::ready()
00113 {
00114     return _flags.get() & FLAG_CONNECT ? true : false;
00115 }
00116 
00117 void USBCDC_ECM::wait_ready()
00118 {
00119     _flags.wait_any(FLAG_CONNECT, osWaitForever, false);
00120 }
00121 
00122 bool USBCDC_ECM::_notify_network_connection(uint8_t value)
00123 {
00124     _write_mutex.lock();
00125 
00126     bool ret = true;
00127     uint8_t request[8] = {0};
00128 
00129     request[0] = 0xA1;
00130     request[1] = NETWORK_CONNECTION;
00131     request[2] = value;
00132     request[3] = 0x00;
00133 
00134     _flags.clear(FLAG_INT_DONE);
00135     USBDevice::write_start(_int_in, request, sizeof(request));
00136     uint32_t flags = _flags.wait_any(FLAG_INT_DONE | FLAG_DISCONNECT, osWaitForever, false);
00137     if (flags & FLAG_DISCONNECT) {
00138         ret = false;
00139     }
00140     USBDevice::write_finish(_int_in);
00141 
00142     _write_mutex.unlock();
00143     return ret;
00144 }
00145 
00146 bool USBCDC_ECM::_notify_connection_speed_change(uint32_t up, uint32_t down)
00147 {
00148     _write_mutex.lock();
00149 
00150     bool ret = true;
00151     struct notification_t {
00152         uint8_t request[8];
00153         uint32_t up;
00154         uint32_t down;
00155     };
00156 
00157     notification_t notification;
00158     memset(&notification, 0, sizeof(notification));
00159 
00160     notification.request[0] = 0xA1;
00161     notification.request[1] = CONNECTION_SPEED_CHANGE;
00162     notification.request[2] = 0x00;
00163     notification.request[3] = 0x00;
00164     notification.request[6] = 0x08;
00165     notification.up = up;
00166     notification.down = down;
00167 
00168     _flags.clear(FLAG_INT_DONE);
00169     USBDevice::write_start(_int_in, (uint8_t *)&notification, sizeof(notification));
00170     uint32_t flags = _flags.wait_any(FLAG_INT_DONE | FLAG_DISCONNECT, osWaitForever, false);
00171     if (flags & FLAG_DISCONNECT) {
00172         ret = false;
00173     }
00174     USBDevice::write_finish(_int_in);
00175 
00176     _write_mutex.unlock();
00177     return ret;
00178 }
00179 
00180 void USBCDC_ECM::_notify_connect()
00181 {
00182     _notify_network_connection(1);
00183     _notify_connection_speed_change(LINK_SPEED, LINK_SPEED);
00184 }
00185 
00186 bool USBCDC_ECM::_write_bulk(uint8_t *buffer, uint32_t size)
00187 {
00188     bool ret = true;
00189 
00190     _flags.clear(FLAG_WRITE_DONE);
00191     USBDevice::write_start(_bulk_in, buffer, size);
00192     uint32_t flags = _flags.wait_any(FLAG_WRITE_DONE | FLAG_DISCONNECT, osWaitForever, false);
00193     if (flags & FLAG_DISCONNECT) {
00194         ret = false;
00195     }
00196 
00197     USBDevice::write_finish(_bulk_in);
00198     return ret;
00199 }
00200 
00201 bool USBCDC_ECM::send(uint8_t *buffer, uint32_t size)
00202 {
00203     _write_mutex.lock();
00204     bool ret = true;
00205     uint32_t sent = 0;
00206     uint32_t data_size = 0;
00207 
00208     if (size > MAX_SEGMENT_SIZE) {
00209         _write_mutex.unlock();
00210         mbed_error_printf("Buffer size is too large\n");
00211         return false;
00212     }
00213 
00214     uint32_t max_packet = USBDevice::endpoint_max_packet_size(_bulk_in);
00215 
00216     while (size - sent > 0) {
00217         data_size = (size - sent > max_packet) ? max_packet : size - sent;
00218         if (_write_bulk(buffer + sent, data_size)) {
00219             sent += data_size;
00220         } else {
00221             _write_mutex.unlock();
00222             return false;
00223         }
00224     }
00225 
00226     /* Send zero length packet */
00227     if (size % max_packet == 0) {
00228         uint8_t buf = 0;
00229         ret = _write_bulk(&buf, 0);
00230     }
00231 
00232     _write_mutex.unlock();
00233     return ret;
00234 }
00235 
00236 void USBCDC_ECM::receive_nb(uint8_t *buffer, uint32_t size, uint32_t *actual)
00237 {
00238     lock();
00239 
00240     uint32_t available = _rx_queue.size();
00241     uint32_t copy_size = available > size ? size : available;
00242     _rx_queue.read(buffer, copy_size);
00243     *actual = copy_size;
00244 
00245     unlock();
00246 }
00247 
00248 void USBCDC_ECM::attach_rx(mbed::Callback<void()> cb)
00249 {
00250     lock();
00251 
00252     _callback_rx = cb;
00253 
00254     unlock();
00255 }
00256 
00257 void USBCDC_ECM::attach_filter(mbed::Callback<void()> cb)
00258 {
00259     lock();
00260 
00261     _callback_filter = cb;
00262 
00263     unlock();
00264 }
00265 
00266 uint16_t USBCDC_ECM::read_packet_filter()
00267 {
00268     return _packet_filter;
00269 }
00270 
00271 void USBCDC_ECM::callback_request(const setup_packet_t *setup)
00272 {
00273     assert_locked();
00274 
00275     RequestResult result = PassThrough;
00276     uint8_t *data = NULL;
00277     uint32_t size = 0;
00278 
00279     if (setup->bmRequestType.Type == CLASS_TYPE) {
00280         //printf("In USBCallback_request: CLASS specific Request: %02x\n", setup->bRequest);
00281         switch (setup->bRequest) {
00282             case SET_ETHERNET_MULTICAST_FILTERS:
00283                 /* TODO: Support is optional, not implemented here */
00284                 break;
00285             case SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
00286                 /* TODO: Support is optional, not implemented here */
00287                 break;
00288             case GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
00289                 /* TODO: Support is optional, not implemented here */
00290                 break;
00291             case SET_ETHERNET_PACKET_FILTER:
00292                 if (_packet_filter != setup->wValue) {
00293                     _packet_filter = setup->wValue;
00294                     // Signal that packet filter configuration is changed
00295                     if (_callback_filter) {
00296                         _callback_filter();
00297                     }
00298                 }
00299                 result = Success;
00300                 break;
00301             case GET_ETHERNET_STATISTIC:
00302                 /* TODO: Support is optional, not implemented here */
00303                 break;
00304             default:
00305                 result = Failure;
00306                 break;
00307         }
00308     }
00309 
00310     complete_request(result, data, size);
00311 }
00312 
00313 void USBCDC_ECM::callback_set_interface(uint16_t interface, uint8_t alternate)
00314 {
00315     assert_locked();
00316     /* Called in ISR context */
00317 
00318     if (alternate) {
00319         _packet_filter = 0;
00320 
00321         endpoint_add(_int_in, MAX_PACKET_SIZE_INT, USB_EP_TYPE_INT, &USBCDC_ECM::_int_callback);
00322         endpoint_add(_bulk_in, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_in_callback);
00323         endpoint_add(_bulk_out, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_out_callback);
00324 
00325         read_start(_bulk_out, _bulk_buf, MAX_PACKET_SIZE_BULK);
00326 
00327         _queue.call(static_cast<USBCDC_ECM *>(this), &USBCDC_ECM::_notify_connect);
00328     }
00329 
00330     complete_set_interface(true);
00331 }
00332 
00333 void USBCDC_ECM::callback_state_change(DeviceState new_state)
00334 {
00335     assert_locked();
00336     /* Called in ISR context */
00337 
00338     if (new_state == Configured) {
00339         _flags.set(FLAG_CONNECT);
00340         _flags.clear(FLAG_DISCONNECT);
00341     } else {
00342         _flags.set(FLAG_DISCONNECT);
00343         _flags.clear(FLAG_CONNECT | FLAG_WRITE_DONE | FLAG_INT_DONE);
00344     }
00345 }
00346 
00347 const uint8_t *USBCDC_ECM::device_desc()
00348 {
00349     uint8_t ep0_size = endpoint_max_packet_size(0x00);
00350     uint8_t device_descriptor_temp[] = {
00351         DEVICE_DESCRIPTOR_LENGTH,       // bLength
00352         DEVICE_DESCRIPTOR,              // bDescriptorType
00353         0x00, 0x02,                     // bcdUSB 2.0
00354         0x02,                           // bDeviceClass
00355         0x00,                           // bDeviceSubClass
00356         0x00,                           // bDeviceProtocol
00357         ep0_size,                       // bMaxPacketSize0
00358         (uint8_t)(LSB(vendor_id)),
00359         (uint8_t)(MSB(vendor_id)),      // idVendor
00360         (uint8_t)(LSB(product_id)),
00361         (uint8_t)(MSB(product_id)),     // idProduct
00362         (uint8_t)(LSB(product_release)),
00363         (uint8_t)(MSB(product_release)),// bcdDevice
00364         STRING_OFFSET_IMANUFACTURER,    // iManufacturer
00365         STRING_OFFSET_IPRODUCT,         // iProduct
00366         STRING_OFFSET_ISERIAL,          // iSerialNumber
00367         0x01                            // bNumConfigurations
00368     };
00369     MBED_ASSERT(sizeof(device_descriptor_temp) == sizeof(device_descriptor));
00370     memcpy(device_descriptor, device_descriptor_temp, sizeof(device_descriptor));
00371     return device_descriptor;
00372 }
00373 
00374 const uint8_t *USBCDC_ECM::string_iproduct_desc()
00375 {
00376     static const uint8_t string_iproduct_descriptor[] = {
00377         26,
00378         STRING_DESCRIPTOR,
00379         'U', 0, 'S', 0, 'B', 0, ' ', 0, 'E', 0, 't', 0, 'h', 0, 'e', 0, 'r', 0, 'n', 0, 'e', 0, 't', 0
00380     };
00381     return string_iproduct_descriptor;
00382 }
00383 
00384 const uint8_t *USBCDC_ECM::string_iconfiguration_desc()
00385 {
00386     uint8_t string_imac_addr_temp[26] = {0};
00387     const char unicodes[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00388                              'A', 'B', 'C', 'D', 'E', 'F'
00389                             };
00390     char mac[6];
00391 
00392     mbed_mac_address(mac);
00393 
00394     string_imac_addr_temp[0] = 26;
00395     string_imac_addr_temp[1] = STRING_DESCRIPTOR;
00396     /* Convert MAC address to USB CDC string format */
00397     for (int i = 0; i < 6; i++) {
00398         string_imac_addr_temp[i * 4 + 2] = unicodes[mac[i] >> 4];
00399         string_imac_addr_temp[i * 4 + 4] = unicodes[mac[i] & 0xF];
00400     }
00401 
00402     MBED_ASSERT(sizeof(string_imac_addr_temp) == sizeof(_string_imac_addr));
00403     memcpy(_string_imac_addr, string_imac_addr_temp, sizeof(string_imac_addr_temp));
00404     return _string_imac_addr;
00405 }
00406 
00407 const uint8_t *USBCDC_ECM::string_iserial_desc()
00408 {
00409     static const uint8_t string_iserial_descriptor[] = {
00410         26,
00411         STRING_DESCRIPTOR,
00412         '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0, 'A', 0, 'B', 0
00413     };
00414     return string_iserial_descriptor;
00415 }
00416 
00417 #define CONFIG_DESC_SIZE (9+9+5+5+13+7+9+9+7+7)
00418 
00419 const uint8_t *USBCDC_ECM::configuration_desc(uint8_t index)
00420 {
00421     if (index != 0) {
00422         return NULL;
00423     }
00424 
00425     uint8_t config_descriptor_temp[] = {
00426         // configuration descriptor, USB spec 9.6.3, page 264-265, Table 9-10
00427         0x09,                           // bLength
00428         CONFIGURATION_DESCRIPTOR,       // bDescriptorType
00429         LSB(CONFIG_DESC_SIZE),          // wTotalLength (LSB)
00430         MSB(CONFIG_DESC_SIZE),          // wTotalLength (MSB)
00431         2,                              // bNumInterfaces
00432         1,                              // bConfigurationValue
00433         0,                              // iConfiguration
00434         0xC0,                           // bmAttributes
00435         50,                             // bMaxPower
00436 
00437         // Communication interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
00438         0x09,                   // bLength
00439         INTERFACE_DESCRIPTOR,   // bDescriptorType
00440         0,                      // bInterfaceNumber
00441         0,                      // bAlternateSetting
00442         1,                      // bNumEndpoints
00443         0x02,                   // bInterfaceClass
00444         0x06,                   // bInterfaceSubClass
00445         0x00,                   // bInterfaceProtocol
00446         0,                      // iInterface
00447 
00448         // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 15
00449         0x05,                   // bFunctionLength
00450         CS_INTERFACE,           // bDescriptorType
00451         0x00,                   // bDescriptorSubtype
00452         0x20, 0x01,             // bcdCDC CDC 1.20
00453 
00454         // CDC Union Functional Descriptor, CDC Spec 5.2.3.2, Table 16
00455         0x05,                   // bFunctionLength
00456         CS_INTERFACE,           // bDescriptorType
00457         0x06,                   // bDescriptorSubType
00458         0,                      // bControlInterface
00459         1,                      // bSubordinateInterface0
00460 
00461         // CDC Ethernet Networking Functional Descriptor, ECM Spec 5.4, Table 3
00462         0x0D,                           // bFunctionLenght
00463         CS_INTERFACE,                   // bDescriptorType
00464         0x0F,                           // bDescriptorSubtype
00465         STRING_OFFSET_ICONFIGURATION,   // iMacAddress
00466         0, 0, 0, 0,                     // bmEthernetStatistics
00467         (uint8_t) LSB(MAX_SEGMENT_SIZE),    // wMaxSegmentSize (LSB)
00468         (uint8_t) MSB(MAX_SEGMENT_SIZE),    // wMaxSegmentSize (MSB)
00469         0, 0,                           // wNumberMCFilters
00470         0,                              // bNumberPowerFilters
00471 
00472         // Endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00473         ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00474         ENDPOINT_DESCRIPTOR,            // bDescriptorType
00475         _int_in,                        // bEndpointAddress
00476         E_INTERRUPT,                    // bmAttributes (0x03=intr)
00477         (uint8_t) LSB(MAX_PACKET_SIZE_INT),     // wMaxPacketSize (LSB)
00478         (uint8_t) MSB(MAX_PACKET_SIZE_INT),     // wMaxPacketSize (MSB)
00479         16,                             // bInterval
00480 
00481         // Default data interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
00482         0x09,                       // bLength
00483         INTERFACE_DESCRIPTOR,       // bDescriptorType
00484         1,                          // bInterfaceNumber
00485         0,                          // bAlternateSetting
00486         0,                          // bNumEndpoints
00487         0x0A,                       // bInterfaceClass
00488         0x00,                       // bInterfaceSubClass
00489         0x00,                       // bInterfaceProtocol
00490         0,                          // iInterface
00491 
00492         // Data interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
00493         0x09,                       // bLength
00494         INTERFACE_DESCRIPTOR,       // bDescriptorType
00495         1,                          // bInterfaceNumber
00496         1,                          // bAlternateSetting
00497         2,                          // bNumEndpoints
00498         0x0A,                       // bInterfaceClass
00499         0x00,                       // bInterfaceSubClass
00500         0x00,                       // bInterfaceProtocol
00501         0,                          // iInterface
00502 
00503         // Endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00504         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00505         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00506         _bulk_in,                   // bEndpointAddress
00507         E_BULK,                     // bmAttributes (0x02=bulk)
00508         (uint8_t) LSB(MAX_PACKET_SIZE_BULK),  // wMaxPacketSize (LSB)
00509         (uint8_t) MSB(MAX_PACKET_SIZE_BULK),  // wMaxPacketSize (MSB)
00510         0,                          // bInterval
00511 
00512         // Endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00513         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00514         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00515         _bulk_out,                  // bEndpointAddress
00516         E_BULK,                     // bmAttributes (0x02=bulk)
00517         (uint8_t) LSB(MAX_PACKET_SIZE_BULK),  // wMaxPacketSize (LSB)
00518         (uint8_t) MSB(MAX_PACKET_SIZE_BULK),  // wMaxPacketSize (MSB)
00519         0                           // bInterval
00520     };
00521 
00522     MBED_ASSERT(sizeof(config_descriptor_temp) == sizeof(_config_descriptor));
00523     memcpy(_config_descriptor, config_descriptor_temp, sizeof(config_descriptor_temp));
00524     return _config_descriptor;
00525 }
00526 
00527 void USBCDC_ECM::_int_callback()
00528 {
00529     assert_locked();
00530 
00531     _flags.set(FLAG_INT_DONE);
00532 }
00533 
00534 void USBCDC_ECM::_bulk_in_callback()
00535 {
00536     assert_locked();
00537 
00538     _flags.set(FLAG_WRITE_DONE);
00539 }
00540 
00541 void USBCDC_ECM::_bulk_out_callback()
00542 {
00543     assert_locked();
00544 
00545     uint32_t read_size = read_finish(_bulk_out);
00546 
00547     if (read_size <= _rx_queue.free()) {
00548         // Copy data over
00549         _rx_queue.write(_bulk_buf, read_size);
00550     }
00551 
00552     // Signal that there is ethernet packet available
00553     if (_callback_rx && (read_size < USBDevice::endpoint_max_packet_size(_bulk_out))) {
00554         _callback_rx();
00555     }
00556 
00557     read_start(_bulk_out, _bulk_buf, MAX_PACKET_SIZE_BULK);
00558 }