USB 主机 UVC 相机 FTDI Vinculum-II 不读取视频流

问题描述

我已将最小程序提取到单个文件中,以演示我在较大程序上下文之外遇到的问题。在最高级别的描述中,USB 主机 (FTDI Vinculum-II) 连接到 UVC 相机,正确枚举设备接口、端点等,设置传输,但最终当它最终执行 vos_dev_read() (第 511 行),它没有错误地返回,并且读取了零字节。主机 -> UVC 摄像头 ioctl r/w 工作正常,从 UVC 摄像头(测试中使用了多个摄像头)检索的所有值都针对 USB 设备查看器的 USB 转储进行了正确验证。因此,双向对话运行良好,只是没有视频数据。如果我将值更改为无效值或拔下相机,我会得到预期的错误代码。

需要明确的是,这个衍生程序除了将读取的字节数写出到 UART 终端(9600 波特,无流量控制)之外,对读取的数据没有任何作用。底线;找到此程序的修复程序,同样适用于实际程序。

我知道会与有 Vinculum-II USB 2.0 芯片经验的人一起寻找独角兽,但我相信问题是 USB/UVC 问题,而不是芯片或它试图做什么的问题. UVC 的蜂巢思维比 FTDI 主机芯片稍大。我试图找到魔法咒语;我试过对着芯片大喊 4 个字母的单词,甚至很好地问,“请”无济于事。该代码最初源自 FTDI 的 WebCam 演示程序,该程序编写得很差,并且包含大量未描述的硬编码数字常量。

我查看了整个互联网上的每个 USB/UVC 驱动程序(主要是 Linux 和 Windows)。请致电所有 USB 主机专家寻求帮助。

谢谢!

...
#include "vos.h"
#include "USBHost.h"
#include "USB.h"
#include "UART.h"
#include "ioctl.h"
#include "stdio.h"

#define VOS_QUANTUM                 50
#define VOS_TICK_INTERVAL           1

#define NUMBER_OF_DEVICES           3
#define VOS_DEV_USBHOST             0
#define VOS_DEV_UVC                 1
#define VOS_DEV_UART                2

#define ISO_TRANSFER_SIZE   192
#define ISO_TRANSFER_COUNT  1
#define WEBCAM_HEADER_SIZE  12
#define WEBCAM_PAYLOAD_SIZE (ISO_TRANSFER_SIZE - WEBCAM_HEADER_SIZE)
#define BUF_SIZE            (ISO_TRANSFER_SIZE * ISO_TRANSFER_COUNT)

enum uvc_ret_e
{
    UVC_OK,UVC_INVALID_PARAMETER,UVC_NOT_FOUND,UVC_ERROR
};  

// configure request structure for VOS_IOCTL_UVC_CLASS_REQUEST
#define set_class_request(d,iface,ent,cs,code,len) \
    do \
    { \
        (d).bRequest = (code); \
        (d).wValue = ((cs) << 8); \
        (d).wIndex = (((ent) << 8) | (iface)); \
        (d).wLength = (len); \
    } \
    while (0)

// UVC ioctl parameter structure
typedef struct _uvc_ioctl_cb_t
{
    unsigned char ioctl_code;
    unsigned char *get;
    unsigned char *set;
} uvc_ioctl_cb_t;

typedef struct _uvc_context_t
{
    // host controller handle
    VOS_HANDLE                 hc;

    unsigned short             vid;
    unsigned short             pid;

    // endpoint handles
    usbhost_ep_handle_ex       epInt;
    usbhost_ep_handle_ex       epCtrl;
    usbhost_ep_handle_ex       epIsoIn;

    // endpoint info
    usbhost_ioctl_cb_ep_info_t epInfo;

    unsigned char              state;
} uvc_context_t;

