eclipse-threadx / usbx

Eclipse ThreadX - USBX is a high-performance USB host, device, and on-the-go (OTG) embedded stack, that is fully integrated with Eclipse ThreadX RTOS
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/usbx/index.md
MIT License
148 stars 88 forks source link

I coudn't able to find uvc device class support sample application in usbx #87

Open MaheshAvula-Alifsemi opened 1 year ago

MaheshAvula-Alifsemi commented 1 year ago

Describe the bug Actually I am trying to give uvc device class support, I am looking for any sample application or any document to understand the flow of UVC.

Can anyone help on this.

Please also mention any information which could help others to understand the problem you're facing:

xiaocq2001 commented 1 year ago

To use UVC on device side, following things need to be done:

  1. Prepare descriptors (passed to stack as "framework"), .e.g., a simulated video camera:
/* Define device payloadwork.  */

#define W(d)        UX_DW0(d), UX_DW1(d)
#define DW(d)       UX_DW0(d), UX_DW1(d), UX_DW2(d), UX_DW3(d)
#define GUID_YUY2   0x59,0x55,0x59,0x32, 0x00,0x00, 0x10,0x00, 0x80,0x00, 0x00,0xAA,0x00,0x38,0x9B,0x71 /* 32595559-0000-0010-8000-00AA00389B71 */

#define _DEVICE_DESCRIPTOR()                                                                        \
/* --------------------------------------- Device Descriptor */                                     \
/* 0  bLength, bDescriptorType                               */ 18,   0x01,                         \
/* 2  bcdUSB                                                 */ W(0x200),                           \
/* 4  bDeviceClass, bDeviceSubClass, bDeviceProtocol         */ 0xEF, 0x02, 0x01,                   \
/* 7  bMaxPacketSize0                                        */ 64,                                 \
/* 8  idVendor, idProduct                                    */ 0x84, 0x84, 0x01, 0x00,             \
/* 12 bcdDevice                                              */ UX_DW0(0x100),UX_DW1(0x100),        \
/* 14 iManufacturer, iProduct, iSerialNumber                 */ 0,    0,    0,                      \
/* 17 bNumConfigurations                                     */ 1,

#define _DEVICE_QUALIFIER_DESCRIPTOR()                                                              \
/* ----------------------------- Device Qualifier Descriptor */                                     \
/* 0 bLength, bDescriptorType                                */ 10,                 0x06,           \
/* 2 bcdUSB                                                  */ W(0x200),                           \
/* 4 bDeviceClass, bDeviceSubClass, bDeviceProtocol          */ 0xEF,               0x02, 0x01,     \
/* 7 bMaxPacketSize0                                         */ 8,                                  \
/* 8 bNumConfigurations                                      */ 1,                                  \
/* 9 bReserved                                               */ 0,

#define _CONFIGURE_DESCRIPTOR(total_len,n_ifc,cfg_v)                                                \
/* -------------------------------- Configuration Descriptor */                                     \
/* 0 bLength, bDescriptorType                                */ 9,    0x02,                         \
/* 2 wTotalLength                                            */ W(total_len),                       \
/* 4 bNumInterfaces, bConfigurationValue                     */ (n_ifc), (cfg_v),                   \
/* 6 iConfiguration                                          */ 0,                                  \
/* 7 bmAttributes, bMaxPower                                 */ 0x80, 50,

#define _IAD_DESCRIPTOR(ifc_0,ifc_cnt,cls,sub,protocol)                                             \
/* ------------------------ Interface Association Descriptor */                                     \
/* 0 bLength, bDescriptorType                                */ 8,    0x0B,                         \
/* 2 bFirstInterface, bInterfaceCount                        */ (ifc_0), (ifc_cnt),                 \
/* 4 bFunctionClass, bFunctionSubClass, bFunctionProtocol    */ (cls), (sub), (protocol),           \
/* 7 iFunction                                               */ 0,

#define _INTERFACE_DESCRIPTOR(ifc,alt,n_ep,cls,sub,protocol)                                        \
/* ------------------------------------ Interface Descriptor */                                     \
/* 0 bLength, bDescriptorType                                */ 9,    0x04,                         \
/* 2 bInterfaceNumber, bAlternateSetting                     */ (ifc), (alt),                       \
/* 4 bNumEndpoints                                           */ (n_ep),                             \
/* 5 bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol */ (cls), (sub), (protocol),           \
/* 8 iInterface                                              */ 0,

#define _ENDPOINT_DESCRIPTOR(addr,attr,pkt_siz,interval)                                            \
/* ------------------------------------- Endpoint Descriptor */                                     \
/* 0  bLength, bDescriptorType                                */ 7,               0x05,             \
/* 2  bEndpointAddress, bmAttributes                          */ (addr),          (attr),           \
/* 4  wMaxPacketSize, bInterval                               */ W(pkt_siz),      (interval),

