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 9:fecabade834a, committed 2013-03-16
- Comitter:
- va009039
- Date:
- Sat Mar 16 13:07:55 2013 +0000
- Parent:
- 8:758190c6c455
- Child:
- 10:387c49b2fc7e
- Commit message:
- LogitechC270 class driver alpha version
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyThread/MyThread.h Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,52 @@
+// MyThread.h 2012/12/9
+#ifndef MY_THREAD_H
+#define MY_THREAD_H
+
+#define MAGIC_WORD 0xE25A2EA5
+static void thread_handler(void const *argument);
+
+class MyThread {
+public:
+ MyThread() {
+ m_stack_size = DEFAULT_STACK_SIZE;
+ m_stack_pointer = NULL;
+ }
+ void set_stack(uint32_t stack_size=DEFAULT_STACK_SIZE, uint8_t* stack_pointer = NULL) {
+ m_stack_size = stack_size;
+ m_stack_pointer = stack_pointer;
+ }
+ virtual void run() = 0;
+ Thread* start(osPriority priority=osPriorityNormal) {
+ if (m_stack_pointer == NULL) {
+ m_stack_pointer = reinterpret_cast<uint8_t*>(malloc(m_stack_size));
+ }
+ for(int i = 0; i < m_stack_size-64; i += 4) {
+ *reinterpret_cast<uint32_t*>(m_stack_pointer+i) = MAGIC_WORD;
+ }
+ return th = new Thread(thread_handler, this, priority, m_stack_size, m_stack_pointer);
+ }
+
+ int stack_used() {
+ int i;
+ for(i = 0; i < m_stack_size; i += 4) {
+ if(*reinterpret_cast<uint32_t*>(m_stack_pointer+i) != MAGIC_WORD) {
+ break;
+ }
+ }
+ return m_stack_size - i;
+ }
+
+ int stack_size() { return m_stack_size; }
+protected:
+ Thread* th;
+ uint32_t m_stack_size;
+ uint8_t* m_stack_pointer;
+};
+static void thread_handler(void const *argument) {
+ MyThread* th = (MyThread*)argument;
+ if (th) {
+ th->run();
+ }
+}
+
+#endif //MY_THREAD_H
--- a/USBHost.lib Thu Mar 14 14:23:42 2013 +0000 +++ b/USBHost.lib Sat Mar 16 13:07:55 2013 +0000 @@ -1,1 +1,1 @@ -https://mbed.org/users/mbed_official/code/USBHost/#7671b6a8c363 +http://mbed.org/users/va009039/code/USBHost/#5cc7bad4f28e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/BaseUvc.cpp Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,195 @@
+#include "USBHostConf.h"
+#include "USBHost.h"
+
+#include "USBHostC270.h"
+#include "BaseUvc.h"
+
+#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->isochronousReveive(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;
+ }
+}
+
+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;
+ }
+}
+
+IsochronousEp::IsochronousEp(int addr, uint8_t ep, uint16_t size):BaseEp(addr, ep, size)
+{
+ C270_DBG("%p FA:%d EP:%02X MPS:%d\n", this, addr, ep, size);
+ TEST_ASSERT(m_pED);
+
+ m_pED->Control |= (1 << 15); // 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->TailTd = reinterpret_cast<HCTD*>(itd);
+ m_pED->HeadTd = reinterpret_cast<HCTD*>(itd);
+ TEST_ASSERT(itd);
+ if (itd == NULL) {
+ return;
+ }
+ _HCCA* hcca = reinterpret_cast<_HCCA*>(LPC_USB->HcHCCA);
+ TEST_ASSERT(hcca);
+ if (hcca == NULL) {
+ return;
+ }
+ for(int i = 0; i < 32; i++) {
+ if (hcca->InterruptTable[i] == NULL) {
+ hcca->InterruptTable[i] = m_pED;
+ } else {
+ _HCED* nextEd = hcca->InterruptTable[i];
+ while(nextEd->Next && nextEd->Next != m_pED) {
+ nextEd = nextEd->Next;
+ }
+ nextEd->Next = m_pED;
+ }
+ }
+ //DBG_ED(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::isochronousReveive(int millisec)
+{
+ TEST_ASSERT(m_itd_queue_count >= 0);
+ while(m_itd_queue_count < 3 && m_itd_queue_count < HCTD_QUEUE_SIZE) {
+ HCITD* itd = reinterpret_cast<HCITD*>(m_pED->TailTd);
+ TEST_ASSERT(itd);
+ if (itd == NULL) {
+ return NULL;
+ }
+ HCITD* blank_itd = new_HCITD(this);
+ TEST_ASSERT(blank_itd);
+ if (blank_itd == NULL) {
+ return NULL;
+ }
+ itd->Next = blank_itd;
+ m_pED->TailTd = reinterpret_cast<HCTD*>(blank_itd);
+ m_itd_queue_count++;
+ //DBG_IED(m_pED);
+ 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 {
+ //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;
+}
+
+BaseEp::BaseEp(int addr, uint8_t ep, uint16_t size, int lowSpeed):m_td_queue_count(0)
+{
+ C270_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);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/BaseUvc.h Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,171 @@
+#pragma once
+
+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;
+ }
+};
+
+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);
+ }
+};
+
+#define HCTD_QUEUE_SIZE 3
+
+class BaseEp { // endpoint
+public:
+ BaseEp(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:
+ IsochronousEp(int addr, uint8_t ep, uint16_t size);
+ void reset(int delay_ms = 100);
+ HCITD* isochronousReveive(int millisec=osWaitForever);
+ int isochronousSend(uint8_t* buf, int len, int millisec=osWaitForever);
+ HCITD* get_queue_HCITD(int millisec);
+ uint16_t m_PacketSize;
+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);
+ int Control(int req, int cs, int index, uint8_t* buf, int size);
+ //ControlEp* m_ctlEp;
+ IsochronousEp* m_isoEp;
+ uint32_t report_cc_count[16]; // ConditionCode
+ uint32_t report_ps_cc_count[16]; // Packt Status ConditionCode
+ // callback
+ void onResult(uint16_t frame, uint8_t* buf, int len);
+ void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) );
+ class CDummy;
+ template<class T>
+ void setOnResult( T* pItem, void (T::*pMethod)(uint16_t, uint8_t*, int) )
+ {
+ m_pCb = NULL;
+ m_pCbItem = (CDummy*) pItem;
+ m_pCbMeth = (void (CDummy::*)(uint16_t, uint8_t*, int)) pMethod;
+ }
+ void clearOnResult();
+ CDummy* m_pCbItem;
+ void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int);
+ void (*m_pCb)(uint16_t, uint8_t*, int);
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBHostC270.cpp Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,129 @@
+#include "USBHostC270.h"
+#include "dbg.h"
+
+// ------------------ HcControl Register ---------------------
+#define OR_CONTROL_IE 0x00000008
+
+USBHostC270::USBHostC270(int formatIndex, int frameIndex, uint32_t interval)
+{
+ _formatIndex = formatIndex;
+ _frameIndex = frameIndex;
+ _interval = interval;
+ host = USBHost::getHostInst();
+ init();
+}
+
+void USBHostC270::init()
+{
+ C270_DBG("");
+ dev_connected = false;
+ dev = NULL;
+ c270_intf = -1;
+ c270_device_found = false;
+ c270_vid_pid_found = false;
+ clearOnResult();
+}
+
+bool USBHostC270::connected()
+{
+ C270_DBG("");
+ return dev_connected;
+}
+
+bool USBHostC270::connect()
+{
+ C270_DBG("");
+ if (dev_connected) {
+ return true;
+ }
+
+ for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+ if ((dev = host->getDevice(i)) != NULL) {
+
+ C270_DBG("Trying to connect C270 device\r\n");
+
+ if(host->enumerate(dev, this))
+ break;
+
+ if (c270_device_found) {
+ USB_INFO("New C270 device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, c270_intf);
+ dev->setName("C270", c270_intf);
+ host->registerDriver(dev, c270_intf, this, &USBHostC270::init);
+ int addr = dev->getAddress();
+ m_isoEp = new IsochronousEp(addr, C270_EN, C270_MPS);
+ uint8_t buf[26];
+ memset(buf, 0, sizeof(buf));
+ buf[2] = _formatIndex;
+ buf[3] = _frameIndex;
+ *reinterpret_cast<uint32_t*>(buf+4) = _interval;
+ USB_TYPE res = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, sizeof(buf));
+ if (res != USB_TYPE_OK) {
+ C270_DBG("SET_CUR VS_COMMIT_CONTROL FAILED");
+ }
+ res = setInterfaceAlternate(1, C270_IF_ALT); // alt=1 packet size = 192
+ if (res != USB_TYPE_OK) {
+ C270_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;
+}
+
+/*virtual*/ void USBHostC270::setVidPid(uint16_t vid, uint16_t pid)
+{
+ C270_DBG("vid:%04x,pid:%04x", vid, pid);
+ if (vid == C270_VID && pid == C270_PID) {
+ c270_vid_pid_found = true;
+ } else {
+ c270_vid_pid_found = false;
+ }
+}
+
+/*virtual*/ bool USBHostC270::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
+{
+ C270_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol);
+ if ((c270_intf == -1) && c270_vid_pid_found) {
+ c270_intf = intf_nb;
+ c270_device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*virtual*/ bool USBHostC270::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+ C270_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir);
+ return false;
+}
+
+USB_TYPE USBHostC270::setInterfaceAlternate(uint8_t intf, uint8_t alt)
+{
+ C270_DBG("intf:%d, alt:%d", intf, alt);
+ return host->controlWrite(dev, USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE,
+ SET_INTERFACE, alt, intf, NULL, 0);
+}
+
+USB_TYPE USBHostC270::Control(int req, int cs, int index, uint8_t* buf, int size)
+{
+ C270_DBG("req:%d,cs:%d,index:%d", req, cs,index);
+ 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);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBHostC270.h Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,105 @@
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "BaseUvc.h"
+
+#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 1
+
+// --- UVC --------------------------------------------------
+#define _30FPS 333333
+#define _25FPS 400000
+#define _20FPS 500000
+#define _15FPS 666666
+#define _10FPS 1000000
+#define _5FPS 2000000
+#define _1FPS 10000000
+
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define GET_MIN 0x82
+#define GET_MAX 0x83
+#define GET_RES 0x84
+#define GET_LEN 0x85
+#define GET_INFO 0x86
+#define GET_DEF 0x87
+
+#define VS_PROBE_CONTROL 0x01
+#define VS_COMMIT_CONTROL 0x02
+
+#define C270_DEBUG 1
+#ifdef C270_DEBUG
+#define C270_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
+#else
+#define C270_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);};
+
+class IsochronousEp;
+class BaseUvc;
+/**
+ * A class to communicate a C270
+ */
+class USBHostC270 : public IUSBEnumerator, public BaseUvc {
+public:
+ /**
+ * Constructor
+ *
+ */
+ USBHostC270(int formatIndex = C270_MJPEG, int frameIndex = C270_160x120, uint32_t interval = _5FPS);
+
+ /**
+ * Check if a C270 device is connected
+ *
+ * @return true if a MSD device is connected
+ */
+ bool connected();
+
+ /**
+ * Try to connect to a C270 device
+ *
+ * @return true if connection was successful
+ */
+ bool connect();
+
+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;
+
+ int c270_intf;
+ bool c270_device_found;
+ bool c270_vid_pid_found;
+ int _formatIndex;
+ int _frameIndex;
+ uint32_t _interval;
+
+ void init();
+ USB_TYPE setInterfaceAlternate(uint8_t intf, uint8_t alt);
+ USB_TYPE Control(int req, int cs, int index, uint8_t* buf, int size);
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/decodeMJPEG/decodeMJPEG.cpp Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,180 @@
+// decodeMJPEG.cpp 2012/12/8
+// decode motion-jpeg to jpeg
+#include "mbed.h"
+#include "decodeMJPEG.h"
+
+#define MARK_SOF0 0xc0
+#define MARK_DHT 0xc4
+#define MARK_RST0 0xd0
+#define MARK_RST7 0xd7
+#define MARK_SOI 0xd8
+#define MARK_EOI 0xd9
+#define MARK_SOS 0xda
+#define MARK_DQT 0xdb
+#define MARK_DRI 0xdd
+#define MARK_APP 0xe0
+
+#define SEQ_INIT 0
+#define SEQ_SOI 1
+#define SEQ_FRAME 2
+#define SEQ_MARK 3
+#define SEQ_SEG_LEN 4
+#define SEQ_SEG_LEN2 5
+#define SEQ_SEG_BODY 6
+#define SEQ_SOS 7
+#define SEQ_SOS2 8
+
+static const uint8_t dht[] = {
+0xFF,0xC4,0x01,0xA2,0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
+0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
+0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x10,0x00,
+0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D,0x01,
+0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,
+0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,
+0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,
+0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,
+0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
+0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,
+0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,0xE3,
+0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
+0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,
+0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,
+0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,
+0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,
+0x1A,0x26,0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,
+0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,
+0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,
+0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,
+0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
+0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,
+0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,
+0xF7,0xF8,0xF9,0xFA,
+};
+
+decodeMJPEG::decodeMJPEG()
+{
+ m_seq = SEQ_INIT;
+}
+
+void decodeMJPEG::inputPacket(const uint8_t* buf, int len)
+{
+ for(int i = 12; i < len; i++) {
+ input(buf[i]);
+ }
+}
+
+void decodeMJPEG::input(uint8_t c)
+{
+ switch(m_seq) {
+ case SEQ_INIT:
+ if (c == 0xff) {
+ m_seq = SEQ_SOI;
+ }
+ break;
+ case SEQ_SOI:
+ if (c == MARK_SOI) {
+ outputJPEG(0xff, JPEG_START); // start
+ outputJPEG(c);
+ m_bDHT = false;
+ m_seq = SEQ_FRAME;
+ } else {
+ m_seq = SEQ_INIT;
+ }
+ break;
+ case SEQ_FRAME:
+ if (c == 0xff) {
+ m_seq = SEQ_MARK;
+ } else {
+ m_seq = SEQ_INIT;
+ }
+ break;
+ case SEQ_MARK:
+ if (c == MARK_SOI || c == MARK_EOI || c == 0x00) {
+ m_seq = SEQ_INIT;
+ break;
+ }
+ m_mark = c;
+ m_seq = SEQ_SEG_LEN;
+ break;
+ case SEQ_SEG_LEN:
+ m_seg_len = c;
+ m_seq = SEQ_SEG_LEN2;
+ break;
+ case SEQ_SEG_LEN2:
+ m_seg_len <<= 8;
+ m_seg_len |= c;
+ m_seg_len -= 2;
+ m_seg_pos = 0;
+ m_seq = SEQ_SEG_BODY;
+ if (m_mark == MARK_SOS) {
+ if (m_bDHT == false) {
+ for(int i = 0; i < sizeof(dht); i++) {
+ outputJPEG(dht[i]);
+ }
+ }
+ m_output_desable = false;
+ } else if (m_mark == MARK_DHT) {
+ m_bDHT = true;
+ m_output_desable = false;
+ } else {
+ m_output_desable = false;
+ }
+ if (!m_output_desable) {
+ outputJPEG(0xff);
+ outputJPEG(m_mark);
+ outputJPEG((m_seg_len+2) >> 8);
+ outputJPEG((m_seg_len+2) & 0xff);
+ }
+ break;
+ case SEQ_SEG_BODY:
+ if (!m_output_desable) {
+ outputJPEG(c);
+ }
+ if (++m_seg_pos < m_seg_len) {
+ break;
+ }
+ if (m_mark == MARK_SOS) {
+ m_seq = SEQ_SOS;
+ break;
+ }
+ m_seq = SEQ_FRAME;
+ break;
+ case SEQ_SOS:
+ if (c == 0xff) {
+ m_seq = SEQ_SOS2;
+ break;
+ }
+ outputJPEG(c);
+ break;
+ case SEQ_SOS2:
+ if (c == 0x00) {
+ outputJPEG(0xff);
+ outputJPEG(0x00);
+ m_seq = SEQ_SOS;
+ break;
+ } else if (c >= MARK_RST0 && c <= MARK_RST7) {
+ outputJPEG(0xff);
+ outputJPEG(c);
+ m_seq = SEQ_SOS;
+ break;
+ } else if (c == MARK_EOI) {
+ outputJPEG(0xff);
+ outputJPEG(c, JPEG_END);
+ m_seq = SEQ_INIT;
+ break;
+ } else if (c == MARK_SOI) {
+ outputJPEG(0xff);
+ outputJPEG(c);
+ m_seq = SEQ_INIT;
+ break;
+ }
+ m_seq = SEQ_INIT;
+ break;
+ default:
+ m_seq = SEQ_INIT;
+ break;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/decodeMJPEG/decodeMJPEG.h Sat Mar 16 13:07:55 2013 +0000
@@ -0,0 +1,25 @@
+// decodeMJPEG.h 2012/12/9
+#ifndef DECODE_MJPEG_H
+#define DECODE_MJPEG_H
+
+#define JPEG_NONE 0
+#define JPEG_START 1
+#define JPEG_END 2
+#define JPEG_ERROR 3
+
+class decodeMJPEG {
+public:
+ decodeMJPEG();
+ void inputPacket(const uint8_t* buf, int len);
+ virtual void outputJPEG(uint8_t c, int status = JPEG_NONE) = 0;
+protected:
+ void input(uint8_t c);
+ int m_seq;
+ uint8_t m_mark;
+ uint16_t m_seg_pos;
+ uint16_t m_seg_len;
+ bool m_bDHT;
+ bool m_output_desable;
+};
+
+#endif // DECODE_MJPEG_H
--- a/main.cpp Thu Mar 14 14:23:42 2013 +0000
+++ b/main.cpp Sat Mar 16 13:07:55 2013 +0000
@@ -1,50 +1,135 @@
+// USBHostC270_HelloWorld/main.cpp
#include "mbed.h"
#include "USBHostMSD.h"
+#include "USBHostC270.h"
+#include "decodeMJPEG.h"
+#include "MyThread.h"
-DigitalOut led(LED1);
+#define IMAGE_BUF_SIZE (1024*3)
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1),led2(LED2),led3(LED3);
+
+struct ImageBuffer {
+ int pos;
+ uint8_t buf[IMAGE_BUF_SIZE];
+ void clear() { pos = 0; }
+ int size() { return pos; }
+ uint8_t get(int pos) { return buf[pos]; }
+ void put(uint8_t c) {
+ if (pos < sizeof(buf)) {
+ buf[pos++] = c;
+ }
+ }
+};
-void msd_task(void const *) {
-
- USBHostMSD msd("usb");
- int i = 0;
-
- while(1) {
-
- // try to connect a MSD device
- while(!msd.connect()) {
- Thread::wait(500);
+Mail<ImageBuffer, 1> mail_box;
+class captureJPEG : public MyThread, public decodeMJPEG {
+public:
+ captureJPEG(BaseUvc* cam) : m_cam(cam) {
+ m_buf = NULL;
+ m_cam->setOnResult(this, &captureJPEG::callback_motion_jpeg);
+ }
+private:
+ virtual void outputJPEG(uint8_t c, int status) {
+ if (m_buf == NULL && status == JPEG_START) {
+ m_buf = mail_box.alloc();
+ if (m_buf) {
+ m_buf->clear();
+ }
+ }
+ if (m_buf) {
+ m_buf->put(c);
+ if (status == JPEG_END) {
+ mail_box.put(m_buf);
+ m_buf = NULL;
+ led3 = !led3;
+ }
+ }
+ }
+
+ void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) {
+ inputPacket(buf, len);
+ led1 = buf[1]&1; // FID
+ if (buf[1]&2) { // EOF
+ led2 = !led2;
+ }
+ }
+
+ virtual void run() {
+ while(true) {
+ if (m_cam) {
+ m_cam->poll();
+ }
}
-
- // in a loop, append a file
- // if the device is disconnected, we try to connect it again
- while(1) {
-
- // append a file
- FILE * fp = fopen("/usb/test1.txt", "a");
-
- if (fp != NULL) {
- fprintf(fp, "Hello fun SD Card World: %d!\r\n", i++);
- printf("Goodbye World!\r\n");
- fclose(fp);
- } else {
- printf("FILE == NULL\r\n");
+ }
+ ImageBuffer* m_buf;
+ BaseUvc* m_cam;
+};
+
+int main() {
+ pc.baud(921600);
+ printf("%s\n", __FILE__);
+
+ USBHostMSD* msd = new USBHostMSD("usb");
+ while(!msd->connect()) {
+ Thread::wait(200);
+ }
+
+
+ USBHostC270* cam = new USBHostC270(C270_MJPEG, C270_160x120, _5FPS);
+ while(!cam->connect()) {
+ Thread::wait(200);
+ }
+
+ captureJPEG* capture = new captureJPEG(cam);
+ capture->set_stack(512);
+ capture->start();
+
+ Timer t;
+ t.reset();
+ t.start();
+ Timer interval_t;
+ interval_t.reset();
+ interval_t.start();
+ int shot = 0;
+ while(1) {
+ osEvent evt = mail_box.get();
+ if (evt.status == osEventMail) {
+ ImageBuffer *buf = reinterpret_cast<ImageBuffer*>(evt.value.p);
+ if (interval_t.read() > 10) {
+ char path[32];
+ snprintf(path, sizeof(path), "/usb/image%02d.jpg", shot % 100);
+ printf("%d %s %d bytes\n", shot, path, buf->size());
+ if (msd->connected()) {
+ FILE* fp = fopen(path, "wb");
+ if (fp) {
+ for(int i = 0; i < buf->size(); i++) {
+ fputc(buf->get(i), fp);
+ }
+ fclose(fp);
+ }
+ }
+ interval_t.reset();
+ shot++;
}
-
- Thread::wait(500);
-
- // if device disconnected, try to connect again
- if (!msd.connected())
- break;
+ mail_box.free(buf);
}
-
+ if (t.read() > 5) {
+ printf("captureJPEG stack used: %d/%d bytes\n", capture->stack_used(), capture->stack_size());
+ printf("CC:");
+ for(int i = 0; i < 16; i++) {
+ printf(" %u", cam->report_cc_count[i]);
+ }
+ printf("\nPS:");
+ for(int i = 0; i < 16; i++) {
+ printf(" %u", cam->report_ps_cc_count[i]);
+ }
+ printf("\n");
+ t.reset();
+ }
+ if (!msd->connected()) {
+ msd->connect();
+ }
}
}
-
-
-int main() {
- Thread msdTask(msd_task, NULL, osPriorityNormal, 1024 * 4);
- while(1) {
- led=!led;
- Thread::wait(500);
- }
-}
\ No newline at end of file
