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@0:3a3146f89bcc, 2015-04-01 (annotated)
- Committer:
- dkato
- Date:
- Wed Apr 01 10:29:31 2015 +0000
- Revision:
- 0:3a3146f89bcc
- Child:
- 1:9ff4cba6524d
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dkato | 0:3a3146f89bcc | 1 | /******************************************************************************* |
dkato | 0:3a3146f89bcc | 2 | * DISCLAIMER |
dkato | 0:3a3146f89bcc | 3 | * This software is supplied by Renesas Electronics Corporation and is only |
dkato | 0:3a3146f89bcc | 4 | * intended for use with Renesas products. No other uses are authorized. This |
dkato | 0:3a3146f89bcc | 5 | * software is owned by Renesas Electronics Corporation and is protected under |
dkato | 0:3a3146f89bcc | 6 | * all applicable laws, including copyright laws. |
dkato | 0:3a3146f89bcc | 7 | * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING |
dkato | 0:3a3146f89bcc | 8 | * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT |
dkato | 0:3a3146f89bcc | 9 | * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE |
dkato | 0:3a3146f89bcc | 10 | * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. |
dkato | 0:3a3146f89bcc | 11 | * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS |
dkato | 0:3a3146f89bcc | 12 | * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE |
dkato | 0:3a3146f89bcc | 13 | * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR |
dkato | 0:3a3146f89bcc | 14 | * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE |
dkato | 0:3a3146f89bcc | 15 | * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
dkato | 0:3a3146f89bcc | 16 | * Renesas reserves the right, without notice, to make changes to this software |
dkato | 0:3a3146f89bcc | 17 | * and to discontinue the availability of this software. By using this software, |
dkato | 0:3a3146f89bcc | 18 | * you agree to the additional terms and conditions found by accessing the |
dkato | 0:3a3146f89bcc | 19 | * following link: |
dkato | 0:3a3146f89bcc | 20 | * http://www.renesas.com/disclaimer |
dkato | 0:3a3146f89bcc | 21 | * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved. |
dkato | 0:3a3146f89bcc | 22 | *******************************************************************************/ |
dkato | 0:3a3146f89bcc | 23 | |
dkato | 0:3a3146f89bcc | 24 | #include "USBHostDac.h" |
dkato | 0:3a3146f89bcc | 25 | |
dkato | 0:3a3146f89bcc | 26 | #define SAMPLING (0x0100) |
dkato | 0:3a3146f89bcc | 27 | #define SET_CUR (0x01) |
dkato | 0:3a3146f89bcc | 28 | #define FRAME_COUNT (8) |
dkato | 0:3a3146f89bcc | 29 | #define PACKET_SIZE (192) |
dkato | 0:3a3146f89bcc | 30 | #define QUEUE_NUM (3) |
dkato | 0:3a3146f89bcc | 31 | |
dkato | 0:3a3146f89bcc | 32 | USBHostDac::USBHostDac() { |
dkato | 0:3a3146f89bcc | 33 | host = USBHost::getHostInst(); |
dkato | 0:3a3146f89bcc | 34 | m_isoEp = new IsochronousEp; |
dkato | 0:3a3146f89bcc | 35 | p_rest_data = new uint8_t[USBDAC_DATA_SIZE]; |
dkato | 0:3a3146f89bcc | 36 | |
dkato | 0:3a3146f89bcc | 37 | init(); |
dkato | 0:3a3146f89bcc | 38 | } |
dkato | 0:3a3146f89bcc | 39 | |
dkato | 0:3a3146f89bcc | 40 | void USBHostDac::init() { |
dkato | 0:3a3146f89bcc | 41 | dev = NULL; |
dkato | 0:3a3146f89bcc | 42 | dev_connected = false; |
dkato | 0:3a3146f89bcc | 43 | audio_device_found = false; |
dkato | 0:3a3146f89bcc | 44 | audio_intf = -1; |
dkato | 0:3a3146f89bcc | 45 | audio_intf_cnt = 0; |
dkato | 0:3a3146f89bcc | 46 | rest_data_index = 0; |
dkato | 0:3a3146f89bcc | 47 | |
dkato | 0:3a3146f89bcc | 48 | wMaxPacketSize = 0; |
dkato | 0:3a3146f89bcc | 49 | bInterfaceNumber = 0; |
dkato | 0:3a3146f89bcc | 50 | bAlternateSetting = 0; |
dkato | 0:3a3146f89bcc | 51 | bEndpointAddress = 0; |
dkato | 0:3a3146f89bcc | 52 | } |
dkato | 0:3a3146f89bcc | 53 | |
dkato | 0:3a3146f89bcc | 54 | bool USBHostDac::connected() { |
dkato | 0:3a3146f89bcc | 55 | return dev_connected; |
dkato | 0:3a3146f89bcc | 56 | } |
dkato | 0:3a3146f89bcc | 57 | |
dkato | 0:3a3146f89bcc | 58 | bool USBHostDac::connect() { |
dkato | 0:3a3146f89bcc | 59 | if (dev_connected) { |
dkato | 0:3a3146f89bcc | 60 | return true; |
dkato | 0:3a3146f89bcc | 61 | } |
dkato | 0:3a3146f89bcc | 62 | |
dkato | 0:3a3146f89bcc | 63 | for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { |
dkato | 0:3a3146f89bcc | 64 | if ((dev = host->getDevice(i)) != NULL) { |
dkato | 0:3a3146f89bcc | 65 | |
dkato | 0:3a3146f89bcc | 66 | if (host->enumerate(dev, this)) { |
dkato | 0:3a3146f89bcc | 67 | break; |
dkato | 0:3a3146f89bcc | 68 | } |
dkato | 0:3a3146f89bcc | 69 | |
dkato | 0:3a3146f89bcc | 70 | if (audio_device_found) { |
dkato | 0:3a3146f89bcc | 71 | USB_INFO("New UsbDac device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, audio_intf); |
dkato | 0:3a3146f89bcc | 72 | dev->setName("UsbDac", audio_intf); |
dkato | 0:3a3146f89bcc | 73 | host->registerDriver(dev, audio_intf, this, &USBHostDac::onDisconnect); |
dkato | 0:3a3146f89bcc | 74 | |
dkato | 0:3a3146f89bcc | 75 | int addr = dev->getAddress(); |
dkato | 0:3a3146f89bcc | 76 | m_isoEp->init(addr, bEndpointAddress, PACKET_SIZE, FRAME_COUNT, QUEUE_NUM); |
dkato | 0:3a3146f89bcc | 77 | setInterface(bAlternateSetting, bInterfaceNumber); |
dkato | 0:3a3146f89bcc | 78 | setSamplingRate(48000); |
dkato | 0:3a3146f89bcc | 79 | |
dkato | 0:3a3146f89bcc | 80 | dev_connected = true; |
dkato | 0:3a3146f89bcc | 81 | return true; |
dkato | 0:3a3146f89bcc | 82 | } |
dkato | 0:3a3146f89bcc | 83 | } |
dkato | 0:3a3146f89bcc | 84 | } |
dkato | 0:3a3146f89bcc | 85 | init(); |
dkato | 0:3a3146f89bcc | 86 | return false; |
dkato | 0:3a3146f89bcc | 87 | } |
dkato | 0:3a3146f89bcc | 88 | |
dkato | 0:3a3146f89bcc | 89 | uint32_t USBHostDac::send(uint8_t* buf, uint32_t len, bool flush) { |
dkato | 0:3a3146f89bcc | 90 | uint32_t send_index = 0; |
dkato | 0:3a3146f89bcc | 91 | uint32_t rest_size = len; |
dkato | 0:3a3146f89bcc | 92 | uint32_t send_size; |
dkato | 0:3a3146f89bcc | 93 | uint32_t copy_size; |
dkato | 0:3a3146f89bcc | 94 | uint32_t def_send_size = PACKET_SIZE * FRAME_COUNT; |
dkato | 0:3a3146f89bcc | 95 | |
dkato | 0:3a3146f89bcc | 96 | if (rest_data_index != 0) { |
dkato | 0:3a3146f89bcc | 97 | if (rest_size > (def_send_size - rest_data_index)) { |
dkato | 0:3a3146f89bcc | 98 | copy_size = (def_send_size - rest_data_index); |
dkato | 0:3a3146f89bcc | 99 | } else { |
dkato | 0:3a3146f89bcc | 100 | copy_size = rest_size; |
dkato | 0:3a3146f89bcc | 101 | } |
dkato | 0:3a3146f89bcc | 102 | memcpy(&p_rest_data[rest_data_index], &buf[send_index], copy_size); |
dkato | 0:3a3146f89bcc | 103 | send_index += copy_size; |
dkato | 0:3a3146f89bcc | 104 | rest_size -= copy_size; |
dkato | 0:3a3146f89bcc | 105 | rest_data_index += copy_size; |
dkato | 0:3a3146f89bcc | 106 | if ((flush != false) || (rest_data_index >= def_send_size)) { |
dkato | 0:3a3146f89bcc | 107 | m_isoEp->isochronousSend(&p_rest_data[0], rest_data_index, 100); |
dkato | 0:3a3146f89bcc | 108 | rest_data_index = 0; |
dkato | 0:3a3146f89bcc | 109 | } |
dkato | 0:3a3146f89bcc | 110 | } |
dkato | 0:3a3146f89bcc | 111 | |
dkato | 0:3a3146f89bcc | 112 | while ((dev_connected) && (rest_size > 0)) { |
dkato | 0:3a3146f89bcc | 113 | if ((flush == false) && (rest_size < def_send_size)) { |
dkato | 0:3a3146f89bcc | 114 | memcpy(&p_rest_data[0], &buf[send_index], rest_size); |
dkato | 0:3a3146f89bcc | 115 | rest_data_index = rest_size; |
dkato | 0:3a3146f89bcc | 116 | break; |
dkato | 0:3a3146f89bcc | 117 | } else { |
dkato | 0:3a3146f89bcc | 118 | if (rest_size >= def_send_size) { |
dkato | 0:3a3146f89bcc | 119 | send_size = def_send_size; |
dkato | 0:3a3146f89bcc | 120 | } else { |
dkato | 0:3a3146f89bcc | 121 | send_size = rest_size; |
dkato | 0:3a3146f89bcc | 122 | } |
dkato | 0:3a3146f89bcc | 123 | m_isoEp->isochronousSend(&buf[send_index], send_size, 100); |
dkato | 0:3a3146f89bcc | 124 | send_index += send_size; |
dkato | 0:3a3146f89bcc | 125 | rest_size -= send_size; |
dkato | 0:3a3146f89bcc | 126 | } |
dkato | 0:3a3146f89bcc | 127 | } |
dkato | 0:3a3146f89bcc | 128 | |
dkato | 0:3a3146f89bcc | 129 | return send_index; |
dkato | 0:3a3146f89bcc | 130 | } |
dkato | 0:3a3146f89bcc | 131 | |
dkato | 0:3a3146f89bcc | 132 | /*virtual*/ void USBHostDac::setVidPid(uint16_t vid, uint16_t pid) |
dkato | 0:3a3146f89bcc | 133 | { |
dkato | 0:3a3146f89bcc | 134 | // we don't check VID/PID for audio driver |
dkato | 0:3a3146f89bcc | 135 | } |
dkato | 0:3a3146f89bcc | 136 | |
dkato | 0:3a3146f89bcc | 137 | /*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 |
dkato | 0:3a3146f89bcc | 138 | { |
dkato | 0:3a3146f89bcc | 139 | bool ret; |
dkato | 0:3a3146f89bcc | 140 | |
dkato | 0:3a3146f89bcc | 141 | if (audio_intf != -1) { |
dkato | 0:3a3146f89bcc | 142 | ret = false; |
dkato | 0:3a3146f89bcc | 143 | } else if ((intf_class == AUDIO_CLASS) && (intf_subclass == 2) && (intf_protocol == 0)) { |
dkato | 0:3a3146f89bcc | 144 | // AUDIOSTREAMING Subclass |
dkato | 0:3a3146f89bcc | 145 | ret = chkAudioStreaming(); |
dkato | 0:3a3146f89bcc | 146 | if (ret != false) { |
dkato | 0:3a3146f89bcc | 147 | audio_intf = intf_nb; |
dkato | 0:3a3146f89bcc | 148 | audio_device_found = true; |
dkato | 0:3a3146f89bcc | 149 | } |
dkato | 0:3a3146f89bcc | 150 | } else { |
dkato | 0:3a3146f89bcc | 151 | ret = false; |
dkato | 0:3a3146f89bcc | 152 | } |
dkato | 0:3a3146f89bcc | 153 | |
dkato | 0:3a3146f89bcc | 154 | return false; |
dkato | 0:3a3146f89bcc | 155 | } |
dkato | 0:3a3146f89bcc | 156 | |
dkato | 0:3a3146f89bcc | 157 | /*virtual*/ bool USBHostDac::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used |
dkato | 0:3a3146f89bcc | 158 | { |
dkato | 0:3a3146f89bcc | 159 | return false; |
dkato | 0:3a3146f89bcc | 160 | } |
dkato | 0:3a3146f89bcc | 161 | |
dkato | 0:3a3146f89bcc | 162 | bool USBHostDac::chkAudioStreaming() { |
dkato | 0:3a3146f89bcc | 163 | uint8_t * conf_descr = host->getConfDescrCurPtr(); |
dkato | 0:3a3146f89bcc | 164 | uint16_t len = host->getConfDescrRestLen(); |
dkato | 0:3a3146f89bcc | 165 | uint32_t index = 0; |
dkato | 0:3a3146f89bcc | 166 | uint32_t len_desc = conf_descr[index]; |
dkato | 0:3a3146f89bcc | 167 | uint32_t cnt; |
dkato | 0:3a3146f89bcc | 168 | uint32_t wk_sampling; |
dkato | 0:3a3146f89bcc | 169 | bool smpling_ok = false; |
dkato | 0:3a3146f89bcc | 170 | bool loop_end = false; |
dkato | 0:3a3146f89bcc | 171 | uint8_t channels = 0; |
dkato | 0:3a3146f89bcc | 172 | uint8_t SubframeSize = 0; |
dkato | 0:3a3146f89bcc | 173 | uint8_t id; |
dkato | 0:3a3146f89bcc | 174 | |
dkato | 0:3a3146f89bcc | 175 | /* bNumEndpoints */ |
dkato | 0:3a3146f89bcc | 176 | if (conf_descr[index + 4] >= 1) { |
dkato | 0:3a3146f89bcc | 177 | bInterfaceNumber = conf_descr[index + 2]; |
dkato | 0:3a3146f89bcc | 178 | bAlternateSetting = conf_descr[index + 3]; |
dkato | 0:3a3146f89bcc | 179 | |
dkato | 0:3a3146f89bcc | 180 | index += len_desc; |
dkato | 0:3a3146f89bcc | 181 | while ((index < len) && (loop_end == false)) { |
dkato | 0:3a3146f89bcc | 182 | len_desc = conf_descr[index]; |
dkato | 0:3a3146f89bcc | 183 | id = conf_descr[index+1]; |
dkato | 0:3a3146f89bcc | 184 | switch (id) { |
dkato | 0:3a3146f89bcc | 185 | case INTERFACE_DESCRIPTOR: |
dkato | 0:3a3146f89bcc | 186 | /* next interface descriptor */ |
dkato | 0:3a3146f89bcc | 187 | loop_end = true; |
dkato | 0:3a3146f89bcc | 188 | break; |
dkato | 0:3a3146f89bcc | 189 | case ENDPOINT_DESCRIPTOR: |
dkato | 0:3a3146f89bcc | 190 | if ((conf_descr[index + 3] & 0x03) == ISOCHRONOUS_ENDPOINT) { |
dkato | 0:3a3146f89bcc | 191 | bEndpointAddress = conf_descr[index + 2]; |
dkato | 0:3a3146f89bcc | 192 | wMaxPacketSize = (conf_descr[index + 5] << 8) + conf_descr[index + 4]; |
dkato | 0:3a3146f89bcc | 193 | loop_end = true; |
dkato | 0:3a3146f89bcc | 194 | } |
dkato | 0:3a3146f89bcc | 195 | break; |
dkato | 0:3a3146f89bcc | 196 | case 0x24: /* Audio Class Specific INTERFACE Descriptor */ |
dkato | 0:3a3146f89bcc | 197 | if ((conf_descr[index + 2] == 2) && (conf_descr[index + 3] == 1)) { |
dkato | 0:3a3146f89bcc | 198 | channels = conf_descr[index + 4]; |
dkato | 0:3a3146f89bcc | 199 | SubframeSize = conf_descr[index + 5]; |
dkato | 0:3a3146f89bcc | 200 | for (cnt = 8; (cnt + 3) <= len_desc; cnt += 3) { |
dkato | 0:3a3146f89bcc | 201 | wk_sampling = ((uint32_t)conf_descr[index + cnt + 0] << 0) |
dkato | 0:3a3146f89bcc | 202 | | ((uint32_t)conf_descr[index + cnt + 1] << 8) |
dkato | 0:3a3146f89bcc | 203 | | ((uint32_t)conf_descr[index + cnt + 2] << 16); |
dkato | 0:3a3146f89bcc | 204 | if (wk_sampling == 48000) { |
dkato | 0:3a3146f89bcc | 205 | smpling_ok = true; |
dkato | 0:3a3146f89bcc | 206 | } |
dkato | 0:3a3146f89bcc | 207 | } |
dkato | 0:3a3146f89bcc | 208 | } |
dkato | 0:3a3146f89bcc | 209 | break; |
dkato | 0:3a3146f89bcc | 210 | default: |
dkato | 0:3a3146f89bcc | 211 | break; |
dkato | 0:3a3146f89bcc | 212 | } |
dkato | 0:3a3146f89bcc | 213 | index += len_desc; |
dkato | 0:3a3146f89bcc | 214 | } |
dkato | 0:3a3146f89bcc | 215 | |
dkato | 0:3a3146f89bcc | 216 | if (((bEndpointAddress & 0x80) == 0) && (wMaxPacketSize >= PACKET_SIZE) |
dkato | 0:3a3146f89bcc | 217 | && (channels == 2) && (SubframeSize == 2) && (smpling_ok != false)) { |
dkato | 0:3a3146f89bcc | 218 | return true; |
dkato | 0:3a3146f89bcc | 219 | } |
dkato | 0:3a3146f89bcc | 220 | } |
dkato | 0:3a3146f89bcc | 221 | |
dkato | 0:3a3146f89bcc | 222 | return false; |
dkato | 0:3a3146f89bcc | 223 | } |
dkato | 0:3a3146f89bcc | 224 | |
dkato | 0:3a3146f89bcc | 225 | void USBHostDac::onDisconnect() { |
dkato | 0:3a3146f89bcc | 226 | if (dev_connected) { |
dkato | 0:3a3146f89bcc | 227 | m_isoEp->disconnect(); |
dkato | 0:3a3146f89bcc | 228 | init(); |
dkato | 0:3a3146f89bcc | 229 | } |
dkato | 0:3a3146f89bcc | 230 | } |
dkato | 0:3a3146f89bcc | 231 | |
dkato | 0:3a3146f89bcc | 232 | USB_TYPE USBHostDac::setInterface(uint16_t alt, uint16_t index) { |
dkato | 0:3a3146f89bcc | 233 | return host->controlWrite( dev, |
dkato | 0:3a3146f89bcc | 234 | USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, |
dkato | 0:3a3146f89bcc | 235 | SET_INTERFACE, |
dkato | 0:3a3146f89bcc | 236 | alt, index, NULL, 0); |
dkato | 0:3a3146f89bcc | 237 | } |
dkato | 0:3a3146f89bcc | 238 | |
dkato | 0:3a3146f89bcc | 239 | void USBHostDac::setSamplingRate(uint32_t sampling_rate) { |
dkato | 0:3a3146f89bcc | 240 | uint8_t data[3]; |
dkato | 0:3a3146f89bcc | 241 | |
dkato | 0:3a3146f89bcc | 242 | data[0] = (uint8_t)((sampling_rate >> 0) & 0xff); |
dkato | 0:3a3146f89bcc | 243 | data[1] = (uint8_t)((sampling_rate >> 8) & 0xff); |
dkato | 0:3a3146f89bcc | 244 | data[2] = (uint8_t)((sampling_rate >> 16) & 0xff); |
dkato | 0:3a3146f89bcc | 245 | host->controlWrite( dev, |
dkato | 0:3a3146f89bcc | 246 | USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, |
dkato | 0:3a3146f89bcc | 247 | SET_CUR, |
dkato | 0:3a3146f89bcc | 248 | SAMPLING, bEndpointAddress, data, 3); |
dkato | 0:3a3146f89bcc | 249 | } |
dkato | 0:3a3146f89bcc | 250 |