#define _VC_DESCRIPTORS_LEN (13+17+9+13)
#define _VC_DESCRIPTORS()                                                                           \
    /*--------------------------- Class VC Interface Descriptor (VC_HEADER).  */                    \
    13, 0x24, 0x01, W(0x110),                                                                       \
    W(_VC_DESCRIPTORS_LEN), /* wTotalLength.  */                                                    \
    DW(UX_DEMO_CLOCK_FREQUENCY),  /* dwClockFrequency.  */                                          \
    1, /* bInCollection.  */                                                                        \
    1, /* BaInterfaceNr(1).  */                                                                     \
    /*--------------------------- Input Terminal (VC_INPUT_TERMINAL, Camera)  */                    \
    17, 0x24, 0x02,                                                                                 \
    0x01, /* bTerminalID, ITT_CAMERA  */                                                            \
    W(0x201), /* wTerminalType  */                                                                  \
    0x00, 0x00, W(0), W(0), W(0),                                                                   \
    0x02, W(0), /* bControlSize, bmControls  */                                                     \
    /*---------------------------- Output Terminal (VC_OUTPUT_TERMINAL, USB)  */                    \
    9, 0x24, 0x03,                                                                                  \
    0x02, /* bTerminalID  */                                                                        \
    W(0x0101), /* wTerminalType, TT_STREAMING  */                                                   \
    0x00, 0x05/* bSourceID  */, 0x00,                                                               \
    /*--------------------------------- Processing Unit (VC_PROCESSING_UNIT)  */                    \
    13, 0x24, 0x05,                                                                                 \
    0x05, /* bUnitID  */                                                                            \
    0x01, /* bSourceID  */                                                                          \
    W(0), /* wMaxMultiplier  */                                                                     \
    3, 0x00, 0x00, 0x00, /* bControlSize, bmControls  */                                            \
    0, /* iProcessing  */                                                                           \
    0x00, /* bmVideoStandards  */                                                                   \

#define _VS_FORMAT_DESCRIPTORS_UNCOMPRESSED_LEN (27+30)
#define _VS_FORMAT_DESCRIPTORS_UNCOMPRESSED()                                                       \
    /*------------------------------- VS Format Descriptor (VS_FORMAT_UNCOMPRESSED)  */             \
    27, 0x24, 0x04,                                                                                 \
    0x01, /* bFormatIndex  */                                                                       \
    0x01, /* bNumFrameDescriptors  */                                                               \
    GUID_YUY2, /* YUY2 : YUV 4:2:2  */                                                              \
    16, /* bBitsPerPixel  */                                                                        \
    0x01, /* bDefaultFrameIndex  */                                                                 \
    0x00, 0x00,                                                                                     \
    0x00, /* bmInterlaceFlags  */                                                                   \
    0x00, /* bCopyProtect  */                                                                       \
    /*--------------------------------- VS Frame Descriptor (VS_FRAME_UNCOMPRESSED)  */             \
    30, 0x24, 0x05,                                                                                 \
    0x01, /* bFrameIndex  */                                                                        \
    0x00, /* bmCapabilities  */                                                                     \
    W(176), W(144), /* wWidth, wHeight  */                                                          \
    DW(912384), DW(912384), /* dwMinBitRate, dwMaxBitRate  */                                       \
    DW(UX_DEMO_FRAME_DATA_SIZE), /* dwMaxVideoFrameBufSize  */                                      \
    DW(UX_DEMO_FRAME_INTERVAL), /* dwDefaultFrameInterval  */                                       \
    0x01, /* bFrameIntervalType  */                                                                 \
    DW(UX_DEMO_FRAME_INTERVAL), /* dwMinFrameInterval(1) */

#define _VS_IN_DESCRIPTORS_LEN (14+_VS_FORMAT_DESCRIPTORS_UNCOMPRESSED_LEN)
#define _VS_IN_DESCRIPTORS()                                                                        \
    /*------------------------- Class VS Header Descriptor (VS_INPUT_HEADER)  */                    \
    14, 0x24, 0x01,                                                                                 \
    0X01, /* bNumFormats  */                                                                        \
    W(_VS_IN_DESCRIPTORS_LEN), /* wTotalLength  */                                                  \
    0x81, /* bEndpointAddress  */                                                                   \
    0x00,                                                                                           \
    0x02, /* bTerminalLink  */                                                                      \
    0x00, /* bStillCaptureMethod  */                                                                \
    0x00, 0x00, /* bTriggerSupport, bTriggerUsage  */                                               \
    0x01, 0x00, /* bControlSize, bmaControls  */                                                    \
    _VS_FORMAT_DESCRIPTORS_UNCOMPRESSED()

