From ada1c9c5b8b5a5f5eda9469fc3275ffae22b90ad Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 6 Jan 2022 15:15:32 +0800 Subject: [PATCH] usb: Add USB Host Library documentation This commit adds the USB Host Library documentation and fixes some nitpicks in the Host Stack types. Closes https://github.com/espressif/esp-idf/issues/6408 --- components/usb/include/usb/usb_types_ch9.h | 2 +- components/usb/include/usb/usb_types_stack.h | 2 +- docs/_static/usb_host_lib_entities.png | Bin 0 -> 65445 bytes docs/_static/usb_host_lib_lifecycle.png | Bin 0 -> 24787 bytes .../en/api-reference/peripherals/usb_host.rst | 373 +++++++++++++++++- 5 files changed, 374 insertions(+), 3 deletions(-) create mode 100644 docs/_static/usb_host_lib_entities.png create mode 100644 docs/_static/usb_host_lib_lifecycle.png diff --git a/components/usb/include/usb/usb_types_ch9.h b/components/usb/include/usb/usb_types_ch9.h index 3cd853b9f6..b11305900f 100644 --- a/components/usb/include/usb/usb_types_ch9.h +++ b/components/usb/include/usb/usb_types_ch9.h @@ -474,7 +474,7 @@ typedef union { struct { uint8_t bLength; /**< Size of the descriptor in bytes */ uint8_t bDescriptorType; /**< STRING Descriptor Type */ - uint16_t wData[0]; /**< UTF-16LE encoded */ + uint16_t wData[]; /**< UTF-16LE encoded */ } USB_DESC_ATTR; uint8_t val[USB_STR_DESC_SIZE]; } usb_str_desc_t; diff --git a/components/usb/include/usb/usb_types_stack.h b/components/usb/include/usb/usb_types_stack.h index b7a525b20d..c438c54a7f 100644 --- a/components/usb/include/usb/usb_types_stack.h +++ b/components/usb/include/usb/usb_types_stack.h @@ -138,7 +138,7 @@ struct usb_transfer_s{ 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. */ - usb_isoc_packet_desc_t isoc_packet_desc[0]; /**< Descriptors for each Isochronous packet */ + usb_isoc_packet_desc_t isoc_packet_desc[]; /**< Descriptors for each Isochronous packet */ }; /** diff --git a/docs/_static/usb_host_lib_entities.png b/docs/_static/usb_host_lib_entities.png new file mode 100644 index 0000000000000000000000000000000000000000..c22186dae42dc7023aa043c80d9847d980405934 GIT binary patch literal 65445 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 G&;$Vc9nBE{ literal 0 HcmV?d00001 diff --git a/docs/_static/usb_host_lib_lifecycle.png b/docs/_static/usb_host_lib_lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..f83e6de3b3c7c6ca1ac2c26fd21fb397f2266c15 GIT binary patch literal 24787 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

