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

Revision:
1:9ff4cba6524d
Parent:
0:3a3146f89bcc
--- a/USBHostDac.cpp	Wed Apr 01 10:29:31 2015 +0000
+++ b/USBHostDac.cpp	Wed Sep 30 06:04:31 2015 +0000
@@ -31,24 +31,40 @@
 
 USBHostDac::USBHostDac() {
     host = USBHost::getHostInst();
-    m_isoEp = new IsochronousEp;
-    p_rest_data = new uint8_t[USBDAC_DATA_SIZE];
+    iso_send.m_isoEp = new IsochronousEp;
+    iso_send.p_rest_data = NULL;
+
+    iso_recv.m_isoEp = new IsochronousEp;
+    iso_recv.p_rest_data = NULL;
 
     init();
 }
 
+USBHostDac::~USBHostDac() {
+    delete iso_send.m_isoEp;
+    delete iso_recv.m_isoEp;
+}
+
 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;
+    iso_send.bEndpointAddress = 0;
+    iso_send.rest_data_index = 0;
+    iso_send.rest_data_size = 0;
+    if (iso_send.p_rest_data != NULL) {
+        delete iso_send.p_rest_data;
+        iso_send.p_rest_data = NULL;
+    }
+    iso_recv.bEndpointAddress = 0;
+    iso_recv.rest_data_index = 0;
+    iso_recv.rest_data_size = 0;
+    if (iso_recv.p_rest_data != NULL) {
+        delete iso_recv.p_rest_data;
+        iso_recv.p_rest_data = NULL;
+    }
 }
 
 bool USBHostDac::connected() {
@@ -73,9 +89,20 @@
                 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);
+
+                if (iso_send.bEndpointAddress != 0) {
+                    iso_send.p_rest_data = new uint8_t[PACKET_SIZE * FRAME_COUNT];
+                    iso_send.m_isoEp->init(addr, iso_send.bEndpointAddress, PACKET_SIZE, FRAME_COUNT, QUEUE_NUM);
+                    setInterface(iso_send.bAlternateSetting, iso_send.bInterfaceNumber);
+                    setSamplingRate(iso_send.bEndpointAddress, 48000);
+                }
+
+                if (iso_recv.bEndpointAddress != 0) {
+                    iso_recv.p_rest_data = new uint8_t[iso_recv.wMaxPacketSize * FRAME_COUNT];
+                    iso_recv.m_isoEp->init(addr, iso_recv.bEndpointAddress, iso_recv.wMaxPacketSize, FRAME_COUNT, QUEUE_NUM);
+                    setInterface(iso_recv.bAlternateSetting, iso_recv.bInterfaceNumber);
+                    setSamplingRate(iso_recv.bEndpointAddress, 48000);
+                }
 
                 dev_connected = true;
                 return true;
@@ -91,44 +118,124 @@
     uint32_t rest_size = len;
     uint32_t send_size;
     uint32_t copy_size;
-    uint32_t def_send_size = PACKET_SIZE * FRAME_COUNT;
+    int      result;
 