#define _VS_OUT_DESCRIPTORS_LEN (11+_VS_FORMAT_DESCRIPTORS_UNCOMPRESSED_LEN)
#define _VS_OUT_DESCRIPTORS()                                                                       \
    /*------------------------- Class VS Header Descriptor (VS_OUTPUT_HEADER)  */                   \
    11, 0x24, 0x02,                                                                                 \
    0x01, /* bNumFormats  */                                                                        \
    W(_VS_OUT_DESCRIPTORS_LEN), /* wTotalLength  */                                                 \
    0x02, /* bEndpointAddress  */                                                                   \
    0x00,                                                                                           \
    0x03, /* bTerminalLink  */                                                                      \
    0x01, 0x00, /* bControlSize, bmaControls  */                                                    \
    _VS_FORMAT_DESCRIPTORS_UNCOMPRESSED()

#define _CONFIGURE_DESCRIPTORS_LEN (9+ 8+ 9+_VC_DESCRIPTORS_LEN+ 9+_VS_IN_DESCRIPTORS_LEN+9+7)
#if UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < _CONFIGURE_DESCRIPTORS_LEN
#error Please increase control request buffer size
#endif
#if UX_SLAVE_REQUEST_DATA_MAX_LENGTH < UX_DEMO_MAX_PAYLOAD_SIZE
#error Please increase endpoint data buffer size
#endif

unsigned char device_payloadwork_full_speed[] = {
    _DEVICE_DESCRIPTOR()
     _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,2,1)
      _IAD_DESCRIPTOR(0,2,0x0E,0x03,0x00)

       _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x00)
        _VC_DESCRIPTORS()

       _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00)
        _VS_IN_DESCRIPTORS()
        _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00)
        _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,UX_DEMO_ENDPOINT_INTERVAL_FS)

};
#define             DEVICE_FRAMEWORK_LENGTH_FULL_SPEED      sizeof(device_payloadwork_full_speed)

unsigned char device_payloadwork_high_speed[] = {
    _DEVICE_DESCRIPTOR()
     _DEVICE_QUALIFIER_DESCRIPTOR()
     _CONFIGURE_DESCRIPTOR(_CONFIGURE_DESCRIPTORS_LEN,2,1)
      _IAD_DESCRIPTOR(0,2,0x0E,0x03,0x00)

       _INTERFACE_DESCRIPTOR(0,0,0,0x0E,0x01,0x00)
        _VC_DESCRIPTORS()

       _INTERFACE_DESCRIPTOR(1,0,0,0x0E,0x02,0x00)
        _VS_IN_DESCRIPTORS()
        _INTERFACE_DESCRIPTOR(1,1,1,0x0E,0x02,0x00)
        _ENDPOINT_DESCRIPTOR(0x81,0x05,UX_DEMO_ENDPOINT_SIZE,UX_DEMO_ENDPOINT_INTERVAL_HS)
};
#define             DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED      sizeof(device_payloadwork_high_speed)
  1. Setup video stream and video, e.g., for upper simulated camera:
    /* Set the parameters for Video streams.  */
    video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_change     = demo_video_write_change;
    video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_payload_done = demo_video_write_done;
    video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_nb   = UX_DEMO_PAYLOAD_BUFFER_NB;
    video_stream_parameter[0].ux_device_class_video_stream_parameter_max_payload_buffer_size = UX_DEMO_MAX_PAYLOAD_SIZE;
    video_stream_parameter[0].ux_device_class_video_stream_parameter_thread_entry = ux_device_class_video_write_thread_entry;

    /* Set the parameters for Video device.  */
    video_parameter.ux_device_class_video_parameter_streams_nb  = 1;
    video_parameter.ux_device_class_video_parameter_streams     = video_stream_parameter;
    video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_activate      = demo_video_instance_activate;
    video_parameter.ux_device_class_video_parameter_callbacks.ux_slave_class_video_instance_deactivate    = demo_video_instance_deactivate;

    video_parameter.ux_device_class_video_parameter_callbacks.ux_device_class_video_request                         = demo_video_vc_request_process;
    video_stream_parameter[0].ux_device_class_video_stream_parameter_callbacks.ux_device_class_video_stream_request = demo_video_vs_request_process;

    /* Initialize the device Video class. This class owns interfaces starting with 0. */
     status =  ux_device_stack_class_register(_ux_system_device_class_video_name, ux_device_class_video_entry,
                                              1, 0, &video_parameter);

callback.ux_device_class_video_stream_change: callback invoked if host select interface alternate setting (0 to close video stream, other value to open video stream in specific data rate) callbacks.ux_device_class_video_stream_payload_done: callback invoked when a video frame is sent to host (example here is video camera) _max_payload_buffer_nb and _max_payload_buffer_size: passed to stack to create a ring buffer to caching payloads, the size is usually the max possible isochronous endpoint size. _thread_entry: ux_device_class_video_write_thread_entry for camera (device sending data to host).

