Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FatFileSystem TB6612FNG2 mbed
uvc/uvccfg.cpp
- Committer:
- mbed_Cookbook_SE
- Date:
- 2015-11-30
- Revision:
- 0:de03cbbcd0ff
File content as of revision 0:de03cbbcd0ff:
#include "mbed.h"
#include "uvc.h"
#define __DEBUG
#include "mydbg.h"
#include "stcamcfg.h"
#include "Utils.h"
#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 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
void _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 _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 _parserVideoControl(uint8_t* buf, int len) {
int subtype = buf[2];
IF_EQ_THEN_PRINTF(VC_HEADER, subtype)
VERBOSE("UVC: %04x\n", LE16(buf+3));
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 _parserVideoStream(struct stcamcfg* cfg, 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++;
}
cfg->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 (cfg->payload == PAYLOAD_YUY2) {
cfg->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 (cfg->payload == PAYLOAD_YUY2) {
if (cfg->width == LE16(buf+5) && cfg->height == LE16(buf+7)) {
cfg->FrameIndex = buf[3];
}
if (cfg->dwFrameInterval == 0) {
cfg->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 (cfg->payload == PAYLOAD_MJPEG) {
cfg->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 (cfg->payload == PAYLOAD_MJPEG) {
if (cfg->width == LE16(buf+5) && cfg->height == LE16(buf+7)) {
cfg->FrameIndex = buf[3];
}
if (cfg->dwFrameInterval == 0) {
cfg->dwFrameInterval = max_fi;
}
}
ENDIF
IF_EQ_THEN_PRINTF(VS_COLOR_FORMAT, subtype)
ENDIF
}
void _parserConfigurationDescriptor(struct stcamcfg* cfg, uint8_t* buf, int len) {
//DBG("buf=%p len=%d\n", buf, len);
//DBG_HEX(buf, len);
int pos = 0;
cfg->_IfClass = 0;
cfg->_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]);
cfg->_If = buf[pos+2];
cfg->_Ifalt = buf[pos+3];
cfg->_IfClass = buf[pos+5];
cfg->_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 (cfg->_IfClass == CC_VIDEO && cfg->_IfSubClass == SC_VIDEOSTREAMING) {
if (cfg->bEndpointAddress == buf[pos+2]) {
if (cfg->wMaxPacketSize == 0) {
cfg->wMaxPacketSize = LE16(buf+pos+4);
}
if (cfg->wMaxPacketSize == LE16(buf+pos+4)) {
cfg->bInterface = cfg->_If;
cfg->bAlternate = cfg->_Ifalt;
}
}
}
ENDIF
IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CS_INTERFACE, type)
IF_EQ_THEN_PRINTF(CC_VIDEO, cfg->_IfClass)
IF_EQ_THEN_PRINTF(SC_VIDEOCONTROL, cfg->_IfSubClass)
_parserVideoControl(buf+pos, buf[pos]);
ENDIF
IF_EQ_THEN_PRINTF(SC_VIDEOSTREAMING, cfg->_IfSubClass)
_parserVideoStream(cfg, buf+pos, buf[pos]);
ENDIF
ENDIF
if (cfg->_IfClass == CLASS_AUDIO) {
if (cfg->_IfSubClass == 0x01) {
_parserAudioControl(buf+pos, buf[pos]);
} else if (cfg->_IfSubClass == 0x02) {
_parserAudioStream(buf+pos, buf[pos]);
}
}
ENDIF
IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_HUB, type)
ENDIF
pos += buf[pos];
}
}
void uvc::_config(struct stcamcfg* cfg)
{
DBG_ASSERT(cfg);
int index = 0;
uint8_t temp[4];
int rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, temp, sizeof(temp));
DBG_ASSERT(rc == USBERR_OK);
DBG_BYTES("Config Descriptor 4bytes", temp, sizeof(temp));
DBG_ASSERT(temp[0] == 9);
DBG_ASSERT(temp[1] == 0x02);
int TotalLength = LE16(temp+2);
DBG("TotalLength: %d\n", TotalLength);
uint8_t* buf = new uint8_t[TotalLength];
DBG_ASSERT(buf);
rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index,
buf, TotalLength);
DBG_ASSERT(rc == USBERR_OK);
_parserConfigurationDescriptor(cfg, buf, TotalLength);
DBG("cfg->FrameIndex=%d\n", cfg->FrameIndex);
DBG("cfg->dwFrameInterval=%u\n", cfg->dwFrameInterval);
//DBG_ASSERT(cfg->FormatIndex >= 1);
//DBG_ASSERT(cfg->FormatIndex <= 2);
//DBG_ASSERT(cfg->FrameIndex >= 1);
//DBG_ASSERT(cfg->FrameIndex <= 6);
delete[] buf;
}