Add USB Host Library API docs

- 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
This commit is contained in:
Darian Leung 2021-08-31 14:14:04 +08:00
parent d910d42a8d
commit 963836f491
17 changed files with 199 additions and 135 deletions

View File

@ -6,7 +6,7 @@ set(priv_require)
if(CONFIG_USB_OTG_SUPPORTED)
list(APPEND srcs "hcd.c"
"hub.c"
"usb_host_misc.c"
"usb_helpers.c"
"usb_host.c"
"usb_private.c"
"usbh.c")

View File

@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
/*
Warning: The USB Host Library API is still a beta version and may be subject to change
*/
#pragma once
#include <stdint.h>
@ -28,7 +32,7 @@ extern "C" {
* the current descriptor. On output, it is the offset of the returned descriptor.
* @return usb_standard_desc_t* Next descriptor, NULL if end of configuration descriptor reached
*/
const usb_standard_desc_t *usb_host_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset);
const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset);
/**
* @brief Get the next descriptor of a particular type
@ -43,7 +47,7 @@ const usb_standard_desc_t *usb_host_parse_next_descriptor(const usb_standard_des
* the current descriptor. On output, it is the offset of the returned descriptor.
* @return usb_standard_desc_t* Next descriptor, NULL if end descriptor is not found or configuration descriptor reached
*/
const usb_standard_desc_t *usb_host_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset);
const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset);
/**
* @brief Get the number of alternate settings for a bInterfaceNumber
@ -55,7 +59,7 @@ const usb_standard_desc_t *usb_host_parse_next_descriptor_of_type(const usb_stan
* @param[in] bInterfaceNumber Interface number
* @return int The number of alternate settings that the interface has, -1 if bInterfaceNumber not found
*/
int usb_host_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber);
int usb_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber);
/**
* @brief Get a particular interface descriptor (using bInterfaceNumber and bAlternateSetting)
@ -63,7 +67,7 @@ int usb_host_parse_interface_number_of_alternate(const usb_config_desc_t *config
* Given a full configuration descriptor, get a particular interface descriptor.
*
* @note To get the number of alternate settings for a particular bInterfaceNumber, call
* usb_host_parse_interface_number_of_alternate()
* usb_parse_interface_number_of_alternate()
*
* @param[in] config_desc Pointer to the start of a full configuration descriptor
* @param[in] bInterfaceNumber Interface number
@ -71,7 +75,7 @@ int usb_host_parse_interface_number_of_alternate(const usb_config_desc_t *config
* @param[out] offset Byte offset of the interface descriptor relative to the start of the configuration descriptor. Can be NULL.
* @return const usb_intf_desc_t* Pointer to interface descriptor, NULL if not found.
*/
const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, int *offset);
const usb_intf_desc_t *usb_parse_interface_descriptor(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, int *offset);
/**
* @brief Get an endpoint descriptor within an interface descriptor
@ -88,10 +92,10 @@ const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_
* of the interface descriptor. On output, it is the offset of the endpoint descriptor.
* @return const usb_ep_desc_t* Pointer to endpoint descriptor, NULL if not found.
*/
const usb_ep_desc_t *usb_host_parse_endpoint_by_index(const usb_intf_desc_t *intf_desc, int index, uint16_t wTotalLength, int *offset);
const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_index(const usb_intf_desc_t *intf_desc, int index, uint16_t wTotalLength, int *offset);
/**
* @brief Get an endpoint descriptor based on the endpoint's address
* @brief Get an endpoint descriptor based on an endpoint's address
*
* Given a configuration descriptor, get an endpoint descriptor based on it's bEndpointAddress, bAlternateSetting, and
* bInterfaceNumber.
@ -103,12 +107,12 @@ const usb_ep_desc_t *usb_host_parse_endpoint_by_index(const usb_intf_desc_t *int
* @param[out] offset Byte offset of the endpoint descriptor relative to the start of the configuration descriptor. Can be NULL
* @return const usb_ep_desc_t* Pointer to endpoint descriptor, NULL if not found.
*/
const usb_ep_desc_t *usb_host_parse_endpoint_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset);
const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset);
// ------------------------------------------------------ Misc ---------------------------------------------------------
/**
* @brief Round up to an integer multiple of an endpoint's MPS
* @brief Round up to an integer multiple of endpoint's MPS
*
* This is a convenience function to round up a size/length to an endpoint's MPS (Maximum packet size). This is useful
* when calculating transfer or buffer lengths of IN endpoints.
@ -117,7 +121,7 @@ const usb_ep_desc_t *usb_host_parse_endpoint_by_address(const usb_config_desc_t
* @param[in] mps MPS
* @return int Round up integer multiple of MPS
*/
static inline int usb_host_round_up_to_mps(int num_bytes, int mps)
static inline int usb_round_up_to_mps(int num_bytes, int mps)
{
if (num_bytes < 0 || mps < 0) {
return 0;

View File

@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
/*
Warning: The USB Host Library API is still a beta version and may be subject to change
*/
#pragma once
#include <stdint.h>
@ -11,7 +15,7 @@
#include "esp_err.h"
#include "esp_intr_alloc.h"
//Include the other USB Host Library headers as well
#include "usb/usb_host_misc.h"
#include "usb/usb_helpers.h"
#include "usb/usb_types_ch9.h"
#include "usb/usb_types_stack.h"
@ -197,7 +201,7 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_
* @brief Close a device
*
* - This function allows a client to close a device
* - A client must close a device after it has finished using the device
* - A client must close a device after it has finished using the device (claimed interfaces must also be released)
* - A client must close all devices it has opened before deregistering
*
* @param[in] client_hdl Client handle
@ -225,7 +229,7 @@ esp_err_t usb_host_device_free_all(void);
// ------------------- Cached Requests ---------------------
/**
* @brief Get a device's information
* @brief Get device's information
*
* - This function gets some basic information of a device
* - The device must be opened first before attempting to get its information
@ -241,7 +245,7 @@ esp_err_t usb_host_device_info(usb_device_handle_t dev_hdl, usb_device_info_t *d
// ----------------- Cached Descriptors --------------------
/**
* @brief Get a device's device descriptor
* @brief Get device's device descriptor
*
* - A client must call usb_host_device_open() first
* - No control transfer is sent. The device's descriptor is cached on enumeration
@ -255,7 +259,7 @@ esp_err_t usb_host_device_info(usb_device_handle_t dev_hdl, usb_device_info_t *d
esp_err_t usb_host_get_device_descriptor(usb_device_handle_t dev_hdl, const usb_device_desc_t **device_desc);
/**
* @brief Get a device's active configuration descriptor
* @brief Get device's active configuration descriptor
*
* - A client must call usb_host_device_open() first
* - No control transfer is sent. The device's active configuration descriptor is cached on enumeration
@ -271,7 +275,7 @@ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, con
// ----------------------------------------------- Interface Functions -------------------------------------------------
/**
* @brief Function for a client to claim an device's interface
* @brief Function for a client to claim a device's interface
*
* - A client must claim a device's interface before attempting to communicate with any of its endpoints
* - Once an interface is claimed by a client, it cannot be claimed by any other client.
@ -285,7 +289,7 @@ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, con
esp_err_t usb_host_interface_claim(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber, uint8_t bAlternateSetting);
/**
* @brief Function for a client to release a device's interface
* @brief Function for a client to release a previously claimed interface
*
* - A client should release a device's interface after it no longer needs to communicate with the interface
* - A client must release all of its interfaces of a device it has claimed before being able to close the device

View File

@ -5,12 +5,7 @@
*/
/*
Note: This header file contains the types and macros belong/relate to the USB2.0 protocol and are HW implementation
and mode (i.e., Host or Device) agnostic.
- On the USB Host Stack, this header is only meant to be used on the HCD layer and above. For types and macros on the
Host stack that are HW implementation specific (i.e., HAL layer and below), add them to the "hal/usb_types_private.h"
header instead.
Warning: The USB Host Library API is still a beta version and may be subject to change
*/
#pragma once
@ -28,15 +23,20 @@ extern "C"
/**
* @brief USB2.0 device states
*
* See Table 9-1 of USB2.0 specification for more details
*
* @note The USB_DEVICE_STATE_NOT_ATTACHED is not part of the USB2.0 specification, but is a catch all state for devices
* that need to be cleaned up after a sudden disconnection or port error.
*/
typedef enum {
USB_DEVICE_STATE_NOT_ATTACHED, //Not in the USB spec, but is a catch all state for devices that need to be cleaned up after a sudden disconnection or port error
USB_DEVICE_STATE_ATTACHED,
USB_DEVICE_STATE_POWERED,
USB_DEVICE_STATE_DEFAULT,
USB_DEVICE_STATE_ADDRESS,
USB_DEVICE_STATE_CONFIGURED,
USB_DEVICE_STATE_SUSPENDED,
USB_DEVICE_STATE_NOT_ATTACHED, /**< The device was previously configured or suspended, but is no longer attached (either suddenly disconnected or a port error) */
USB_DEVICE_STATE_ATTACHED, /**< Device is attached to the USB, but is not powered. */
USB_DEVICE_STATE_POWERED, /**< Device is attached to the USB and powered, but has not been reset. */
USB_DEVICE_STATE_DEFAULT, /**< Device is attached to the USB and powered and has been reset, but has not been assigned a unique address. Device responds at the default address. */
USB_DEVICE_STATE_ADDRESS, /**< Device is attached to the USB, powered, has been reset, and a unique device address has been assigned. Device is not configured. */
USB_DEVICE_STATE_CONFIGURED, /**< Device is attached to the USB, powered, has been reset, has a unique address, is configured, and is not suspended. The host may now use the function provided by the device. */
USB_DEVICE_STATE_SUSPENDED, /**< Device is, at minimum, attached to the USB and is powered and has not seen bus activity for 3 ms. It may also have a unique address and be configured for use. However, because the device is suspended, the host may not use the devices function. */
} usb_device_state_t;
/**
@ -85,14 +85,16 @@ typedef enum {
/**
* @brief Structure representing a USB control transfer setup packet
*
* See Table 9-2 of USB2.0 specification for more details
*/
typedef union {
struct {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint8_t bmRequestType; /**< Characteristics of request */
uint8_t bRequest; /**< Specific request */
uint16_t wValue; /**< Word-sized field that varies according to request */
uint16_t wIndex; /**< Word-sized field that varies according to request; typically used to pass an index or offset */
uint16_t wLength; /**< Number of bytes to transfer if there is a data stage */
} __attribute__((packed));
uint8_t val[USB_SETUP_PACKET_SIZE];
} usb_setup_packet_t;
@ -220,14 +222,14 @@ _Static_assert(sizeof(usb_setup_packet_t) == USB_SETUP_PACKET_SIZE, "Size of usb
#define USB_STANDARD_DESC_SIZE 2
/**
* @brief Dummy USB standard descriptor
* @brief USB standard descriptor
*
* All USB standard descriptors start with these two bytes. Use this type traversing over descriptors
* All USB standard descriptors start with these two bytes. Use this type when traversing over configuration descriptors
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< Descriptor Type */
} USB_DESC_ATTR;
uint8_t val[USB_STANDARD_DESC_SIZE];
} usb_standard_desc_t;
@ -242,23 +244,25 @@ _Static_assert(sizeof(usb_standard_desc_t) == USB_STANDARD_DESC_SIZE, "Size of u
/**
* @brief Structure representing a USB device descriptor
*
* See Table 9-8 of USB2.0 specification for more details
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< DEVICE Descriptor Type */
uint16_t bcdUSB; /**< USB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H) */
uint8_t bDeviceClass; /**< Class code (assigned by the USB-IF) */
uint8_t bDeviceSubClass; /**< Subclass code (assigned by the USB-IF) */
uint8_t bDeviceProtocol; /**< Protocol code (assigned by the USB-IF) */
uint8_t bMaxPacketSize0; /**< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid) */
uint16_t idVendor; /**< Vendor ID (assigned by the USB-IF) */
uint16_t idProduct; /**< Product ID (assigned by the manufacturer) */
uint16_t bcdDevice; /**< Device release number in binary-coded decimal */
uint8_t iManufacturer; /**< Index of string descriptor describing manufacturer */
uint8_t iProduct; /**< Index of string descriptor describing product */
uint8_t iSerialNumber; /**< Index of string descriptor describing the devices serial number */
uint8_t bNumConfigurations; /**< Number of possible configurations */
} USB_DESC_ATTR;
uint8_t val[USB_DEVICE_DESC_SIZE];
} usb_device_desc_t;
@ -307,19 +311,21 @@ _Static_assert(sizeof(usb_device_desc_t) == USB_DEVICE_DESC_SIZE, "Size of usb_d
/**
* @brief Structure representing a short USB configuration descriptor
*
* See Table 9-10 of USB2.0 specification for more details
*
* @note The full USB configuration includes all the interface and endpoint
* descriptors of that configuration.
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< CONFIGURATION Descriptor Type */
uint16_t wTotalLength; /**< Total length of data returned for this configuration */
uint8_t bNumInterfaces; /**< Number of interfaces supported by this configuration */
uint8_t bConfigurationValue; /**< Value to use as an argument to the SetConfiguration() request to select this configuration */
uint8_t iConfiguration; /**< Index of string descriptor describing this configuration */
uint8_t bmAttributes; /**< Configuration characteristics */
uint8_t bMaxPower; /**< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. */
} USB_DESC_ATTR;
uint8_t val[USB_CONFIG_DESC_SIZE];
} usb_config_desc_t;
@ -345,14 +351,14 @@ _Static_assert(sizeof(usb_config_desc_t) == USB_CONFIG_DESC_SIZE, "Size of usb_c
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< INTERFACE ASSOCIATION Descriptor Type */
uint8_t bFirstInterface; /**< Interface number of the first interface that is associated with this function */
uint8_t bInterfaceCount; /**< Number of contiguous interfaces that are associated with this function */
uint8_t bFunctionClass; /**< Class code (assigned by USB-IF) */
uint8_t bFunctionSubClass; /**< Subclass code (assigned by USB-IF) */
uint8_t bFunctionProtocol; /**< Protocol code (assigned by USB-IF) */
uint8_t iFunction; /**< Index of string descriptor describing this function */
} USB_DESC_ATTR;
uint8_t val[USB_IAD_DESC_SIZE];
} usb_iad_desc_t;
@ -367,18 +373,20 @@ _Static_assert(sizeof(usb_iad_desc_t) == USB_IAD_DESC_SIZE, "Size of usb_iad_des
/**
* @brief Structure representing a USB interface descriptor
*
* See Table 9-12 of USB2.0 specification for more details
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< INTERFACE Descriptor Type */
uint8_t bInterfaceNumber; /**< Number of this interface. */
uint8_t bAlternateSetting; /**< Value used to select this alternate setting for the interface identified in the prior field */
uint8_t bNumEndpoints; /**< Number of endpoints used by this interface (excluding endpoint zero). */
uint8_t bInterfaceClass; /**< Class code (assigned by the USB-IF) */
uint8_t bInterfaceSubClass; /**< Subclass code (assigned by the USB-IF) */
uint8_t bInterfaceProtocol; /**< Protocol code (assigned by the USB) */
uint8_t iInterface; /**< Index of string descriptor describing this interface */
} USB_DESC_ATTR;
uint8_t val[USB_INTF_DESC_SIZE];
} usb_intf_desc_t;
@ -393,15 +401,17 @@ _Static_assert(sizeof(usb_intf_desc_t) == USB_INTF_DESC_SIZE, "Size of usb_intf_
/**
* @brief Structure representing a USB endpoint descriptor
*
* See Table 9-13 of USB2.0 specification for more details
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< ENDPOINT Descriptor Type */
uint8_t bEndpointAddress; /**< The address of the endpoint on the USB device described by this descriptor */
uint8_t bmAttributes; /**< This field describes the endpoints attributes when it is configured using the bConfigurationValue. */
uint16_t wMaxPacketSize; /**< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. */
uint8_t bInterval; /**< Interval for polling Isochronous and Interrupt endpoints. Expressed in frames or microframes depending on the device operating speed (1 ms for Low-Speed and Full-Speed or 125 us for USB High-Speed and above). */
} USB_DESC_ATTR;
uint8_t val[USB_EP_DESC_SIZE];
} usb_ep_desc_t;
@ -451,9 +461,9 @@ _Static_assert(sizeof(usb_ep_desc_t) == USB_EP_DESC_SIZE, "Size of usb_ep_desc_t
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[1]; /* UTF-16LE encoded */
uint8_t bLength; /**< Size of the descriptor in bytes */
uint8_t bDescriptorType; /**< STRING Descriptor Type */
uint16_t wData[1]; /**< UTF-16LE encoded */
} USB_DESC_ATTR;
uint8_t val[USB_STR_DESC_SIZE];
} usb_str_desc_t;