typedef enum _VS_InterfaceControlStatus_e
{
    VS_CONTROL_UNDEFINED = 0x00,// 0x00
    VS_PROBE_CONTROL,// 0x01
    VS_COMMIT_CONTROL,// 0x02
    VS_STILL_PROBE_CONTROL,// 0x03
    VS_STILL_COMMIT_CONTROL,// 0x04
    VS_STILL_IMAGE_TRIGGER_CONTROL,// 0x05
    VS_STREAM_ERROR_CODE_CONTROL,// 0x06
    VS_GENERATE_KEY_FRAME_CONTROL,// 0x07
    VS_UPDATE_FRAME_SEGMENT_CONTROL,// 0x08
    VS_SYNCH_DELAY_CONTROL             // 0x09
} VS_InterfaceControlStatus_e;

typedef enum _VS_ControlRequest_e
{
    RC_UNDEFINED = 0x00,// 0x00
    SET_CUR,// 0x01
    GET_CUR = 0x81,// 0x81
    GET_MIN,// 0x82
    GET_MAX,// 0x83
    GET_RES,// 0x84
    GET_LEN,// 0x85
    GET_INFO,// 0x86
    GET_DEF                            // 0x87
} VS_ControlRequest_e;

typedef struct _VideoProbeAndCommiteControl_t
{
    unsigned short bmHint;
    unsigned char  bFormatIndex;
    unsigned char  bFrameIndex;
    unsigned int   dwFrameInterval;
    unsigned short wKeyFrameRate;
    unsigned short wPFrameRate;
    unsigned short wCompQuality;
    unsigned short wCompWindowSize;
    unsigned short wDelay;
    unsigned int   dwMaxVideoFrameSize;
    unsigned int   dwMaxPayloadTransferSize;
    unsigned int   dwClockFrequency;
    unsigned char  bmFramingInfo;
    unsigned char  bPreferedVersion;
    unsigned char  bMinVersion;
    unsigned char  bMaxVersion;
} VideoProbeAndCommiteControl_t;

// IOCTLS
#define VOS_IOCTL_UVC_ATTACH        1
#define VOS_IOCTL_UVC_DETACH        2
#define VOS_IOCTL_UVC_CLASS_REQUEST 3

unsigned char uvc_init(unsigned char vos_dev_num);
unsigned char uvc_ioctl(uvc_ioctl_cb_t *cb,uvc_context_t *ctx);
void uvc_open(uvc_context_t *ctx);
void uvc_close(uvc_context_t *ctx);
unsigned char uvc_read(char *buffer,unsigned short num_to_read,unsigned short *num_read,uvc_context_t *ctx);
unsigned char uvc_write(char *buffer,unsigned short num_to_write,unsigned short *num_written,uvc_context_t *ctx);

void setupUART(void);
void firmware(void);
void open_drivers(void);
void attach_drivers(void);

vos_tcb_t *tcbFIRMWARE;
VOS_HANDLE hUsbHost;
VOS_HANDLE hUvc;
VOS_HANDLE hUART;      
unsigned char buffer1[BUF_SIZE];
VideoProbeAndCommiteControl_t VProbeAndCom;     

void firmware(void)
{
    unsigned short iRead;
    unsigned char iStatus;
    unsigned int iLoopCnt = 0;
    uvc_ioctl_cb_t uvc_iocb;
    usb_deviceRequest_t desc_dev;
    unsigned char USBState;
    hUsbHost = vos_dev_open(VOS_DEV_USBHOST);
    hUvc = vos_dev_open(VOS_DEV_UVC);
    hUART = vos_dev_open(VOS_DEV_UART);
    
    setupUART();
    stdioAttach(hUART);
    printf ("Start\n");
    
    do
    {
        uvc_iocb.ioctl_code = VOS_IOCTL_UVC_ATTACH;
        uvc_iocb.set = (void *) hUsbHost;
        if (vos_dev_ioctl(hUvc,&uvc_iocb) != UVC_OK)
        {
            asm {HALT};
        }

        // Get the CUR supported res
        set_class_request(desc_dev,1,VS_PROBE_CONTROL,GET_CUR,26 /*sizeof (VProbeAndCom)*/);

        uvc_iocb.ioctl_code = VOS_IOCTL_UVC_CLASS_REQUEST;
        uvc_iocb.set = &desc_dev;
        uvc_iocb.get = &VProbeAndCom;
        iStatus = vos_dev_ioctl(hUvc,&uvc_iocb);
        if (iStatus != UVC_OK)
        {
            asm {HALT};
        }
    
        VProbeAndCom.dwMaxPayloadTransferSize = ISO_TRANSFER_SIZE;

        set_class_request(desc_dev,VS_COMMIT_CONTROL,SET_CUR,&uvc_iocb);
        if (iStatus != UVC_OK)
        {
            asm {HALT};
        }
        
        break;
    }
    while (1);
    
    vos_delay_msecs(300);

    do
    {
        iStatus = iRead = 0;
        iStatus = vos_dev_read(hUvc,buffer1,ISO_TRANSFER_SIZE * ISO_TRANSFER_COUNT,&iRead);  // read from the ISO endpoint
        printf("%d: status = %d,iRead = %d\n",iLoopCnt++,iStatus,iRead);
    }
    while (1);
}
    
