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
Diff: USBHostDac.cpp
- 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); }