View File

@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
/*
Warning: The USB Host Library API is still a beta version and may be subject to change
*/
#pragma once
#include "usb/usb_types_ch9.h"
@ -101,7 +105,7 @@ typedef struct {
* of the endpoint.
*
* @note For Bulk/Control/Interrupt IN transfers, the num_bytes must be a integer multiple of the endpoint's MPS
* @note This structure should be allocated via __insert_func_name__()
* @note This structure should be allocated via usb_host_transfer_alloc()
* @note Once the transfer has be submitted, users should not modify the structure until the transfer has completed
*/
typedef struct usb_transfer_s usb_transfer_t;
@ -123,7 +127,7 @@ struct usb_transfer_s{
usb_device_handle_t device_handle; /**< Device handle */
uint8_t bEndpointAddress; /**< Endpoint Address */
usb_transfer_status_t status; /**< Status of the transfer */
uint32_t timeout; /**< Timeout (in milliseconds) of the packet (currently not supported yet) */
uint32_t timeout_ms; /**< Timeout (in milliseconds) of the packet (currently not supported yet) */
usb_transfer_cb_t callback; /**< Transfer callback */
void *context; /**< Context variable for transfer to associate transfer with something */
const int num_isoc_packets; /**< Only relevant to Isochronous. Number of service periods (i.e., intervals) to transfer data buffer over. */

View File

@ -143,7 +143,7 @@ void msc_client_async_seq_task(void *arg)
usb_transfer_t *xfer_out = NULL; //Must be large enough to contain CBW and MSC reset control transfer
usb_transfer_t *xfer_in = NULL; //Must be large enough to contain CSW and Data
size_t out_worst_case_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t));
size_t in_worst_case_size = usb_host_round_up_to_mps(MAX(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, sizeof(mock_msc_bulk_csw_t)), MOCK_MSC_SCSI_BULK_EP_MPS);
size_t in_worst_case_size = usb_round_up_to_mps(MAX(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, sizeof(mock_msc_bulk_csw_t)), MOCK_MSC_SCSI_BULK_EP_MPS);
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(out_worst_case_size, 0, &xfer_out));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(in_worst_case_size, 0, &xfer_in));
xfer_out->callback = msc_transfer_cb;
@ -207,7 +207,7 @@ void msc_client_async_seq_task(void *arg)
}
case TEST_STAGE_MSC_DATA: {
ESP_LOGD(MSC_CLIENT_TAG, "Data");
xfer_in->num_bytes = usb_host_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, MOCK_MSC_SCSI_BULK_EP_MPS);
xfer_in->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, MOCK_MSC_SCSI_BULK_EP_MPS);
xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in));
//Next stage set from transfer callback
@ -215,7 +215,7 @@ void msc_client_async_seq_task(void *arg)
}
case TEST_STAGE_MSC_CSW: {
ESP_LOGD(MSC_CLIENT_TAG, "CSW");
xfer_in->num_bytes = usb_host_round_up_to_mps(sizeof(mock_msc_bulk_csw_t), MOCK_MSC_SCSI_BULK_EP_MPS);
xfer_in->num_bytes = usb_round_up_to_mps(sizeof(mock_msc_bulk_csw_t), MOCK_MSC_SCSI_BULK_EP_MPS);
xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in));
//Next stage set from transfer callback

