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 GR-PEACH_producer_meeting

Files at this revision

API Documentation at this revision

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