At least stream request should be assigned, since application should handle some request (following the request is simply accepted, but in real application video parameters should be applied and returned in specific format):

UINT    demo_video_vs_request_process(UX_DEVICE_CLASS_VIDEO_STREAM *stream, UX_SLAVE_TRANSFER *transfer)
{

UINT                                    status = UX_ERROR;
UCHAR                                   bRequest;
USHORT                                  wValue_CS; /* In high byte.  */
USHORT                                  wLength;
UCHAR                                   *data;

    /* Decode setup packet.  */
    bRequest = transfer -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST];
    wValue_CS = transfer -> ux_slave_transfer_request_setup[UX_SETUP_VALUE + 1];
    wLength = ux_utility_short_get(transfer -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
    data = transfer -> ux_slave_transfer_request_data_pointer;

    /* Check CS.  */
    switch(wValue_CS)
    {
    case UX_DEVICE_CLASS_VIDEO_VS_PROBE_CONTROL:

        switch(bRequest)
        {
        case UX_DEVICE_CLASS_VIDEO_SET_CUR:

            /* Simply accept without change setting.  */
            status = UX_SUCCESS;
            break;

        case UX_DEVICE_CLASS_VIDEO_GET_CUR:
        case UX_DEVICE_CLASS_VIDEO_GET_MIN:
        case UX_DEVICE_CLASS_VIDEO_GET_MAX:

            /* Simply send our data back (first 26 bytes).  */

            /* Check request length.  */
            if (wLength < 26)
                break;

            /* Copy data for transfer.  */
            ux_utility_memory_copy(data, video_probe_commit_buffer, 26);

            /* Transfer request.  */
            status = ux_device_stack_transfer_request(transfer, 26, wLength);
            break;

        default:
            break;
        }

        break;

    case UX_DEVICE_CLASS_VIDEO_VS_COMMIT_CONTROL:

        /* Simply accept request.  */
        status = UX_SUCCESS;
        break;

    /* CS not supported now.  */
    default:
        break;
    }

    return(status);
}
  1. After host activate the stream (change callback with none-zero alternate setting), in application payload buffer can be filled to streaming data, ux_device_class_video_write_payload_get is used to get data buffer to fill things and ux_device_class_video_write_payload_commit is used to commit the filled buffer. Background transfer is started once ux_device_class_video_transmission_start is called. Once a payload is sent there is a callback to let application to fill more buffer .
static VOID demo_video_write_a_payload(UX_DEVICE_CLASS_VIDEO_STREAM *stream)
{
UCHAR                                   *buffer;
ULONG                                   buffer_length, length;
UX_DEVICE_CLASS_VIDEO_PAYLOAD_HEADER    *header;
UCHAR                                   *data;
UCHAR                                   *frame_data;

    /* If disabled, no write.  */
    if (video_payload_data_length == 0)
        return;

    /* Get payload buffer.  */
    ux_device_class_video_write_payload_get(stream, &buffer, &buffer_length);
    header = (UX_DEVICE_CLASS_VIDEO_PAYLOAD_HEADER *)buffer;
    data = buffer + UX_DEMO_PAYLOAD_HEADER_SIZE;

    /* Get frame data buffer.  */
    frame_data = video_frame_buffer + video_frame_write_pos;

    /* Calculate data length.  */
    length = video_frame_buffer_size - video_frame_write_pos;
    if (length > video_payload_data_length)
        length = video_payload_data_length;

    /* Fill data.  */
    ux_utility_memory_copy(data, frame_data, length);    

    /* Fill payload header (no PTS nor SCR, total 10 bytes).  */
    header -> bHeaderLength = UX_DEMO_PAYLOAD_HEADER_SIZE;
    header -> bmHeaderInfo.value = video_frame_count & 0x1; /* FID @ B0  */
    header -> bmHeaderInfo.bm.bEOH = 1;

    /* Move write pos.  */
    video_frame_write_pos += length;
    if (video_frame_write_pos >= video_frame_buffer_size)
    {
        /* EOF.  */
        header -> bmHeaderInfo.bm.bEOF = 1;
        video_frame_write_pos = 0;

        /* A frame sent.  */
        video_frame_count ++;
    }

    /* Commit payload buffer.  */
    ux_device_class_video_write_payload_commit(stream, length + UX_DEMO_PAYLOAD_HEADER_SIZE);
}
VOID    demo_video_write_change(UX_DEVICE_CLASS_VIDEO_STREAM *stream, ULONG alternate_setting)
{
INT             i;

    /* Stop video payload loop back if stream closed.  */
    if (alternate_setting == 0)
    {
        video_payload_data_length = 0;
        return;
    }

    /* Payload data length: exclude header.  */
    video_payload_data_length = ux_device_class_video_max_payload_length(stream);
    video_payload_data_length -= UX_DEMO_PAYLOAD_HEADER_SIZE;

    /* Frame not started.  */
    video_frame_write_pos = 0;

    /* Write buffers until achieve threadshold.  */
    for (i = 0; i < UX_DEMO_TRANSMIT_START_THRESHOLD; i ++)
        demo_video_write_a_payload(stream);
    ux_device_class_video_transmission_start(stream);
}
VOID    demo_video_write_done(UX_DEVICE_CLASS_VIDEO_STREAM *stream, ULONG length)
{

    /* Invoked when a payload sent to host, currently no use for loop back.  */
    (void)stream;
    (void)length;
    if (length)
    {
        /* A payload sent.  */
        video_payload_count ++;

        /* Prepare next payload.  */
        demo_video_write_a_payload(stream);
    }
}
MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 , Thank you so much for detailed information.

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

