UVC host library
Dependents: LifeCam WebcamServer
Diff: uvc/uvc.cpp
- Revision:
- 0:b0f04c137829
diff -r 000000000000 -r b0f04c137829 uvc/uvc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uvc/uvc.cpp Tue Jul 31 13:58:03 2012 +0000 @@ -0,0 +1,264 @@ +#include "mbed.h" +#include "uvc.h" + +//#define __DEBUG +//#define __DEBUG3 +#include "mydbg.h" +#include "usb_itd.h" + +uvc::uvc(int cam) +{ + DBG("cam=%d\n", cam); + DBG_ASSERT(cam >= 0); + m_cam = cam; + m_init = false; + m_connect = false; + m_int_seq = 0; + m_iso_seq = 0; + m_width = 0; + m_height = 0; + m_payload = PAYLOAD_MJPEG; + m_FormatIndex = 0; + m_FrameIndex = 0; + m_FrameInterval = 0; + m_PacketSize = 0; + m_stream = NULL; + for(int i = 0; i <= 15; i++) { + ReportConditionCode[i] = 0; + } + clearOnResult(); +} + +uvc::~uvc() +{ + clearOnResult(); +} + +int uvc::setup() +{ + if (!m_init) { + return _init(); + } + return 0; +} + +int uvc::get_jpeg(const char* path) +{ + const int size = 4800; + const int timeout = 5000; + uint8_t* buf = new uint8_t[size]; + DBG_ASSERT(buf); + if (buf == NULL) { + return -1; + } + usb_mjpeg mjpeg(buf, size); + attach(&mjpeg); + Timer t; + t.reset(); + t.start(); + while(t.read_ms() < timeout) { + int stat = isochronous(); + if (mjpeg.status() >= 0) { + break; + } + } + detach(); + int len = mjpeg.status(); + if (len >= 0) { + if (path != NULL) { + FILE *fp = fopen(path, "wb"); + if (fp != NULL) { + for(int i = 0; i < len; i++) { + fputc(buf[i], fp); + } + fclose(fp); + } + } + } + delete[] buf; + return len; +} + +int uvc::get_jpeg(uint8_t* buf, int size) +{ + //DBG("buf=%p size=%d\n", buf, size); + const int timeout = 5000; + usb_mjpeg mjpeg(buf, size); + attach(&mjpeg); + Timer t; + t.reset(); + t.start(); + while(t.read_ms() < timeout) { + int stat = isochronous(); + if (mjpeg.status() >= 0) { + break; + } + } + detach(); + int len = mjpeg.status(); + return len; +} + +bool uvc::interrupt() +{ + if (!m_init) { + _init(); + } + if (m_int_seq == 0) { + int rc = m_pEpIntIn->transfer(m_int_buf, sizeof(m_int_buf)); + if (rc != USBERR_PROCESSING) { + return false; + } + m_int_seq++; + } + int len = m_pEpIntIn->status(); + if (len > 0) { + m_int_seq = 0; + DBG_BYTES("interrupt", m_int_buf, len); + return true; + } + return false; +} + +#define CC_NOERROR 0x0 +#define CC_DATAOVERRUN 0x8 +#define CC_DATAUNDERRUN 0x9 + +inline void DI() +{ + NVIC_DisableIRQ(USB_IRQn); +} + +inline void EI() +{ + NVIC_EnableIRQ(USB_IRQn); +} + +int uvc::isochronous() +{ + if (m_iso_seq == 0) { + uint16_t frame = LPC_USB->HcFmNumber; + m_iso_frame = frame + 10; // 10msec + DBG_ASSERT(m_pEpIsoIn->m_itdActive == 0); + m_iso_seq++; + } + if (m_iso_seq == 1) { + DBG_ASSERT(m_itdCount > 0 && m_itdCount <= 8); + while(m_pEpIsoIn->m_itdActive < m_itdCount) { + int len = m_PacketSize * m_FrameCount; + uint8_t* buf = (uint8_t*)usb_get_bp(len); + if (buf == NULL) { + DBG("len=%d\n", len); + DBG("m_itdCount=%d\n", m_itdCount); + } + DBG_ASSERT(buf); + int rc = m_pEpIsoIn->transfer(m_iso_frame, m_FrameCount, buf, len); + m_iso_frame += m_FrameCount; + DBG_ASSERT(rc == USBERR_PROCESSING); + } + m_iso_seq++; + } + if (m_iso_seq == 2) { + //DBG("frame:%04X\n", LPC_USB->HcFmNumber); + while(1) { + DI(); + bool empty = m_pEpIsoIn->queue_done_itd.empty(); + EI(); + + if (empty) { + break; + } + + DI(); + HCITD* itd = m_pEpIsoIn->queue_done_itd.front(); + m_pEpIsoIn->queue_done_itd.pop(); + EI(); + + m_pEpIsoIn->m_itdActive--; + usb_itd iso_td(itd); + //DBG("frame:%04X\n", LPC_USB->HcFmNumber); + //DBG("itd->Control=%08X\n", itd->Control); + int cc = iso_td.ConditionCode(); + DBG_ASSERT(cc >= 0 && cc <= 15); + ReportConditionCode[cc]++; + if (cc != CC_NOERROR) { + DBG3("%04X ERR:%X\n", LPC_USB->HcFmNumber, cc); + iso_td.free(); + m_iso_seq = 3; + return -1; + } + uint16_t frame = iso_td.StartingFrame(); + int fc = iso_td.FrameCount(); + for(int i = 0; i < fc; i++) { + int len = iso_td.Length(i); + if (len > 0) { + if (m_stream) { + m_stream->input(frame+i, iso_td.BufferPage(i, m_PacketSize), len); + } + onResult(frame+i, iso_td.BufferPage(i, m_PacketSize), len); + } + } + iso_td.free(); + } + //DBG("frame:%04X\n", LPC_USB->HcFmNumber); + m_iso_seq = 1; + return m_pEpIsoIn->m_itdActive; + } + if (m_iso_seq == 3) { // cleanup + DBG("m_pEpIsoIn->queue_done_itd.size() :%d\n", m_pEpIsoIn->queue_done_itd.size()); + while(1) { + DI(); + bool empty = m_pEpIsoIn->queue_done_itd.empty(); + EI(); + + if (empty) { + break; + } + + DI(); + HCITD* itd = m_pEpIsoIn->queue_done_itd.front(); + m_pEpIsoIn->queue_done_itd.pop(); + EI(); + + m_pEpIsoIn->m_itdActive--; + usb_itd iso_td(itd); + iso_td.free(); + } + if (m_pEpIsoIn->m_itdActive == 0) { + m_iso_seq = 0; + } + } + return m_pEpIsoIn->m_itdActive; +} + +void uvc::attach(usb_stream* stream) +{ + m_stream = stream; +} + +void uvc::detach() +{ + m_stream = NULL; +} + +void uvc::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 uvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) ) +{ + m_pCb = pMethod; + m_pCbItem = NULL; + m_pCbMeth = NULL; +} + +void uvc::clearOnResult() +{ + m_pCb = NULL; + m_pCbItem = NULL; + m_pCbMeth = NULL; +}