Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBHostMSD_HelloWorld by
USBHostC270/BaseUvc.cpp
- Committer:
- va009039
- Date:
- 2013-03-18
- Revision:
- 11:6a8eef89eb22
- Parent:
- 10:387c49b2fc7e
- Child:
- 12:ea4badc78215
File content as of revision 11:6a8eef89eb22:
// BaseUvc.cpp
#include "USBHostConf.h"
#include "USBHost.h"
#include "BaseUvc.h"
//#define ISO_DEBUG 1
#ifdef ISO_DEBUG
#define ISO_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define ISO_DBG(...) while(0);
#endif
#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
void BaseUvc::poll(int millisec)
{
HCITD* itd = m_isoEp->isochronousReceive(millisec);
if (itd) {
uint8_t cc = itd->ConditionCode();
report_cc_count[cc]++;
if (cc == 0) {
uint16_t frame = itd->StartingFrame();
int fc = itd->FrameCount();
uint8_t* buf = const_cast<uint8_t*>(itd->buf);
int mps = 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 len = psw & 0x7ff;
onResult(frame, buf, len);
}
report_ps_cc_count[cc]++;
buf += mps;
frame++;
}
}
delete itd;
}
}
USB_TYPE BaseUvc::Control(int req, int cs, int index, uint8_t* buf, int size)
{
if (req == SET_CUR) {
return host->controlWrite(dev,
USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE,
req, cs<<8, index, buf, size);
}
return host->controlRead(dev,
USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE,
req, cs<<8, index, buf, size);
}
USB_TYPE BaseUvc::setInterfaceAlternate(uint8_t intf, uint8_t alt)
{
return host->controlWrite(dev, USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE,
SET_INTERFACE, alt, intf, NULL, 0);
}
void BaseUvc::onResult(uint16_t frame, uint8_t* buf, int len)
{
if(m_pCbItem && m_pCbMeth)
(m_pCbItem->*m_pCbMeth)(frame, buf, len);
else if(m_pCb)
m_pCb(frame, buf, len);
}
void BaseUvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) )
{
m_pCb = pMethod;
m_pCbItem = NULL;
m_pCbMeth = NULL;
}
void BaseUvc::clearOnResult()
{
m_pCb = NULL;
m_pCbItem = NULL;
m_pCbMeth = NULL;
}
HCITD::HCITD(BaseEp* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) {
Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED
((FrameCount-1) << 24)| // FC FrameCount
TD_DELAY_INT(0) | // DI DelayInterrupt
FrameNumber; // SF StartingFrame
BufferPage0 = const_cast<uint8_t*>(buf);
BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1;
Next = NULL;
ep = obj;
uint32_t addr = reinterpret_cast<uint32_t>(buf);
for(int i = 0; i < FrameCount; i++) {
uint16_t offset = addr & 0x0fff;
if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) {
offset |= 0x1000;
}
OffsetPSW[i] = 0xe000|offset;
addr += PacketSize;
}
}
void IsochronousEp::init(int addr, uint8_t ep, uint16_t size)
{
//ISO_DBG("%p FA:%d EP:%02X MPS:%d\n", this, addr, ep, size);
BaseEp::init(addr, ep, size);
TEST_ASSERT(m_pED);
m_pED->setFormat(); // F Format ITD
TEST_ASSERT(size >= 128 && size <= 1023);
m_PacketSize = size;
m_FrameCount = 4; // 1-8
TEST_ASSERT(m_FrameCount >= 1 && m_FrameCount <= 8);
m_itd_queue_count = 0;
reset();
HCITD* itd = new_HCITD(this);
m_pED->init_queue<HCITD>(itd);
TEST_ASSERT(itd);
if (itd == NULL) {
return;
}
_HCCA* hcca = reinterpret_cast<_HCCA*>(LPC_USB->HcHCCA);
TEST_ASSERT(hcca);
if (hcca == NULL) {
return;
}
hcca->enqueue(m_pED);
}
void IsochronousEp::reset(int delay_ms)
{
m_FrameNumber = LPC_USB->HcFmNumber + delay_ms;
}
HCITD* IsochronousEp::new_HCITD(BaseEp* obj)
{
HCITD* itd = new(m_PacketSize*m_FrameCount)HCITD(obj, m_FrameNumber, m_FrameCount, m_PacketSize);
if (itd == NULL) {
return NULL;
}
m_FrameNumber += m_FrameCount;
return itd;
}
HCITD* IsochronousEp::isochronousReceive(int millisec)
{
TEST_ASSERT(m_itd_queue_count >= 0);
while(m_itd_queue_count < 3 && m_itd_queue_count < HCTD_QUEUE_SIZE) {
TEST_ASSERT(m_pED);
if (m_pED->Skip()) {
break;
}
HCITD* blank_itd = new_HCITD(this);
TEST_ASSERT(blank_itd);
if (m_pED->enqueue<HCITD>(blank_itd)) {
m_itd_queue_count++;
}
enable(); // Enable Periodic
}
HCITD* itd = get_queue_HCITD(millisec);
if (itd) {
m_itd_queue_count--;
}
return itd;
}
HCITD* IsochronousEp::get_queue_HCITD(int millisec)
{
for(int i = 0; i < 16; i++) {
osEvent evt = m_queue.get(millisec);
if (evt.status == osEventMessage) {
HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p);
TEST_ASSERT(itd);
return itd;
} else if (evt.status == osOK) {
continue;
} else if (evt.status == osEventTimeout) {
return NULL;
} else {
ISO_DBG("evt.status: %02x\n", evt.status);
TEST_ASSERT(evt.status == osEventMessage);
return NULL;
}
}
return NULL;
}
void IsochronousEp::enable()
{
LPC_USB->HcControl |= OR_CONTROL_PLE;
}
void IsochronousEp::disconnect()
{
m_pED->setSkip();
Thread::wait(50);
ISO_DBG("rtos-queue: %d", m_itd_queue_count);
int queue_count = m_itd_queue_count;
Timer t;
t.reset();
t.start();
while(queue_count > 0 && t.read_ms() < 50) {
HCITD* itd = get_queue_HCITD(10);
if (itd) {
ISO_DBG("delete ITD:%p from rtos-queue %d ms", itd, t.read_ms());
delete itd;
queue_count--;
t.reset();
}
}
ISO_DBG("rtos-queue: %d, %d ms", queue_count, t.read_ms());
while(1) {
HCITD* itd = m_pED->dequeue<HCITD>();
if (itd == NULL) {
break;
}
ISO_DBG("delete ITD:%p from ED(%p)-queue", itd, m_pED);
delete itd;
TEST_ASSERT(queue_count > 0);
queue_count--;
}
TEST_ASSERT(queue_count == 0);
HCITD* tail = reinterpret_cast<HCITD*>(m_pED->TailTd);
ISO_DBG("delete ITD:%p from ED(%p)-tail", tail, m_pED);
TEST_ASSERT(tail);
delete tail;
m_pED->init_queue<HCITD>(NULL);
_HCCA* hcca = reinterpret_cast<_HCCA*>(LPC_USB->HcHCCA);
TEST_ASSERT(hcca);
hcca->dequeue(m_pED);
ISO_DBG("delete ED:%p", m_pED);
delete m_pED;
m_pED = NULL;
}
void BaseEp::init(int addr, uint8_t ep, uint16_t size, int lowSpeed)
{
ISO_DBG("%p FA=%d EN=%02x MPS=%d S=%d\n", this, addr, ep, size, lowSpeed);
TEST_ASSERT(size >= 8 && size <= 1023);
TEST_ASSERT(lowSpeed == 0 || lowSpeed == 1);
m_pED = new _HCED(addr, ep, size, lowSpeed);
TEST_ASSERT(m_pED);
m_td_queue_count = 0;
}