I have one doubt that, as you explained _max_payload_buffer_nb and _max_payload_buffer_size both the variables size would be same as Isochrnous endpoint size..? if I give both sizes as Isocronous endpoint size, class registration was failing because it requires almost 1MB memory, i have less memory on my device. *memory_size = stream -> ux_device_class_video_stream_payload_buffer_size stream_parameter -> ux_device_class_video_stream_parameter_max_payload_buffer_nb;** Could you please confirm that.

Thanks Mahesh Avula

xiaocq2001 commented 1 year ago

_buffer_size is max endpoint size, _buffer_nb is number of payloads buffered.

MaheshAvula-Alifsemi commented 1 year ago

Thank you so much @xiaocq2001

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Note: 1

Below are descriptors for video class driver which i have prepared, with these descriptors, Isochrnous endpoint is not creating because of this endpoint is associated with video stream interface with alternate setting =1, I have gone through code and found that my device not getting UX_SET_INTERFACE request from host machine(Ubuntu 18.04)

Could you please help on this issue, if i am doing anything wrong here.

UCHAR device_framework_high_speed[] = {

/*
Device descriptor 18 bytes
0x00 bDeviceClass: base class, the class code will be defining in interface descriptor
*/
0x12, 0x01, 0x00, 0x00,
0xEF, 0x02, 0x01, 0x40,
0x25, 0x05, 0xa7, 0xa4,
0x00, 0x01, 0x01, 0x02,
0x03, 0x01,

/* Configuration  descriptor 9 bytes  */
0x09, 0x02, 0xb5, 0x00, 0x02, 0x01, 0x00, 0xC0, 0x01,

/* Interface association descriptor  */
0x08, 0x0b, 0x00,
0x02, 0x0E, 0x03, 0x00, 0x00,

/* interface_descriptor UVC_control */
0x09, 0x04, 0x00, 0x00, 0x01, 0x0E, 0x01, 0x00, 0x00,

/* Class-specific VC Interface Header Descriptor */
 0x0d,0x24,0x01,0x10,0x01,0x34,0x00,0x00,0x00,0x00,0x00,0x01, 0x01,

  /*  Input Terminal (VC_INPUT_TERMINAL, Camera)  */
 0x11,0x24,0x02,0x01,0x01,0x02,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,

 /*  Output Terminal (VC_OUTPUT_TERMINAL, USB)  */
 0x09, 0x24, 0x03, 0x02,0x01,0x01,0x00,0x05,0x00,

  /* Processing Unit (VC_PROCESSING_UNIT)  */
 0x0d, 0x24, 0x05,0x05,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,

/* interrupt endpoint_descriptor for uvc_control 7 bytes */
0x07,0x05,0x83,0x03,0x08,0x00,0x08,

/* Interface Descriptor for UVC streaming where altsetting = 0 */
0x09, 0x04, 0x01, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x00,

/* Class Video streaming input Header Descriptor (VS_INPUT_HEADER)  */
0x0e,0x24,0x01,0x01,0x47,00,0x81,0x00,0x02,0x00,0x00,0x00,0x01,0x00,

/* VS Format Descriptor (VS_FORMAT_UNCOMPRESSED)  */
0x1b,0x24,0x04,0x01,0x01,0x59,0x55,0x59,0x32, 0x00,0x00, 0x10,0x00, 0x80,0x00, 0x00,0xAA,0x00,0x38,0x9B,0x71,0x10,0x01,0x00,0x00,0x00,0x00,

 /* VS Frame Descriptor (VS_FRAME_UNCOMPRESSED)  */
0x1e,0x24, 0x05,0x01, 0x00,0x00,0x1e,0x00,0x1e,0x00,0xec,0x0d,0x00,0x00,0xec,0x0d,0x00,0x00,0x8c,0x0a,0x00,0x00,0x64,0x00,0x00,0x01,0x00,0x64,0x00,0x00,

 /* Interface Descriptor for UVC streaming where altsetting = 1 */
0x09, 0x04, 0x01, 0x01, 0x01, 0x0e, 0x02, 0x00, 0x00,

/* Isochronous IN endpoint descriptor for UVC streaming  */
0x07, 0x05, 0x85, 0x05, 0x00, 0x04, 0x01,

}

