UVC host library
Dependents: LifeCam WebcamServer
Diff: uvc/uvcini.cpp
- 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); +}