LogitechC270 webcam class driver alpha version
Fork of USBHostMSD_HelloWorld 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