Note: 2

When I run my application I have collected dmesg logs at host side(ubuntu18.04) and attaching here. node has not created for video class driver in /dev/ directory.

[18159350.110416] usb 1-4.4.4.2: new high-speed USB device number 78 using xhci_hcd [18159350.210765] usb 1-4.4.4.2: config 1 interface 1 altsetting 1 endpoint 0x85 has an invalid bInterval 0, changing to 7 [18159350.211131] usb 1-4.4.4.2: New USB device found, idVendor=0525, idProduct=a4a7 [18159350.211132] usb 1-4.4.4.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [18159350.211133] usb 1-4.4.4.2: Product: Devkit [18159350.211134] usb 1-4.4.4.2: Manufacturer: AlifSemiconductor [18159350.211152] usb 1-4.4.4.2: SerialNumber: 1200 [18159350.274379] uvcvideo: Found UVC 1.10 device Devkit (0525:a4a7) [18159360.538136] uvcvideo: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround. [18159365.657965] uvcvideo: Failed to query (129) UVC probe control : -110 (exp. 34). [18159365.657966] uvcvideo: Failed to initialize the device (-5).

Regards, Mahesh

xiaocq2001 commented 1 year ago

[18159360.538136] uvcvideo: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround. [18159365.657965] uvcvideo: Failed to query (129) UVC probe control : -110 (exp. 34). [18159365.657966] uvcvideo: Failed to initialize the device (-5).

