esp-idf/components/usb/test/usb_host/test_usb_helpers.c

440 lines
20 KiB
C
Raw Normal View History

/*
* 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);
}