+CH 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 literal 0 HcmV?d00001 diff --git a/docs/en/api-reference/peripherals/usb_host.rst b/docs/en/api-reference/peripherals/usb_host.rst index 91a2ae44d1..169328c57a 100644 --- a/docs/en/api-reference/peripherals/usb_host.rst +++ b/docs/en/api-reference/peripherals/usb_host.rst @@ -4,7 +4,378 @@ 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). +The document provides information regarding the USB Host Library. This document is split into the following sections: + +.. contents:: Sections + :depth: 2 + + +.. ---------------------------------------------------- Overview ------------------------------------------------------- + +Overview +-------- + +The USB Host Library (hereinafter referred to as the Host Library) is the lowest public facing API layer of the ESP-IDF USB Host Stack. In most cases, applications that require USB Host functionality will not need to interface with the Host Library directly. Instead, most applications will use the API provided by a host class driver that is implemented on top of the Host Library. + +However, users may want to use the Host Library directly for some of (but not limited to) the following reasons: + +- The user needs to implement a custom host class driver such as a vendor specific class driver +- The user has a requirement for a lower level of abstraction due to resource/latency requirements + +Features & Limitations +^^^^^^^^^^^^^^^^^^^^^^ + +The Host Library has the following features: + +- Supports Full Speed (FS) and Low Speed (LS) Devices +- Supports all four transfer types (Control, Bulk, Interrupt, and Isochronous) +- Allows multiple class drivers to run simultaneously (i.e., multiple clients of the Host Library) +- A single device can be used by multiple clients simultaneously (e.g., composite devices) +- The Host Library itself (and the underlying Host Stack) does not internally instantiate any OS tasks. The number of tasks are entirely controlled by how the Host Library interface is used. However, a general rule of thumb regarding the number of tasks is ``(the number of host class drivers running + 1)``. + +Currently, the Host Library (and the underlying Host Stack) has the following limitations: + +- Only supports a single device, but the Host Library's API is designed for multiple device support. +- Only supports Asynchronous transfers +- Transfer timeouts are not supported yet + + +.. -------------------------------------------------- Architecture ----------------------------------------------------- + +Architecture +------------ + +.. figure:: ../../../_static/usb_host_lib_entities.png + :align: center + :alt: Diagram of the Key Entities of USB Host Functionality + :figclass: align-center + + Diagram of the key entities involved in USB Host functionality + +The diagram above shows the key entities that are involved when implementing USB Host functionality. These entities are: + +- The **Host Library** +- **Clients** of the Host Library +- **Devices** +- Host Library **Daemon Task** + +Host Library +^^^^^^^^^^^^ + +The Host Library is the a lowest public facing layer of the USB Host Stack. Any other IDF component (such as a class driver or a user component) that needs to communicate with a connected USB device can only do so using the Host Library API either directly or indirectly. + +The Host Library's API is split into two sub-sets, namely the **Library API** and **Client API**. + +- The Client API handles the communication between a client of the Host Library and one or more USB devices. The Client API should only be called by registered clients of the Host Library. +- The Library API handles all of the Host Library processing that is not specific to a single client (e.g., device enumeration). Usually, the library API is called by a Host Library Daemon Task. + +Clients +^^^^^^^ + +A client of the Host Library is a software component (such as a host class driver or user component) that uses the Host Library to communicate with a USB device. Generally each client has a one-to-one relation with a task, meaning that for a particular client, all of its Client API calls should be done from the context of the same task. + +By organizing the software components that use the Host Library's into clients, the Host Library can delegate the handling of all client events (i.e., the events specific to that client) to the client's task. In other words, each client task is responsible for all the required processing and event handling associated with the USB communication that the client initiates. + +Daemon Task +^^^^^^^^^^^ + +Although the Host Library delegates the handling of client events to the clients themselves, there are still Library events (i.e., events that are not specific to a client) that need to be handled. Library event handling can include things such as: + +- Handling USB device connection, enumeration, and disconnection +- Rerouting control transfers to/from clients +- Forwarding events to clients + +Therefore, in addition to the client tasks, the Host Library also requires a task (usually the Host Library Daemon Task) to handle all of the library events. + +Devices +^^^^^^^ + +The Host Library hides the details of device handling (such as connection, memory allocation, and enumeration) from the clients. The clients are provided only with a list of already connected and enumerated devices to choose from. During enumeration, each device is configured to use configuration 1. + +It is possible for a two or more clients to simultaneously communicate with the same device as long as they are not communicating to the same interface. However, multiple clients can simultaneously communicate with the same device's default endpoint (EP0), which will result in their control transfers being serialized. + +For a client to communicate with a device, the client must: + +#. Open the device using the device's address. This lets the Host Library know that the client is using that device. +#. Claim the interface(s) that will be used for communication. This prevents other clients from claiming the same interface(s). +#. Send transfers to the endpoints in the claimed interface. The client's task is responsible for handling its own processing and events. + + +.. ------------------------------------------------------ Usage -------------------------------------------------------- + +Usage +----- + +The Host Library (and the underlying Host Stack) will not create any tasks. All tasks (i.e., the client tasks and the Daemon Task) will need to be created by the class drivers or the user. Instead, the Host Library provides two event handler functions that will handle all of the required Host Library processing, thus these functions should be called repeatedly from the client tasks and the Daemon Task. Therefore, the implementation of client tasks and the Daemon Task will be the largely centered around the invocation of these event handler functions. + +Host Library & Daemon Task +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Basic Usage +""""""""""" + +The Host Library API provides :cpp:func:`usb_host_lib_handle_events` to handle library events. This function should be called repeatedly, typically from the daemon task. Some notable features regarding :cpp:func:`usb_host_lib_handle_events` are: + +- The function can block until a library event needs handling +- Event flags are returned on each invocation. These event flags are useful for knowing when the Host Library can be uninstalled. + +A bare-bones Daemon Task would resemble something like the following code snippet: + +.. code-block:: c + + #include "usb/usb_host.h" + + void daemon_task(void *arg) + { + ... + bool exit = false; + while (!exit) { + uint32_t event_flags; + usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + ... + } + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + ... + } + ... + } + ... + } + +.. note:: + See the :example:`peripherals/usb/host/usb_host_lib` example for a full implementation of the Daemon Task + +Lifecycle +""""""""" + +.. figure:: ../../../_static/usb_host_lib_lifecycle.png + :align: center + :alt: Graph of Typical USB Host Library Lifecycle + :figclass: align-center + + Graph of Typical USB Host Library Lifecycle + +The graph above illustrates the typical lifecycle of the Host Library with multiple clients and devices. Specifically, the example involves... + +- two registered clients (Client 1 and Client 2) +- two connected devices (Device 1 and Device 2), where Client 1 communicates with Device 1 and Client 2 communicates with Device 2. + +With reference the graph above, the typical lifecycle involves the following key stages. + +1. The Host Library is installed by calling :cpp:func:`usb_host_install`. + - Installation must be done before any other Host Library API is called. + - Where :cpp:func:`usb_host_install` is called (e.g., from the Daemon Task or another task) will depend on the synchronization logic between the Daemon Task, client tasks, and the rest of the system. +2. Once the Host Library is installed, the clients can be registered by calling :cpp:func:`usb_host_client_register`. + - This is typically called from the client task (where the client task waits for a signal from the Daemon Task). + - This can be called elsewhere if necessary as long it is called after :cpp:func:`usb_host_install`. +3. Device 1 connects and is then enumerated. + - Each registered client (in this case Client 1 and Client 2) are notified of the new device by way of the :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event. + - Client 1 opens Device 1 and begins communication with it. +4. Similarly Device 2 connects and is enumerated. + - Client 1 and 2 are notified of a new device (via a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event). + - Client 2 opens Device 2 and begins communication with it. +5. Device 1 suddenly disconnects. + - Client 1 is notified by way of :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` and begins its cleanup. + - Client 2 is not notified as it has not opened Device 1. +6. Client 1 completes its clean up and deregisters by calling :cpp:func:`usb_host_client_deregister`. + - This is typically called from the client task before the task exits. + - This can be called elsewhere if necessary as long as Client 1 has already completed its clean up. +7. Client 2 completes its communication with Device 2. Client 2 then closes Device 2 and deregisters itself. + - The Daemon Task is notified of the deregistration of all clients by way the :c:macro:`USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS` event flag as Client 2 is the last client to deregister. + - Device 2 is still allocated (i.e., not freed) as it is still connected albeit not currently opened by any client. +8. The Daemon Task decides to cleanup as there are no more clients. + - The Daemon Task must free Device 2 first by calling :cpp:func:`usb_host_device_free_all`. + - If :cpp:func:`usb_host_device_free_all` was able to free all devices, the function will return `ESP_OK` indicating that all devices have been freed. + - If :cpp:func:`usb_host_device_free_all` was unable to free all devices (e.g., because the device is still opened by a client), the function will return `ESP_ERR_NOT_FINISHED`. + - The Daemon Task must wait for :cpp:func:`usb_host_lib_handle_events` to return the :c:macro:`USB_HOST_LIB_EVENT_FLAGS_ALL_FREE` event flag in order to know when all devices have been freed. +9. Once the Daemon Task has verified that all clients have deregistered and all devices have been freed, it can now uninstall the Host Library by calling :cpp:func:`usb_host_uninstall`. + +Clients & Class Driver +^^^^^^^^^^^^^^^^^^^^^^ + +Basic Usage +""""""""""" + +The Host Library API provides :cpp:func:`usb_host_client_handle_events` to handle a particular client's events. This function should be called repeatedly, typically from the client's task. Some notable features regarding :cpp:func:`usb_host_client_handle_events` are: + +- The function can block until a client event needs handling +- The function's primary purpose is to call the various event handling callbacks when a client event occurs. + +The following callbacks are called from within :cpp:func:`usb_host_client_handle_events` thus allowing the client task to be notified of events. + +- The client event callback of type :cpp:type:`usb_host_client_event_cb_t` which delivers client event messages to the client. Client event messages indicate events such as the addition or removal of a device. +- The USB transfer completion callback of type :cpp:type:`usb_transfer_cb_t` which indicates that a particular USB transfer previously submitted by the client has completed. + +.. note:: + Given that the callbacks are called from within :cpp:func:`usb_host_client_handle_events`, users should avoid blocking from within the callbacks as this will result in :cpp:func:`usb_host_client_handle_events` being blocked as well, thus preventing other pending client events from being handled. + +The following code snippet demonstrates a bare-bones host class driver and its client task. The code snippet contains: + +- A simple client task function ``client_task`` that calls :cpp:func:`usb_host_client_handle_events` in a loop. +- Implementations of a client event callback and transfer completion callbacks. +- Implementation of a simple state machine for the class driver. The class driver simply opens a device, sends an OUT transfer to EP1, then closes the device. + +.. code-block:: c + + #include + #include "usb/usb_host.h" + + #define CLASS_DRIVER_ACTION_OPEN_DEV 0x01 + #define CLASS_DRIVER_ACTION_TRANSFER 0x02 + #define CLASS_DRIVER_ACTION_CLOSE_DEV 0x03 + + struct class_driver_control { + uint32_t actions; + uint8_t dev_addr; + usb_host_client_handle_t client_hdl; + usb_device_handle_t dev_hdl; + }; + + static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg) + { + //This is function is called from within usb_host_client_handle_events(). Don't block and try to keep it short + struct class_driver_control *class_driver_obj = (struct class_driver_control *)arg; + switch (event_msg->event) { + case USB_HOST_CLIENT_EVENT_NEW_DEV: + class_driver_obj->actions |= CLASS_DRIVER_ACTION_OPEN_DEV; + class_driver_obj->dev_addr = event_msg->new_dev.address; //Store the address of the new device + break; + case USB_HOST_CLIENT_EVENT_DEV_GONE: + class_driver_obj->actions |= CLASS_DRIVER_ACTION_CLOSE_DEV; + break; + default: + break; + } + } + + static void transfer_cb(usb_transfer_t *transfer) + { + //This is function is called from within usb_host_client_handle_events(). Don't block and try to keep it short + struct class_driver_control *class_driver_obj = (struct class_driver_control *)transfer->context; + printf("Transfer status %d, actual number of bytes transferred %d\n", transfer->status, transfer->actual_num_bytes); + class_driver_obj->actions |= CLASS_DRIVER_ACTION_CLOSE_DEV; + } + + void client_task(void *arg) + { + ... //Wait until Host Library is installed + //Initialize class driver objects + struct class_driver_control class_driver_obj = {0}; + //Register the client + usb_host_client_config_t client_config = { + .is_synchronous = false, + .max_num_event_msg = 5, + .async = { + .client_event_callback = client_event_cb, + .callback_arg = &class_driver_obj, + } + }; + usb_host_client_register(&client_config, &class_driver_obj.client_hdl); + //Allocate a USB transfer + usb_transfer_t *transfer; + usb_host_transfer_alloc(1024, 0, &transfer); + + //Event handling loop + bool exit = false; + while (!exit) { + //Call the client event handler function + usb_host_client_handle_events(class_driver_obj.client_hdl, portMAX_DELAY); + //Execute pending class driver actions + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_OPEN_DEV) { + //Open the device and claim interface 1 + usb_host_device_open(class_driver_obj.client_hdl, class_driver_obj.dev_addr, &class_driver_obj.dev_hdl); + usb_host_interface_claim(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1, 0); + } + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_TRANSFER) { + //Send an OUT transfer to EP1 + memset(transfer->data_buffer, 0xAA, 1024); + transfer->num_bytes = 1024; + transfer->device_handle = class_driver_obj.dev_hdl; + transfer->bEndpointAddress = 0x01; + transfer->callback = transfer_cb; + transfer->context = (void *)&class_driver_obj; + usb_host_transfer_submit(transfer); + } + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_CLOSE_DEV) { + //Release the interface and close the device + usb_host_interface_release(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1); + usb_host_device_close(class_driver_obj.client_hdl, class_driver_obj.dev_hdl); + exit = true; + } + ... //Handle any other actions required by the class driver + } + + //Cleanup class driver + usb_host_transfer_free(transfer); + usb_host_client_deregister(class_driver_obj.client_hdl); + ... //Delete the task and any other signal Daemon Task if required + } + +.. note:: + An actual host class driver will likely supported many more features, thus will have a much more complex state machine. A host class driver will likely also need to: + + - Be able to open multiple devices + - Parse an opened device's descriptors to identify if the device is of the target class + - Communicate with multiple endpoints of an interface in a particular order + - Claim multiple interfaces of a device + - Handle various errors + +Lifecycle +""""""""" + +The typical life cycle of a client task and class driver will go through the following stages: + +#. Wait for some signal regarding the Host Library being installed. +#. Register the client via :cpp:func:`usb_host_client_register` and allocate any other class driver resources (e.g., allocating transfers using :cpp:func:`usb_host_transfer_alloc`). +#. For each new device that the class driver needs to communicate with: + + a. Check if the device is already connected via :cpp:func:`usb_host_device_addr_list_fill`. + b. If the device is not already connected, wait for a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event from the client event callback. + c. Open the device via :cpp:func:`usb_host_device_open`. + d. Parse the device and configuration descriptors via :cpp:func:`usb_host_get_device_descriptor` and :cpp:func:`usb_host_get_active_config_descriptor` respectively. + e. Claim the necessary interfaces of the device via :cpp:func:`usb_host_interface_claim`. + +#. Submit transfers to the device via :cpp:func:`usb_host_transfer_submit` or :cpp:func:`usb_host_transfer_submit_control`. +#. Once an opened device is no longer needed by the class driver, or has disconnected (as indicated by a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` event): + + a. Stop any previously submitted transfers to the device's endpoints by calling :cpp:func:`usb_host_endpoint_halt` and :cpp:func:`usb_host_endpoint_flush` on those endpoints. + b. Release all previously claimed interfaces via :cpp:func:`usb_host_interface_release`. + c. Close the device via :cpp:func:`usb_host_device_close`. + +#. Deregister the client via :cpp:func:`usb_host_client_deregister` and free any other class driver resources. +#. Delete the client task. Signal the Daemon Task if necessary. + + +.. ---------------------------------------------------- Examples ------------------------------------------------------- + +Examples +-------- + +Host Library Examples +^^^^^^^^^^^^^^^^^^^^^ + +The :example:`peripherals/usb/host/usb_host_lib` demonstrates basic usage of the USB Host Library's API to implement a pseudo class driver. + +Class Driver Examples +^^^^^^^^^^^^^^^^^^^^^ + +The USB Host Stack provides a number examples that implement host class drivers using the Host Library's API. + +CDC-ACM +""""""" + +* A host class driver for the Communication Device Class (Abstract Control Model) is currently implemented as an example component (found via :example:`peripherals/usb/host/cdc/common/cdc_acm_host`). +* The :example:`peripherals/usb/host/cdc/cdc_acm_host` example uses the CDC-ACM host driver component to communicate with CDC-ACM devices +* The :example:`peripherals/usb/host/cdc/cdc_acm_bg96` example uses the CDC-ACM host driver component to communicate with non-compliant CDC-ACM devices (i.e., vendor-specific classes that support a subset of CDC-ACM features) such as the Quectel BG96 modem. + +MSC +""" + +* A host class driver for the Mass Storage Class (Bulk-Only Transport) is current implemented as an example found via :example:`peripherals/usb/host/msc`. + + +.. -------------------------------------------------- API Reference ---------------------------------------------------- API Reference -------------