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
Revision 0:3a3146f89bcc, committed 2015-04-01
- Comitter:
- dkato
- Date:
- Wed Apr 01 10:29:31 2015 +0000
- Child:
- 1:9ff4cba6524d
- Commit message:
- first commit
Changed in this revision
| USBHostDac.cpp | Show annotated file Show diff for this revision Revisions of this file |
| USBHostDac.h | Show annotated file Show diff for this revision Revisions of this file |
--- /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);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostDac.h Wed Apr 01 10:29:31 2015 +0000
@@ -0,0 +1,98 @@
+/*******************************************************************************
+* 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.
+*******************************************************************************/
+
+#ifndef USBHOSTAUDIO_H
+#define USBHOSTAUDIO_H
+
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "USBIsochronous.h"
+
+#define USBDAC_DATA_SIZE (192 * 8)
+
+/**
+ * A class to communicate a USB dac (only 48kHz,16bit,2ch)
+ */
+class USBHostDac : public IUSBEnumerator {
+public:
+
+ /**
+ * Constructor
+ */
+ USBHostDac();
+
+ /**
+ * Try to connect a audio device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ /**
+ * Check if a audio is connected
+ *
+ * @returns true if a audio is connected
+ */
+ bool connected();
+
+ /**
+ * Data send : It's sent by the 1536byte unit.
+ *
+ * @param buf pointer on a buffer which will be written
+ * @param len length of the transfer
+ * @param flush if true, less than 1536 bytes of data is sent
+ *
+ * @returns the number of bytes written is returned
+ */
+ uint32_t send(uint8_t* buf, uint32_t len, bool flush = true);
+
+protected:
+ //From IUSBEnumerator
+ virtual void setVidPid(uint16_t vid, uint16_t pid);
+ virtual bool 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
+ virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+ USBHost * host;
+ USBDeviceConnected * dev;
+
+ bool dev_connected;
+ bool audio_device_found;
+ int audio_intf;
+ int audio_intf_cnt;
+
+ IsochronousEp* m_isoEp;
+ uint16_t wMaxPacketSize;
+ uint8_t bEndpointAddress;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t* p_rest_data;
+ uint32_t rest_data_index;
+
+ void init();
+ void onDisconnect();
+ bool chkAudioStreaming();
+ USB_TYPE setInterface(uint16_t alt, uint16_t index);
+ void setSamplingRate(uint32_t sampling_rate);
+};
+#endif
