mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
963836f491
- This commit adds the API documentation for the USB Host Library. - Warnings about the beta API are also added. - usb_host_misc.h renamed to usb_helpers.h
440 lines
20 KiB
C
440 lines
20 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "unity.h"
|
|
#include "test_utils.h"
|
|
#include "usb/usb_host.h"
|
|
|
|
/*
|
|
Tests that check the configuration descriptor parsing functions provided in usb_host.h work by parsing a fixed
|
|
configuration descriptor. The fixed configuration descriptor used in this test is provided below (both in textual and
|
|
byte format), and is of a UVC device. Thus the configuration descriptor has a good set of scenarios that can be tested
|
|
(such as multiple interfaces, alternate settings, class specific descriptors, default endpoint only interfaces etc).
|
|
*/
|
|
|
|
/*
|
|
Configuration Descriptor:
|
|
bLength 9
|
|
bDescriptorType 2
|
|
wTotalLength 0x0185
|
|
bNumInterfaces 2
|
|
bConfigurationValue 1
|
|
iConfiguration 0
|
|
bmAttributes 0x80
|
|
(Bus Powered)
|
|
MaxPower 500mA
|
|
Interface Association:
|
|
bLength 8
|
|
bDescriptorType 11
|
|
bFirstInterface 0
|
|
bInterfaceCount 2
|
|
bFunctionClass 14 Video
|
|
bFunctionSubClass 3 Video Interface Collection
|
|
bFunctionProtocol 0
|
|
iFunction 5
|
|
Interface Descriptor:
|
|
bLength 9
|
|
bDescriptorType 4
|
|
bInterfaceNumber 0
|
|
bAlternateSetting 0
|
|
bNumEndpoints 1
|
|
bInterfaceClass 14 Video
|
|
bInterfaceSubClass 1 Video Control
|
|
bInterfaceProtocol 0
|
|
iInterface 5
|
|
VideoControl Interface Descriptor:
|
|
bLength 13
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 1 (HEADER)
|
|
bcdUVC 1.00
|
|
wTotalLength 0x004f
|
|
dwClockFrequency 15.000000MHz
|
|
bInCollection 1
|
|
baInterfaceNr( 0) 1
|
|
VideoControl Interface Descriptor:
|
|
bLength 9
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
|
|
bTerminalID 4
|
|
wTerminalType 0x0101 USB Streaming
|
|
bAssocTerminal 0
|
|
bSourceID 3
|
|
iTerminal 0
|
|
VideoControl Interface Descriptor:
|
|
bLength 28
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 6 (EXTENSION_UNIT)
|
|
bUnitID 3
|
|
guidExtensionCode {4cf18db6-abd0-495c-9876-1fa3942ff9fa}
|
|
bNumControl 24
|
|
bNrPins 1
|
|
baSourceID( 0) 2
|
|
bControlSize 3
|
|
bmControls( 0) 0xff
|
|
bmControls( 1) 0xff
|
|
bmControls( 2) 0xff
|
|
iExtension 0
|
|
VideoControl Interface Descriptor:
|
|
bLength 18
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 2 (INPUT_TERMINAL)
|
|
bTerminalID 1
|
|
wTerminalType 0x0201 Camera Sensor
|
|
bAssocTerminal 0
|
|
iTerminal 0
|
|
wObjectiveFocalLengthMin 0
|
|
wObjectiveFocalLengthMax 0
|
|
wOcularFocalLength 0
|
|
bControlSize 3
|
|
bmControls 0x0000000e
|
|
Auto-Exposure Mode
|
|
Auto-Exposure Priority
|
|
Exposure Time (Absolute)
|
|
VideoControl Interface Descriptor:
|
|
bLength 11
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 5 (PROCESSING_UNIT)
|
|
Warning: Descriptor too short
|
|
bUnitID 2
|
|
bSourceID 1
|
|
wMaxMultiplier 0
|
|
bControlSize 2
|
|
bmControls 0x0000177f
|
|
Brightness
|
|
Contrast
|
|
Hue
|
|
Saturation
|
|
Sharpness
|
|
Gamma
|
|
White Balance Temperature
|
|
Backlight Compensation
|
|
Gain
|
|
Power Line Frequency
|
|
White Balance Temperature, Auto
|
|
iProcessing 0
|
|
bmVideoStandards 0x62
|
|
NTSC - 525/60
|
|
PAL - 525/60
|
|
Endpoint Descriptor:
|
|
bLength 7
|
|
bDescriptorType 5
|
|
bEndpointAddress 0x83 EP 3 IN
|
|
bmAttributes 3
|
|
Transfer Type Interrupt
|
|
Synch Type None
|
|
Usage Type Data
|
|
wMaxPacketSize 0x0010 1x 16 bytes
|
|
bInterval 6
|
|
Interface Descriptor:
|
|
bLength 9
|
|
bDescriptorType 4
|
|
bInterfaceNumber 1
|
|
bAlternateSetting 0
|
|
bNumEndpoints 0
|
|
bInterfaceClass 14 Video
|
|
bInterfaceSubClass 2 Video Streaming
|
|
bInterfaceProtocol 0
|
|
iInterface 0
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 15
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 1 (INPUT_HEADER)
|
|
bNumFormats 2
|
|
wTotalLength 0x00f7
|
|
bEndPointAddress 129
|
|
bmInfo 0
|
|
bTerminalLink 4
|
|
bStillCaptureMethod 0
|
|
bTriggerSupport 0
|
|
bTriggerUsage 0
|
|
bControlSize 1
|
|
bmaControls( 0) 0
|
|
bmaControls( 1) 0
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 27
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
|
|
bFormatIndex 1
|
|
bNumFrameDescriptors 2
|
|
guidFormat {85f6cc1d-0c9f-44f5-9ce0-97c7dd8c98ab}
|
|
bBitsPerPixel 16
|
|
bDefaultFrameIndex 1
|
|
bAspectRatioX 0
|
|
bAspectRatioY 0
|
|
bmInterlaceFlags 0x00
|
|
Interlaced stream or variable: No
|
|
Fields per frame: 2 fields
|
|
Field 1 first: No
|
|
Field pattern: Field 1 only
|
|
bCopyProtect 0
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 30
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
|
|
bFrameIndex 1
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 480
|
|
wHeight 320
|
|
dwMinBitRate 12288000
|
|
dwMaxBitRate 12288000
|
|
dwMaxVideoFrameBufferSize 307200
|
|
dwDefaultFrameInterval 2000000
|
|
bFrameIntervalType 1
|
|
dwFrameInterval( 0) 2000000
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 30
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
|
|
bFrameIndex 2
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 640
|
|
wHeight 480
|
|
dwMinBitRate 73728000
|
|
dwMaxBitRate 73728000
|
|
dwMaxVideoFrameBufferSize 614400
|
|
dwDefaultFrameInterval 666666
|
|
bFrameIntervalType 1
|
|
dwFrameInterval( 0) 666666
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 11
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 6 (FORMAT_MJPEG)
|
|
bFormatIndex 2
|
|
bNumFrameDescriptors 4
|
|
bFlags 0
|
|
Fixed-size samples: No
|
|
bDefaultFrameIndex 1
|
|
bAspectRatioX 0
|
|
bAspectRatioY 0
|
|
bmInterlaceFlags 0x00
|
|
Interlaced stream or variable: No
|
|
Fields per frame: 1 fields
|
|
Field 1 first: No
|
|
Field pattern: Field 1 only
|
|
bCopyProtect 0
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 30
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 7 (FRAME_MJPEG)
|
|
bFrameIndex 1
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 640
|
|
wHeight 480
|
|
dwMinBitRate 36864000
|
|
dwMaxBitRate 36864000
|
|
dwMaxVideoFrameBufferSize 307789
|
|
dwDefaultFrameInterval 666666
|
|
bFrameIntervalType 1
|
|
dwFrameInterval( 0) 666666
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 38
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 7 (FRAME_MJPEG)
|
|
bFrameIndex 2
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 480
|
|
wHeight 320
|
|
dwMinBitRate 6144000
|
|
dwMaxBitRate 18432000
|
|
dwMaxVideoFrameBufferSize 154189
|
|
dwDefaultFrameInterval 666666
|
|
bFrameIntervalType 3
|
|
dwFrameInterval( 0) 666666
|
|
dwFrameInterval( 1) 1000000
|
|
dwFrameInterval( 2) 2000000
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 30
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 7 (FRAME_MJPEG)
|
|
bFrameIndex 3
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 352
|
|
wHeight 288
|
|
dwMinBitRate 12165120
|
|
dwMaxBitRate 12165120
|
|
dwMaxVideoFrameBufferSize 101965
|
|
dwDefaultFrameInterval 666666
|
|
bFrameIntervalType 1
|
|
dwFrameInterval( 0) 666666
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 30
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 7 (FRAME_MJPEG)
|
|
bFrameIndex 4
|
|
bmCapabilities 0x00
|
|
Still image unsupported
|
|
wWidth 320
|
|
wHeight 240
|
|
dwMinBitRate 9216000
|
|
dwMaxBitRate 9216000
|
|
dwMaxVideoFrameBufferSize 77389
|
|
dwDefaultFrameInterval 666666
|
|
bFrameIntervalType 1
|
|
dwFrameInterval( 0) 666666
|
|
VideoStreaming Interface Descriptor:
|
|
bLength 6
|
|
bDescriptorType 36
|
|
bDescriptorSubtype 13 (COLORFORMAT)
|
|
bColorPrimaries 1 (BT.709,sRGB)
|
|
bTransferCharacteristics 1 (BT.709)
|
|
bMatrixCoefficients 4 (SMPTE 170M (BT.601))
|
|
Interface Descriptor:
|
|
bLength 9
|
|
bDescriptorType 4
|
|
bInterfaceNumber 1
|
|
bAlternateSetting 1
|
|
bNumEndpoints 1
|
|
bInterfaceClass 14 Video
|
|
bInterfaceSubClass 2 Video Streaming
|
|
bInterfaceProtocol 0
|
|
iInterface 0
|
|
Endpoint Descriptor:
|
|
bLength 7
|
|
bDescriptorType 5
|
|
bEndpointAddress 0x81 EP 1 IN
|
|
bmAttributes 5
|
|
Transfer Type Isochronous
|
|
Synch Type Asynchronous
|
|
Usage Type Data
|
|
wMaxPacketSize 0x03bc 1x 956 bytes
|
|
bInterval 1
|
|
*/
|
|
|
|
static uint8_t config_desc_bytes [] = {
|
|
0x09, 0x02, 0x85, 0x01, 0x02, 0x01, 0x00, 0x80, 0xFA, 0x08, 0x0B, 0x00, 0x02, 0x0E, 0x03, 0x00, 0x05, 0x09, 0x04,
|
|
0x00, 0x00, 0x01, 0x0E, 0x01, 0x00, 0x05, 0x0D, 0x24, 0x01, 0x00, 0x01, 0x4F, 0x00, 0xC0, 0xE1, 0xE4, 0x00, 0x01,
|
|
0x01, 0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x03, 0x00, 0x1C, 0x24, 0x06, 0x03, 0xB6, 0x8D, 0xF1, 0x4C, 0xD0,
|
|
0xAB, 0x5C, 0x49, 0x76, 0x98, 0xFA, 0xF9, 0x2F, 0x94, 0xA3, 0x1F, 0x18, 0x01, 0x02, 0x03, 0xFF, 0xFF, 0xFF, 0x00,
|
|
0x12, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x00, 0x00, 0x0B,
|
|
0x24, 0x05, 0x02, 0x01, 0x00, 0x00, 0x02, 0x7F, 0x17, 0x00, 0x07, 0x05, 0x83, 0x03, 0x10, 0x00, 0x06, 0x05, 0x25,
|
|
0x03, 0x80, 0x00, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0E, 0x02, 0x00, 0x00, 0x0F, 0x24, 0x01, 0x02, 0xF7, 0x00, 0x81,
|
|
0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1B, 0x24, 0x04, 0x01, 0x02, 0x1D, 0xCC, 0xF6, 0x85, 0x9F, 0x0C,
|
|
0xF5, 0x44, 0xE0, 0x9C, 0xAB, 0x98, 0x8C, 0xDD, 0xC7, 0x97, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x24, 0x05,
|
|
0x01, 0x00, 0xE0, 0x01, 0x40, 0x01, 0x00, 0x80, 0xBB, 0x00, 0x00, 0x80, 0xBB, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x80,
|
|
0x84, 0x1E, 0x00, 0x01, 0x80, 0x84, 0x1E, 0x00, 0x1E, 0x24, 0x05, 0x02, 0x00, 0x80, 0x02, 0xE0, 0x01, 0x00, 0x00,
|
|
0x65, 0x04, 0x00, 0x00, 0x65, 0x04, 0x00, 0x60, 0x09, 0x00, 0x2A, 0x2C, 0x0A, 0x00, 0x01, 0x2A, 0x2C, 0x0A, 0x00,
|
|
0x0B, 0x24, 0x06, 0x02, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x24, 0x07, 0x01, 0x00, 0x80, 0x02, 0xE0,
|
|
0x01, 0x00, 0x80, 0x32, 0x02, 0x00, 0x80, 0x32, 0x02, 0x4D, 0xB2, 0x04, 0x00, 0x2A, 0x2C, 0x0A, 0x00, 0x01, 0x2A,
|
|
0x2C, 0x0A, 0x00, 0x26, 0x24, 0x07, 0x02, 0x00, 0xE0, 0x01, 0x40, 0x01, 0x00, 0xC0, 0x5D, 0x00, 0x00, 0x40, 0x19,
|
|
0x01, 0x4D, 0x5A, 0x02, 0x00, 0x2A, 0x2C, 0x0A, 0x00, 0x03, 0x2A, 0x2C, 0x0A, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x80,
|
|
0x84, 0x1E, 0x00, 0x1E, 0x24, 0x07, 0x03, 0x00, 0x60, 0x01, 0x20, 0x01, 0x00, 0xA0, 0xB9, 0x00, 0x00, 0xA0, 0xB9,
|
|
0x00, 0x4D, 0x8E, 0x01, 0x00, 0x2A, 0x2C, 0x0A, 0x00, 0x01, 0x2A, 0x2C, 0x0A, 0x00, 0x1E, 0x24, 0x07, 0x04, 0x00,
|
|
0x40, 0x01, 0xF0, 0x00, 0x00, 0xA0, 0x8C, 0x00, 0x00, 0xA0, 0x8C, 0x00, 0x4D, 0x2E, 0x01, 0x00, 0x2A, 0x2C, 0x0A,
|
|
0x00, 0x01, 0x2A, 0x2C, 0x0A, 0x00, 0x06, 0x24, 0x0D, 0x01, 0x01, 0x04, 0x09, 0x04, 0x01, 0x01, 0x01, 0x0E, 0x02,
|
|
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0xBC, 0x03, 0x01,
|
|
};
|
|
_Static_assert(sizeof(config_desc_bytes) == 0x0185, "Configuration Descriptor size does not match");
|
|
|
|
#define TEST_NUM_INTF_DESC 3 //Total number of interface descriptors (including alternate)
|
|
|
|
// --------------------- Sub-Test 1 ------------------------
|
|
|
|
/*
|
|
Test if we can walk the configuration descriptor to find each interface descriptor
|
|
*/
|
|
static void test_walk_desc(const usb_config_desc_t *config_desc)
|
|
{
|
|
int offset = 0;
|
|
const usb_standard_desc_t *cur_desc = (usb_standard_desc_t *)config_desc;
|
|
for (int i = 0; i < TEST_NUM_INTF_DESC; i++) {
|
|
cur_desc = usb_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, cur_desc);
|
|
}
|
|
//Attempting to look for another interface descriptor should result in NULL
|
|
cur_desc = usb_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
|
|
TEST_ASSERT_EQUAL(NULL, cur_desc);
|
|
}
|
|
|
|
/*
|
|
Test if the count of number of alternate descriptors is correct
|
|
*/
|
|
static void test_alt_intf_desc_count(const usb_config_desc_t *config_desc)
|
|
{
|
|
//bInterface 0 has no alternate interfaces
|
|
TEST_ASSERT_EQUAL(0, usb_parse_interface_number_of_alternate(config_desc, 0));
|
|
//bInterface 1 has 1 alternate interface
|
|
TEST_ASSERT_EQUAL(1, usb_parse_interface_number_of_alternate(config_desc, 1));
|
|
//Non existent bInterface 2 should return -1
|
|
TEST_ASSERT_EQUAL(-1, usb_parse_interface_number_of_alternate(config_desc, 2));
|
|
}
|
|
|
|
static void test_parse_intf_and_ep(const usb_config_desc_t *config_desc)
|
|
{
|
|
int offset_intf = 0;
|
|
|
|
//Get bInterfaceNumber 0 (index 0)
|
|
const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, 0, 0, &offset_intf);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, intf_desc);
|
|
//Should only have one endpoint
|
|
int offset_ep = offset_intf;
|
|
const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, ep_desc);
|
|
TEST_ASSERT_EQUAL(0x83, ep_desc->bEndpointAddress);
|
|
offset_ep = offset_intf;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep);
|
|
TEST_ASSERT_EQUAL(NULL, ep_desc);
|
|
|
|
//Get bInterfaceNumber 1 alternate setting 0
|
|
offset_intf = 0;
|
|
intf_desc = usb_parse_interface_descriptor(config_desc, 1, 0, &offset_intf);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, intf_desc);
|
|
//Should have no endpoints
|
|
offset_ep = offset_intf;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
|
|
TEST_ASSERT_EQUAL(NULL, ep_desc);
|
|
|
|
//Get bInterfaceNumber 1 alternate setting 1
|
|
offset_intf = 0;
|
|
intf_desc = usb_parse_interface_descriptor(config_desc, 1, 1, &offset_intf);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, intf_desc);
|
|
//Should only have one endpoint
|
|
offset_ep = offset_intf;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, ep_desc);
|
|
TEST_ASSERT_EQUAL(0x81, ep_desc->bEndpointAddress);
|
|
offset_ep = offset_intf;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep);
|
|
TEST_ASSERT_EQUAL(NULL, ep_desc);
|
|
}
|
|
|
|
static void test_parse_ep_by_address(const usb_config_desc_t *config_desc)
|
|
{
|
|
int offset_ep = 0;
|
|
//Get bInterface 0 bAlternateSetting 0 EP 0x83
|
|
const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 0, 0, 0x83, &offset_ep);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, ep_desc);
|
|
TEST_ASSERT_EQUAL(0x83, ep_desc->bEndpointAddress);
|
|
//Getting same EP address under different interface should return NULL
|
|
offset_ep = 0;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 0, 0x83, &offset_ep);
|
|
TEST_ASSERT_EQUAL(NULL, ep_desc);
|
|
|
|
//Get bInterface 1 bAlternateSetting 1 EP 0x81
|
|
offset_ep = 0;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 1, 0x81, &offset_ep);
|
|
TEST_ASSERT_NOT_EQUAL(NULL, ep_desc);
|
|
TEST_ASSERT_EQUAL(0x81, ep_desc->bEndpointAddress);
|
|
//Getting same EP address under different interface should return NULL
|
|
offset_ep = 0;
|
|
ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 0, 0x81, &offset_ep);
|
|
TEST_ASSERT_EQUAL(NULL, ep_desc);
|
|
}
|
|
|
|
TEST_CASE("Test USB Helpers descriptor parsing", "[usb_host][ignore]")
|
|
{
|
|
const usb_config_desc_t *config_desc = (const usb_config_desc_t *)config_desc_bytes;
|
|
test_walk_desc(config_desc);
|
|
test_alt_intf_desc_count(config_desc);
|
|
test_parse_intf_and_ep(config_desc);
|
|
test_parse_ep_by_address(config_desc);
|
|
}
|