It seems the UVC requests are not handled correctly. From the log, GET_DEF(PROBE) is requested but not answered correctly. Please check the VS request callback (demo_video_vs_request_process in previous example), maybe you can try to handle GET_DEF, like following:

    switch(wValue_CS)
    {
    case UX_DEVICE_CLASS_VIDEO_VS_PROBE_CONTROL:

        switch(bRequest)
        {
        case UX_DEVICE_CLASS_VIDEO_SET_CUR:

            /* Simply accept without change setting.  */
            status = UX_SUCCESS;
            break;

        case UX_DEVICE_CLASS_VIDEO_GET_DEF: // <- when GET_DEF requsted
        case UX_DEVICE_CLASS_VIDEO_GET_CUR:
        case UX_DEVICE_CLASS_VIDEO_GET_MIN:
        case UX_DEVICE_CLASS_VIDEO_GET_MAX:

            /* Simply send our data back (first 26 bytes).  */
MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 , Thank you so much for your inputs,

Actually VS request callback is not getting invoking because VS request callback get invoke only when UX_SET_INTERFACE request comes from the host machine, but here my device not getting UX_SET_INTERFACE request.

could you please explain that when device suppose to get UX_SET_INTERFACE from host.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

Usually UX_SET_INTERFACE is received when there is host application using the video camera, e.g., open a camera application that can preview the video input.

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , Thank you for the quick replay.

Is host application for receive video stream data from device..?,

xiaocq2001 commented 1 year ago

Yes. When host application starts receiving video stream data, the alternate setting is selected to indicate consuming USB bus bandwidth, then the ISO transfer starts to transfer video stream. When host application stops receiving video stream the interface alternate setting is back to 0 to reduce USB bus bandwidth consumed.

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , got it and thank you so much,

But still I have some doubt that as per the usbx stack When UX_SET_INTERFACE request comes from host then only Isochronous endpoint will be created and VS request callback get invoked , demo_video_vs_request_process will set the probe control and commit control right..?

Once this process is completed then device will start send video streaming data to the host right..?

could you please correct above points.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

Usually host set alternate setting to 0 and use VS request to probe control and commit control. Then host set interface to expected alternate setting and streaming data.

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Got it and thank you so much.

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

host setting alternate setting to 0 and VS request callback getting invoking to probe control and commit control,

I can see these two requests UX_DEVICE_CLASS_VIDEO_GET_DEF and UX_DEVICE_CLASS_VIDEO_GET_CUR, my device is receiving from host.

UINT demo_video_vs_request_process(UX_DEVICE_CLASS_VIDEO_STREAM stream, UX_SLAVE_TRANSFER transfer) {

UINT status = UX_ERROR; UCHAR bRequest; USHORT wValue_CS; / In high byte. / USHORT wLength; UCHAR *data;

/* Decode setup packet.  */
bRequest = transfer -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST];
wValue_CS = transfer -> ux_slave_transfer_request_setup[UX_SETUP_VALUE + 1];
wLength = ux_utility_short_get(transfer -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
data = transfer -> ux_slave_transfer_request_data_pointer;

/* Check CS.  */
switch(wValue_CS)
{
case UX_DEVICE_CLASS_VIDEO_VS_PROBE_CONTROL:

    switch(bRequest)
    {
    case UX_DEVICE_CLASS_VIDEO_SET_CUR:

        /* Simply accept without change setting.  */
        status = UX_SUCCESS;
        break;

    case UX_DEVICE_CLASS_VIDEO_GET_CUR:
    case UX_DEVICE_CLASS_VIDEO_GET_MIN:
    case UX_DEVICE_CLASS_VIDEO_GET_MAX:

        /* Simply send our data back (first 26 bytes).  */

        /* Check request length.  */
        if (wLength < 26)
            break;

        /* Copy data for transfer.  */
        ux_utility_memory_copy(**data**, video_probe_commit_buffer, 26);
      **here, what is the  video_probe_commit_buffer ..? also we are not passing data pointer to any function below, could you please explain this**

        /* Transfer request.  */
        status = ux_device_stack_transfer_request(transfer, 26, wLength);
        break;

    default:
        break;
    }

    break;

case UX_DEVICE_CLASS_VIDEO_VS_COMMIT_CONTROL:

    /* Simply accept request.  */
    status = UX_SUCCESS;
    break;

/* CS not supported now.  */
default:
    break;
}

return(status);

}

could you please help on this

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

This is my testing data for you to reference:

/* APP specific probe/commit settings.  */
static UCHAR                            video_probe_commit_buffer[48] = {
    W(0x0000), /* bmHint  */
    1, /* bFormatIndex  */
    1, /* bFrameIndex  */
    DW(UX_DEMO_FRAME_INTERVAL), /* dwFrameInterval  */
    W(0), /* wKeyFrameRate  */
    W(0), /* wPFrameRate  */
    W(0), /* wCompQuality  */
    W(0), /* wCompWindowSize  */
    W(0), /* wDelay  */
    DW(UX_DEMO_FRAME_DATA_SIZE), /* dwMaxVideoFrameSize  */
    DW(UX_DEMO_MAX_PAYLOAD_SIZE), /* dwMaxPayloadTransferSize  */
    DW(UX_DEMO_CLOCK_FREQUENCY), /* dwClockFrequency  */
    0x03, /* bmFramingInfo  */
    1, /* bPreferedVersion  */
    1, /* bMinVersion  */
    1, /* bMaxVersion  */
    0, /* bUsage  */
    0, /* bBitDepthLuma  */
    0x00, /* bmSettings  */
    0, /* bMaxNumberOfRefFramesPlus1  */
    W(0x0000), /* bmRateControlModes  */
    W(0), W(0), W(0), W(0) /* bmLayoutPerStream  */
};

For details about the structure and fields, please refer to USB Video spec.

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , Thank you so much, We need to send this structure info to the host when probe and commit request comes right..? could you please share usbx video class driver sample application, so that it will be easy to understand,

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 , My device is enumerated at host and created node (/dev/video0)for it, I really thank you for your support.

One doubt that, from where ux_device_class_video_write_thread_entry get invoke, and could you please share any azure usbx documents for video stream data tranfer flow.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

ux_device_class_video_write_thread_entry is passed to stack to start a thread to send data in FIFO to host, the FIFO is created from parameters passed in register function. When you need to add data to FIFO, use ux_device_class_video_write_payload_get to get buffer to fill and use ux_device_class_video_write_payload_commit to commit to transfer.

BTW, which board are you working on for now?

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001, Thanks for your support, I am using ASIC Board(with arm coretx m55 processor). I was bit struggling to write video class application , earlier I have given support for CDC-ACM class support and that was working fine.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Is there any open source host application for UVC driver to validate, or could you please suggest how the host application would be..?

Regards Mahesh

xiaocq2001 commented 1 year ago

Here is an example (on ST NUCLEO-H723ZG) that you can reference: https://github.com/STMicroelectronics/x-cube-azrtos-h7/tree/main/Projects/NUCLEO-H723ZG/Applications/USBX/Ux_Device_Video

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Thank you so much for all your inputs

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

I am using host application as VLC media player to stream the data from the device, but device not receiving SET_INTERFACE request with the alternate setting is selected to 1.

I have observed one thing at host side while running VLC media player , i have collected dmesg logs that i am posting here.

[20125207.047025] usb 1-4.4.4.2: new high-speed USB device number 65 using xhci_hcd [20125207.147717] usb 1-4.4.4.2: New USB device found, idVendor=0525, idProduct=a4a7 [20125207.147719] usb 1-4.4.4.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [20125207.147720] usb 1-4.4.4.2: Product: Devkit [20125207.147721] usb 1-4.4.4.2: Manufacturer: AlifSemiconductor [20125207.147722] usb 1-4.4.4.2: SerialNumber: 1200 [20125207.272416] uvcvideo: Found UVC 1.10 device Devkit (0525:a4a7) [20125207.644515] input: Devkit as /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4/1-4.4.4/1-4.4.4.2/1-4.4.4.2:1.0/input/input36 [20125207.650508] kauditd_printk_skb: 8 callbacks suppressed [20125207.650511] audit: type=1400 audit(1680155724.219:25407): apparmor="DENIED" operation="open" profile="snap.notepad-plus-plus.notepad-plus-plus" name="/sys/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4/1-4.4.4/1-4.4.4.2/busnum" pid=18819 comm="winedevice.exe" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0 [20125207.721901] audit: type=1400 audit(1680155724.291:25408): apparmor="DENIED" operation="open" profile="snap.notepad-plus-plus.notepad-plus-plus" name="/sys/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4/1-4.4.4/1-4.4.4.2/busnum" pid=18819 comm="winedevice.exe" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0 [20125330.019469] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125335.139257] uvcvideo: Failed to set UVC commit control : -110 (exp. 34). [20125340.259294] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.379047] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.782295] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785626] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785684] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). root@alif:/home/mahesh#