-    if (rest_data_index != 0) {
-        if (rest_size > (def_send_size - rest_data_index)) {
-            copy_size = (def_send_size - rest_data_index);
+    if (iso_send.bEndpointAddress == 0) {
+        return 0;
+    }
+
+    if (iso_send.rest_data_index != 0) {
+        if (rest_size > iso_send.rest_data_size) {
+            copy_size = iso_send.rest_data_size;
         } else {
             copy_size = rest_size;
         }
-        memcpy(&p_rest_data[rest_data_index], &buf[send_index], copy_size);
+        memcpy(&iso_send.p_rest_data[iso_send.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;
+        iso_send.rest_data_index += copy_size;
+        if ((flush != false) || (iso_send.rest_data_index >= (PACKET_SIZE * FRAME_COUNT))) {
+            if (iso_send.m_isoEp->getQueueNum() == 0) {
+                iso_send.m_isoEp->reset(4);
+            }
+            result = iso_send.m_isoEp->isochronousSend(&iso_send.p_rest_data[0], iso_send.rest_data_index, 100);
+            iso_send.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;
+        if ((flush == false) && (rest_size < (PACKET_SIZE * FRAME_COUNT))) {
+            memcpy(&iso_send.p_rest_data[0], &buf[send_index], rest_size);
+            iso_send.rest_data_index = rest_size;
+            iso_send.rest_data_size  = (PACKET_SIZE * FRAME_COUNT) - rest_size;
             break;
         } else {
-            if (rest_size >= def_send_size) {
-                send_size = def_send_size;
+            if (rest_size >= (PACKET_SIZE * FRAME_COUNT)) {
+                send_size = (PACKET_SIZE * FRAME_COUNT);
             } else {
                 send_size = rest_size;
             }
-            m_isoEp->isochronousSend(&buf[send_index], send_size, 100);
-            send_index += send_size;
-            rest_size  -= send_size;
+            if (iso_send.m_isoEp->getQueueNum() == 0) {
+                iso_send.m_isoEp->reset(4);
+            }
+            result = iso_send.m_isoEp->isochronousSend(&buf[send_index], send_size, 100);
+            send_index += result;
+            rest_size  -= result;
         }
     }
 
     return send_index;
 }
 
+uint32_t USBHostDac::receive(uint8_t* buf, uint32_t len) {
+    uint32_t recv_index = 0;
+    uint32_t rest_size = len;
+    uint32_t copy_size;
+
+    if (iso_recv.bEndpointAddress == 0) {
+        return 0;
+    }
+
+    if (iso_recv.rest_data_size != 0) {
+        if (rest_size > iso_recv.rest_data_size) {
+            copy_size = iso_recv.rest_data_size;
+        } else {
+            copy_size = rest_size;
+        }
+        memcpy(&buf[recv_index], &iso_recv.p_rest_data[iso_recv.rest_data_index], copy_size);
+        recv_index      += copy_size;
+        rest_size       -= copy_size;
+        iso_recv.rest_data_index += copy_size; 
+        iso_recv.rest_data_size  -= copy_size;
+    }
+
+    while ((dev_connected) && (rest_size > 0)) {
+        iso_recv.rest_data_index = 0;
+        iso_recv.rest_data_size  = 0;
+
+        if (iso_recv.m_isoEp->getQueueNum() == 0) {
+            iso_recv.m_isoEp->reset(4);
+        }
+        HCITD* itd = iso_recv.m_isoEp->isochronousReceive(100);
+        if (itd) {
+            uint8_t cc = itd->ConditionCode();
+            if (cc == 0) {
+                int fc = itd->FrameCount();
+                uint8_t* wk_buf = const_cast<uint8_t*>(itd->buf); 
+                int mps = iso_recv.m_isoEp->m_PacketSize;
+                for (int i = 0; i < fc; i++) {
+                    uint16_t psw = itd->OffsetPSW[i];
+                    cc = psw>>12;
+                    if (cc == 0 || cc == 9) {
+                        int wk_len = psw & 0x7ff;
+                        if (rest_size > 0) {
+                            if (rest_size > wk_len) {
+                                copy_size = wk_len;
+                            } else {
+                                copy_size = rest_size;
+                            }
+                            memcpy(&buf[recv_index], wk_buf, copy_size);
+                            recv_index += copy_size;
+                            rest_size  -= copy_size;
+                            if (copy_size < wk_len) {
+                                memcpy(&iso_recv.p_rest_data[iso_recv.rest_data_size], &wk_buf[copy_size], (wk_len - copy_size));
+                                iso_recv.rest_data_size += (wk_len - copy_size);
+                            }
+                        } else {
+                            memcpy(&iso_recv.p_rest_data[iso_recv.rest_data_size], &wk_buf[0], wk_len);
+                            iso_recv.rest_data_size += wk_len;
+                        }
+                    }
+                    wk_buf += mps;
+                }
+            }
+            delete itd;
+        }
+    }
+
+    return recv_index;
+}
+
 /*virtual*/ void USBHostDac::setVidPid(uint16_t vid, uint16_t pid)
 {
     // we don't check VID/PID for audio driver
@@ -138,7 +245,7 @@
 {
     bool ret;
 
-    if (audio_intf != -1) {
+    if (audio_intf_cnt >= 2) {
         ret = false;
     } else if ((intf_class == AUDIO_CLASS) && (intf_subclass == 2) && (intf_protocol == 0)) {
         // AUDIOSTREAMING Subclass
@@ -146,6 +253,7 @@
         if (ret != false) {
             audio_intf = intf_nb;
             audio_device_found = true;
+            audio_intf_cnt++;
         }
     } else {
         ret = false;
@@ -171,11 +279,17 @@
     uint8_t  channels     = 0;
     uint8_t  SubframeSize = 0;
     uint8_t  id;
+    uint16_t wk_wMaxPacketSize;
+    uint8_t  wk_bEndpointAddress;
+    uint8_t  wk_bInterfaceNumber;
+    uint8_t  wk_bAlternateSetting;
 
     /* bNumEndpoints */
     if (conf_descr[index + 4] >= 1) {
-        bInterfaceNumber  = conf_descr[index + 2];
-        bAlternateSetting = conf_descr[index + 3];
+        wk_bInterfaceNumber  = conf_descr[index + 2];
+        wk_bAlternateSetting = conf_descr[index + 3];
+        wk_wMaxPacketSize    = 0;
+        wk_bEndpointAddress  = 0;
 
         index += len_desc;
         while ((index < len) && (loop_end == false)) {
@@ -188,8 +302,8 @@
                     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];
+                        wk_bEndpointAddress = conf_descr[index + 2];
+                        wk_wMaxPacketSize   = (conf_descr[index + 5] << 8) + conf_descr[index + 4];
                         loop_end = true;
                     }
                     break;
@@ -213,8 +327,21 @@
             index += len_desc;
         }
 
-        if (((bEndpointAddress & 0x80) == 0) && (wMaxPacketSize >= PACKET_SIZE)
+        if (((wk_bEndpointAddress & 0x80) == 0) && (wk_wMaxPacketSize >= PACKET_SIZE)
          && (channels == 2) && (SubframeSize == 2) && (smpling_ok != false)) {
+            iso_send.wMaxPacketSize    = wk_wMaxPacketSize;
+            iso_send.bEndpointAddress  = wk_bEndpointAddress;
+            iso_send.bInterfaceNumber  = wk_bInterfaceNumber;
+            iso_send.bAlternateSetting = wk_bAlternateSetting;
+            return true;
+        }
+
+        if (((wk_bEndpointAddress & 0x80) != 0) && (wk_wMaxPacketSize >= (PACKET_SIZE/2))
+         && (channels == 1) && (SubframeSize == 2) && (smpling_ok != false)) {
+            iso_recv.wMaxPacketSize    = wk_wMaxPacketSize;
+            iso_recv.bEndpointAddress  = wk_bEndpointAddress;
+            iso_recv.bInterfaceNumber  = wk_bInterfaceNumber;
+            iso_recv.bAlternateSetting = wk_bAlternateSetting;
             return true;
         }
     }
@@ -224,7 +351,12 @@
 
 void USBHostDac::onDisconnect() {
     if (dev_connected) {
-        m_isoEp->disconnect();
+        if (iso_send.bEndpointAddress != 0) {
+            iso_send.m_isoEp->disconnect();
+        }
+        if (iso_recv.bEndpointAddress != 0) {
+            iso_recv.m_isoEp->disconnect();
+        }
         init();
     }
 }
@@ -236,7 +368,7 @@
                                  alt, index, NULL, 0);
 }
 
-void USBHostDac::setSamplingRate(uint32_t sampling_rate) {
+void USBHostDac::setSamplingRate(uint8_t endpoint_adder, uint32_t sampling_rate) {
     uint8_t  data[3];
 
     data[0] = (uint8_t)((sampling_rate >>  0) & 0xff);
@@ -245,6 +377,6 @@
     host->controlWrite(   dev,
                           USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
                           SET_CUR,
-                          SAMPLING, bEndpointAddress, data, 3);
+                          SAMPLING, endpoint_adder, data, 3);
 }