UVC host library

Dependents:   LifeCam WebcamServer

Revision:
0:b0f04c137829
Child:
2:812d604caad4
diff -r 000000000000 -r b0f04c137829 uvc/uvcini.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvcini.cpp	Tue Jul 31 13:58:03 2012 +0000
@@ -0,0 +1,325 @@
+#include "mbed.h"
+#include "uvc.h"
+#define __DEBUG
+#include "mydbg.h"
+#include "stcamcfg.h"
+
+#define UNDEF_VAL  (0)
+const struct stcamcfg stcamcfg_table[] = {
+/*
+{0x045e, 0x074a, "Microsoft LifeCam VX-700",
+160,120, PAYLOAD_MJPEG,
+0x81, 128,
+1, 5, 2000000, // 160x120 5.0fps
+1, 1, 
+8, 3,
+},*/
+/*
+{0x0c45, 0x62c0, "UVCA130AF",
+160,120, PAYLOAD_MJPEG,
+0x81, 128,
+1, 5, 2000000, // 160x120 5.0fps
+1, 1, 
+8, 3,
+},*/
+
+{0x046d, 0x0994, "Logitech QuickCam Orbit AF",
+160,120, PAYLOAD_MJPEG,
+UNDEF_VAL, UNDEF_VAL,
+UNDEF_VAL, UNDEF_VAL, 2000000, // 160x120 10.0fps
+UNDEF_VAL, UNDEF_VAL, 
+UNDEF_VAL, 3,
+},
+{0x0000, 0x0000, "default",
+160,120, PAYLOAD_MJPEG,
+UNDEF_VAL, UNDEF_VAL,
+UNDEF_VAL, UNDEF_VAL, 2000000,
+UNDEF_VAL, UNDEF_VAL, 
+UNDEF_VAL, 3,
+},
+};
+
+inline void LE32(uint32_t n, uint8_t* d)
+{
+    d[0] = (uint8_t)n;
+    d[1] = (uint8_t)(n >> 8);
+    d[2] = (uint8_t)(n >> 16);
+    d[3] = (uint8_t)(n >> 24);
+}
+
+void uvc::SetFormatIndex(int index)
+{
+    DBG_ASSERT(index >= 1);
+    DBG_ASSERT(index <= 2);
+    m_FormatIndex = index;
+}
+
+void uvc::SetFrameIndex(int index)
+{
+    DBG_ASSERT(index >= 1);
+    DBG_ASSERT(index <= 8);
+    m_FrameIndex = index;
+}
+
+void uvc::SetFrameInterval(int val)
+{
+    DBG_ASSERT(val >= 333333);
+    DBG_ASSERT(val <= 10000000);
+    m_FrameInterval = val;
+}
+
+void uvc::SetPacketSize(int size)
+{
+    DBG_ASSERT(size >= 128);
+    DBG_ASSERT(size <= 1024);
+    m_PacketSize = size;
+}
+
+void uvc::SetImageSize(int width, int height)
+{
+    DBG_ASSERT(width >= 160);
+    DBG_ASSERT(width <= 800);
+    DBG_ASSERT(height >= 120);
+    DBG_ASSERT(height <= 600);
+    m_width = width;
+    m_height = height;
+}
+
+void uvc::SetPayload(int payload)
+{
+    DBG_ASSERT(payload == PAYLOAD_MJPEG || payload == PAYLOAD_YUY2);
+    m_payload = payload;
+}
+
+void uvc::poll()
+{
+    isochronous();
+}
+
+int uvc::_init()
+{
+    m_init = true;
+    UsbErr rc;
+    for(int i = 0; i < 2; i++) {
+        m_pDev = m_pHost->getDeviceByClass(CLASS_VIDEO, m_cam); // UVC
+        if (m_pDev || i > 0) {
+            break;
+        }
+        rc = Usb_poll();
+        if (rc == USBERR_PROCESSING) {
+            VERBOSE("%p USBERR_PROCESSING\n", this);
+            return -1;
+        }
+    }
+    DBG("m_pDev=%p\n", m_pDev);
+    if (!m_pDev) {
+        VERBOSE("%p UVC CAMERA(%d) NOT FOUND\n", this, m_cam);
+        return -1;
+    }
+    DBG_ASSERT(m_pDev);
+    
+    struct stcamcfg cfg;
+    for(int i = 0; ; i++) {
+        cfg = stcamcfg_table[i];
+        if (cfg.idVender == 0x0000) {
+            DBG("not cam config\n");
+            DBG("vid: %04X\n", m_pDev->getVid());
+            DBG("pid: %04X\n", m_pDev->getPid());
+            break;
+        }
+        if (cfg.idVender == m_pDev->getVid() && cfg.idProduct ==  m_pDev->getPid()) {
+            DBG_ASSERT(cfg.name);
+            DBG("found %s\n", cfg.name);
+            break;
+        }
+    }
+
+    if (m_width) {
+        cfg.width = m_width;
+    }
+    if (m_height) {
+        cfg.height = m_height;
+    }
+    if (m_payload != PAYLOAD_UNDEF) {
+        cfg.payload = m_payload;
+    }
+    if (m_FormatIndex) {
+        cfg.FormatIndex = m_FormatIndex;
+    }
+    if (m_FrameIndex) {
+        cfg.FrameIndex = m_FrameIndex;
+    }
+    if (m_FrameInterval) {
+        cfg.dwFrameInterval = m_FrameInterval;
+    }
+    if (m_PacketSize) {
+        cfg.wMaxPacketSize = m_PacketSize;
+    }
+
+    _config(&cfg);
+
+    if (cfg.FormatIndex == UNDEF_VAL) {
+        if (cfg.payload == PAYLOAD_MJPEG) {
+            VERBOSE("MJPG(Motion JPEG) FORMAT NOT FOUND\n");
+        } else if (cfg.payload == PAYLOAD_YUY2) {
+            VERBOSE("YUY2 FORMAT NOT FOUND\n");
+        } else {
+            VERBOSE("??? FORMAT NOT FOUND\n");
+        }
+        return -1;
+    }
+
+    if (cfg.bInterface == UNDEF_VAL) {
+        VERBOSE("PacketSize(%d) CONFIG ERROR\n", cfg.wMaxPacketSize);
+        return -1;
+    }
+
+    if (cfg.iso_FrameCount == 0) {
+        int c = usb_bp_size() / cfg.wMaxPacketSize;
+        if (c > 8) {
+            c = 8;
+        }
+        cfg.iso_FrameCount = c; 
+    }
+    DBG_ASSERT(cfg.iso_FrameCount >= 1);
+    DBG_ASSERT(cfg.iso_FrameCount <= 8);
+    DBG_ASSERT((cfg.iso_FrameCount * cfg.wMaxPacketSize) <= usb_bp_size());
+    if (cfg.iso_itdCount == 0) {
+        cfg.iso_itdCount = 3;
+    }
+    DBG_ASSERT(cfg.iso_itdCount >= 1);
+    DBG("cfg.wMaxPacketSize=%d\n", cfg.wMaxPacketSize);
+    DBG("cfg.iso_FrameCount=%d\n", cfg.iso_FrameCount);
+    DBG("cfg.iso_itdCount=%d\n", cfg.iso_itdCount);
+    DBG_ASSERT(cfg.iso_FrameCount >= 1 && cfg.iso_FrameCount <= 8);
+    //m_pEpIntIn = new UsbEndpoint(m_pDev, 0x83, true, USB_INT, 16);
+    //DBG_ASSERT(m_pEpIntIn);
+    
+    DBG_ASSERT(cfg.bEndpointAddress & 0x80);
+    DBG_ASSERT(cfg.wMaxPacketSize >= 128);
+    DBG_ASSERT(cfg.wMaxPacketSize <= 1020);
+    m_PacketSize = cfg.wMaxPacketSize;
+    
+    DBG_ASSERT(m_PacketSize); 
+    m_pEpIsoIn = new UsbEndpoint(m_pDev, cfg.bEndpointAddress, true, USB_ISO, m_PacketSize);
+    DBG_ASSERT(m_pEpIsoIn);
+
+    DBG_ASSERT(cfg.FormatIndex >= 1);
+    DBG_ASSERT(cfg.FormatIndex <= 2);
+    DBG_ASSERT(cfg.FrameIndex >= 1);
+    DBG_ASSERT(cfg.FrameIndex <= 8);
+    DBG_ASSERT(cfg.dwFrameInterval <= 10000000);
+    DBG_ASSERT(cfg.dwFrameInterval >= 333333);
+
+    probe_commit_control(&cfg);
+
+    DBG("cfg.bInterface = %d, cfg.bAlternate = %d\n", cfg.bInterface, cfg.bAlternate);
+    //USBH_SET_INTERFACE(1, 1); // alt=1 size=128
+    DBG_ASSERT(cfg.bInterface >= 1); 
+    DBG_ASSERT(cfg.bAlternate >= 1);
+    DBG_ASSERT(cfg.bAlternate <= 7);
+    rc = m_pDev->SetInterfaceAlternate(cfg.bInterface, cfg.bAlternate);
+    DBG_ASSERT(rc == USBERR_OK);
+
+    DBG_ASSERT(cfg.iso_FrameCount >= 1);
+    DBG_ASSERT(cfg.iso_FrameCount <= 8);
+    m_FrameCount = cfg.iso_FrameCount;
+    
+    DBG_ASSERT(cfg.iso_itdCount >= 1);
+    DBG_ASSERT(cfg.iso_itdCount <= 8);
+    m_itdCount = cfg.iso_itdCount;
+    
+    LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
+    LPC_USB->HcControl |= OR_CONTROL_IE;  // IsochronousEnable
+
+    m_connect = true;
+    return 0;
+}
+
+static void dump_param(uint8_t* buf)
+{
+    VERBOSE("Hint: %04x\n", LE16(buf+0));
+    VERBOSE("FormatIndex: %d\n", buf[2]);
+    VERBOSE("FrameIndex: %d\n", buf[3]);
+    VERBOSE("FrameInterval: %d\n", LE32(buf+4));
+    VERBOSE("KeyFrameRate: %d\n", LE16(buf+8));
+    VERBOSE("PFrameRate: %d\n", LE16(buf+10));
+    VERBOSE("CompQuality: %d\n", LE16(buf+12));
+    VERBOSE("CompWindowSize: %d\n", LE16(buf+14));
+    VERBOSE("Delay: %d\n", LE16(buf+16));
+    VERBOSE("MaxVideoFrameSize: %d\n", LE32(buf+18));
+    VERBOSE("MaxPayloadTransferSize: %d\n", LE32(buf+22));
+}
+
+void uvc::probe_commit_control(struct stcamcfg* cfg)
+{
+    DBG_ASSERT(cfg);
+    uint8_t param[34];
+    uint8_t temp[34];
+
+    int param_len = 34;
+    DBG_ASSERT(cfg->bcdUVC >= 0x0100);
+    if (cfg->bcdUVC == 0x0100) { // UVC ver. 1.0
+        param_len = 26;
+    }
+
+    UsbErr rc;
+    rc = Control(GET_INFO, VS_PROBE_CONTROL, 1, param, 1);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_INFO Probe ", param, 1);
+
+    rc = Control(GET_DEF, VS_PROBE_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_DEF Probe ", temp, param_len);
+    dump_param(temp);
+    
+    rc = Control(GET_MIN, VS_PROBE_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_MIN Probe ", temp, param_len);
+    dump_param(temp);
+    
+    rc = Control(GET_MAX, VS_PROBE_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_MAX Probe ", temp, param_len);
+    dump_param(temp);
+    
+    rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Probe ", temp, param_len);
+    dump_param(temp);
+    
+    memset(param, 0x00, param_len);
+    param[2] = cfg->FormatIndex;
+    param[3] = cfg->FrameIndex; // 160x120
+    LE32(cfg->dwFrameInterval, param+4); // Frame Interval
+
+    DBG_BYTES("SET_CUR Probe ", param, param_len);
+    rc = Control(SET_CUR, VS_PROBE_CONTROL, 1, param, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+
+    rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Probe ", temp, param_len);
+
+    rc = Control(GET_INFO, VS_COMMIT_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_INFO Commit", temp, 1);
+
+    rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Commit", temp, param_len);
+    dump_param(temp);
+
+    DBG_BYTES("SET_CUR Commit", param, param_len);
+    dump_param(param);
+    rc = Control(SET_CUR, VS_COMMIT_CONTROL, 1, param, param_len);
+    if (rc != USBERR_OK) {
+        VERBOSE("Error SET_CUR VS_COMMIT_CONTROL\n");
+    }
+    DBG_ASSERT(rc == USBERR_OK);
+
+    rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, temp, param_len);
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Commit", temp, param_len);
+    dump_param(temp);
+}