supported GR-PEACH original: http://developer.mbed.org/users/va009039/code/USBHostC270_example/ The function of Isochronous has moved to USBHost_AddIso library.
Dependencies: USBHost_custom_Addiso
Fork of USBHostC270_example_GR-PEACH by
Revision 12:ea4badc78215, committed 2013-03-20
- Comitter:
- va009039
- Date:
- Wed Mar 20 14:28:39 2013 +0000
- Parent:
- 11:6a8eef89eb22
- Child:
- 13:fa85d3614acf
- Commit message:
- support detach
Changed in this revision
--- a/USBHost.lib Mon Mar 18 12:34:47 2013 +0000 +++ b/USBHost.lib Wed Mar 20 14:28:39 2013 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/va009039/code/USBHost/#5cc7bad4f28e +http://mbed.org/users/va009039/code/USBHost/#a338d6a681fb
--- a/USBHostC270/BaseUvc.cpp Mon Mar 18 12:34:47 2013 +0000
+++ b/USBHostC270/BaseUvc.cpp Wed Mar 20 14:28:39 2013 +0000
@@ -1,19 +1,9 @@
// BaseUvc.cpp
-
#include "USBHostConf.h"
#include "USBHost.h"
-
+#include "USBIsochronous.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);
@@ -82,168 +72,3 @@
}
-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;
-}
--- a/USBHostC270/BaseUvc.h Mon Mar 18 12:34:47 2013 +0000
+++ b/USBHostC270/BaseUvc.h Wed Mar 20 14:28:39 2013 +0000
@@ -1,5 +1,5 @@
// BaseUvc.h
-
+#include "USBIsochronous.h"
#pragma once
// --- UVC --------------------------------------------------
@@ -23,230 +23,11 @@
#define VS_PROBE_CONTROL 0x01
#define VS_COMMIT_CONTROL 0x02
-class BaseEp;
-struct HCITD { // HostController Isochronous Transfer Descriptor
- __IO uint32_t Control; // +0 Transfer descriptor control
- uint8_t* BufferPage0; // +4 Buffer Page 0
- HCITD* Next; // +8 Physical pointer to next Isochronous Transfer Descriptor
- uint8_t* BufferEnd; // +12 buffer End
- __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
- BaseEp* ep; // +32 endpoint object
- __IO uint8_t buf[0]; // +36 buffer
- // +36
- HCITD(BaseEp* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize);
- inline void* operator new(size_t size, int buf_size) {
- void* p;
- if (posix_memalign(&p, 32, size+buf_size) == 0) {
- return p;
- }
- return NULL;
- }
-
- inline void operator delete(void* p) {
- free(p);
- }
-
- inline uint16_t StartingFrame() {
- return Control & 0xffff;
- }
-
- inline uint8_t FrameCount() {
- return ((Control>>24)&7)+1;
- }
-
- inline uint8_t ConditionCode() {
- return Control>>28;
- }
-};
-
-struct _HCED { // HostController EndPoint Descriptor
- __IO uint32_t Control; // +0 Endpoint descriptor control
- HCTD* TailTd; // +4 Physical address of tail in Transfer descriptor list
- __IO HCTD* HeadTd; // +8 Physcial address of head in Transfer descriptor list
- _HCED* Next; // +12 Physical address of next Endpoint descriptor
- // +16
- _HCED(int addr, uint8_t ep, uint16_t size, int lowSpeed) {
- Control = addr | /* USB address */
- ((ep & 0x7F) << 7) | /* Endpoint address */
- (ep!=0?(((ep&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
- ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */
- (size << 16); /* MaxPkt Size */
- Next = NULL;
- }
-
- inline void* operator new(size_t size) {
- void* p;
- if (posix_memalign(&p, 16, size) == 0) {
- return p;
- }
- return NULL;
- }
-
- inline void operator delete(void* p) {
- free(p);
- }
-
- inline uint8_t FunctionAddress() {
- return Control & 0x7f;
- }
-
- inline int Speed() {
- return (Control>>13)&1;
- }
-
- inline void setFunctionAddress(int addr) {
- Control &= ~0x7f;
- Control |= addr;
- }
-
- inline void setMaxPacketSize(uint16_t size) {
- Control &= ~0xffff0000;
- Control |= size<<16;
- }
-
- int Skip() {
- return (Control>>14) & 1;
- }
-
- void setSkip() {
- Control |= (1<<14);
- }
-
- void setFormat() {
- Control |= (1<<15);
- }
-
- template<typename T>
- inline bool enqueue(T* td) {
- if (td) {
- T* tail = reinterpret_cast<T*>(TailTd);
- if (tail) {
- tail->Next = td;
- TailTd = reinterpret_cast<HCTD*>(td);
- return true;
- }
- }
- return false;
- }
-
- template<typename T>
- inline T* dequeue() {
- T* head = reinterpret_cast<T*>(reinterpret_cast<uint32_t>(HeadTd)&~3); // delete Halted and Toggle Carry bit
- T* tail = reinterpret_cast<T*>(TailTd);
- if (head == NULL || tail == NULL || head == tail) {
- return NULL;
- }
- HeadTd = reinterpret_cast<HCTD*>(head->Next);
- return head;
- }
- template<typename T>
- void init_queue(T* td) {
- TailTd = reinterpret_cast<HCTD*>(td);
- HeadTd = reinterpret_cast<HCTD*>(td);
- }
-};
-
-struct _HCCA { // Host Controller Communication Area
- _HCED* InterruptTable[32]; // +0 Interrupt Table
- __IO uint16_t FrameNumber;// +128 Frame Number
- __IO uint16_t Pad1; // +130
- __IO HCTD* DoneHead; // +132 Done Head
- uint8_t Reserved[116]; // +136 Reserved for future use
- uint8_t Unknown[4]; // +252 Unused
- // +256
- inline void* operator new(size_t size) {
- void* p;
- if (posix_memalign(&p, 256, size) == 0) {
- return p;
- }
- return NULL;
- }
-
- inline void operator delete(void* p) {
- free(p);
- }
-
- inline void enqueue(_HCED* ed) {
- for(int i = 0; i < 32; i++) {
- if (InterruptTable[i] == NULL) {
- InterruptTable[i] = ed;
- } else {
- _HCED* nextEd = InterruptTable[i];
- while(nextEd->Next && nextEd->Next != ed) {
- nextEd = nextEd->Next;
- }
- nextEd->Next = ed;
- }
- }
- }
-
- inline void dequeue(_HCED* ed) {
- for(int i = 0; i < 32; i++) {
- if (InterruptTable[i] == ed) {
- InterruptTable[i] = ed->Next;
- } else if (InterruptTable[i]) {
- _HCED* nextEd = InterruptTable[i];
- while(nextEd) {
- if (nextEd->Next == ed) {
- nextEd->Next = ed->Next;
- break;
- }
- nextEd = nextEd->Next;
- }
- }
- }
- }
-};
-
-#define HCTD_QUEUE_SIZE 3
-
-class BaseEp { // endpoint
-public:
- void init(int addr, uint8_t ep = 0, uint16_t size = 8, int lowSpeed = 0);
- int GetAddr();
- int GetLowSpeed();
- void update_FunctionAddress(int addr);
- void update_MaxPacketSize(uint16_t size);
- int transfer(uint8_t* buf, int len);
- int status(uint32_t millisec=osWaitForever);
- //
- virtual void enable() = 0;
- virtual void irqWdhHandler(HCTD* td) {m_queue.put(td);} // WDH
- int wait_queue_HCTD(HCTD* wait_td, uint32_t millisec=osWaitForever);
- // report
- uint8_t m_ConditionCode;
- int m_report_queue_error;
-protected:
- int send_receive(uint8_t* buf, int len, int millisec);
- HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever);
- _HCED* m_pED;
- Queue<HCTD, HCTD_QUEUE_SIZE> m_queue; // TD done queue
- int m_td_queue_count;
-};
-
-class IsochronousEp : public BaseEp {
-public:
- void init(int addr, uint8_t ep, uint16_t size);
- void reset(int delay_ms = 100);
- HCITD* isochronousReceive(int millisec=osWaitForever);
- int isochronousSend(uint8_t* buf, int len, int millisec=osWaitForever);
- HCITD* get_queue_HCITD(int millisec);
- uint16_t m_PacketSize;
- void disconnect();
-private:
- HCITD* new_HCITD(BaseEp* obj);
- int m_itd_queue_count;
- uint16_t m_FrameNumber;
- int m_FrameCount; // 1-8
- virtual void enable();
-};
-
class BaseUvc {
public:
- void poll(int millisec=osWaitForever);
+ void poll(int millisec = 0);
USB_TYPE Control(int req, int cs, int index, uint8_t* buf, int size);
USB_TYPE setInterfaceAlternate(uint8_t intf, uint8_t alt);
- //ControlEp* m_ctlEp;
IsochronousEp* m_isoEp;
uint32_t report_cc_count[16]; // ConditionCode
uint32_t report_ps_cc_count[16]; // Packt Status ConditionCode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBisochronous/USBIsochronous.cpp Wed Mar 20 14:28:39 2013 +0000
@@ -0,0 +1,212 @@
+// USBIsochronous.cpp
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "USBIsochronous.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);};
+
+HCITD::HCITD(IsochronousEp* 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, uint8_t frameCount, uint8_t queueLimit)
+{
+ //ISO_DBG("%p FA:%d EP:%02X MPS:%d\n", this, addr, ep, size);
+ TEST_ASSERT(addr >= 1);
+ TEST_ASSERT(size >= 8 && size <= 1023);
+ m_pED = new _HCED(addr, ep, size);
+ TEST_ASSERT(m_pED);
+
+ m_pED->setFormat(); // F Format ITD
+
+ TEST_ASSERT(size >= 128 && size <= 1023);
+ m_PacketSize = size;
+ TEST_ASSERT(frameCount >= 1 && frameCount <= 8);
+ m_FrameCount = frameCount;
+ TEST_ASSERT(queueLimit >= 1 && queueLimit <= HCITD_QUEUE_SIZE);
+ m_itd_queue_limit = queueLimit;
+
+ 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(IsochronousEp* 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 timeout_ms)
+{
+ TEST_ASSERT(m_itd_queue_count >= 0);
+ while(m_itd_queue_count < m_itd_queue_limit) {
+ if (m_pED == NULL) {
+ ISO_DBG("m_pED is NULL");
+ break;
+ }
+ 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(timeout_ms);
+ if (itd) {
+ m_itd_queue_count--;
+ }
+ return itd;
+}
+
+int IsochronousEp::isochronousSend(uint8_t* buf, int len, int timeout_ms)
+{
+ //ISO_DBG("buf: %p, len: %d", buf, len);
+ HCITD* itd = get_queue_HCITD(timeout_ms);
+ if (itd) {
+ delete itd;
+ m_itd_queue_count--;
+ TEST_ASSERT(m_itd_queue_count >= 0);
+ }
+ TEST_ASSERT(m_itd_queue_count >= 0);
+ if(m_itd_queue_count < m_itd_queue_limit) {
+ if (m_pED == NULL) {
+ ISO_DBG("m_pED is NULL");
+ return 0;
+ }
+ if (m_pED->Skip()) {
+ return 0;
+ }
+ itd = new_HCITD(this);
+ TEST_ASSERT(itd);
+ //ISO_DBG("m_pED: %p itd: %p", m_pED, itd);
+ memcpy(const_cast<uint8_t*>(itd->buf), buf, len);
+ if (m_pED->enqueue<HCITD>(itd)) {
+ m_itd_queue_count++;
+ }
+ enable(); // Enable Periodic
+ //ISO_DBG("m_itd_queue_count: %d", m_itd_queue_count);
+ return len;
+ }
+ return 0;
+}
+
+HCITD* IsochronousEp::get_queue_HCITD(int timeout_ms)
+{
+ Timer t;
+ t.reset();
+ t.start();
+ do {
+ osEvent evt = m_queue.get(0);
+ if (evt.status == osEventMessage) {
+ HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p);
+ TEST_ASSERT(itd);
+ return itd;
+ } else if (evt.status == osOK) {
+ ;
+ } else if (evt.status == osEventTimeout) {
+ break;
+ } else {
+ ISO_DBG("evt.status: %02x\n", evt.status);
+ TEST_ASSERT(evt.status == osEventMessage);
+ break;
+ }
+ } while(t.read_ms() < timeout_ms);
+ return NULL;
+}
+
+void IsochronousEp::enable()
+{
+ LPC_USB->HcControl |= OR_CONTROL_PLE;
+}
+
+void IsochronousEp::disconnect()
+{
+ m_pED->setSkip(); // skip bit on
+ ISO_DBG("rtos-queue: %d", m_itd_queue_count);
+ int queue_count = m_itd_queue_count;
+ Timer t;
+ t.reset();
+ t.start();
+ do {
+ 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();
+ }
+ } while(t.read_ms() < 50);
+ ISO_DBG("rtos-queue: %d, %d ms", queue_count, t.read_ms());
+ TEST_ASSERT(queue_count >= 0);
+ 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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBisochronous/USBIsochronous.h Wed Mar 20 14:28:39 2013 +0000
@@ -0,0 +1,200 @@
+// USBIsochronous.h
+#pragma once
+
+class IsochronousEp;
+struct HCITD { // HostController Isochronous Transfer Descriptor
+ __IO uint32_t Control; // +0 Transfer descriptor control
+ uint8_t* BufferPage0; // +4 Buffer Page 0
+ HCITD* Next; // +8 Physical pointer to next Isochronous Transfer Descriptor
+ uint8_t* BufferEnd; // +12 buffer End
+ __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
+ IsochronousEp* ep; // +32 endpoint object
+ __IO uint8_t buf[0]; // +36 buffer
+ // +36
+ HCITD(IsochronousEp* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize);
+ inline void* operator new(size_t size, int buf_size) {
+ void* p;
+ if (posix_memalign(&p, 32, size+buf_size) == 0) {
+ return p;
+ }
+ return NULL;
+ }
+
+ inline void operator delete(void* p) {
+ free(p);
+ }
+
+ inline uint16_t StartingFrame() {
+ return Control & 0xffff;
+ }
+
+ inline uint8_t FrameCount() {
+ return ((Control>>24)&7)+1;
+ }
+
+ inline uint8_t ConditionCode() {
+ return Control>>28;
+ }
+};
+
+struct _HCED { // HostController EndPoint Descriptor
+ __IO uint32_t Control; // +0 Endpoint descriptor control
+ HCTD* TailTd; // +4 Physical address of tail in Transfer descriptor list
+ __IO HCTD* HeadTd; // +8 Physcial address of head in Transfer descriptor list
+ _HCED* Next; // +12 Physical address of next Endpoint descriptor
+ // +16
+ _HCED(int addr, uint8_t ep, uint16_t size, int lowSpeed = 0) {
+ Control = addr | /* USB address */
+ ((ep & 0x7F) << 7) | /* Endpoint address */
+ (ep!=0?(((ep&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
+ ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */
+ (size << 16); /* MaxPkt Size */
+ Next = NULL;
+ }
+
+ inline void* operator new(size_t size) {
+ void* p;
+ if (posix_memalign(&p, 16, size) == 0) {
+ return p;
+ }
+ return NULL;
+ }
+
+ inline void operator delete(void* p) {
+ free(p);
+ }
+
+ inline uint8_t FunctionAddress() {
+ return Control & 0x7f;
+ }
+
+ inline int Speed() {
+ return (Control>>13)&1;
+ }
+
+ inline void setFunctionAddress(int addr) {
+ Control &= ~0x7f;
+ Control |= addr;
+ }
+
+ inline void setMaxPacketSize(uint16_t size) {
+ Control &= ~0xffff0000;
+ Control |= size<<16;
+ }
+
+ int Skip() {
+ return (Control>>14) & 1;
+ }
+
+ void setSkip() {
+ Control |= (1<<14);
+ }
+
+ void setFormat() {
+ Control |= (1<<15);
+ }
+
+ template<typename T>
+ inline bool enqueue(T* td) {
+ if (td) {
+ T* tail = reinterpret_cast<T*>(TailTd);
+ if (tail) {
+ tail->Next = td;
+ TailTd = reinterpret_cast<HCTD*>(td);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template<typename T>
+ inline T* dequeue() {
+ T* head = reinterpret_cast<T*>(reinterpret_cast<uint32_t>(HeadTd)&~3); // delete Halted and Toggle Carry bit
+ T* tail = reinterpret_cast<T*>(TailTd);
+ if (head == NULL || tail == NULL || head == tail) {
+ return NULL;
+ }
+ HeadTd = reinterpret_cast<HCTD*>(head->Next);
+ return head;
+ }
+ template<typename T>
+ void init_queue(T* td) {
+ TailTd = reinterpret_cast<HCTD*>(td);
+ HeadTd = reinterpret_cast<HCTD*>(td);
+ }
+};
+
+struct _HCCA { // Host Controller Communication Area
+ _HCED* InterruptTable[32]; // +0 Interrupt Table
+ __IO uint16_t FrameNumber;// +128 Frame Number
+ __IO uint16_t Pad1; // +130
+ __IO HCTD* DoneHead; // +132 Done Head
+ uint8_t Reserved[116]; // +136 Reserved for future use
+ uint8_t Unknown[4]; // +252 Unused
+ // +256
+ inline void* operator new(size_t size) {
+ void* p;
+ if (posix_memalign(&p, 256, size) == 0) {
+ return p;
+ }
+ return NULL;
+ }
+
+ inline void operator delete(void* p) {
+ free(p);
+ }
+
+ inline void enqueue(_HCED* ed) {
+ for(int i = 0; i < 32; i++) {
+ if (InterruptTable[i] == NULL) {
+ InterruptTable[i] = ed;
+ } else {
+ _HCED* nextEd = InterruptTable[i];
+ while(nextEd->Next && nextEd->Next != ed) {
+ nextEd = nextEd->Next;
+ }
+ nextEd->Next = ed;
+ }
+ }
+ }
+
+ inline void dequeue(_HCED* ed) {
+ for(int i = 0; i < 32; i++) {
+ if (InterruptTable[i] == ed) {
+ InterruptTable[i] = ed->Next;
+ } else if (InterruptTable[i]) {
+ _HCED* nextEd = InterruptTable[i];
+ while(nextEd) {
+ if (nextEd->Next == ed) {
+ nextEd->Next = ed->Next;
+ break;
+ }
+ nextEd = nextEd->Next;
+ }
+ }
+ }
+ }
+};
+
+#define HCITD_QUEUE_SIZE 3
+
+class IsochronousEp {
+public:
+ void init(int addr, uint8_t ep, uint16_t size, uint8_t frameCount = 4, uint8_t queueLimit = HCITD_QUEUE_SIZE);
+ void reset(int delay_ms = 100);
+ HCITD* isochronousReceive(int timeout_ms);
+ int isochronousSend(uint8_t* buf, int len, int timeout_ms);
+ HCITD* get_queue_HCITD(int timeout_ms);
+ uint16_t m_PacketSize;
+ void disconnect();
+ void irqWdhHandler(HCITD* itd) {m_queue.put(itd);} // WDH
+private:
+ HCITD* new_HCITD(IsochronousEp* obj);
+ Queue<HCITD, HCITD_QUEUE_SIZE> m_queue; // ITD done queue
+ int m_itd_queue_count;
+ int m_itd_queue_limit;
+ uint16_t m_FrameNumber;
+ int m_FrameCount; // 1-8
+ void enable();
+ _HCED* m_pED;
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostCam/CamInfo.cpp Wed Mar 20 14:28:39 2013 +0000
@@ -0,0 +1,193 @@
+// CamInfo.cpp
+#include "USBHostCam.h"
+
+// Logitech C270
+#define C270_VID 0x046d
+#define C270_PID 0x0825
+#define C270_160x120 2
+#define C270_176x144 3
+#define C270_320x176 4
+#define C270_320x240 5
+#define C270_352x288 6
+#define C270_432x240 7
+#define C270_640x480 1
+#define C270_544x288 8
+#define C270_640x360 9
+#define C270_752x416 10
+#define C270_800x448 11
+#define C270_800x600 12
+
+#define C270_MJPEG 2
+#define C270_YUV2 1
+
+#define C270_EN 0x81
+#define C270_MPS 192
+#define C270_IF_ALT_192 1
+#define C270_IF_ALT(A) C270_IF_ALT_##A
+
+#define C270_INFO(SIZE) {C270_VID, C270_PID, _##SIZE, 0, \
+ "C270", \
+ C270_MJPEG, \
+ C270_##SIZE, \
+ _5FPS, \
+ C270_EN, \
+ 192, \
+ C270_IF_ALT(192), \
+ 4, \
+ 3}
+
+#define C210_PID 0x819
+#define C210_INFO(SIZE) {C270_VID, C210_PID, _##SIZE, 0, \
+ "C270", \
+ C270_MJPEG, \
+ C270_##SIZE, \
+ _5FPS, \
+ C270_EN, \
+ 192, \
+ C270_IF_ALT(192), \
+ 4, \
+ 3}
+
+// Logitech Qcam Orbit AF QCAM-200R
+#define Q200R_VID 0x046d
+#define Q200R_PID 0x0994
+#define Q200R_160x120 1
+#define Q200R_176x144 2
+#define Q200R_320x240 3
+#define Q200R_352x288 4
+#define Q200R_640x480 5
+#define Q200R_800x600 6
+
+#define Q200R_MJPEG 1
+#define Q200R_YUV2 2
+
+#define Q200R_EN 0x81
+#define Q200R_MPS 192
+#define Q200R_IF_ALT_192 1
+#define Q200R_IF_ALT_384 2
+#define Q200R_IF_ALT_512 3
+#define Q200R_IF_ALT_640 4
+#define Q200R_IF_ALT_800 5
+#define Q200R_IF_ALT_944 6
+#define Q200R_IF_ALT(A) Q200R_IF_ALT_##A
+#define Q200R_INFO(SIZE) {Q200R_VID, Q200R_PID, _##SIZE, 0, \
+ "Q200R", \
+ Q200R_MJPEG, \
+ Q200R_##SIZE, \
+ _5FPS, \
+ Q200R_EN, \
+ 192, \
+ Q200R_IF_ALT(192), \
+ 4, \
+ 3}
+
+//LifeCam VX700 / VX500
+#define VX700_VID 0x045e
+#define VX700_PID 0x074a
+
+#define VX700_160x120 5
+#define VX700_176x144 4
+#define VX700_320x240 3
+#define VX700_352x288 2
+#define VX700_640x480 1
+
+#define VX700_MJPEG 1
+
+#define VX700_EN 0x81
+#define VX700_MPS 128
+#define VX700_IF_ALT_128 1
+#define VX700_IF_ALT(A) VX700_IF_ALT_##A
+#define VX700_INFO(SIZE) {VX700_VID, VX700_PID, _##SIZE, 0, \
+ "VX700", \
+ VX700_MJPEG, \
+ VX700_##SIZE, \
+ _5FPS, \
+ VX700_EN, \
+ 128, \
+ VX700_IF_ALT(128), \
+ 4, \
+ 3}
+
+//Sonix USB 2.0 Camera
+#define SONIX_160x120 5
+#define SONIX_176x144 4
+#define SONIX_320x240 3
+#define SONIX_352x288 2
+#define SONIX_640x480 1
+
+#define SONIX_IF_ALT_128 1
+#define SONIX_IF_ALT_256 2
+#define SONIX_IF_ALT_512 3
+#define SONIX_IF_ALT_600 4
+#define SONIX_IF_ALT_800 5
+#define SONIX_IF_ALT_956 6
+#define SONIX_IF_ALT(A) SONIX_IF_ALT_##A
+#define SONIX_INFO(SIZE) {0x0c45, 0x62c0, _##SIZE, 0, \
+ "SONIX", \
+ 1, \
+ SONIX_##SIZE, \
+ _5FPS, \
+ 0x81, \
+ 128, \
+ SONIX_IF_ALT(128), \
+ 4, \
+ 3}
+
+static const CamInfo CamInfoList[] = {
+// Logitech C270
+C270_INFO(160x120),
+C270_INFO(176x144),
+C270_INFO(320x176),
+C270_INFO(320x240),
+C270_INFO(352x288),
+C270_INFO(432x240),
+C270_INFO(640x480),
+C270_INFO(544x288),
+C270_INFO(640x360),
+C270_INFO(752x416),
+C270_INFO(800x448),
+C270_INFO(800x600),
+
+// Logitech C210
+C210_INFO(160x120),
+C210_INFO(176x144),
+C210_INFO(320x176),
+C210_INFO(320x240),
+C210_INFO(352x288),
+C210_INFO(432x240),
+C210_INFO(640x480),
+C210_INFO(544x288),
+C210_INFO(640x360),
+C210_INFO(752x416),
+C210_INFO(800x448),
+C210_INFO(800x600),
+
+// Logitech Qcam Orbit AF QCAM-200R
+Q200R_INFO(160x120),
+Q200R_INFO(176x144),
+Q200R_INFO(320x240),
+Q200R_INFO(352x288),
+Q200R_INFO(640x480),
+Q200R_INFO(800x600),
+
+// LifeCam VX700
+VX700_INFO(160x120),
+VX700_INFO(176x144),
+VX700_INFO(320x240),
+VX700_INFO(352x288),
+VX700_INFO(640x480),
+
+// Sonix USB 2.0 Camera
+SONIX_INFO(160x120),
+SONIX_INFO(176x144),
+SONIX_INFO(320x240),
+SONIX_INFO(352x288),
+SONIX_INFO(640x480),
+
+// Not found
+{0,0,0,0},
+};
+
+CamInfo* getCamInfoList() {
+ return const_cast<CamInfo*>(CamInfoList);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostCam/USBHostCam.cpp Wed Mar 20 14:28:39 2013 +0000
@@ -0,0 +1,176 @@
+// USBHostCam.cpp
+#include "USBHostCam.h"
+#include "dbg.h"
+
+//#define CAM_DEBUG 1
+#ifdef CAM_DEBUG
+#define CAM_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
+#else
+#define CAM_DBG(...) while(0);
+#endif
+
+// ------------------ HcControl Register ---------------------
+#define OR_CONTROL_IE 0x00000008
+
+CamInfo* getCamInfoList(); // CamInfo.cpp
+
+USBHostCam::USBHostCam(uint8_t size, uint8_t option, CamInfo* user_caminfo)
+{
+ CAM_DBG("size: %d, option: %d", size, option);
+ _caminfo_size = size;
+ _caminfo_option = option;
+ if (user_caminfo) {
+ CamInfoList = user_caminfo;
+ } else {
+ CamInfoList = getCamInfoList();
+ }
+ clearOnResult();
+ host = USBHost::getHostInst();
+ m_isoEp = new IsochronousEp;
+ init();
+}
+
+void USBHostCam::init()
+{
+ CAM_DBG("");
+ dev_connected = false;
+ dev = NULL;
+ cam_intf = -1;
+ device_found = false;
+ caminfo_found = false;
+}
+
+bool USBHostCam::connected()
+{
+ return dev_connected;
+}
+
+bool USBHostCam::connect()
+{
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ CAM_DBG("Trying to connect Cam device\r\n");
+
+ if(host->enumerate(dev, this)) {
+ break;
+ }
+ if (device_found) {
+ USB_INFO("New Cam: %s device: VID:%04x PID:%04x [dev: %p - intf: %d]", caminfo->name, dev->getVid(), dev->getPid(), dev, cam_intf);
+ dev->setName(caminfo->name, cam_intf);
+ host->registerDriver(dev, cam_intf, this, &USBHostCam::onDisconnect);
+ int addr = dev->getAddress();
+ m_isoEp->init(addr, caminfo->en, caminfo->mps, caminfo->frameCount, caminfo->queueLimit);
+ uint8_t buf[26];
+ memset(buf, 0, sizeof(buf));
+ buf[2] = caminfo->formatIndex;
+ buf[3] = caminfo->frameIndex;
+ *reinterpret_cast<uint32_t*>(buf+4) = caminfo->interval;
+ USB_TYPE res = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, sizeof(buf));
+ if (res != USB_TYPE_OK) {
+ CAM_DBG("SET_CUR VS_COMMIT_CONTROL FAILED");
+ }
+ res = setInterfaceAlternate(1, caminfo->if_alt);
+ if (res != USB_TYPE_OK) {
+ CAM_DBG("SET_INTERFACE FAILED");
+ }
+ for(int i = 0; i < 16; i++) {
+ report_cc_count[i] = 0;
+ report_ps_cc_count[i] = 0;
+ }
+ LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
+ LPC_USB->HcControl |= OR_CONTROL_IE; // IsochronousEnable
+
+ dev_connected = true;
+ return true;
+ }
+ }
+ }
+ init();
+ return false;
+}
+
+void USBHostCam::onDisconnect()
+{
+ CAM_DBG("dev_connected: %d", dev_connected);
+ if (dev_connected) {
+ m_isoEp->disconnect();
+ init();
+ }
+}
+
+/*virtual*/ void USBHostCam::setVidPid(uint16_t vid, uint16_t pid)
+{
+ CAM_DBG("vid:%04x,pid:%04x", vid, pid);
+ caminfo = CamInfoList;
+ while(caminfo->vid != 0) {
+ if (caminfo->vid == vid && caminfo->pid == pid &&
+ caminfo->size == _caminfo_size && caminfo->option == _caminfo_option) {
+ caminfo_found = true;
+ break;
+ }
+ caminfo++;
+ }
+}
+
+/*virtual*/ bool USBHostCam::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
+{
+ CAM_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol);
+ if ((cam_intf == -1) && caminfo_found) {
+ cam_intf = intf_nb;
+ device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostCam::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ CAM_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir);
+ return false;
+}
+
+#define SEQ_READ_IDOL 0
+#define SEQ_READ_EXEC 1
+#define SEQ_READ_DONE 2
+
+int USBHostCam::readJPEG(uint8_t* buf, int size, int timeout_ms) {
+ _buf = buf;
+ _pos = 0;
+ _size = size;
+ _seq = SEQ_READ_IDOL;
+ setOnResult(this, &USBHostCam::callback_motion_jpeg);
+ Timer timeout_t;
+ timeout_t.reset();
+ timeout_t.start();
+ while(timeout_t.read_ms() < timeout_ms && _seq != SEQ_READ_DONE && connected()) {
+ poll();
+ Thread::wait(1);
+ }
+ return _pos;
+}
+
+/* virtual */ void USBHostCam::outputJPEG(uint8_t c, int status) { // from decodeMJPEG
+ if (_seq == SEQ_READ_IDOL) {
+ if (status == JPEG_START) {
+ _pos = 0;
+ _seq = SEQ_READ_EXEC;
+ }
+ }
+ if (_seq == SEQ_READ_EXEC) {
+ if (_pos < _size) {
+ _buf[_pos++] = c;
+ }
+ if (status == JPEG_END) {
+ _seq = SEQ_READ_DONE;
+ }
+ }
+}
+
+void USBHostCam::callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) {
+ inputPacket(buf, len);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostCam/USBHostCam.h Wed Mar 20 14:28:39 2013 +0000
@@ -0,0 +1,101 @@
+// USBHostCam.h
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "USBIsochronous.h"
+#include "BaseUvc.h"
+#include "decodeMJPEG.h"
+#pragma once
+
+#define _160x120 2
+#define _176x144 3
+#define _320x176 4
+#define _320x240 5
+#define _352x288 6
+#define _432x240 7
+#define _640x480 1
+#define _544x288 8
+#define _640x360 9
+#define _752x416 10
+#define _800x448 11
+#define _800x600 12
+
+#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+
+struct CamInfo {
+ uint16_t vid;
+ uint16_t pid;
+ uint8_t size;
+ uint8_t option;
+//
+ const char* name;
+ uint8_t formatIndex;
+ uint8_t frameIndex;
+ uint32_t interval;
+ uint8_t en;
+ uint8_t mps;
+ uint8_t if_alt;
+ uint8_t frameCount; // ITD frame count 1-8
+ uint8_t queueLimit; // ITD queue limit 1-3
+};
+
+/**
+ * A class to communicate a Cam
+ */
+class USBHostCam : public IUSBEnumerator, public BaseUvc, public decodeMJPEG {
+public:
+ /**
+ * Constructor
+ *
+ */
+ USBHostCam(uint8_t size = _160x120, uint8_t option = 0, CamInfo* user_caminfo = NULL);
+
+ /**
+ * Check if a Cam device is connected
+ *
+ * @return true if a Cam device is connected
+ */
+ bool connected();
+
+ /**
+ * Try to connect to a Cam device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+ /**
+ * read jpeg image
+ *
+ * @param buf read buffer
+ * @param size buffer size
+ * @param timeout_ms timeout default 15sec
+ * @return jpeg size if read success else -1
+ */
+ int readJPEG(uint8_t* buf, int size, int timeout_ms = 15*1000);
+
+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:
+ bool dev_connected;
+
+ int cam_intf;
+ bool device_found;
+ bool caminfo_found;
+ uint8_t _seq;
+ uint8_t* _buf;
+ int _pos;
+ int _size;
+ CamInfo* CamInfoList;
+ CamInfo* caminfo;
+ uint8_t _caminfo_size;
+ uint8_t _caminfo_option;
+
+ virtual void outputJPEG(uint8_t c, int status); // from decodeMJPEG
+ void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len);
+ void init();
+ void onDisconnect();
+};
