Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBMIDI.cpp Source File

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 }