Could you please help on this.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

[20125330.019469] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125335.139257] uvcvideo: Failed to set UVC commit control : -110 (exp. 34). [20125340.259294] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.379047] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.782295] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785626] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785684] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). I usually test video device under windows. But from upper log, it seems host send probe requests to device but fail. Maybe you can check if the VS control request callback in application is called and correct answer is reported to host.

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 , Thank you for your inputs

[20125330.019469] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125335.139257] uvcvideo: Failed to set UVC commit control : -110 (exp. 34). [20125340.259294] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.379047] uvcvideo: Failed to set UVC probe control : -110 (exp. 34). [20125345.782295] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785626] uvcvideo: Failed to set UVC probe control : -71 (exp. 34). [20125345.785684] uvcvideo: Failed to set UVC probe control : -71 (exp. 34).

These errors I have resolved, now i could see video probe control requests and commit control requests are comming also device also responding back to host.

Host application as VLC media player sending UX_SET_INTERFACE request after(video probe control requests and commit control) with the alternate setting is selected to 0, but host app suppose to send UX_SET_INTERFACE request with the alternate setting is selected to 1. I am attching screenshot for reference.

MicrosoftTeams-image (15).

could you please help on this.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

One more thing I have observed that when we run host application as VLC media player , I could see below error that to not immediatly after running VLC media player after some time this error is comming. MicrosoftTeams-image (17)

could you please help on this.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

I am have tested usb video class driver on window machine and used host application as VLC media player, sending UX_SET_INTERFACE request after(video probe control requests and commit control) with the alternate setting is selected to 0, but host app suppose to send UX_SET_INTERFACE request with the alternate setting is selected to 1 to use USB bandwidth to stream data. I would say that behaviour of my application is same on Windows machine as well as Linux machine, could you please help on this to move further, I am not understanding where it's going wrong.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

Here is something under windows for you to reference:

The USB traces as a whole: image

Get Cur/Max/Min content: image

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , Thank you so much for your inputs.

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Yes, I have compared my usb analyzer trace with your screenshot , found very few differences, as part of video stream request i am not seeing usb commit control request and also host app not sending SET_INTERFACE request. I am attaching my screenshot here. USB trace when i tested on window machine.

Usb_video_class_usb_analyzer_01 Usb_video_class_usb_analyzer

I really appriciate your help.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

When I tested on linux machine i could see that USB commit control request is comming also SET_INTERFACE request also comming from host,

I am attaching USB trace here.

Usb_video_class_usb_analyzer_with_linux_machine Usb_video_class_usb_analyzer_with_linux_machine_01

I was thinking some where it's going wrong but i couldn't able to find that.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

Hi @xiaocq2001 ,

Here I am attaching usb video class analyzer trace file, could you please check anything is wrong in the usb trace. USB_analyzer.zip

if it's possible, could you please share your trace also.

Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 ,

Any inputs on my observations. Thanks

xiaocq2001 commented 1 year ago

From USB requests it seems there is no issue. Maybe you can try more commonly seen video frame format for better host application support.

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , Thank you for your inputs, Could you please suggest which video frame format i should try, because first time i am trying on video class support. I really appreciate your help. Regards Mahesh Avula

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001 , If I am using different video frame format, what are the places i need to change in the descriptors, could you please give any example snippet for different video frame format.

Regards Mahesh Avula

xiaocq2001 commented 1 year ago

Please check "Universal Serial Bus Device Class Definition for Video Devices: Frame Based Payload" for details of the descriptor. Maybe you can capture trace of existing USB Camera on market for reference, of just check the example trace in total phase data center.

MaheshAvula-Alifsemi commented 1 year ago

@xiaocq2001, Sure, thank you so much.