void main(void)
{
    uart_context_t uartContext;
    usbhost_context_t usbhostContext;
    
    vos_set_clock_frequency(VOS_48MHZ_CLOCK_FREQUENCY);
    vos_init(VOS_QUANTUM,VOS_TICK_INTERVAL,NUMBER_OF_DEVICES);

    // configure USB Host port 1 only
    // use a max of 4 USB devices
    usbhostContext.if_count = 16;
    usbhostContext.ep_count = 10;
    usbhostContext.xfer_count = 2;
    usbhostContext.iso_xfer_count = 36;
    
    uartContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;

    usbhost_init(VOS_DEV_USBHOST,-1,&usbhostContext);
    uvc_init(VOS_DEV_UVC);
    uart_init(VOS_DEV_UART,&uartContext);

    tcbFIRMWARE = vos_create_thread_ex(20,4096,firmware,"Application",0);   
    vos_start_scheduler();

main_loop:
    goto main_loop;
}

static vos_driver_t uvc_cb;

unsigned char uvc_init(unsigned char vos_dev_num)
{
    uvc_context_t *ctx;

    // allocate  context
    ctx = vos_malloc(sizeof(uvc_context_t));
    if (ctx == 0)
    {
        return UVC_ERROR;
    }

    // Set up function pointers to the driver
    uvc_cb.flags = 0;
    uvc_cb.read = uvc_read;
    uvc_cb.write = uvc_write;
    uvc_cb.ioctl = uvc_ioctl;
    uvc_cb.interrupt = (PF_INT) 0;
    uvc_cb.open = uvc_open;
    uvc_cb.close = uvc_close;

    // OK - register with device manager
    vos_dev_init(vos_dev_num,&uvc_cb,ctx);

    return UVC_OK;
}

void uvc_open(uvc_context_t *ctx)
{
    vos_memset(ctx,sizeof(uvc_context_t));
}

void uvc_close(uvc_context_t *ctx)
{
    vos_memset(ctx,sizeof(uvc_context_t));
}

unsigned char uvc_detach(uvc_context_t *ctx)
{
    vos_memset(ctx,sizeof(uvc_context_t));
    return UVC_OK;
}

