BaseJpegDeocde exampe program
Dependencies: BaseJpegDecode Terminal BaseUsbHost mbed mbed-rtos
Fork of BaseJpegDecode by
Diff: UvcCam/UvcCam.cpp
- Revision:
- 7:3ad9c948bc06
diff -r 95be1cd2bc14 -r 3ad9c948bc06 UvcCam/UvcCam.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UvcCam/UvcCam.cpp Sun Jan 27 11:15:26 2013 +0000 @@ -0,0 +1,566 @@ +// UvcCam.cpp 2013/1/25 +#include "mbed.h" +#include "rtos.h" +#include "BaseUsbHost.h" +//#define DEBUG +#include "BaseUsbHostDebug.h" +#define TEST +#include "BaseUsbHostTest.h" +#include "UvcCam.h" + +UvcCam::UvcCam(int formatIndex, int frameIndex, uint32_t interval, ControlEp* ctlEp) +{ + uint8_t buf[34]; + int rc; + int alt; + int cfg2; + + if (ctlEp == NULL) { // root hub + DBG_OHCI(LPC_USB->HcRhPortStatus1); + TEST_ASSERT_FALSE(LPC_USB->HcRhPortStatus1 & 0x200); + ctlEp = new ControlEp(); + TEST_ASSERT_TRUE(ctlEp); + } + bool r = check(ctlEp); + TEST_ASSERT(r); + m_ctlEp = ctlEp; + + UvcCfg* cfg = new UvcCfg(formatIndex, frameIndex, ctlEp); + TEST_ASSERT(cfg); + + int param_len = 34; + TEST_ASSERT(cfg->bcdUVC >= 0x0100); + if (cfg->bcdUVC == 0x0100) { // UVC ver. 1.0 + param_len = 26; + } + + int addr = m_ctlEp->GetAddr(); + m_isoEp = new IsochronousEp(addr, cfg->bEndpointAddress, cfg->wMaxPacketSize); + TEST_ASSERT_TRUE(m_isoEp); + +//#define USE_PROBE + +#ifdef USE_PROBE + rc = Control(GET_INFO, VS_PROBE_CONTROL, 1, buf, 1); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_INFO Prob", buf, 1); + + rc = Control(GET_DEF, VS_PROBE_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_DEF Probe", buf, param_len); + + rc = Control(GET_MIN, VS_PROBE_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_MIN Probe", buf, param_len); + + rc = Control(GET_MAX, VS_PROBE_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_MAX Probe", buf, param_len); + + rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_CUR Probe", buf, param_len); +#endif // USE_PROBE + + rc = Control(GET_INFO, VS_COMMIT_CONTROL, 1, buf, 1); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("GET_INFO Commit", buf, 1); + + memset(buf, 0, param_len); + buf[2] = cfg->FormatIndex; + buf[3] = cfg->FrameIndex; + *reinterpret_cast<uint32_t*>(buf+4) = interval; + + DBG_BYTES("SET_CUR Commit", buf, param_len); + rc = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + + rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, buf, param_len); + TEST_ASSERT(rc == USB_OK); + TEST_ASSERT_EQUAL(buf[2], cfg->FormatIndex); + TEST_ASSERT_EQUAL(buf[3], cfg->FrameIndex); + TEST_ASSERT_EQUAL(*reinterpret_cast<uint32_t*>(buf+4), interval); + DBG_BYTES("GET_CUR Commit", buf, param_len); + + rc = m_ctlEp->GetConfiguration(&cfg2); + TEST_ASSERT_EQUAL(rc, USB_OK); + DBG("config: %d\n", cfg2); + + rc = m_ctlEp->SetConfiguration(1); + TEST_ASSERT_EQUAL(rc, USB_OK); + + rc = m_ctlEp->GetConfiguration(&cfg2); + TEST_ASSERT_EQUAL(rc, USB_OK); + DBG("config: %d\n", cfg2); + TEST_ASSERT_EQUAL(cfg2, 1); + + rc = m_ctlEp->GetInterface(cfg->bInterface, &alt); + TEST_ASSERT_EQUAL(rc, USB_OK); + DBG("alt: %d\n", alt); + + rc = m_ctlEp->SetInterfaceAlternate(cfg->bInterface, cfg->bAlternate); + TEST_ASSERT_EQUAL(rc, USB_OK); + + rc = m_ctlEp->GetInterface(cfg->bInterface, &alt); + TEST_ASSERT_EQUAL(rc, USB_OK); + DBG("alt: %d\n", alt); + TEST_ASSERT_EQUAL(alt, cfg->bAlternate); + delete cfg; + + for(int i = 0; i < 16; i++) { + report_cc_count[i] = 0; + report_ps_cc_count[i] = 0; + } + + LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable + LPC_USB->HcControl |= OR_CONTROL_IE; // IsochronousEnable +} + +bool UvcCam::check(ControlEp* ctlEp) +{ + if (ctlEp == NULL) { + return false; + } + uint8_t buf[18]; + int r = ctlEp->GetDescriptor(1, 0, buf, 8); + if (r != USB_OK) { + return false; + } + DBG_HEX(buf, 8); + const uint8_t desc[] = {0x12,0x01,0x00,0x02,0xef,0x02,0x01}; + if (memcmp(buf, desc, sizeof(desc)) != 0) { + return false; + } + r = ctlEp->GetDescriptor(1, 0, buf, 18); + if (r != USB_OK) { + return false; + } + DBG_HEX(buf, 18); + return true; +} + +#define DESCRIPTOR_TYPE_DEVICE 1 +#define DESCRIPTOR_TYPE_CONFIGURATION 2 +#define DESCRIPTOR_TYPE_STRING 3 +#define DESCRIPTOR_TYPE_INTERFACE 4 +#define DESCRIPTOR_TYPE_ENDPOINT 5 + +#define DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0b + +#define DESCRIPTOR_TYPE_HID 0x21 +#define DESCRIPTOR_TYPE_REPORT 0x22 +#define DESCRIPTOR_TYPE_PHYSICAL 0x23 +#define DESCRIPTOR_TYPE_CS_INTERFACE 0x24 +#define DESCRIPTOR_TYPE_CS_ENDPOINT 0x25 +#define DESCRIPTOR_TYPE_HUB 0x29 + +#define CLASS_AUDIO 0x02 +#define CLASS_HUB 0x09 + +#define IF_EQ_THEN_PRINTF(A,B) if (A == B) {VERBOSE("%s\n", #A); +#define ENDIF } + +#define CC_AUDIO 0x01 +#define SC_AUDIOCONTROL 0x01 +#define SC_AUDIOSTREAMING 0x02 + +#define AC_HEADER 0x01 +#define AC_INPUT_TERMINAL 0x02 +#define AC_OUTPUT_TERMINAL 0x03 +#define AC_FEATURE_UNIT 0x06 + +// Input Terminal Types +#define ITT_CAMERA 0x0201 + +static int LE16(const uint8_t* d) +{ + return d[0] | (d[1] << 8); +} + +static int LE24(const uint8_t* d) { + return d[0] | (d[1]<<8) | (d[2] << 16); +} + +static int LE32(const uint8_t* d) { + return d[0] |(d[1]<<8) | (d[2] << 16) |(d[3] << 24) ; +} + +UvcCfg::UvcCfg(int formatIndex, int frameIndex, ControlEp* ctlEp):wMaxPacketSize(0) +{ + TEST_ASSERT(ctlEp); + switch(formatIndex) { + case UVC_MJPEG: _payload = UVC_MJPEG; break; + case UVC_YUY2: _payload = UVC_YUY2; break; + default: _payload = UVC_MJPEG; break; + } + + switch(frameIndex) { + case UVC_160x120: _width = 160; _height = 120; break; + case UVC_176x144: _width = 176; _height = 144; break; + case UVC_320x176: _width = 320; _height = 176; break; + case UVC_320x240: _width = 320; _height = 240; break; + case UVC_352x288: _width = 352; _height = 288; break; + case UVC_432x240: _width = 432; _height = 240; break; + case UVC_640x480: _width = 640; _height = 480; break; + case UVC_544x288: _width = 544; _height = 288; break; + case UVC_640x360: _width = 640; _height = 360; break; + case UVC_752x416: _width = 752; _height = 416; break; + case UVC_800x448: _width = 800; _height = 448; break; + case UVC_800x600: _width = 800; _height = 600; break; + default: _width = 160; _height = 120; break; + } + int index = 0; + uint8_t temp[4]; + int rc = ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, temp, sizeof(temp)); + TEST_ASSERT(rc == USB_OK); + DBG_BYTES("Config Descriptor 4bytes", temp, sizeof(temp)); + TEST_ASSERT(temp[0] == 9); + TEST_ASSERT(temp[1] == 0x02); + int TotalLength = LE16(temp+2); + DBG("TotalLength: %d\n", TotalLength); + + uint8_t* buf = new uint8_t[TotalLength]; + TEST_ASSERT(buf); + rc = ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, TotalLength); + TEST_ASSERT(rc == USB_OK); + if (rc != USB_OK) { + delete[] buf; + return; + } + _parserConfigurationDescriptor(buf, TotalLength); + delete[] buf; +} + +void UvcCfg::_parserAudioControl(uint8_t* buf, int len) { + int subtype = buf[2]; + IF_EQ_THEN_PRINTF(AC_HEADER, subtype) + VERBOSE("ADC: %04x\n", LE16(buf+3)); + VERBOSE("TotalLength: %d\n", LE16(buf+5)); + VERBOSE("InCollection: %d\n", buf[7]); + for (int n = 1; n <= buf[7]; n++) { + VERBOSE("aInterfaceNr(%d): %d\n", n, buf[8+n-1]); + } + ENDIF + IF_EQ_THEN_PRINTF(AC_INPUT_TERMINAL, subtype) + VERBOSE("TerminalID: %d\n", buf[3]); + VERBOSE("TerminalType: %04X\n", LE16(buf+4)); + VERBOSE("AssocTermianl: %d\n", buf[6]); + VERBOSE("NrChannels: %d\n", buf[7]); + ENDIF + IF_EQ_THEN_PRINTF(AC_OUTPUT_TERMINAL, subtype) + VERBOSE("TerminalID: %d\n", buf[3]); + VERBOSE("TerminalType: %04X\n", LE16(buf+4)); + VERBOSE("AssocTermianl: %d\n", buf[6]); + ENDIF + IF_EQ_THEN_PRINTF(AC_FEATURE_UNIT, subtype) + VERBOSE("UnitID: %d\n", buf[3]); + VERBOSE("SourceID: %d\n", buf[4]); + VERBOSE("ControlSize: %d\n", buf[5]); + ENDIF +} + +#define AS_GENERAL 0x01 +#define AS_FORMAT_TYPE 0x02 + +void UvcCfg::_parserAudioStream(uint8_t* buf, int len) { + int subtype = buf[2]; + IF_EQ_THEN_PRINTF(AS_GENERAL, subtype) + VERBOSE("TerminalLink: %d\n", buf[3]); + VERBOSE("Delay: %d\n", buf[4]); + VERBOSE("FormatTag: %04x\n", LE16(buf+5)); + ENDIF + IF_EQ_THEN_PRINTF(AS_FORMAT_TYPE, subtype) + VERBOSE("FormatType: %d\n", buf[3]); + VERBOSE("NrChannels: %d\n", buf[4]); + VERBOSE("SubFrameSize: %d\n", buf[5]); + VERBOSE("BitResolution: %d\n", buf[6]); + VERBOSE("SamFreqType: %d\n", buf[7]); + VERBOSE("SamFreq(1): %d\n", LE24(buf+8)); + ENDIF +} + +#define CC_VIDEO 0x0e + +#define SC_VIDEOCONTROL 0x01 +#define SC_VIDEOSTREAMING 0x02 + +#define VC_HEADER 0x01 +#define VC_INPUT_TERMINAL 0x02 +#define VC_OUTPUT_TERMINAL 0x03 +#define VC_SELECTOR_UNIT 0x04 +#define VC_PROCESSING_UNIT 0x05 +#define VC_EXTENSION_UNIT 0x06 + +void UvcCfg::_parserVideoControl(uint8_t* buf, int len) { + int subtype = buf[2]; + IF_EQ_THEN_PRINTF(VC_HEADER, subtype) + bcdUVC = LE16(buf+3); + VERBOSE("UVC: %04x\n", bcdUVC); + VERBOSE("TotalLength: %d\n", LE16(buf+5)); + VERBOSE("ClockFrequency: %d\n", LE32(buf+7)); + VERBOSE("InCollection: %d\n", buf[11]); + VERBOSE("aInterfaceNr(1): %d\n", buf[12]); + ENDIF + IF_EQ_THEN_PRINTF(VC_INPUT_TERMINAL, subtype) + VERBOSE("TerminalID: %d\n", buf[3]); + uint16_t tt = LE16(buf+4); + VERBOSE("TerminalType: %04X\n", tt); + VERBOSE("AssocTerminal: %d\n", buf[6]); + VERBOSE("Terminal: %d\n", buf[7]); + if (tt == ITT_CAMERA) { // camera + int bControlSize = buf[14]; + VERBOSE("ControlSize: %d\n", bControlSize); + for(int i = 0; i < bControlSize; i++) { + uint8_t bControls = buf[15+i]; + VERBOSE("Controls(%d): %02X\n", i, bControls); + } + } + ENDIF + IF_EQ_THEN_PRINTF(VC_OUTPUT_TERMINAL, subtype) + VERBOSE("TerminalID: %d\n", buf[3]); + VERBOSE("TerminalType: %04X\n", LE16(buf+4)); + VERBOSE("AssocTerminal: %d\n", buf[6]); + VERBOSE("SourceID: %d\n", buf[7]); + VERBOSE("Terminal: %d\n", buf[8]); + ENDIF + IF_EQ_THEN_PRINTF(VC_SELECTOR_UNIT, subtype) + VERBOSE("UnitID: %d\n", buf[3]); + ENDIF + IF_EQ_THEN_PRINTF(VC_PROCESSING_UNIT, subtype) + VERBOSE("UnitID: %d\n", buf[3]); + VERBOSE("SourceID: %d\n", buf[4]); + VERBOSE("MaxMultiplier: %d\n", LE16(buf+5)); + VERBOSE("ControlSize: %d\n", buf[7]); + int pos = 8; + for (int n = 1; n <= buf[7]; n++) { + VERBOSE("Controls(%d): %02X\n", n , buf[pos]); + pos++; + } + VERBOSE("Processing: %d\n", buf[pos]); + pos++; + VERBOSE("VideoStanders: %02X\n", buf[pos]); + ENDIF + IF_EQ_THEN_PRINTF(VC_EXTENSION_UNIT, subtype) + VERBOSE("UnitID: %d\n", buf[3]); + ENDIF +} + +#define VS_INPUT_HEADER 0x01 +#define VS_STILL_FRAME 0x03 +#define VS_FORMAT_UNCOMPRESSED 0x04 +#define VS_FRAME_UNCOMPRESSED 0x05 +#define VS_FORMAT_MJPEG 0x06 +#define VS_FRAME_MJPEG 0x07 +#define VS_COLOR_FORMAT 0x0d + +void UvcCfg::_parserVideoStream(uint8_t* buf, int len) { + int subtype = buf[2]; + IF_EQ_THEN_PRINTF(VS_INPUT_HEADER, subtype) + VERBOSE("NumFormats: %d\n", buf[3]); + VERBOSE("TotalLength: %d\n", LE16(buf+4)); + VERBOSE("EndpointAddress: %02X\n", buf[6]); + VERBOSE("Info: %02X\n", buf[7]); + VERBOSE("TerminalLink: %d\n", buf[8]); + VERBOSE("StillCaptureMethod: %d\n", buf[9]); + VERBOSE("TriggerSupport: %d\n", buf[10]); + VERBOSE("TriggerUsage: %d\n", buf[11]); + VERBOSE("ControlSize: %d\n", buf[12]); + int pos = 13; + for (int n = 1; n <= buf[12]; n++) { + VERBOSE("Controls(%d): %02X\n", n, buf[pos]); + pos++; + } + bEndpointAddress = buf[6]; + ENDIF + IF_EQ_THEN_PRINTF(VS_STILL_FRAME, subtype) + VERBOSE("EndpointAdress: %02X\n", buf[3]); + VERBOSE("NumImageSizePatterns: %d\n", buf[4]); + int ptn = buf[4]; + int pos = 5; + for (int n = 1; n <= ptn; n++) { + VERBOSE("Width(%d): %d\n", n, LE16(buf+pos)); + VERBOSE("Height(%d): %d\n", n, LE16(buf+pos+2)); + pos += 4; + } + VERBOSE("NumCompressPtn: %d\n", buf[pos]); + ptn = buf[pos++]; + for (int n = 1; n <= ptn; n++) { + VERBOSE("Compress(%d): %d\n", n, buf[pos]); + pos++; + } + ENDIF + IF_EQ_THEN_PRINTF(VS_FORMAT_UNCOMPRESSED, subtype) + VERBOSE("FormatIndex: %d\n", buf[3]); + VERBOSE("NumFrameDescriptors: %d\n", buf[4]); + uint32_t guid = LE32(buf+5); + if (guid == 0x32595559) { + VERBOSE("GUID: YUY2\n"); + } else if (guid == 0x3231564e) { + VERBOSE("GUID: NV12\n"); + } else { + VERBOSE("GUID: %08x\n", guid); + } + VERBOSE("DefaultFrameIndex: %d\n", buf[22]); + if (_payload == UVC_YUY2) { + FormatIndex = buf[3]; + } + ENDIF + IF_EQ_THEN_PRINTF(VS_FRAME_UNCOMPRESSED, subtype) + VERBOSE("FrameIndex: %d\n", buf[3]); + VERBOSE("Capabilites: %d\n", buf[4]); + VERBOSE("Width: %d\n", LE16(buf+5)); + VERBOSE("Height: %d\n", LE16(buf+7)); + VERBOSE("MinBitRate: %d\n", LE32(buf+9)); + VERBOSE("MaxBitRate: %d\n", LE32(buf+13)); + VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17)); + VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21)); + VERBOSE("FrameIntervalType: %d\n", buf[25]); + int it = buf[25]; + uint32_t max_fi = 333333; // 30.0fps + if (it == 0) { + VERBOSE("FrameMinInterval: %d\n", buf[26]); + VERBOSE("FrameMaxInterval: %d\n", buf[30]); + VERBOSE("FrameIntervalStep: %d\n", buf[34]); + } else { + int pos = 26; + for (int n = 1; n <= it; n++) { + uint32_t fi = LE32(buf+pos); + if (fi >= max_fi) { + max_fi = fi; + } + float fps = 1e+7 / fi; + VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps); + pos += 4; + } + } + if (_payload == UVC_YUY2) { + if (_width == LE16(buf+5) && _height == LE16(buf+7)) { + FrameIndex = buf[3]; + } + if (dwFrameInterval == 0) { + dwFrameInterval = max_fi; + } + } + ENDIF + IF_EQ_THEN_PRINTF(VS_FORMAT_MJPEG, subtype) + VERBOSE("FormatIndex: %d\n", buf[3]); + VERBOSE("NumFrameDescriptors: %d\n", buf[4]); + VERBOSE("Flags: %d\n", buf[5]); + VERBOSE("DefaultFrameIndex: %d\n", buf[6]); + if (_payload == UVC_MJPEG) { + FormatIndex = buf[3]; + } + ENDIF + IF_EQ_THEN_PRINTF(VS_FRAME_MJPEG, subtype) + VERBOSE("FrameIndex: %d\n", buf[3]); + VERBOSE("Capabilites: %d\n", buf[4]); + VERBOSE("Width: %d\n", LE16(buf+5)); + VERBOSE("Height: %d\n", LE16(buf+7)); + VERBOSE("MinBitRate: %d\n", LE32(buf+9)); + VERBOSE("MaxBitRate: %d\n", LE32(buf+13)); + VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17)); + VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21)); + VERBOSE("FrameIntervalType: %d\n", buf[25]); + int it = buf[25]; + uint32_t max_fi = 333333; // 30.0fps + if (it == 0) { + VERBOSE("FrameMinInterval: %d\n", buf[26]); + VERBOSE("FrameMaxInterval: %d\n", buf[30]); + VERBOSE("FrameIntervalStep: %d\n", buf[34]); + } else { + int pos = 26; + for (int n = 1; n <= it; n++) { + uint32_t fi = LE32(buf+pos); + if (fi >= max_fi) { + max_fi = fi; + } + float fps = 1e+7 / fi; + VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps); + pos += 4; + } + } + if (_payload == UVC_MJPEG) { + if (_width == LE16(buf+5) && _height == LE16(buf+7)) { + FrameIndex = buf[3]; + } + if (dwFrameInterval == 0) { + dwFrameInterval = max_fi; + } + } + ENDIF + IF_EQ_THEN_PRINTF(VS_COLOR_FORMAT, subtype) + ENDIF +} + +void UvcCfg::_parserConfigurationDescriptor(uint8_t* buf, int len) { + int pos = 0; + _IfClass = 0; + _IfSubClass = 0; + while (pos < len) { + int type = buf[pos+1]; + //DBG_BYTES(TYPE_Str(type), buf+pos, buf[pos]); + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CONFIGURATION, type) + VERBOSE("NumInterfaces: %d\n", buf[pos+4]); + ENDIF + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, type) + VERBOSE("FirstInterface: %d\n", buf[pos+2]); + VERBOSE("InterfaceCount: %d\n", buf[pos+3]); + VERBOSE("FunctionClass: %02X\n", buf[pos+4]); + VERBOSE("FunctionSubClass: %02X\n", buf[pos+5]); + VERBOSE("FunctionProtocol: %02X\n", buf[pos+6]); + VERBOSE("Function: %d\n", buf[pos+7]); + ENDIF + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE,type) + VERBOSE("InterfaceNumber: %d\n", buf[pos+2]); + VERBOSE("AlternateSetting: %d\n", buf[pos+3]); + VERBOSE("NumEndpoint: %d\n", buf[pos+4]); + VERBOSE("InterfaceClass: %02X\n", buf[pos+5]); + VERBOSE("InterfaceSubClass: %02X\n", buf[pos+6]); + VERBOSE("InterfaceProtocol: %02X\n", buf[pos+7]); + VERBOSE("Interface: %d\n", buf[pos+8]); + _If = buf[pos+2]; + _Ifalt = buf[pos+3]; + _IfClass = buf[pos+5]; + _IfSubClass = buf[pos+6]; + ENDIF + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_ENDPOINT, type) + VERBOSE("EndpointAddress: %02X\n", buf[pos+2]); + VERBOSE("Attributes: %02X\n", buf[pos+3]); + VERBOSE("MaxPacketSize: %d\n", LE16(buf+pos+4)); + VERBOSE("Interval: %d\n", buf[pos+6]); + if (_IfClass == CC_VIDEO && _IfSubClass == SC_VIDEOSTREAMING) { + if (bEndpointAddress == buf[pos+2]) { + if (wMaxPacketSize == 0) { + wMaxPacketSize = LE16(buf+pos+4); + } + if (wMaxPacketSize == LE16(buf+pos+4)) { + bInterface = _If; + bAlternate = _Ifalt; + } + } + } + ENDIF + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CS_INTERFACE, type) + IF_EQ_THEN_PRINTF(CC_VIDEO, _IfClass) + IF_EQ_THEN_PRINTF(SC_VIDEOCONTROL, _IfSubClass) + _parserVideoControl(buf+pos, buf[pos]); + ENDIF + IF_EQ_THEN_PRINTF(SC_VIDEOSTREAMING, _IfSubClass) + _parserVideoStream(buf+pos, buf[pos]); + ENDIF + ENDIF + IF_EQ_THEN_PRINTF(CC_AUDIO, _IfClass) + IF_EQ_THEN_PRINTF(SC_AUDIOCONTROL, _IfSubClass) + _parserAudioControl(buf+pos, buf[pos]); + ENDIF + IF_EQ_THEN_PRINTF(SC_AUDIOSTREAMING, _IfSubClass) + _parserAudioStream(buf+pos, buf[pos]); + ENDIF + ENDIF + ENDIF + IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_HUB, type) + ENDIF + pos += buf[pos]; + } +} +