LogitechC270 webcam class driver alpha version

Dependencies:   USBHost mbed

Fork of USBHostMSD_HelloWorld by Samuel Mokrani

Files at this revision

API Documentation at this revision

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

MyThread/MyThread.h Show annotated file Show diff for this revision Revisions of this file
USBHost.lib Show annotated file Show diff for this revision Revisions of this file
USBHostC270/BaseUvc.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/BaseUvc.h Show annotated file Show diff for this revision Revisions of this file
USBHostC270/USBHostC270.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/USBHostC270.h Show annotated file Show diff for this revision Revisions of this file
USBHostC270/decodeMJPEG/decodeMJPEG.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/decodeMJPEG/decodeMJPEG.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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