unsigned char uvc_attach(uvc_context_t *ctx,void *params)
{
    usbhost_ioctl_cb_t hc_iocb;        // USBHost ioctl request block
    usbhost_ioctl_cb_class_t hc_class;
    usbhost_ioctl_cb_dev_info_t devInfo;
    usbhost_device_handle_ex ifDev;    // device handle
    int ifs,aset;
    unsigned char status;
    unsigned char ret;
    unsigned char num_dev;
    unsigned char i;

    status = ret = UVC_OK;

    ctx->hc = (VOS_HANDLE) params;

    do
    {
        vos_delay_msecs(1000);

        // poll for enumeration to complete
        hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_GET_CONNECT_STATE;
        hc_iocb.get = &i;
        ret = vos_dev_ioctl(ctx->hc,&hc_iocb);
        if (ret != USBHOST_OK)
        {
            ret = UVC_ERROR;
            break;
        }

        if (i == PORT_STATE_ENUMERATED)
        {
            num_dev = 0;
            // user ioctl to find device count
            hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_COUNT;
            hc_iocb.set = NULL;
            hc_iocb.get = &num_dev;

            if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
            {
                status = UVC_ERROR;
                break;
            }

            ifDev = NULL;

            for (i = 0; i < num_dev; )
            {
                // user ioctl to find first device
                hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_NEXT_HANDLE;
                hc_iocb.handle.dif = ifDev;
                hc_iocb.get = &ifDev;

                if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
                {
                    ret = UVC_ERROR;
                    break;
                }

                if (ifDev)
                {
                    vos_memset(&hc_class,sizeof(usbhost_ioctl_cb_class_t));
                    hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_CLASS_INFO;
                    hc_iocb.get = &hc_class;
                    vos_dev_ioctl(ctx->hc,&hc_iocb);

                    hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_DEV_INFO;
                    hc_iocb.handle.dif = ifDev;
                    hc_iocb.set = NULL;
                    hc_iocb.get = &devInfo;
                    ret = vos_dev_ioctl(ctx->hc,&hc_iocb);
                    if (ret != USBHOST_OK)
                    {
                        ret = UVC_ERROR;
                        break;
                    }

                    ifs = devInfo.interface_number;
                    aset = devInfo.alt;

                    if ((hc_class.dev_class == USB_CLASS_VIDEO) &&
                        (hc_class.dev_subclass == USB_SUBCLASS_VIDEO_VIDEOSTREAMING))
                    {
                        // find interface 1,alternate 1
                        // this is an interface with an isochromous endpoint
                        // it is 192 bytes max packet size
                        if ((ifs == 1 /*1*/) && (aset == 1 /*1*/ ))
                        {
                            // user ioctl to find iso out endpoint on this device
                            hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_ISO_IN_ENDPOINT_HANDLE;
                            hc_iocb.handle.dif = ifDev;
                            hc_iocb.get = &ctx->epIsoIn;

                            if (vos_dev_ioctl(ctx->hc,&hc_iocb) == USBHOST_OK)
                            {
                                break;
                            }
                        }
                    }
                }

                i++;
            }

            if (ret == UVC_ERROR)
            {
                status = UVC_ERROR;
                break;
            }

            if (ifDev == NULL)
            {
                status = UVC_ERROR;
                break;
            }

            // user ioctl to find interrupt endpoint on this device
            hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_CONTROL_ENDPOINT_HANDLE;
            hc_iocb.handle.dif = ifDev;
            hc_iocb.get = &ctx->epCtrl;
            if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
            {
                status = UVC_ERROR;
                break;
            }

            // set this interface to be enabled
            hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_SET_INTERFACE;
            hc_iocb.handle.dif = ifDev;
            if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
            {
                status = UVC_ERROR;
                break;
            }

            // user ioctl to find interrupt endpoint on this device
            hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_ENDPOINT_INFO;
            hc_iocb.handle.ep = ctx->epIsoIn;
            hc_iocb.get = &ctx->epInfo;
            if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
            {
                status = UVC_ERROR;
                break;
            }

            break;
        }
    }
    while (1);

    return status;
}

unsigned char host_device_setup_transfer(uvc_context_t *ctx,usb_deviceRequest_t *req_desc,void *out_data)
{
    // USBHost ioctl request block
    usbhost_ioctl_cb_t iocb;

    iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_SETUP_TRANSFER;
    iocb.handle.ep = ctx->epCtrl;
    iocb.set = req_desc;
    iocb.get = out_data;

    if (vos_dev_ioctl(ctx->hc,&iocb) != USBHOST_OK)
        return UVC_ERROR;

    return UVC_OK;
}

unsigned char uvc_class_request(uvc_context_t *ctx,void *in_data,void *out_data)
{
    usb_deviceRequest_t *req = (usb_deviceRequest_t *) in_data;

    if (req->bRequest == SET_CUR)
    {
        req->bmRequestType = USB_BMREQUESTTYPE_HOST_TO_DEV |
            USB_BMREQUESTTYPE_CLASS |
            USB_BMREQUESTTYPE_INTERFACE;
    }
    else
    {
        req->bmRequestType = USB_BMREQUESTTYPE_DEV_TO_HOST |
            USB_BMREQUESTTYPE_CLASS |
            USB_BMREQUESTTYPE_INTERFACE;
    }

    return host_device_setup_transfer(ctx,req,out_data);
}