View File

@ -346,11 +346,11 @@ 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_host_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
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_host_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
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);
}
@ -360,11 +360,11 @@ 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_host_parse_interface_number_of_alternate(config_desc, 0));
TEST_ASSERT_EQUAL(0, usb_parse_interface_number_of_alternate(config_desc, 0));
//bInterface 1 has 1 alternate interface
TEST_ASSERT_EQUAL(1, usb_host_parse_interface_number_of_alternate(config_desc, 1));
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_host_parse_interface_number_of_alternate(config_desc, 2));
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)
@ -372,37 +372,37 @@ 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_host_parse_interface(config_desc, 0, 0, &offset_intf);
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_host_parse_endpoint_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
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_host_parse_endpoint_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep);
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_host_parse_interface(config_desc, 1, 0, &offset_intf);
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_host_parse_endpoint_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
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_host_parse_interface(config_desc, 1, 1, &offset_intf);
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_host_parse_endpoint_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep);
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_host_parse_endpoint_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep);
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep);
TEST_ASSERT_EQUAL(NULL, ep_desc);
}
@ -410,26 +410,26 @@ 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_host_parse_endpoint_by_address(config_desc, 0, 0, 0x83, &offset_ep);
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_host_parse_endpoint_by_address(config_desc, 1, 0, 0x83, &offset_ep);
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_host_parse_endpoint_by_address(config_desc, 1, 1, 0x81, &offset_ep);
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_host_parse_endpoint_by_address(config_desc, 1, 0, 0x81, &offset_ep);
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 Host descriptor parsing", "[usb_host][ignore]")
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);

