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
USBHostDac.cpp
- Committer:
- dkato
- Date:
- 2015-04-01
- Revision:
- 0:3a3146f89bcc
- Child:
- 1:9ff4cba6524d
File content as of revision 0:3a3146f89bcc:
/******************************************************************************* * 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); }