
Simple USBHost WebCam test program
Dependencies: F401RE-USBHost mbed
Fork of KL46Z-USBHostC270_example by
WebカメラからJPEG画像を読み取るテストプログラムです。
使い方はKL46Z-USBHostC270_exampleと同じです。
動作確認カメラ: Logitech C270, Logitech C210, Logitech Q200R(Qcam Orbit AF), LifeCam VX-500
Revision 0:a72d9b047d8d, committed 2014-01-27
- Comitter:
- va009039
- Date:
- Mon Jan 27 11:07:34 2014 +0000
- Child:
- 1:22304b8f8395
- Commit message:
- first commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KL46Z-USBHost.lib Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/va009039/code/KL46Z-USBHost/#10bfc10afcc8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KL46Z-USBHostC270/BaseUvc.cpp Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,56 @@ +// BaseUvc.cpp +#include "USBHostConf.h" +#include "USBHost.h" +//#include "USBIsochronous.h" +#include "BaseUvc.h" + +void BaseUvc::poll() +{ + uint8_t buf[ep_iso_in.getSize()]; + int result = host->IsochronousRead(&ep_iso_in, buf, sizeof(buf)); + if (result >= 0) { + uint16_t frame = 0; + onResult(frame, buf, result); + } +} + +USB_TYPE BaseUvc::Control(int req, int cs, int index, uint8_t* buf, int size) +{ + if (req == SET_CUR) { + return host->controlWrite(dev, + USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, + req, cs<<8, index, buf, size); + } + return host->controlRead(dev, + USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, + req, cs<<8, index, buf, size); +} + +USB_TYPE BaseUvc::setInterfaceAlternate(uint8_t intf, uint8_t alt) +{ + return host->controlWrite(dev, USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, + SET_INTERFACE, alt, intf, NULL, 0); +} + +void BaseUvc::onResult(uint16_t frame, uint8_t* buf, int len) +{ + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(frame, buf, len); + else if(m_pCb) + m_pCb(frame, buf, len); +} + +void BaseUvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) ) +{ + m_pCb = pMethod; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void BaseUvc::clearOnResult() +{ + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KL46Z-USBHostC270/BaseUvc.h Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,51 @@ +// BaseUvc.h +//#include "USBIsochronous.h" +#pragma once + +// --- 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 + +class BaseUvc { +public: + void poll(); + USB_TYPE Control(int req, int cs, int index, uint8_t* buf, int size); + USB_TYPE setInterfaceAlternate(uint8_t intf, uint8_t alt); + //IsochronousEp* m_isoEp; + // 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); +protected: + USBHost * host; + USBDeviceConnected * dev; // dummy + USBEndpoint ep_iso_in; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KL46Z-USBHostC270/USBHostC270.cpp Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,77 @@ +#include "USBHostC270.h" +//#include "dbg.h" + +#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 + +USBHostC270::USBHostC270(int formatIndex, int frameIndex, uint32_t interval) { + _formatIndex = formatIndex; + _frameIndex = frameIndex; + _interval = interval; + clearOnResult(); + host = USBHost::getHostInst(); + report = &host->report; + setup(); +} + +void USBHostC270::setup() { + ep_iso_in.setAddress(C270_EN); + ep_iso_in.setSize(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"); + } +} + +#define SEQ_READ_IDOL 0 +#define SEQ_READ_EXEC 1 +#define SEQ_READ_DONE 2 + +int USBHostC270::readJPEG(uint8_t* buf, int size, int timeout_ms) { + _buf = buf; + _pos = 0; + _size = size; + _seq = SEQ_READ_IDOL; + setOnResult(this, &USBHostC270::callback_motion_jpeg); + Timer timeout_t; + timeout_t.reset(); + timeout_t.start(); + while(timeout_t.read_ms() < timeout_ms && _seq != SEQ_READ_DONE) { + poll(); + } + return _pos; +} + +/* virtual */ void USBHostC270::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 USBHostC270::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/KL46Z-USBHostC270/USBHostC270.h Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,57 @@ +// Simple USBHost Logtigech C270 for FRDM-KL46Z +#include "USBHost.h" +#include "BaseUvc.h" +#include "decodeMJPEG.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 1 + +class USBHostC270 : public BaseUvc, public decodeMJPEG { +public: + USBHostC270(int formatIndex = C270_MJPEG, int frameIndex = C270_160x120, uint32_t interval = _5FPS); + /** + * 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); + + Report* report; + +private: + int _formatIndex; + int _frameIndex; + uint32_t _interval; + uint8_t _seq; + uint8_t* _buf; + int _pos; + int _size; + + void setup(); + virtual void outputJPEG(uint8_t c, int status); // from decodeMJPEG + void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len); +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KL46Z-USBHostC270/decodeMJPEG.cpp Mon Jan 27 11:07:34 2014 +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/KL46Z-USBHostC270/decodeMJPEG.h Mon Jan 27 11:07:34 2014 +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,79 @@ +#include "USBHostC270.h" +RawSerial pc(USBTX, USBRX); +DigitalOut led1(LED_GREEN); +DigitalOut led2(LED_RED); +#define LED_OFF 1 +#define LED_ON 0 + +#if defined(TARGET_KL46Z) +uint8_t image_buf[1024*24]; +#elif defined(TARGET_KL25Z) +uint8_t image_buf[1024*12]; +#endif + +int main() { + pc.baud(9600); + led1 = led2 = LED_OFF; + + // Logitech C270 + USBHostC270* cam = new USBHostC270(C270_MJPEG, C270_320x240, _5FPS); + + int pos = 0; + int size = 0; + Timer t; + for(int seq = 0;;) { + int c = -1; + if (pc.readable()) { + c = pc.getc(); + } + switch(seq) { + case 0: + pc.printf("\nReady, please download JPEG using XMODEM from FRDM-KL46Z.\n"); + t.start(); + seq++; + break; + case 1: + if (c == 0x15) { // NAK + size = cam->readJPEG(image_buf, sizeof(image_buf)); + pos = 0; + seq++; + } + break; + case 2: + if (pos >= size) { + pc.putc(0x04); // EOT + } else { + pc.putc(0x01); // SOH + uint8_t block = pos/128 + 1; + pc.putc(block); + pc.putc(block ^ 0xff); + uint8_t checksum = 0x00; + for(int i = 0; i < 128; i++) { + uint8_t c = image_buf[pos + i]; + checksum += c; + pc.putc(c); + } + pc.putc(checksum); + } + seq++; + t.reset(); + led2 = !led2; + break; + case 3: + if (c == 0x06) { // ACK + if (pos >= size) { + seq = 0; + } else { + pos += 128; + seq--; + } + } + break; + } + if (t.read_ms() > 15*1000) { // timeout + t.reset(); + seq = 0; + } + cam->poll(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Jan 27 11:07:34 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/824293ae5e43 \ No newline at end of file