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_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(¬ification, 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 *)¬ification, 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 }
Generated on Tue Jul 12 2022 13:55:02 by