// UVC read function
unsigned char uvc_read(char *buffer,uvc_context_t *ctx)
{
    usbhost_ioctl_cb_t hc_iocb;
    usbhost_xfer_iso_t xfer;
    vos_semaphore_t semDum;
    unsigned char status;
    unsigned short frame;
    unsigned char i = 0;
    unsigned short xfer_size = ISO_TRANSFER_SIZE; // LAZ,Was ctx->epInfo.max_size; Snake cam returns too big of size for example

    vos_init_semaphore(&semDum,0);

    // form isochronous transfer descriptor
    xfer.cond_code = USBHOST_CC_NOTACCESSED;
    xfer.flags = 0;
    xfer.s = &semDum;
    xfer.ep = ctx->epIsoIn;
    xfer.buf = buffer;
    xfer.len = num_to_read;

    xfer.count = (unsigned char) (num_to_read / xfer_size);

    while (num_to_read)
    {
        xfer.len_psw[i].size = (num_to_read > xfer_size)?xfer_size:num_to_read;
        num_to_read -= xfer_size;
        i++;
    }
    
    // user ioctl to find frame number (as close as possible to use)
    hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_HW_GET_FRAME_NUMBER;
    hc_iocb.get = &frame;
    if (vos_dev_ioctl(ctx->hc,&hc_iocb) != USBHOST_OK)
    {
        return UVC_ERROR;
    }

    xfer.frame = frame + 1;
    
    num_read = 0; // LAZ,Added
    
    // now start the read from the ISO endpoint (line 511)
    status = vos_dev_read(ctx->hc,(unsigned char *) &xfer,sizeof(usbhost_xfer_t),num_read);

    if (status != USBHOST_OK)
    {
        return UVC_ERROR;
    }

    if (xfer.cond_code != USBHOST_CC_NOERROR)
    {
        return UVC_ERROR;
    }

    return UVC_OK;
}

// UVC write function
unsigned char uvc_write(char *buffer,uvc_context_t *ctx)
{
    unsigned char status = UVC_OK;

    return status;
}

// UVC IOCTL function
unsigned char uvc_ioctl(uvc_ioctl_cb_t *cb,uvc_context_t *ctx)
{
    unsigned char status = UVC_INVALID_PARAMETER;

    switch (cb->ioctl_code)
    {
    case VOS_IOCTL_UVC_ATTACH:
        status = uvc_attach(ctx,cb->set);
        break;

    case VOS_IOCTL_UVC_DETACH:
        status = uvc_detach(ctx);
        break;

    case VOS_IOCTL_UVC_CLASS_REQUEST:
        status = uvc_class_request(ctx,cb->set,cb->get);
        break;

    default:
        break;
    }

    return status;
}


void setupUART(void)
{
    common_ioctl_cb_t uart_iocb;
    
    // setup the UART interface
    uart_iocb.ioctl_code = VOS_IOCTL_COMMON_ENABLE_DMA;
    vos_dev_ioctl(hUART,&uart_iocb);

    // set baud rate
    uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_BAUD_RATE;
    uart_iocb.set.uart_baud_rate = UART_BAUD_9600;
    vos_dev_ioctl(hUART,&uart_iocb);

    // set flow control
    uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_FLOW_CONTROL;
    uart_iocb.set.param = UART_FLOW_NONE; 
    vos_dev_ioctl(hUART,&uart_iocb);

    // set data bits
    uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_DATA_BITS;
    uart_iocb.set.param = UART_DATA_BITS_8;
    vos_dev_ioctl(hUART,&uart_iocb);

    // set stop bits
    uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_STOP_BITS;
    uart_iocb.set.param = UART_STOP_BITS_1;
    vos_dev_ioctl(hUART,&uart_iocb);

    // set parity
    uart_iocb.ioctl_code = VOS_IOCTL_UART_SET_PARITY;
    uart_iocb.set.param = UART_PARITY_NONE;
    vos_dev_ioctl(hUART,&uart_iocb);
}   

...

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...