View File

@ -8,12 +8,12 @@
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "usb/usb_host_misc.h"
#include "usb/usb_helpers.h"
#include "usb/usb_types_ch9.h"
// ---------------------------------------- Configuration Descriptor Parsing -------------------------------------------
const usb_standard_desc_t *usb_host_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset)
const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset)
{
assert(cur_desc != NULL && offset != NULL);
if (*offset >= wTotalLength) {
@ -28,17 +28,17 @@ const usb_standard_desc_t *usb_host_parse_next_descriptor(const usb_standard_des
return ret_desc;
}
const usb_standard_desc_t *usb_host_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset)
const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset)
{
assert(cur_desc != NULL && offset != NULL);
int offset_temp = *offset; //We only want to update offset if we've actually found a descriptor
//Keep stepping over descriptors until we find one of bDescriptorType or until we go out of bounds
const usb_standard_desc_t *ret_desc = usb_host_parse_next_descriptor(cur_desc, wTotalLength, &offset_temp);
const usb_standard_desc_t *ret_desc = usb_parse_next_descriptor(cur_desc, wTotalLength, &offset_temp);
while (ret_desc != NULL) {
if (ret_desc->bDescriptorType == bDescriptorType) {
break;
}
ret_desc = usb_host_parse_next_descriptor(ret_desc, wTotalLength, &offset_temp);
ret_desc = usb_parse_next_descriptor(ret_desc, wTotalLength, &offset_temp);
}
if (ret_desc != NULL) {
//We've found a descriptor. Update the offset
@ -47,29 +47,29 @@ const usb_standard_desc_t *usb_host_parse_next_descriptor_of_type(const usb_stan
return ret_desc;
}
int usb_host_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber)
int usb_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber)
{
assert(config_desc != NULL);
int offset = 0;
//Find the first interface descriptor of bInterfaceNumber
const usb_intf_desc_t *first_intf_desc = usb_host_parse_interface(config_desc, bInterfaceNumber, 0, &offset);
const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, 0, &offset);
if (first_intf_desc == NULL) {
return -1; //bInterfaceNumber not found
}
int num_alt_setting = 0;
const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)first_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)first_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
while (next_intf_desc != NULL) {
if (next_intf_desc->bInterfaceNumber != bInterfaceNumber) {
break;
}
num_alt_setting++;
next_intf_desc = (const usb_intf_desc_t *)usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset);
}
return num_alt_setting;
}
const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, int *offset)
const usb_intf_desc_t *usb_parse_interface_descriptor(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, int *offset)
{
assert(config_desc != NULL);
if (bInterfaceNumber >= config_desc->bNumInterfaces) {
@ -78,12 +78,12 @@ const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_
//Walk to first interface descriptor of bInterfaceNumber
int offset_temp = 0;
const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)config_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)config_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
while (next_intf_desc != NULL) {
if (next_intf_desc->bInterfaceNumber == bInterfaceNumber) {
break; //We found the first interface descriptor with matching bInterfaceNumber
}
next_intf_desc = (const usb_intf_desc_t *)usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
}
if (next_intf_desc == NULL) {
return NULL; //Couldn't find a interface with bInterfaceNumber
@ -101,7 +101,7 @@ const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_
break;
}
//Get the next interface descriptor
next_intf_desc = (const usb_intf_desc_t *)usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
}
if (next_intf_desc != NULL && offset != NULL) {
*offset = offset_temp;
@ -109,7 +109,7 @@ const usb_intf_desc_t *usb_host_parse_interface(const usb_config_desc_t *config_
return next_intf_desc;
}
const usb_ep_desc_t *usb_host_parse_endpoint_by_index(const usb_intf_desc_t *intf_desc, int index, uint16_t wTotalLength, int *offset)
const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_index(const usb_intf_desc_t *intf_desc, int index, uint16_t wTotalLength, int *offset)
{
assert(intf_desc != NULL && offset != NULL);
if (index >= intf_desc->bNumEndpoints) {
@ -120,7 +120,7 @@ const usb_ep_desc_t *usb_host_parse_endpoint_by_index(const usb_intf_desc_t *int
bool ep_found = true;
const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)intf_desc;
for (int i = 0; i <= index; i++) {
next_desc = usb_host_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_desc, wTotalLength, USB_B_DESCRIPTOR_TYPE_ENDPOINT, &offset_temp);
next_desc = usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_desc, wTotalLength, USB_B_DESCRIPTOR_TYPE_ENDPOINT, &offset_temp);
if (next_desc == NULL) {
ep_found = false;
break;
@ -133,13 +133,13 @@ const usb_ep_desc_t *usb_host_parse_endpoint_by_index(const usb_intf_desc_t *int
return NULL;
}
const usb_ep_desc_t *usb_host_parse_endpoint_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset)
const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset)
{
assert(config_desc != NULL);
//Find the interface descriptor
int offset_intf;
const usb_intf_desc_t *intf_desc = usb_host_parse_interface(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
if (intf_desc == NULL) {
return NULL;
}
@ -150,7 +150,7 @@ const usb_ep_desc_t *usb_host_parse_endpoint_by_address(const usb_config_desc_t
const usb_ep_desc_t *ep_desc = NULL;
for (int index = 0; index < intf_desc->bNumEndpoints; index++) {
offset_ep = offset_intf;
ep_desc = usb_host_parse_endpoint_by_index(intf_desc, index, config_desc->wTotalLength, &offset_ep);
ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, index, config_desc->wTotalLength, &offset_ep);
if (ep_desc == NULL) {
break;
}

View File

@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
/*
Warning: The USB Host Library API is still a beta version and may be subject to change
*/
#include <stdlib.h>
#include <stdint.h>
#include "freertos/FreeRTOS.h"
@ -921,7 +925,7 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h
//We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors
//Find the interface descriptor and allocate the interface object
int offset_intf;
const usb_intf_desc_t *intf_desc = usb_host_parse_interface(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
if (intf_desc == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto exit;
@ -935,7 +939,7 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h
//Find each endpoint descriptor in the interface by index, and allocate those endpoints
for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
int offset_ep = offset_intf;
const usb_ep_desc_t *ep_desc = usb_host_parse_endpoint_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep);
const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep);
if (ep_desc == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto ep_alloc_err;

View File

@ -17,7 +17,7 @@
#include "esp_heap_caps.h"
#include "hcd.h"
#include "usbh.h"
#include "usb/usb_host_misc.h"
#include "usb/usb_helpers.h"
#include "usb/usb_types_ch9.h"
//Device action flags. Listed in the order they should handled in. Some actions are mutually exclusive

View File

@ -49,6 +49,7 @@ LEGACY_DOCS = ['api-guides/build-system-legacy.rst',
'get-started-legacy/**']
USB_DOCS = ['api-reference/peripherals/usb_device.rst',
'api-reference/peripherals/usb_host.rst',
'api-guides/usb-otg-console.rst',
'api-guides/dfu.rst']

View File

@ -14,4 +14,8 @@ INPUT += \
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_element.h \
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_button.h \
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_slider.h \
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_matrix.h
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_matrix.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_types_ch9.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_types_stack.h

View File

@ -6,4 +6,8 @@ INPUT += \
$(PROJECT_PATH)/components/hal/include/hal/pcnt_types.h \
$(PROJECT_PATH)/components/driver/include/driver/pcnt.h \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/touch_sensor_channel.h \
$(PROJECT_PATH)/components/driver/$(IDF_TARGET)/include/driver/touch_sensor.h
$(PROJECT_PATH)/components/driver/$(IDF_TARGET)/include/driver/touch_sensor.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_types_ch9.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_types_stack.h

View File

@ -34,5 +34,6 @@ Peripherals API
TWAI <twai>
UART <uart>
:SOC_USB_OTG_SUPPORTED: USB Device <usb_device>
:SOC_USB_OTG_SUPPORTED: USB Host <usb_host>
Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples.

View File

@ -0,0 +1,26 @@
USB Host
========
.. warning::
The USB Host Library API is a beta version thus is subject to change.
The following document lists the API and types of the USB Host Library (that is currently under development).
API Reference
-------------
The API of the USB Host Library is separated into the following header files. However, it is sufficient for applications to only ``#include "usb/usb_host.h"`` and all of USB Host Library headers will also be included.
- :component_file:`usb/include/usb/usb_host.h` contains the functions and types of the USB Host Library
- :component_file:`usb/include/usb/usb_helpers.h` contains various helper functions that are related to the USB protocol such as descriptor parsing.
- :component_file:`usb/include/usb/usb_types_stack.h` contains types that are are used across multiple layers of the USB Host stack.
- :component_file:`usb/include/usb/usb_types_ch9.h` contains types and macros related to Chapter 9 of the USB2.0 specification (i.e., descriptors and standard requests).
.. include-build-file:: inc/usb_host.inc
.. include-build-file:: inc/usb_helpers.inc
.. include-build-file:: inc/usb_types_stack.inc
.. include-build-file:: inc/usb_types_ch9.inc

View File

@ -33,6 +33,7 @@
:esp32s2: Touch Element <touch_element>
TWAI <twai>
UART <uart>
:SOC_USB_OTG_SUPPORTED: USB Device <usb_device>
:SOC_USB_OTG_SUPPORTED: USB 设备 (Device) <usb_device>
:SOC_USB_OTG_SUPPORTED: USB 主机 (Host) <usb_host>
本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/peripherals/usb_host.rst