UVC host library

Dependents:   LifeCam WebcamServer

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;
+}