/* * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "stdint.h" #include "USBAudio.h" #include "USBAudio_Types.h" #include "EndpointResolver.h" #include "usb_phy_api.h" #define SAMPLE_SIZE 2 #define XFER_FREQUENCY_HZ 1000 #define WRITE_READY_UNBLOCK (1 << 0) #define READ_READY_UNBLOCK (1 << 1) class USBAudio::AsyncWrite: public AsyncOp { public: AsyncWrite(USBAudio *audio, uint8_t *buf, uint32_t size): audio(audio), tx_buf(buf), tx_size(size), result(false) { } virtual ~AsyncWrite() { } virtual bool process() { if (audio->_tx_state != Opened) { result = false; return true; } uint32_t actual_size = 0; audio->write_nb(tx_buf, tx_size, &actual_size); tx_size -= actual_size; tx_buf += actual_size; if (tx_size == 0) { result = true; return true; } return false; } USBAudio *audio; uint8_t *tx_buf; uint32_t tx_size; bool result; }; class USBAudio::AsyncRead: public AsyncOp { public: AsyncRead(USBAudio *audio, uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all) : audio(audio), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false) { } virtual ~AsyncRead() { } virtual bool process() { if (audio->_rx_state != Opened) { result = false; return true; } uint32_t actual_size = 0; audio->read_nb(rx_buf, rx_size, &actual_size); rx_buf += actual_size; *rx_actual += actual_size; rx_size -= actual_size; if ((!all && *rx_actual > 0) || (rx_size == 0)) { // Wake thread if request is done result = true; return true; } return false; } USBAudio *audio; uint8_t *rx_buf; uint32_t rx_size; uint32_t *rx_actual; bool all; bool result; }; static void stub_volume() { } static void stub_handler(USBAudio::AudioEvent event) { (void)event; } USBAudio::USBAudio(bool connect, uint32_t frequency_rx, uint8_t channel_count_rx, uint32_t frequency_tx, uint8_t channel_count_tx, uint32_t buffer_ms, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(get_usb_phy(), vendor_id, product_id, product_release) { _init(frequency_rx, channel_count_rx, frequency_tx, channel_count_tx, buffer_ms); // connect or init device if (connect) { USBDevice::connect(); } else { USBDevice::init(); } } USBAudio::USBAudio(USBPhy *phy, uint32_t frequency_rx, uint8_t channel_count_rx, uint32_t frequency_tx, uint8_t channel_count_tx, uint32_t buffer_ms, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(phy, vendor_id, product_id, product_release) { _init(frequency_rx, channel_count_rx, frequency_tx, channel_count_tx, buffer_ms); } void USBAudio::_init(uint32_t frequency_rx, uint8_t channel_count_rx, uint32_t frequency_tx, uint8_t channel_count_tx, uint32_t buffer_ms) { _connected = false; _volume = 0; _mute = 0; _vol_cur = 0x0080; _vol_min = 0x0000; _vol_max = 0x0100; _vol_res = 0x0004; _update_vol = mbed::callback(stub_volume); _tx_done = mbed::callback(stub_handler); _rx_done = mbed::callback(stub_handler); _rx_overflow = 0; _tx_underflow = 0; _tx_freq = frequency_tx; _rx_freq = frequency_rx; _tx_channel_count = channel_count_tx; _rx_channel_count = channel_count_rx; _tx_idle = true; _tx_frame_fract = 0; _tx_whole_frames_per_xfer = _tx_freq / XFER_FREQUENCY_HZ; _tx_fract_frames_per_xfer = _tx_freq % XFER_FREQUENCY_HZ; uint32_t max_frames = _tx_whole_frames_per_xfer + (_tx_fract_frames_per_xfer ? 1 : 0); _tx_packet_size_max = max_frames * SAMPLE_SIZE * _tx_channel_count; _rx_packet_size_max = (_rx_freq + 1000 - 1) / 1000 * _rx_channel_count * 2; _tx_packet_buf = new uint8_t[_tx_packet_size_max](); _rx_packet_buf = new uint8_t[_rx_packet_size_max](); _tx_queue.resize(buffer_ms * _tx_channel_count * SAMPLE_SIZE * _tx_freq / XFER_FREQUENCY_HZ); _rx_queue.resize(buffer_ms * _rx_channel_count * SAMPLE_SIZE * _rx_freq / XFER_FREQUENCY_HZ); _tx_state = Closed; _rx_state = Closed; EndpointResolver resolver(endpoint_table()); resolver.endpoint_ctrl(64); _episo_out = resolver.endpoint_out(USB_EP_TYPE_ISO, _tx_packet_size_max); _episo_in = resolver.endpoint_in(USB_EP_TYPE_ISO, _rx_packet_size_max); MBED_ASSERT(resolver.valid()); _channel_config_rx = (_rx_channel_count == 1) ? CHANNEL_M : CHANNEL_L + CHANNEL_R; _channel_config_tx = (_tx_channel_count == 1) ? CHANNEL_M : CHANNEL_L + CHANNEL_R; _build_configuration_desc(); } USBAudio::~USBAudio() { disconnect(); deinit(); delete[] _tx_packet_buf; delete[] _rx_packet_buf; } void USBAudio::connect() { lock(); if (!_connected) { USBDevice::connect(); _connected = true; _receive_change(Closed); _send_change(Closed); } unlock(); } void USBAudio::disconnect() { lock(); if (_connected) { _connected = false; USBDevice::disconnect(); _receive_change(Powerdown); _send_change(Powerdown); } unlock(); } bool USBAudio::read(uint8_t *buf, uint32_t size) { lock(); uint32_t actual; AsyncRead read(this, buf, size, &actual, true); _read_list.add(&read); unlock(); read.wait(NULL); return read.result; } void USBAudio::read_nb(uint8_t *buf, uint32_t size, uint32_t *actual) { lock(); uint32_t available = _rx_queue.size(); uint32_t copy_size = available > size ? size : available; _rx_queue.read(buf, copy_size); *actual = copy_size; unlock(); } uint32_t USBAudio::read_overflows(bool clear) { lock(); uint32_t overflows = _rx_overflow; if (clear) { _rx_overflow = 0; } unlock(); return overflows; } bool USBAudio::read_ready() { lock(); bool ready = _rx_state == Opened; unlock(); return ready; } void USBAudio::read_wait_ready() { _flags.wait_any(READ_READY_UNBLOCK, osWaitForever, false); } bool USBAudio::write(uint8_t *buf, uint32_t size) { lock(); AsyncWrite write(this, buf, size); _write_list.add(&write); unlock(); write.wait(NULL); return write.result; } void USBAudio::write_nb(uint8_t *buf, uint32_t size, uint32_t *actual) { lock(); uint32_t available = _tx_queue.free(); uint32_t copy_size = available > size ? size : available; _tx_queue.write(buf, copy_size); *actual = copy_size; _send_isr_start(); unlock(); } uint32_t USBAudio::write_underflows(bool clear) { lock(); uint32_t underflows = _tx_underflow; if (clear) { _tx_underflow = 0; } unlock(); return underflows; } bool USBAudio::write_ready() { lock(); bool ready = _tx_state == Opened; unlock(); return ready; } void USBAudio::write_wait_ready() { _flags.wait_any(WRITE_READY_UNBLOCK, osWaitForever, false); } float USBAudio::get_volume() { lock(); float ret = _mute ? 0.0f : _volume; unlock(); return ret; } void USBAudio::attach(mbed::Callback &cb) { lock(); _update_vol = cb; if (!_update_vol) { _update_vol = stub_volume; } unlock(); } void USBAudio::attach_tx(mbed::Callback &cb) { lock(); _tx_done = cb; if (!_tx_done) { _tx_done = mbed::callback(stub_handler); } unlock(); } void USBAudio::attach_rx(mbed::Callback &cb) { lock(); _rx_done = cb; if (!_rx_done) { _rx_done = mbed::callback(stub_handler); } unlock(); } void USBAudio::callback_state_change(DeviceState new_state) { assert_locked(); if (_connected && (new_state != Configured)) { _receive_change(Closed); _send_change(Closed); } } void USBAudio::callback_request(const setup_packet_t *setup) { assert_locked(); RequestResult result = PassThrough; uint8_t *data = NULL; uint32_t size = 0; // Process class-specific requests if (setup->bmRequestType.Type == CLASS_TYPE) { // Feature Unit: Interface = 0, ID = 2 if (setup->wIndex == 0x0200) { // Master Channel if ((setup->wValue & 0xff) == 0) { switch (setup->wValue >> 8) { case MUTE_CONTROL: switch (setup->bRequest) { case REQUEST_GET_CUR: size = 1; data = &_mute; result = Send; break; case REQUEST_SET_CUR: size = 1; data = _control_receive; result = Receive; break; default: break; } break; case VOLUME_CONTROL: switch (setup->bRequest) { case REQUEST_GET_CUR: size = 2; data = (uint8_t *)&_vol_cur; result = Send; break; case REQUEST_GET_MIN: size = 2; data = (uint8_t *)&_vol_min; result = Send; break; case REQUEST_GET_MAX: size = 2; data = (uint8_t *)&_vol_max; result = Send; break; case REQUEST_GET_RES: size = 2; data = (uint8_t *)&_vol_res; result = Send; break; case REQUEST_SET_CUR: size = 2; data = _control_receive; result = Receive; break; case REQUEST_SET_MIN: size = 2; data = _control_receive; result = Receive; break; case REQUEST_SET_MAX: size = 2; data = _control_receive; result = Receive; break; case REQUEST_SET_RES: size = 2; data = _control_receive; result = Receive; break; } break; default: break; } } } } complete_request(result, data, size); } void USBAudio::callback_request_xfer_done(const setup_packet_t *setup, bool aborted) { assert_locked(); if (aborted) { complete_request_xfer_done(false); return; } if (setup->bmRequestType.dataTransferDirection == DEVICE_TO_HOST) { complete_request_xfer_done(true); return; } if ((setup->wLength == 1) || (setup->wLength == 2)) { uint16_t data = (_control_receive[0] << 0) | (_control_receive[1] << 8); data &= ((setup->wLength == 1) ? 0xFF : 0xFFFF); switch (setup->wValue >> 8) { case MUTE_CONTROL: switch (setup->bRequest) { case REQUEST_SET_CUR: _mute = data & 0xff; _update_vol.call(); break; default: break; } break; case VOLUME_CONTROL: switch (setup->bRequest) { case REQUEST_SET_CUR: _vol_cur = data; _volume = (float)_vol_cur / (float)_vol_max; _update_vol.call(); break; default: break; } break; default: break; } complete_request_xfer_done(true); return; } complete_request_xfer_done(false); } void USBAudio::callback_set_configuration(uint8_t configuration) { assert_locked(); bool ret = false; if (configuration == DEFAULT_CONFIGURATION) { endpoint_remove_all(); // Configure isochronous endpoint endpoint_add(_episo_out, _rx_packet_size_max, USB_EP_TYPE_ISO, static_cast(&USBAudio::_receive_isr)); endpoint_add(_episo_in, _tx_packet_size_max, USB_EP_TYPE_ISO, static_cast(&USBAudio::_send_isr)); // activate readings on this endpoint read_start(_episo_out, _rx_packet_buf, _rx_packet_size_max); ret = true; } complete_set_configuration(ret); } void USBAudio::callback_set_interface(uint16_t interface, uint8_t alternate) { assert_locked(); bool ret = false; if (interface == 0 && alternate == 0) { ret = true; } if (interface == 1 && (alternate == 0 || alternate == 1)) { _receive_change(alternate == 1 ? Opened : Closed); ret = true; } if (interface == 2 && (alternate == 0 || alternate == 1)) { _send_change(alternate == 1 ? Opened : Closed); ret = true; } complete_set_interface(ret); } const uint8_t *USBAudio::configuration_desc(uint8_t index) { if (index != 0) { return NULL; } return _config_descriptor; } const uint8_t *USBAudio::string_iinterface_desc() { static const uint8_t stringIinterfaceDescriptor[] = { 0x0c, //bLength STRING_DESCRIPTOR, //bDescriptorType 0x03 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 //bString iInterface - Audio }; return stringIinterfaceDescriptor; } const uint8_t *USBAudio::string_iproduct_desc() { static const uint8_t stringIproductDescriptor[] = { 0x16, //bLength STRING_DESCRIPTOR, //bDescriptorType 0x03 'M', 0, 'b', 0, 'e', 0, 'd', 0, ' ', 0, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 //bString iProduct - Mbed Audio }; return stringIproductDescriptor; } #define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \ + (5 * INTERFACE_DESCRIPTOR_LENGTH) \ + (1 * CONTROL_INTERFACE_DESCRIPTOR_LENGTH + 1) \ + (2 * INPUT_TERMINAL_DESCRIPTOR_LENGTH) \ + (1 * FEATURE_UNIT_DESCRIPTOR_LENGTH) \ + (2 * OUTPUT_TERMINAL_DESCRIPTOR_LENGTH) \ + (2 * STREAMING_INTERFACE_DESCRIPTOR_LENGTH) \ + (2 * FORMAT_TYPE_I_DESCRIPTOR_LENGTH) \ + (2 * (ENDPOINT_DESCRIPTOR_LENGTH + 2)) \ + (2 * STREAMING_ENDPOINT_DESCRIPTOR_LENGTH) ) #define TOTAL_CONTROL_INTF_LENGTH (CONTROL_INTERFACE_DESCRIPTOR_LENGTH + 1 + \ 2*INPUT_TERMINAL_DESCRIPTOR_LENGTH + \ FEATURE_UNIT_DESCRIPTOR_LENGTH + \ 2*OUTPUT_TERMINAL_DESCRIPTOR_LENGTH) void USBAudio::_build_configuration_desc() { uint8_t config_descriptor_temp[] = { // Configuration 1 CONFIGURATION_DESCRIPTOR_LENGTH, // bLength CONFIGURATION_DESCRIPTOR, // bDescriptorType LSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (LSB) MSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (MSB) 0x03, // bNumInterfaces DEFAULT_CONFIGURATION, // bConfigurationValue 0x00, // iConfiguration 0x80, // bmAttributes 50, // bMaxPower // Interface 0, Alternate Setting 0, Audio Control INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR, // bDescriptorType 0x00, // bInterfaceNumber 0x00, // bAlternateSetting 0x00, // bNumEndpoints AUDIO_CLASS, // bInterfaceClass SUBCLASS_AUDIOCONTROL, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // Audio Control Interface CONTROL_INTERFACE_DESCRIPTOR_LENGTH + 1,// bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_HEADER, // bDescriptorSubtype LSB(0x0100), // bcdADC (LSB) MSB(0x0100), // bcdADC (MSB) LSB(TOTAL_CONTROL_INTF_LENGTH), // wTotalLength MSB(TOTAL_CONTROL_INTF_LENGTH), // wTotalLength 0x02, // bInCollection 0x01, // baInterfaceNr 0x02, // baInterfaceNr // Audio Input Terminal (Speaker) INPUT_TERMINAL_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_INPUT_TERMINAL, // bDescriptorSubtype 0x01, // bTerminalID LSB(TERMINAL_USB_STREAMING), // wTerminalType MSB(TERMINAL_USB_STREAMING), // wTerminalType 0x00, // bAssocTerminal _rx_channel_count, // bNrChannels (uint8_t)(LSB(_channel_config_rx)), // wChannelConfig (uint8_t)(MSB(_channel_config_rx)), // wChannelConfig 0x00, // iChannelNames 0x00, // iTerminal // Audio Feature Unit (Speaker) FEATURE_UNIT_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_FEATURE_UNIT, // bDescriptorSubtype 0x02, // bUnitID 0x01, // bSourceID 0x01, // bControlSize CONTROL_MUTE | CONTROL_VOLUME, // bmaControls(0) 0x00, // bmaControls(1) 0x00, // iTerminal // Audio Output Terminal (Speaker) OUTPUT_TERMINAL_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_OUTPUT_TERMINAL, // bDescriptorSubtype 0x03, // bTerminalID LSB(TERMINAL_SPEAKER), // wTerminalType MSB(TERMINAL_SPEAKER), // wTerminalType 0x00, // bAssocTerminal 0x02, // bSourceID 0x00, // iTerminal // Audio Input Terminal (Microphone) INPUT_TERMINAL_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_INPUT_TERMINAL, // bDescriptorSubtype 0x04, // bTerminalID LSB(TERMINAL_MICROPHONE), // wTerminalType MSB(TERMINAL_MICROPHONE), // wTerminalType 0x00, // bAssocTerminal _tx_channel_count, // bNrChannels (uint8_t)(LSB(_channel_config_tx)), // wChannelConfig (uint8_t)(MSB(_channel_config_tx)), // wChannelConfig 0x00, // iChannelNames 0x00, // iTerminal // Audio Output Terminal (Microphone) OUTPUT_TERMINAL_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType CONTROL_OUTPUT_TERMINAL, // bDescriptorSubtype 0x05, // bTerminalID LSB(TERMINAL_USB_STREAMING), // wTerminalType MSB(TERMINAL_USB_STREAMING), // wTerminalType 0x00, // bAssocTerminal 0x04, // bSourceID 0x00, // iTerminal // Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR, // bDescriptorType 0x01, // bInterfaceNumber 0x00, // bAlternateSetting 0x00, // bNumEndpoints AUDIO_CLASS, // bInterfaceClass SUBCLASS_AUDIOSTREAMING, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // Interface 1, Alternate Setting 1, Audio Streaming - Operational INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR, // bDescriptorType 0x01, // bInterfaceNumber 0x01, // bAlternateSetting 0x01, // bNumEndpoints AUDIO_CLASS, // bInterfaceClass SUBCLASS_AUDIOSTREAMING, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // Audio Streaming Interface STREAMING_INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType STREAMING_GENERAL, // bDescriptorSubtype 0x01, // bTerminalLink 0x00, // bDelay LSB(FORMAT_PCM), // wFormatTag MSB(FORMAT_PCM), // wFormatTag // Audio Type I Format FORMAT_TYPE_I_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType STREAMING_FORMAT_TYPE, // bDescriptorSubtype FORMAT_TYPE_I, // bFormatType _rx_channel_count, // bNrChannels 0x02, // bSubFrameSize 16, // bBitResolution 0x01, // bSamFreqType (uint8_t)(LSB(_rx_freq)), // tSamFreq (uint8_t)((_rx_freq >> 8) & 0xff), // tSamFreq (uint8_t)((_rx_freq >> 16) & 0xff), // tSamFreq // Endpoint - Standard Descriptor ENDPOINT_DESCRIPTOR_LENGTH + 2, // bLength ENDPOINT_DESCRIPTOR, // bDescriptorType _episo_out, // bEndpointAddress E_ISOCHRONOUS, // bmAttributes (uint8_t)(LSB(_rx_packet_size_max)), // wMaxPacketSize (uint8_t)(MSB(_rx_packet_size_max)), // wMaxPacketSize 0x01, // bInterval 0x00, // bRefresh 0x00, // bSynchAddress // Endpoint - Audio Streaming STREAMING_ENDPOINT_DESCRIPTOR_LENGTH, // bLength ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType ENDPOINT_GENERAL, // bDescriptor 0x00, // bmAttributes 0x00, // bLockDelayUnits LSB(0x0000), // wLockDelay MSB(0x0000), // wLockDelay // Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR, // bDescriptorType 0x02, // bInterfaceNumber 0x00, // bAlternateSetting 0x00, // bNumEndpoints AUDIO_CLASS, // bInterfaceClass SUBCLASS_AUDIOSTREAMING, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // Interface 1, Alternate Setting 1, Audio Streaming - Operational INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR, // bDescriptorType 0x02, // bInterfaceNumber 0x01, // bAlternateSetting 0x01, // bNumEndpoints AUDIO_CLASS, // bInterfaceClass SUBCLASS_AUDIOSTREAMING, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // Audio Streaming Interface STREAMING_INTERFACE_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType SUBCLASS_AUDIOCONTROL, // bDescriptorSubtype 0x05, // bTerminalLink (output terminal microphone) 0x01, // bDelay 0x01, // wFormatTag 0x00, // wFormatTag // Audio Type I Format FORMAT_TYPE_I_DESCRIPTOR_LENGTH, // bLength INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType SUBCLASS_AUDIOSTREAMING, // bDescriptorSubtype FORMAT_TYPE_I, // bFormatType _tx_channel_count, // bNrChannels 0x02, // bSubFrameSize 0x10, // bBitResolution 0x01, // bSamFreqType (uint8_t)(LSB(_tx_freq)), // tSamFreq (uint8_t)((_tx_freq >> 8) & 0xff), // tSamFreq (uint8_t)((_tx_freq >> 16) & 0xff), // tSamFreq // Endpoint - Standard Descriptor ENDPOINT_DESCRIPTOR_LENGTH + 2, // bLength ENDPOINT_DESCRIPTOR, // bDescriptorType _episo_in, // bEndpointAddress E_ISOCHRONOUS, // bmAttributes (uint8_t)(LSB(_tx_packet_size_max)), // wMaxPacketSize (uint8_t)(MSB(_tx_packet_size_max)), // wMaxPacketSize 0x01, // bInterval 0x00, // bRefresh 0x00, // bSynchAddress // Endpoint - Audio Streaming STREAMING_ENDPOINT_DESCRIPTOR_LENGTH, // bLength ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType ENDPOINT_GENERAL, // bDescriptor 0x00, // bmAttributes 0x00, // bLockDelayUnits LSB(0x0000), // wLockDelay MSB(0x0000), // wLockDelay }; MBED_ASSERT(sizeof(config_descriptor_temp) == sizeof(_config_descriptor)); memcpy(_config_descriptor, config_descriptor_temp, sizeof(_config_descriptor)); } void USBAudio::_receive_change(ChannelState new_state) { assert_locked(); ChannelState prev_state = _rx_state; _rx_state = new_state; if (prev_state == new_state) { // no change return; } if (prev_state == Opened) { // Leaving the opened state _read_list.process(); _rx_done.call(End); } if (new_state == Opened) { // Entering the opened state _read_list.process(); _rx_done.call(Start); } if (new_state == Closed) { // Only block if the channel is closed _flags.clear(READ_READY_UNBLOCK); } else { _flags.set(READ_READY_UNBLOCK); } } void USBAudio::_receive_isr() { assert_locked(); uint32_t size = read_finish(_episo_out); if (size > _rx_queue.free()) { _rx_overflow++; } else { // Copy data over _rx_queue.write(_rx_packet_buf, size); // Signal that there is more data available _read_list.process(); if (_rx_done) { _rx_done.call(Transfer); } } read_start(_episo_out, _rx_packet_buf, _rx_packet_size_max); } void USBAudio::_send_change(ChannelState new_state) { assert_locked(); ChannelState prev_state = _tx_state; _tx_state = new_state; if (prev_state == new_state) { // no change return; } if (prev_state == Opened) { // Leaving the opened state _write_list.process(); _tx_done.call(End); } if (new_state == Opened) { // Entering the opened state _write_list.process(); _tx_done.call(Start); } if (new_state == Closed) { // Only block if the channel is closed _flags.clear(WRITE_READY_UNBLOCK); } else { _flags.set(WRITE_READY_UNBLOCK); } } void USBAudio::_send_isr_start() { assert_locked(); if (!_tx_idle) { return; } _send_isr_next_sync(); } void USBAudio::_send_isr_next_sync() { // Compute size to send uint32_t fames = _tx_whole_frames_per_xfer; if (_tx_frame_fract >= XFER_FREQUENCY_HZ) { _tx_frame_fract -= XFER_FREQUENCY_HZ; fames += 1; } uint32_t send_size = fames * _tx_channel_count * 2; // Check if this is the initial TX packet if (_tx_idle && !_tx_queue.full()) { // Don't start until the TX buffer is full return; } // Check if this stream was closed if (_tx_state != Opened) { _tx_idle = true; return; } // Check for enough data to send if (_tx_queue.size() < send_size) { _tx_underflow++; _tx_idle = true; return; } // Copy data over _tx_queue.read(_tx_packet_buf, send_size); // Start the write write_start(_episo_in, _tx_packet_buf, send_size); _tx_idle = false; _tx_frame_fract += _tx_fract_frames_per_xfer; } void USBAudio::_send_isr() { assert_locked(); write_finish(_episo_in); _send_isr_next_sync(); // Signal that there is space for more data _write_list.process(); if (_tx_done) { _tx_done.call(Transfer); } }