A class to communicate a USB dac (send:only 48kHz,16bit,2ch , receive:only 48kHz,16bit,1ch). Need "USBHost_AddIso" library.
Dependents: USBHostDac_Audio_in_out
Fork of USBHostDac by
Diff: USBHostDac.cpp
- Revision:
- 0:3a3146f89bcc
- Child:
- 1:9ff4cba6524d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostDac.cpp Wed Apr 01 10:29:31 2015 +0000 @@ -0,0 +1,250 @@ +/******************************************************************************* +* DISCLAIMER +* This software is supplied by Renesas Electronics Corporation and is only +* intended for use with Renesas products. No other uses are authorized. This +* software is owned by Renesas Electronics Corporation and is protected under +* all applicable laws, including copyright laws. +* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING +* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT +* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE +* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. +* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS +* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE +* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR +* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE +* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +* Renesas reserves the right, without notice, to make changes to this software +* and to discontinue the availability of this software. By using this software, +* you agree to the additional terms and conditions found by accessing the +* following link: +* http://www.renesas.com/disclaimer +* Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved. +*******************************************************************************/ + +#include "USBHostDac.h" + +#define SAMPLING (0x0100) +#define SET_CUR (0x01) +#define FRAME_COUNT (8) +#define PACKET_SIZE (192) +#define QUEUE_NUM (3) + +USBHostDac::USBHostDac() { + host = USBHost::getHostInst(); + m_isoEp = new IsochronousEp; + p_rest_data = new uint8_t[USBDAC_DATA_SIZE]; + + init(); +} + +void USBHostDac::init() { + dev = NULL; + dev_connected = false; + audio_device_found = false; + audio_intf = -1; + audio_intf_cnt = 0; + rest_data_index = 0; + + wMaxPacketSize = 0; + bInterfaceNumber = 0; + bAlternateSetting = 0; + bEndpointAddress = 0; +} + +bool USBHostDac::connected() { + return dev_connected; +} + +bool USBHostDac::connect() { + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + if (host->enumerate(dev, this)) { + break; + } + + if (audio_device_found) { + USB_INFO("New UsbDac device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, audio_intf); + dev->setName("UsbDac", audio_intf); + host->registerDriver(dev, audio_intf, this, &USBHostDac::onDisconnect); + + int addr = dev->getAddress(); + m_isoEp->init(addr, bEndpointAddress, PACKET_SIZE, FRAME_COUNT, QUEUE_NUM); + setInterface(bAlternateSetting, bInterfaceNumber); + setSamplingRate(48000); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +uint32_t USBHostDac::send(uint8_t* buf, uint32_t len, bool flush) { + uint32_t send_index = 0; + uint32_t rest_size = len; + uint32_t send_size; + uint32_t copy_size; + uint32_t def_send_size = PACKET_SIZE * FRAME_COUNT; + + if (rest_data_index != 0) { + if (rest_size > (def_send_size - rest_data_index)) { + copy_size = (def_send_size - rest_data_index); + } else { + copy_size = rest_size; + } + memcpy(&p_rest_data[rest_data_index], &buf[send_index], copy_size); + send_index += copy_size; + rest_size -= copy_size; + rest_data_index += copy_size; + if ((flush != false) || (rest_data_index >= def_send_size)) { + m_isoEp->isochronousSend(&p_rest_data[0], rest_data_index, 100); + rest_data_index = 0; + } + } + + while ((dev_connected) && (rest_size > 0)) { + if ((flush == false) && (rest_size < def_send_size)) { + memcpy(&p_rest_data[0], &buf[send_index], rest_size); + rest_data_index = rest_size; + break; + } else { + if (rest_size >= def_send_size) { + send_size = def_send_size; + } else { + send_size = rest_size; + } + m_isoEp->isochronousSend(&buf[send_index], send_size, 100); + send_index += send_size; + rest_size -= send_size; + } + } + + return send_index; +} + +/*virtual*/ void USBHostDac::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for audio driver +} + +/*virtual*/ bool USBHostDac::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + bool ret; + + if (audio_intf != -1) { + ret = false; + } else if ((intf_class == AUDIO_CLASS) && (intf_subclass == 2) && (intf_protocol == 0)) { + // AUDIOSTREAMING Subclass + ret = chkAudioStreaming(); + if (ret != false) { + audio_intf = intf_nb; + audio_device_found = true; + } + } else { + ret = false; + } + + return false; +} + +/*virtual*/ bool USBHostDac::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + return false; +} + +bool USBHostDac::chkAudioStreaming() { + uint8_t * conf_descr = host->getConfDescrCurPtr(); + uint16_t len = host->getConfDescrRestLen(); + uint32_t index = 0; + uint32_t len_desc = conf_descr[index]; + uint32_t cnt; + uint32_t wk_sampling; + bool smpling_ok = false; + bool loop_end = false; + uint8_t channels = 0; + uint8_t SubframeSize = 0; + uint8_t id; + + /* bNumEndpoints */ + if (conf_descr[index + 4] >= 1) { + bInterfaceNumber = conf_descr[index + 2]; + bAlternateSetting = conf_descr[index + 3]; + + index += len_desc; + while ((index < len) && (loop_end == false)) { + len_desc = conf_descr[index]; + id = conf_descr[index+1]; + switch (id) { + case INTERFACE_DESCRIPTOR: + /* next interface descriptor */ + loop_end = true; + break; + case ENDPOINT_DESCRIPTOR: + if ((conf_descr[index + 3] & 0x03) == ISOCHRONOUS_ENDPOINT) { + bEndpointAddress = conf_descr[index + 2]; + wMaxPacketSize = (conf_descr[index + 5] << 8) + conf_descr[index + 4]; + loop_end = true; + } + break; + case 0x24: /* Audio Class Specific INTERFACE Descriptor */ + if ((conf_descr[index + 2] == 2) && (conf_descr[index + 3] == 1)) { + channels = conf_descr[index + 4]; + SubframeSize = conf_descr[index + 5]; + for (cnt = 8; (cnt + 3) <= len_desc; cnt += 3) { + wk_sampling = ((uint32_t)conf_descr[index + cnt + 0] << 0) + | ((uint32_t)conf_descr[index + cnt + 1] << 8) + | ((uint32_t)conf_descr[index + cnt + 2] << 16); + if (wk_sampling == 48000) { + smpling_ok = true; + } + } + } + break; + default: + break; + } + index += len_desc; + } + + if (((bEndpointAddress & 0x80) == 0) && (wMaxPacketSize >= PACKET_SIZE) + && (channels == 2) && (SubframeSize == 2) && (smpling_ok != false)) { + return true; + } + } + + return false; +} + +void USBHostDac::onDisconnect() { + if (dev_connected) { + m_isoEp->disconnect(); + init(); + } +} + +USB_TYPE USBHostDac::setInterface(uint16_t alt, uint16_t index) { + return host->controlWrite( dev, + USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + SET_INTERFACE, + alt, index, NULL, 0); +} + +void USBHostDac::setSamplingRate(uint32_t sampling_rate) { + uint8_t data[3]; + + data[0] = (uint8_t)((sampling_rate >> 0) & 0xff); + data[1] = (uint8_t)((sampling_rate >> 8) & 0xff); + data[2] = (uint8_t)((sampling_rate >> 16) & 0xff); + host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, + SET_CUR, + SAMPLING, bEndpointAddress, data, 3); +} +