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
USBMIDI.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 "USBMIDI.h" 00020 #include "EndpointResolver.h" 00021 #include "usb_phy_api.h" 00022 00023 #define FLAG_WRITE_DONE (1 << 0) 00024 #define FLAG_DISCONNECT (1 << 1) 00025 #define FLAG_CONNECT (1 << 2) 00026 00027 USBMIDI::USBMIDI(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) 00028 : USBDevice(get_usb_phy(), vendor_id, product_id, product_release) 00029 { 00030 _init(); 00031 00032 if (connect_blocking) { 00033 USBDevice::connect(); 00034 wait_ready(); 00035 } else { 00036 init(); 00037 } 00038 } 00039 00040 USBMIDI::USBMIDI(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) 00041 : USBDevice(phy, vendor_id, product_id, product_release) 00042 { 00043 _init(); 00044 00045 // User or child responsible for calling connect or init 00046 } 00047 00048 USBMIDI::~USBMIDI() 00049 { 00050 deinit(); 00051 } 00052 00053 void USBMIDI::_init() 00054 { 00055 _bulk_buf_pos = 0; 00056 _bulk_buf_size = 0; 00057 00058 _data_ready = false; 00059 _cur_data = 0; 00060 00061 EndpointResolver resolver(endpoint_table()); 00062 00063 resolver.endpoint_ctrl(64); 00064 _bulk_in = resolver.endpoint_in(USB_EP_TYPE_BULK, MaxSize); 00065 _bulk_out = resolver.endpoint_out(USB_EP_TYPE_BULK, MaxSize); 00066 MBED_ASSERT(resolver.valid()); 00067 } 00068 00069 bool USBMIDI::ready() 00070 { 00071 return _flags.get() & FLAG_CONNECT ? true : false; 00072 } 00073 00074 void USBMIDI::wait_ready() 00075 { 00076 _flags.wait_any(FLAG_CONNECT, osWaitForever, false); 00077 } 00078 00079 // write plain MIDIMessage that will be converted to USBMidi event packet 00080 bool USBMIDI::write(MIDIMessage m) 00081 { 00082 _write_mutex.lock(); 00083 00084 bool ret = true; 00085 // first byte keeped for retro-compatibility 00086 for (int p = 1; p < m.length; p += 3) { 00087 uint8_t buf[4]; 00088 // Midi message to USBMidi event packet 00089 buf[0] = m.data[1] >> 4; 00090 // SysEx 00091 if (buf[0] == 0xF) { 00092 if ((m.length - p) > 3) { 00093 // SysEx start or continue 00094 buf[0] = 0x4; 00095 } else { 00096 switch (m.length - p) { 00097 case 1: 00098 // SysEx end with one byte 00099 buf[0] = 0x5; 00100 break; 00101 case 2: 00102 // SysEx end with two bytes 00103 buf[0] = 0x6; 00104 break; 00105 case 3: 00106 // SysEx end with three bytes 00107 buf[0] = 0x7; 00108 break; 00109 } 00110 } 00111 } 00112 buf[1] = m.data[p]; 00113 00114 if (p + 1 < m.length) { 00115 buf[2] = m.data[p + 1]; 00116 } else { 00117 buf[2] = 0; 00118 } 00119 00120 if (p + 2 < m.length) { 00121 buf[3] = m.data[p + 2]; 00122 } else { 00123 buf[3] = 0; 00124 } 00125 00126 _flags.clear(FLAG_WRITE_DONE); 00127 USBDevice::write_start(_bulk_in, buf, 4); 00128 uint32_t flags = _flags.wait_any(FLAG_WRITE_DONE | FLAG_DISCONNECT, osWaitForever, false); 00129 if (flags & FLAG_DISCONNECT) { 00130 ret = false; 00131 break; 00132 } 00133 USBDevice::write_finish(_bulk_in); 00134 } 00135 00136 _write_mutex.unlock(); 00137 return ret; 00138 } 00139 00140 bool USBMIDI::readable() 00141 { 00142 lock(); 00143 00144 bool ret = _data_ready; 00145 00146 unlock(); 00147 00148 return ret; 00149 } 00150 00151 bool USBMIDI::read(MIDIMessage *m) 00152 { 00153 lock(); 00154 00155 // Invalidate message 00156 m->length = 0; 00157 00158 if (!_data_ready) { 00159 unlock(); 00160 return false; 00161 } 00162 00163 m->from_raw(_data, _cur_data); 00164 _cur_data = 0; 00165 _next_message(); 00166 00167 if (!_data_ready) { 00168 read_start(_bulk_out, _bulk_buf, MaxSize); 00169 } 00170 00171 unlock(); 00172 00173 return true; 00174 } 00175 00176 void USBMIDI::attach(mbed::Callback<void()> callback) 00177 { 00178 lock(); 00179 00180 _callback = callback; 00181 00182 unlock(); 00183 } 00184 00185 void USBMIDI::callback_state_change(DeviceState new_state) 00186 { 00187 assert_locked(); 00188 00189 if (new_state == Configured) { 00190 _flags.set(FLAG_CONNECT); 00191 _flags.clear(FLAG_DISCONNECT); 00192 } else { 00193 _flags.set(FLAG_DISCONNECT); 00194 _flags.clear(FLAG_CONNECT | FLAG_WRITE_DONE); 00195 } 00196 } 00197 00198 void USBMIDI::callback_request(const setup_packet_t *setup) 00199 { 00200 assert_locked(); 00201 00202 RequestResult result = PassThrough; 00203 uint8_t *data = NULL; 00204 uint32_t size = 0; 00205 00206 complete_request(result, data, size); 00207 } 00208 00209 void USBMIDI::callback_request_xfer_done(const setup_packet_t *setup, bool aborted) 00210 { 00211 assert_locked(); 00212 00213 complete_request_xfer_done(false); 00214 } 00215 00216 void USBMIDI::callback_set_configuration(uint8_t configuration) 00217 { 00218 assert_locked(); 00219 00220 if (configuration == DEFAULT_CONFIGURATION) { 00221 complete_set_configuration(false); 00222 } 00223 00224 endpoint_remove_all(); 00225 endpoint_add(_bulk_in, MaxSize, USB_EP_TYPE_BULK, &USBMIDI::_in_callback); 00226 endpoint_add(_bulk_out, MaxSize, USB_EP_TYPE_BULK, &USBMIDI::_out_callback); 00227 00228 read_start(_bulk_out, _bulk_buf, MaxSize); 00229 00230 complete_set_configuration(true); 00231 } 00232 00233 void USBMIDI::callback_set_interface(uint16_t interface, uint8_t alternate) 00234 { 00235 assert_locked(); 00236 00237 complete_set_interface(true); 00238 } 00239 00240 const uint8_t *USBMIDI::string_iinterface_desc() 00241 { 00242 static const uint8_t string_iinterface_descriptor[] = { 00243 0x0c, //bLength 00244 STRING_DESCRIPTOR, //bDescriptorType 0x03 00245 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 //bString iInterface - Audio 00246 }; 00247 return string_iinterface_descriptor; 00248 } 00249 00250 const uint8_t *USBMIDI::string_iproduct_desc() 00251 { 00252 static const uint8_t string_iproduct_descriptor[] = { 00253 0x16, //bLength 00254 STRING_DESCRIPTOR, //bDescriptorType 0x03 00255 'M', 0, 'b', 0, 'e', 0, 'd', 0, ' ', 0, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 //bString iProduct - Mbed Audio 00256 }; 00257 return string_iproduct_descriptor; 00258 } 00259 00260 const uint8_t *USBMIDI::configuration_desc(uint8_t index) 00261 { 00262 if (index != 0) { 00263 return NULL; 00264 } 00265 00266 uint8_t config_descriptor_temp[] = { 00267 // configuration descriptor 00268 0x09, 0x02, 0x65, 0x00, 0x02, 0x01, 0x00, 0xc0, 0x50, 00269 00270 // The Audio Interface Collection 00271 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, // Standard AC Interface Descriptor 00272 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, // Class-specific AC Interface Descriptor 00273 0x09, 0x04, 0x01, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, // MIDIStreaming Interface Descriptors 00274 0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00, // Class-Specific MS Interface Header Descriptor 00275 00276 // MIDI IN JACKS 00277 0x06, 0x24, 0x02, 0x01, 0x01, 0x00, 00278 0x06, 0x24, 0x02, 0x02, 0x02, 0x00, 00279 00280 // MIDI OUT JACKS 00281 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 00282 0x09, 0x24, 0x03, 0x02, 0x06, 0x01, 0x01, 0x01, 0x00, 00283 00284 // OUT endpoint - Standard MS Bulk Data Endpoint Descriptor 00285 0x09, // bLength 00286 0x05, // bDescriptorType 00287 _bulk_out, // bEndpointAddress 00288 0x02, // bmAttributes 00289 0x40, // wMaxPacketSize (LSB) 00290 0x00, // wMaxPacketSize (MSB) 00291 0x00, // bInterval (milliseconds) 00292 0x00, // bRefresh 00293 0x00, // bSynchAddress 00294 00295 0x05, 0x25, 0x01, 0x01, 0x01, 00296 00297 // IN endpoint - Standard MS Bulk Data Endpoint Descriptor 00298 0x09, // bLength 00299 0x05, // bDescriptorType 00300 _bulk_in, // bEndpointAddress 00301 0x02, // bmAttributes 00302 0x40, // wMaxPacketSize (LSB) 00303 0x00, // wMaxPacketSize (MSB) 00304 0x00, // bInterval (milliseconds) 00305 0x00, // bRefresh 00306 0x00, // bSynchAddress 00307 00308 0x05, 0x25, 0x01, 0x01, 0x03, 00309 }; 00310 MBED_ASSERT(sizeof(config_descriptor_temp) == sizeof(_config_descriptor)); 00311 memcpy(_config_descriptor, config_descriptor_temp, sizeof(config_descriptor_temp)); 00312 return _config_descriptor; 00313 } 00314 00315 void USBMIDI::_in_callback() 00316 { 00317 assert_locked(); 00318 00319 _flags.set(FLAG_WRITE_DONE); 00320 } 00321 00322 void USBMIDI::_out_callback() 00323 { 00324 assert_locked(); 00325 00326 _bulk_buf_size = read_finish(_bulk_out); 00327 _bulk_buf_pos = 0; 00328 00329 if (_callback && _next_message()) { 00330 _callback(); 00331 return; 00332 } 00333 00334 read_start(_bulk_out, _bulk_buf, MaxSize); 00335 } 00336 00337 bool USBMIDI::_next_message() 00338 { 00339 assert_locked(); 00340 00341 bool data_ready = false; 00342 while (_bulk_buf_pos < _bulk_buf_size) { 00343 uint8_t data_read; 00344 bool data_end = true; 00345 switch (_bulk_buf[_bulk_buf_pos]) { 00346 case 0x2: 00347 // Two-bytes System Common Message - undefined in USBMidi 1.0 00348 data_read = 2; 00349 break; 00350 case 0x4: 00351 // SysEx start or continue 00352 data_end = false; 00353 data_read = 3; 00354 break; 00355 case 0x5: 00356 // Single-byte System Common Message or SysEx end with one byte 00357 data_read = 1; 00358 break; 00359 case 0x6: 00360 // SysEx end with two bytes 00361 data_read = 2; 00362 break; 00363 case 0xC: 00364 // Program change 00365 data_read = 2; 00366 break; 00367 case 0xD: 00368 // Channel pressure 00369 data_read = 2; 00370 break; 00371 case 0xF: 00372 // Single byte 00373 data_read = 1; 00374 break; 00375 default: 00376 // Others three-bytes messages 00377 data_read = 3; 00378 break; 00379 } 00380 00381 for (uint8_t j = 1; j < data_read + 1; j++) { 00382 if (_cur_data < sizeof(_data)) { 00383 _data[_cur_data] = _bulk_buf[_bulk_buf_pos + j]; 00384 } 00385 _cur_data++; 00386 } 00387 _bulk_buf_pos += 4; 00388 00389 if (data_end) { 00390 // Message is ready to be read 00391 data_ready = true; 00392 break; 00393 } 00394 } 00395 00396 _data_ready = data_ready; 00397 return data_ready; 00398 }
Generated on Tue Jul 12 2022 13:55:02 by
