add example code to pio test projet
This commit is contained in:
parent
61fce0f5da
commit
88207a7632
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
managed_components
|
@ -1,27 +0,0 @@
|
||||
## 2.0.3
|
||||
|
||||
- Added `cdc_acm_host_cdc_desc_get()` function that enables users to get CDC functional descriptors of the device
|
||||
- Fixed closing of a CDC device from multiple threads
|
||||
- Fixed reaction on TX transfer timeout (https://github.com/espressif/esp-protocols/issues/514)
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- Return an error if the selected interface does not have IN and OUT bulk endpoints
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- Added support for USB "triple null" devices, which use USB interface association descriptors, but have Device Class, Device Subclass, and Device Protocol all set to 0x00, instead of 0xEF, 0x02, and 0x01 respectively. USB Standard reference: https://www.usb.org/defined-class-codes, Base Class 00h (Device) section.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- New function `cdc_acm_host_register_new_dev_callback`. This allows you to get New Device notifications even if you use the default driver.
|
||||
- Receive buffer has configurable size. This is useful if you expect data transfers larger then Maximum Packet Size.
|
||||
- Receive buffer has 'append' function. In the Data Received callback you can signal that you wait for more data and the current data were not yet processed. In this case, the CDC driver appends new data to the already received data. This is especially useful if the upper layer messages consist of multiple USB transfers and you don't want to waste more RAM and CPU copying the data around.
|
||||
|
||||
## 1.0.4
|
||||
|
||||
- C++ methods are now virtual to allow derived classes to override them.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- Initial version
|
@ -1,15 +0,0 @@
|
||||
set(srcs)
|
||||
set(include)
|
||||
# As CONFIG_USB_OTG_SUPPORTED comes from Kconfig, it is not evaluated yet
|
||||
# when components are being registered.
|
||||
set(require usb)
|
||||
|
||||
if(CONFIG_USB_OTG_SUPPORTED)
|
||||
list(APPEND srcs "cdc_acm_host.c")
|
||||
list(APPEND include "include")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include}
|
||||
REQUIRES ${require}
|
||||
)
|
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,49 +0,0 @@
|
||||
# USB Host CDC-ACM Class Driver
|
||||
|
||||
[](https://components.espressif.com/components/espressif/usb_host_cdc_acm)
|
||||
|
||||
This component contains an implementation of a USB CDC-ACM Host Class Driver that is implemented on top of the [USB Host Library](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_host.html).
|
||||
|
||||
## Supported Devices
|
||||
|
||||
The CDC-ACM Host driver supports the following types of CDC devices:
|
||||
|
||||
1. CDC-ACM devices
|
||||
2. CDC-like vendor specific devices (usually found on USB to UART bridge devices or cellular modems)
|
||||
|
||||
### CDC-ACM Devices
|
||||
|
||||
The CDC-ACM Class driver supports CDC-ACM devices that meet the following requirements:
|
||||
- The device class code must be set to the CDC class `0x02` or implement Interface Association Descriptor (IAD)
|
||||
- The CDC-ACM must contain the following interfaces:
|
||||
- A Communication Class Interface containing a management element (EP0) and may also contain a notification element (an interrupt endpoint). The driver will check this interface for CDC Functional Descriptors.
|
||||
- A Data Class Interface with two BULK endpoints (IN and OUT). Other transfer types are not supported by the driver
|
||||
|
||||
### CDC-Like Vendor Specific Devices
|
||||
|
||||
The CDC-ACM Class driver supports CDC-like devices that meet the following requirements:
|
||||
- The device class code must be set to the vendor specific class code `0xFF`
|
||||
- The device needs to provide and interface containing the following endpoints:
|
||||
- (Mandatory) Two Bulk endpoints (IN and OUT) for data
|
||||
- (Optional) An interrupt endpoint (IN) for the notification element
|
||||
|
||||
For CDC-like devices, users are responsible for ensuring that they only call APIs (e.g., `cdc_acm_host_send_break()`) that are supported by the target device.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
The following steps outline the typical API call pattern of the CDC-ACM Class Driver
|
||||
|
||||
1. Install the USB Host Library via `usb_host_install()`
|
||||
2. Install the CDC-ACM driver via `cdc_acm_host_install()`
|
||||
3. Call `cdc_acm_host_open()`/`cdc_acm_host_open_vendor_specific()` to open a target CDC-ACM/CDC-like device. These functions will block until the target device is connected or time-out
|
||||
4. To transmit data, call `cdc_acm_host_data_tx_blocking()`
|
||||
5. When data is received, the driver will automatically run the receive data callback
|
||||
6. An opened device can be closed via `cdc_acm_host_close()`
|
||||
7. The CDC-ACM driver can be uninstalled via `cdc_acm_host_uninstall()`
|
||||
|
||||
## Examples
|
||||
|
||||
- For an example with a CDC-ACM device, refer to [cdc_acm_host](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/cdc/cdc_acm_host)
|
||||
- For an example with Virtual COM devices, refer to [cdc_acm_vcp](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/cdc/cdc_acm_vcp)
|
||||
- For examples with [esp_modem](https://components.espressif.com/components/espressif/esp_modem), refer to [esp_modem examples](https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples)
|
File diff suppressed because it is too large
Load Diff
@ -1,18 +0,0 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.4'
|
||||
description: USB Host CDC-ACM driver
|
||||
repository: git://github.com/espressif/esp-usb.git
|
||||
repository_info:
|
||||
commit_sha: d938736c500397f92fc8fe8881539e33a9edc93b
|
||||
path: host/class/cdc/usb_host_cdc_acm
|
||||
tags:
|
||||
- usb
|
||||
- usb_host
|
||||
- cdc
|
||||
targets:
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
- esp32p4
|
||||
url: https://github.com/espressif/esp-usb/tree/master/host/class/cdc/usb_host_cdc_acm
|
||||
version: 2.0.3
|
@ -1,375 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb_types_cdc.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct cdc_dev_s *cdc_acm_dev_hdl_t;
|
||||
|
||||
/**
|
||||
* @brief Line Coding structure
|
||||
* @see Table 17, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t dwDTERate; // in bits per second
|
||||
uint8_t bCharFormat; // 0: 1 stopbit, 1: 1.5 stopbits, 2: 2 stopbits
|
||||
uint8_t bParityType; // 0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
|
||||
uint8_t bDataBits; // 5, 6, 7, 8 or 16
|
||||
} __attribute__((packed)) cdc_acm_line_coding_t;
|
||||
|
||||
/**
|
||||
* @brief UART State Bitmap
|
||||
* @see Table 31, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t bRxCarrier : 1; // State of receiver carrier detection mechanism of device. This signal corresponds to V.24 signal 109 and RS-232 signal DCD.
|
||||
uint16_t bTxCarrier : 1; // State of transmission carrier. This signal corresponds to V.24 signal 106 and RS-232 signal DSR.
|
||||
uint16_t bBreak : 1; // State of break detection mechanism of the device.
|
||||
uint16_t bRingSignal : 1; // State of ring signal detection of the device.
|
||||
uint16_t bFraming : 1; // A framing error has occurred.
|
||||
uint16_t bParity : 1; // A parity error has occurred.
|
||||
uint16_t bOverRun : 1; // Received data has been discarded due to overrun in the device.
|
||||
uint16_t reserved : 9;
|
||||
};
|
||||
uint16_t val;
|
||||
} cdc_acm_uart_state_t;
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM Device Event types to upper layer
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CDC_ACM_HOST_ERROR,
|
||||
CDC_ACM_HOST_SERIAL_STATE,
|
||||
CDC_ACM_HOST_NETWORK_CONNECTION,
|
||||
CDC_ACM_HOST_DEVICE_DISCONNECTED
|
||||
} cdc_acm_host_dev_event_t;
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM Device Event data structure
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
cdc_acm_host_dev_event_t type;
|
||||
union {
|
||||
int error; //!< Error code from USB Host
|
||||
cdc_acm_uart_state_t serial_state; //!< Serial (UART) state
|
||||
bool network_connected; //!< Network connection event
|
||||
cdc_acm_dev_hdl_t cdc_hdl; //!< Disconnection event
|
||||
} data;
|
||||
} cdc_acm_host_dev_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief New USB device callback
|
||||
*
|
||||
* Provides already opened usb_dev, that will be closed after this callback returns.
|
||||
* This is useful for peeking device's descriptors, e.g. peeking VID/PID and loading proper driver.
|
||||
*
|
||||
* @attention This callback is called from USB Host context, so the CDC device can't be opened here.
|
||||
*/
|
||||
typedef void (*cdc_acm_new_dev_callback_t)(usb_device_handle_t usb_dev);
|
||||
|
||||
/**
|
||||
* @brief Data receive callback type
|
||||
*
|
||||
* @param[in] data Pointer to received data
|
||||
* @param[in] data_len Length of received data in bytes
|
||||
* @param[in] user_arg User's argument passed to open function
|
||||
* @return true Received data was processed -> Flush RX buffer
|
||||
* @return false Received data was NOT processed -> Append new data to the buffer
|
||||
*/
|
||||
typedef bool (*cdc_acm_data_callback_t)(const uint8_t *data, size_t data_len, void *user_arg);
|
||||
|
||||
/**
|
||||
* @brief Device event callback type
|
||||
*
|
||||
* @param[in] event Event structure
|
||||
* @param[in] user_arg User's argument passed to open function
|
||||
*/
|
||||
typedef void (*cdc_acm_host_dev_callback_t)(const cdc_acm_host_dev_event_data_t *event, void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Configuration structure of USB Host CDC-ACM driver
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
size_t driver_task_stack_size; /**< Stack size of the driver's task */
|
||||
unsigned driver_task_priority; /**< Priority of the driver's task */
|
||||
int xCoreID; /**< Core affinity of the driver's task */
|
||||
cdc_acm_new_dev_callback_t new_dev_cb; /**< New USB device connected callback. Can be NULL. */
|
||||
} cdc_acm_host_driver_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration structure of CDC-ACM device
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t connection_timeout_ms; /**< Timeout for USB device connection in [ms] */
|
||||
size_t out_buffer_size; /**< Maximum size of USB bulk out transfer, set to 0 for read-only devices */
|
||||
size_t in_buffer_size; /**< Maximum size of USB bulk in transfer */
|
||||
cdc_acm_host_dev_callback_t event_cb; /**< Device's event callback function. Can be NULL */
|
||||
cdc_acm_data_callback_t data_cb; /**< Device's data RX callback function. Can be NULL for write-only devices */
|
||||
void *user_arg; /**< User's argument that will be passed to the callbacks */
|
||||
} cdc_acm_host_device_config_t;
|
||||
|
||||
/**
|
||||
* @brief Install CDC-ACM driver
|
||||
*
|
||||
* - USB Host Library must already be installed before calling this function (via usb_host_install())
|
||||
* - This function should be called before calling any other CDC driver functions
|
||||
*
|
||||
* @param[in] driver_config Driver configuration structure. If set to NULL, a default configuration will be used.
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_install(const cdc_acm_host_driver_config_t *driver_config);
|
||||
|
||||
/**
|
||||
* @brief Uninstall CDC-ACM driver
|
||||
*
|
||||
* - Users must ensure that all CDC devices must be closed via cdc_acm_host_close() before calling this function
|
||||
*
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_uninstall(void);
|
||||
|
||||
/**
|
||||
* @brief Register new USB device callback
|
||||
*
|
||||
* The callback will be called for every new USB device, not just CDC-ACM class.
|
||||
*
|
||||
* @param[in] new_dev_cb New device callback function
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_register_new_dev_callback(cdc_acm_new_dev_callback_t new_dev_cb);
|
||||
|
||||
/**
|
||||
* @brief Open CDC-ACM compliant device
|
||||
*
|
||||
* CDC-ACM compliant device must contain either an Interface Association Descriptor or CDC-Union descriptor,
|
||||
* which are used for the driver's configuration.
|
||||
*
|
||||
* @param[in] vid Device's Vendor ID
|
||||
* @param[in] pid Device's Product ID
|
||||
* @param[in] interface_idx Index of device's interface used for CDC-ACM communication
|
||||
* @param[in] dev_config Configuration structure of the device
|
||||
* @param[out] cdc_hdl_ret CDC device handle
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
|
||||
|
||||
/**
|
||||
* @brief Open CDC-ACM non-compliant device
|
||||
*
|
||||
* CDC-ACM non-compliant device acts as CDC-ACM device but doesn't support all its features.
|
||||
* User must provide the interface index that will be used (zero for non-composite devices).
|
||||
*
|
||||
* @param[in] vid Device's Vendor ID
|
||||
* @param[in] pid Device's Product ID
|
||||
* @param[in] interface_idx Index of device's interface used for CDC-ACM like communication
|
||||
* @param[in] dev_config Configuration structure of the device
|
||||
* @param[out] cdc_hdl_ret CDC device handle
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_open_vendor_specific(uint16_t vid, uint16_t pid, uint8_t interface_num, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
|
||||
|
||||
/**
|
||||
* @brief Close CDC device and release its resources
|
||||
*
|
||||
* @note All in-flight transfers will be prematurely canceled.
|
||||
* @param[in] cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @return
|
||||
* - ESP_OK: Success - device closed
|
||||
* - ESP_ERR_INVALID_STATE: cdc_hdl is NULL or the CDC driver is not installed
|
||||
*/
|
||||
esp_err_t cdc_acm_host_close(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
|
||||
/**
|
||||
* @brief Transmit data - blocking mode
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] data Data to be sent
|
||||
* @param[in] data_len Data length
|
||||
* @param[in] timeout_ms Timeout in [ms]
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_data_tx_blocking(cdc_acm_dev_hdl_t cdc_hdl, const uint8_t *data, size_t data_len, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief SetLineCoding function
|
||||
*
|
||||
* @see Chapter 6.3.10, USB CDC-PSTN specification rev. 1.2
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] line_coding Line Coding structure
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_line_coding_set(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_line_coding_t *line_coding);
|
||||
|
||||
/**
|
||||
* @brief GetLineCoding function
|
||||
*
|
||||
* @see Chapter 6.3.11, USB CDC-PSTN specification rev. 1.2
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[out] line_coding Line Coding structure to be filled
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_line_coding_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_acm_line_coding_t *line_coding);
|
||||
|
||||
/**
|
||||
* @brief SetControlLineState function
|
||||
*
|
||||
* @see Chapter 6.3.12, USB CDC-PSTN specification rev. 1.2
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] dtr Indicates to DCE if DTE is present or not. This signal corresponds to V.24 signal 108/2 and RS-232 signal Data Terminal Ready.
|
||||
* @param[in] rts Carrier control for half duplex modems. This signal corresponds to V.24 signal 105 and RS-232 signal Request To Send.
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_set_control_line_state(cdc_acm_dev_hdl_t cdc_hdl, bool dtr, bool rts);
|
||||
|
||||
/**
|
||||
* @brief SendBreak function
|
||||
*
|
||||
* This function will block until the duration_ms has passed.
|
||||
*
|
||||
* @see Chapter 6.3.13, USB CDC-PSTN specification rev. 1.2
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] duration_ms Duration of the Break signal in [ms]
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_send_break(cdc_acm_dev_hdl_t cdc_hdl, uint16_t duration_ms);
|
||||
|
||||
/**
|
||||
* @brief Print device's descriptors
|
||||
*
|
||||
* Device and full Configuration descriptors are printed in human readable format to stdout.
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
*/
|
||||
void cdc_acm_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
|
||||
/**
|
||||
* @brief Get protocols defined in USB-CDC interface descriptors
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[out] comm Communication protocol
|
||||
* @param[out] data Data protocol
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_protocols_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_comm_protocol_t *comm, cdc_data_protocol_t *data);
|
||||
|
||||
/**
|
||||
* @brief Get CDC functional descriptor
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] desc_type Type of functional descriptor
|
||||
* @param[out] desc_out Pointer to the required descriptor
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid device or descriptor type
|
||||
* - ESP_ERR_NOT_FOUND: The required descriptor is not present in the device
|
||||
*/
|
||||
esp_err_t cdc_acm_host_cdc_desc_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_desc_subtype_t desc_type, const usb_standard_desc_t **desc_out);
|
||||
|
||||
/**
|
||||
* @brief Send command to CTRL endpoint
|
||||
*
|
||||
* Sends Control transfer as described in USB specification chapter 9.
|
||||
* This function can be used by device drivers that use custom/vendor specific commands.
|
||||
* These commands can either extend or replace commands defined in USB CDC-PSTN specification rev. 1.2.
|
||||
*
|
||||
* @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
|
||||
* @param[in] bmRequestType Field of USB control request
|
||||
* @param[in] bRequest Field of USB control request
|
||||
* @param[in] wValue Field of USB control request
|
||||
* @param[in] wIndex Field of USB control request
|
||||
* @param[in] wLength Field of USB control request
|
||||
* @param[inout] data Field of USB control request
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t cdc_acm_host_send_custom_request(cdc_acm_dev_hdl_t cdc_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
class CdcAcmDevice {
|
||||
public:
|
||||
// Operators
|
||||
CdcAcmDevice() : cdc_hdl(NULL) {};
|
||||
virtual ~CdcAcmDevice()
|
||||
{
|
||||
// Close CDC-ACM device, if it wasn't explicitly closed
|
||||
if (this->cdc_hdl != NULL) {
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
|
||||
inline esp_err_t tx_blocking(uint8_t *data, size_t len, uint32_t timeout_ms = 100)
|
||||
{
|
||||
return cdc_acm_host_data_tx_blocking(this->cdc_hdl, data, len, timeout_ms);
|
||||
}
|
||||
|
||||
inline esp_err_t open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config)
|
||||
{
|
||||
return cdc_acm_host_open(vid, pid, interface_idx, dev_config, &this->cdc_hdl);
|
||||
}
|
||||
|
||||
inline esp_err_t open_vendor_specific(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config)
|
||||
{
|
||||
return cdc_acm_host_open_vendor_specific(vid, pid, interface_idx, dev_config, &this->cdc_hdl);
|
||||
}
|
||||
|
||||
inline esp_err_t close()
|
||||
{
|
||||
const esp_err_t err = cdc_acm_host_close(this->cdc_hdl);
|
||||
if (err == ESP_OK) {
|
||||
this->cdc_hdl = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
virtual inline esp_err_t line_coding_get(cdc_acm_line_coding_t *line_coding) const
|
||||
{
|
||||
return cdc_acm_host_line_coding_get(this->cdc_hdl, line_coding);
|
||||
}
|
||||
|
||||
virtual inline esp_err_t line_coding_set(cdc_acm_line_coding_t *line_coding)
|
||||
{
|
||||
return cdc_acm_host_line_coding_set(this->cdc_hdl, line_coding);
|
||||
}
|
||||
|
||||
virtual inline esp_err_t set_control_line_state(bool dtr, bool rts)
|
||||
{
|
||||
return cdc_acm_host_set_control_line_state(this->cdc_hdl, dtr, rts);
|
||||
}
|
||||
|
||||
virtual inline esp_err_t send_break(uint16_t duration_ms)
|
||||
{
|
||||
return cdc_acm_host_send_break(this->cdc_hdl, duration_ms);
|
||||
}
|
||||
|
||||
inline esp_err_t send_custom_request(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data)
|
||||
{
|
||||
return cdc_acm_host_send_custom_request(this->cdc_hdl, bmRequestType, bRequest, wValue, wIndex, wLength, data);
|
||||
}
|
||||
|
||||
private:
|
||||
CdcAcmDevice &operator= (const CdcAcmDevice &Copy);
|
||||
bool operator== (const CdcAcmDevice ¶m) const;
|
||||
bool operator!= (const CdcAcmDevice ¶m) const;
|
||||
cdc_acm_dev_hdl_t cdc_hdl;
|
||||
};
|
||||
#endif
|
@ -1,248 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @brief USB CDC Descriptor Subtypes
|
||||
*
|
||||
* @see Table 13, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_DESC_SUBTYPE_HEADER = 0x00, // Header Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_CALL = 0x01, // Call Management Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_ACM = 0x02, // Abstract Control Management Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_DLM = 0x03, // Direct Line Management Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_TEL_RINGER = 0x04, // Telephone Ringer Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_TEL_CLSR = 0x05, // Telephone Call and Line State Reporting Capabilities Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_UNION = 0x06, // Union Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_COUNTRY = 0x07, // Country Selection Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_TEL_MODE = 0x08, // Telephone Operational Modes Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_TERMINAL = 0x09, // USB Terminal
|
||||
USB_CDC_DESC_SUBTYPE_NCHT = 0x0A, // Network Channel Terminal
|
||||
USB_CDC_DESC_SUBTYPE_PROTOCOL = 0x08, // Protocol Unit
|
||||
USB_CDC_DESC_SUBTYPE_EXTENSION = 0x0C, // Extension Unit
|
||||
USB_CDC_DESC_SUBTYPE_MULTI_CHAN = 0x0D, // Multi-Channel Management Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_CAPI = 0x0E, // CAPI Control
|
||||
USB_CDC_DESC_SUBTYPE_ETH = 0x0F, // Ethernet Networking
|
||||
USB_CDC_DESC_SUBTYPE_ATM = 0x10, // ATM Networking
|
||||
USB_CDC_DESC_SUBTYPE_WHANDSET = 0x11, // Wireless Handset Control Model Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_MDLM = 0x12, // Mobile Direct Line Model
|
||||
USB_CDC_DESC_SUBTYPE_MDLM_DETAIL = 0x13, // MDLM Detail
|
||||
USB_CDC_DESC_SUBTYPE_DMM = 0x14, // Device Management Model
|
||||
USB_CDC_DESC_SUBTYPE_OBEX = 0x15, // OBEX Functional
|
||||
USB_CDC_DESC_SUBTYPE_COMMAND_SET = 0x16, // Command Set
|
||||
USB_CDC_DESC_SUBTYPE_COMMAND_SET_DETAIL = 0x17, // Command Set Detail Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_TEL_CM = 0x18, // Telephone Control Model Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_OBEX_SERVICE = 0x19, // OBEX Service Identifier Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_NCM = 0x1A, // NCM Functional Descriptor
|
||||
USB_CDC_DESC_SUBTYPE_MAX
|
||||
} __attribute__((packed)) cdc_desc_subtype_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Subclass codes
|
||||
*
|
||||
* @see Table 4, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_SUBCLASS_DLCM = 0x01, // Direct Line Control Model
|
||||
USB_CDC_SUBCLASS_ACM = 0x02, // Abstract Control Model
|
||||
USB_CDC_SUBCLASS_TCM = 0x03, // Telephone Control Model
|
||||
USB_CDC_SUBCLASS_MCHCM = 0x04, // Multi-Channel Control Model
|
||||
USB_CDC_SUBCLASS_CAPI = 0x05, // CAPI Control Model
|
||||
USB_CDC_SUBCLASS_ECM = 0x06, // Ethernet Networking Control Model
|
||||
USB_CDC_SUBCLASS_ATM = 0x07, // ATM Networking Model
|
||||
USB_CDC_SUBCLASS_HANDSET = 0x08, // Wireless Handset Control Model
|
||||
USB_CDC_SUBCLASS_DEV_MAN = 0x09, // Device Management
|
||||
USB_CDC_SUBCLASS_MOBILE = 0x0A, // Mobile Direct Line Model
|
||||
USB_CDC_SUBCLASS_OBEX = 0x0B, // OBEX
|
||||
USB_CDC_SUBCLASS_EEM = 0x0C, // Ethernet Emulation Model
|
||||
USB_CDC_SUBCLASS_NCM = 0x0D // Network Control Model
|
||||
} __attribute__((packed)) cdc_subclass_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Communications Protocol Codes
|
||||
*
|
||||
* @see Table 5, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_COMM_PROTOCOL_NONE = 0x00, // No class specific protocol required
|
||||
USB_CDC_COMM_PROTOCOL_V250 = 0x01, // AT Commands: V.250 etc
|
||||
USB_CDC_COMM_PROTOCOL_PCAA = 0x02, // AT Commands defined by PCCA-101
|
||||
USB_CDC_COMM_PROTOCOL_PCAA_A = 0x03, // AT Commands defined by PCAA-101 & Annex O
|
||||
USB_CDC_COMM_PROTOCOL_GSM = 0x04, // AT Commands defined by GSM 07.07
|
||||
USB_CDC_COMM_PROTOCOL_3GPP = 0x05, // AT Commands defined by 3GPP 27.007
|
||||
USB_CDC_COMM_PROTOCOL_TIA = 0x06, // AT Commands defined by TIA for CDMA
|
||||
USB_CDC_COMM_PROTOCOL_EEM = 0x07, // Ethernet Emulation Model
|
||||
USB_CDC_COMM_PROTOCOL_EXT = 0xFE, // External Protocol: Commands defined by Command Set Functional Descriptor
|
||||
USB_CDC_COMM_PROTOCOL_VENDOR = 0xFF // Vendor-specific
|
||||
} __attribute__((packed)) cdc_comm_protocol_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Data Protocol Codes
|
||||
*
|
||||
* @see Table 7, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_DATA_PROTOCOL_NONE = 0x00, // No class specific protocol required
|
||||
USB_CDC_DATA_PROTOCOL_NCM = 0x01, // Network Transfer Block
|
||||
USB_CDC_DATA_PROTOCOL_I430 = 0x30, // Physical interface protocol for ISDN BRI
|
||||
USB_CDC_DATA_PROTOCOL_HDLC = 0x31, // HDLC
|
||||
USB_CDC_DATA_PROTOCOL_Q921M = 0x50, // Management protocol for Q.921 data link protocol
|
||||
USB_CDC_DATA_PROTOCOL_Q921 = 0x51, // Data link protocol for Q.931
|
||||
USB_CDC_DATA_PROTOCOL_Q921TM = 0x52, // TEI-multiplexor for Q.921 data link protocol
|
||||
USB_CDC_DATA_PROTOCOL_V42BIS = 0x90, // Data compression procedures
|
||||
USB_CDC_DATA_PROTOCOL_Q931 = 0x91, // Euro-ISDN protocol control
|
||||
USB_CDC_DATA_PROTOCOL_V120 = 0x92, // V.24 rate adaptation to ISDN
|
||||
USB_CDC_DATA_PROTOCOL_CAPI = 0x93, // CAPI Commands
|
||||
USB_CDC_DATA_PROTOCOL_VENDOR = 0xFF // Vendor-specific
|
||||
} __attribute__((packed)) cdc_data_protocol_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Request Codes
|
||||
*
|
||||
* @see Table 19, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_REQ_SEND_ENCAPSULATED_COMMAND = 0x00,
|
||||
USB_CDC_REQ_GET_ENCAPSULATED_RESPONSE = 0x01,
|
||||
USB_CDC_REQ_SET_COMM_FEATURE = 0x02,
|
||||
USB_CDC_REQ_GET_COMM_FEATURE = 0x03,
|
||||
USB_CDC_REQ_CLEAR_COMM_FEATURE = 0x04,
|
||||
USB_CDC_REQ_SET_AUX_LINE_STATE = 0x10,
|
||||
USB_CDC_REQ_SET_HOOK_STATE = 0x11,
|
||||
USB_CDC_REQ_PULSE_SETUP = 0x12,
|
||||
USB_CDC_REQ_SEND_PULSE = 0x13,
|
||||
USB_CDC_REQ_SET_PULSE_TIME = 0x14,
|
||||
USB_CDC_REQ_RING_AUX_JACK = 0x15,
|
||||
USB_CDC_REQ_SET_LINE_CODING = 0x20,
|
||||
USB_CDC_REQ_GET_LINE_CODING = 0x21,
|
||||
USB_CDC_REQ_SET_CONTROL_LINE_STATE = 0x22,
|
||||
USB_CDC_REQ_SEND_BREAK = 0x23,
|
||||
USB_CDC_REQ_SET_RINGER_PARMS = 0x30,
|
||||
USB_CDC_REQ_GET_RINGER_PARMS = 0x31,
|
||||
USB_CDC_REQ_SET_OPERATION_PARMS = 0x32,
|
||||
USB_CDC_REQ_GET_OPERATION_PARMS = 0x33,
|
||||
USB_CDC_REQ_SET_LINE_PARMS = 0x34,
|
||||
USB_CDC_REQ_GET_LINE_PARMS = 0x35,
|
||||
USB_CDC_REQ_DIAL_DIGITS = 0x36,
|
||||
USB_CDC_REQ_SET_UNIT_PARAMETER = 0x37,
|
||||
USB_CDC_REQ_GET_UNIT_PARAMETER = 0x38,
|
||||
USB_CDC_REQ_CLEAR_UNIT_PARAMETER = 0x39,
|
||||
USB_CDC_REQ_GET_PROFILE = 0x3A,
|
||||
USB_CDC_REQ_SET_ETHERNET_MULTICAST_FILTERS = 0x40,
|
||||
USB_CDC_REQ_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41,
|
||||
USB_CDC_REQ_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42,
|
||||
USB_CDC_REQ_SET_ETHERNET_PACKET_FILTER = 0x43,
|
||||
USB_CDC_REQ_GET_ETHERNET_STATISTIC = 0x44,
|
||||
USB_CDC_REQ_SET_ATM_DATA_FORMAT = 0x50,
|
||||
USB_CDC_REQ_GET_ATM_DEVICE_STATISTICS = 0x51,
|
||||
USB_CDC_REQ_SET_ATM_DEFAULT_VC = 0x52,
|
||||
USB_CDC_REQ_GET_ATM_VC_STATISTICS = 0x53,
|
||||
USB_CDC_REQ_GET_NTB_PARAMETERS = 0x80,
|
||||
USB_CDC_REQ_GET_NET_ADDRESS = 0x81,
|
||||
USB_CDC_REQ_SET_NET_ADDRESS = 0x82,
|
||||
USB_CDC_REQ_GET_NTB_FORMAT = 0x83,
|
||||
USB_CDC_REQ_SET_NTB_FORMAT = 0x84,
|
||||
USB_CDC_REQ_GET_NTB_INPUT_SIZE = 0x85,
|
||||
USB_CDC_REQ_SET_NTB_INPUT_SIZE = 0x86,
|
||||
USB_CDC_REQ_GET_MAX_DATAGRAM_SIZE = 0x87,
|
||||
USB_CDC_REQ_SET_MAX_DATAGRAM_SIZE = 0x88,
|
||||
USB_CDC_REQ_GET_CRC_MODE = 0x89,
|
||||
USB_CDC_REQ_SET_CRC_MODE = 0x8A
|
||||
} __attribute__((packed)) cdc_request_code_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Notification Codes
|
||||
*
|
||||
* @see Table 20, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
USB_CDC_NOTIF_NETWORK_CONNECTION = 0x00,
|
||||
USB_CDC_NOTIF_RESPONSE_AVAILABLE = 0x01,
|
||||
USB_CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,
|
||||
USB_CDC_NOTIF_RING_DETECT = 0x09,
|
||||
USB_CDC_NOTIF_SERIAL_STATE = 0x20,
|
||||
USB_CDC_NOTIF_CALL_STATE_CHANGE = 0x28,
|
||||
USB_CDC_NOTIF_LINE_STATE_CHANGE = 0x29,
|
||||
USB_CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A
|
||||
} __attribute__((packed)) cdc_notification_code_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
cdc_notification_code_t bNotificationCode;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
uint8_t Data[];
|
||||
} __attribute__((packed)) cdc_notification_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Header Functional Descriptor
|
||||
*
|
||||
* @see Table 15, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
const uint8_t bDescriptorType; // Upper nibble: CDC code 0x02, Lower nibble: intf/ep descriptor type 0x04/0x05
|
||||
const cdc_desc_subtype_t bDescriptorSubtype;
|
||||
uint16_t bcdCDC; // CDC version as binary-coded decimal. This driver is written for version 1.2
|
||||
} __attribute__((packed)) cdc_header_desc_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC Union Functional Descriptor
|
||||
*
|
||||
* @see Table 16, USB CDC specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
const uint8_t bDescriptorType; // Upper nibble: CDC code 0x02, Lower nibble: intf/ep descriptor type 0x04/0x05
|
||||
const cdc_desc_subtype_t bDescriptorSubtype;
|
||||
const uint8_t bControlInterface; // Master/controlling interface
|
||||
uint8_t bSubordinateInterface[]; // Slave/subordinate interfaces
|
||||
} __attribute__((packed)) cdc_union_desc_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC PSTN Call Descriptor
|
||||
*
|
||||
* @see Table 3, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
const uint8_t bDescriptorType;
|
||||
const cdc_desc_subtype_t bDescriptorSubtype;
|
||||
union {
|
||||
struct {
|
||||
uint8_t call_management: 1; // Device handles call management itself
|
||||
uint8_t call_over_data_if: 1; // Device sends/receives call management information over Data Class interface
|
||||
uint8_t reserved: 6;
|
||||
};
|
||||
uint8_t val;
|
||||
} bmCapabilities;
|
||||
uint8_t bDataInterface; // Interface number of Data Class interface optionally used for call management
|
||||
} __attribute__((packed)) cdc_acm_call_desc_t;
|
||||
|
||||
/**
|
||||
* @brief USB CDC PSTN Abstract Control Model Descriptor
|
||||
*
|
||||
* @see Table 4, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bFunctionLength;
|
||||
const uint8_t bDescriptorType;
|
||||
const cdc_desc_subtype_t bDescriptorSubtype;
|
||||
union {
|
||||
struct {
|
||||
uint8_t feature: 1; // Device supports Set/Clear/Get_Comm_Feature requests
|
||||
uint8_t serial: 1; // Device supports Set/Get_Line_Coding, Set_Control_Line_State and Serial_State request and notifications
|
||||
uint8_t send_break: 1; // Device supports Send_Break request
|
||||
uint8_t network: 1; // Device supports Network_Connection notification
|
||||
uint8_t reserved: 4;
|
||||
};
|
||||
uint8_t val;
|
||||
} bmCapabilities;
|
||||
} __attribute__((packed)) cdc_acm_acm_desc_t;
|
@ -1,20 +0,0 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
../../esp_modem_usb_dte
|
||||
../../usb_host_cdc_acm
|
||||
../../usb_host_ch34x_vcp
|
||||
../../usb_host_cp210x_vcp
|
||||
../../usb_host_ftdi_vcp
|
||||
../../usb_host_vcp
|
||||
)
|
||||
|
||||
# Set the components to include the tests for.
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS ../../../../../device/esp_tinyusb)
|
||||
endif()
|
||||
|
||||
project(test_app_usb_host_cdc)
|
@ -1,15 +0,0 @@
|
||||
| Supported Targets | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# USB: CDC Class test application
|
||||
|
||||
## CDC-ACM driver
|
||||
|
||||
It tests basic functionality of the driver like open/close/read/write operations,
|
||||
advanced features like CDC control request, multi-threaded or multi-device access,
|
||||
as well as reaction to sudden disconnection and other error states.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This test expects that TinyUSB dual CDC device with VID = 0x303A and PID = 0x4002
|
||||
is connected to the USB host.
|
@ -1,23 +0,0 @@
|
||||
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
|
||||
set (TINYUSB_LIB)
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
|
||||
set(TINYUSB_LIB "esp_tinyusb")
|
||||
else()
|
||||
set(TINYUSB_LIB "tinyusb")
|
||||
endif()
|
||||
|
||||
# TODO: once IDF_v4.4 is at the EOL support, use WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS "test_cdc_acm_host.c" "usb_device.c" "test_app_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES usb_host_cdc_acm unity ${TINYUSB_LIB})
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
|
||||
# Due to the backward compatibility to IDFv4.4 (in which WHOLE_ARCHIVE is not implemented) we use following approach:
|
||||
# Any non-static function test_app/main/*.c (apart from test_app_main.c) file is added as an undefined symbol
|
||||
# because otherwise the linker will ignore test_app/main/*.c as it has no other files depending on any
|
||||
# symbols in it.
|
||||
|
||||
# force-link test_cdc_acm_host.c
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u usb_lib_task")
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-530)
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// ____ ___ ___________________ __ __
|
||||
// | | \/ _____/\______ \ _/ |_ ____ _______/ |_
|
||||
// | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\.
|
||||
// | | / / \ | | \ | | \ ___/ \___ \ | |
|
||||
// |______/ /_______ / |______ / |__| \___ >____ > |__|
|
||||
// \/ \/ \/ \/
|
||||
printf(" ____ ___ ___________________ __ __ \r\n");
|
||||
printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n");
|
||||
printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n");
|
||||
printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n");
|
||||
printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n");
|
||||
printf(" \\/ \\/ \\/ \\/ \r\n");
|
||||
|
||||
UNITY_BEGIN();
|
||||
unity_run_menu();
|
||||
UNITY_END();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
@ -1,645 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/cdc_acm_host.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
|
||||
static uint8_t tx_buf[] = "HELLO";
|
||||
static uint8_t tx_buf2[] = "WORLD";
|
||||
static int nb_of_responses;
|
||||
static int nb_of_responses2;
|
||||
static bool new_dev_cb_called = false;
|
||||
static bool rx_overflow = false;
|
||||
static usb_phy_handle_t phy_hdl = NULL;
|
||||
|
||||
static void force_conn_state(bool connected, TickType_t delay_ticks)
|
||||
{
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, phy_hdl);
|
||||
if (delay_ticks > 0) {
|
||||
//Delay of 0 ticks causes a yield. So skip if delay_ticks is 0.
|
||||
vTaskDelay(delay_ticks);
|
||||
}
|
||||
ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN));
|
||||
}
|
||||
|
||||
void usb_lib_task(void *arg)
|
||||
{
|
||||
// Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
.otg_mode = USB_OTG_MODE_HOST,
|
||||
.otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_hdl));
|
||||
// Install USB Host driver. Should only be called once in entire application
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = true,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_install(&host_config));
|
||||
printf("USB Host installed\n");
|
||||
xTaskNotifyGive(arg);
|
||||
|
||||
bool all_clients_gone = false;
|
||||
bool all_dev_free = false;
|
||||
while (!all_clients_gone || !all_dev_free) {
|
||||
// Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
printf("No more clients\n");
|
||||
usb_host_device_free_all();
|
||||
all_clients_gone = true;
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
printf("All devices freed\n");
|
||||
all_dev_free = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up USB Host
|
||||
vTaskDelay(10); // Short delay to allow clients clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_uninstall());
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); //Tear down USB PHY
|
||||
phy_hdl = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void test_install_cdc_driver(void)
|
||||
{
|
||||
// Create a task that will handle USB library events
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(usb_lib_task, "usb_lib", 4 * 4096, xTaskGetCurrentTaskHandle(), 10, NULL, 0));
|
||||
ulTaskNotifyTake(false, 1000);
|
||||
|
||||
printf("Installing CDC-ACM driver\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_install(NULL));
|
||||
}
|
||||
|
||||
/* ------------------------------- Callbacks -------------------------------- */
|
||||
static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
printf("Data received\n");
|
||||
nb_of_responses++;
|
||||
TEST_ASSERT_EQUAL_STRING_LEN(data, arg, data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_rx2(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
printf("Data received 2\n");
|
||||
nb_of_responses2++;
|
||||
TEST_ASSERT_EQUAL_STRING_LEN(data, arg, data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_rx_advanced(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
bool *process_data = (bool *)arg;
|
||||
return *process_data;
|
||||
}
|
||||
|
||||
static void notif_cb(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
switch (event->type) {
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
printf("Error event %d\n", event->data.error);
|
||||
break;
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
if (event->data.serial_state.bOverRun) {
|
||||
rx_overflow = true;
|
||||
}
|
||||
break;
|
||||
case CDC_ACM_HOST_NETWORK_CONNECTION:
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
printf("Disconnection event\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(event->data.cdc_hdl));
|
||||
xTaskNotifyGive(user_ctx);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void new_dev_cb(usb_device_handle_t usb_dev)
|
||||
{
|
||||
new_dev_cb_called = true;
|
||||
const usb_config_desc_t *config_desc;
|
||||
const usb_device_desc_t *device_desc;
|
||||
|
||||
// Get descriptors
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(usb_dev, &device_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(usb_dev, &config_desc));
|
||||
|
||||
printf("New device connected. VID = 0x%04X PID = %04X\n", device_desc->idVendor, device_desc->idProduct);
|
||||
}
|
||||
|
||||
/* Basic test to check CDC communication:
|
||||
* open/read/write/close device
|
||||
* CDC-ACM specific commands: set/get_line_coding, set_control_line_state */
|
||||
TEST_CASE("read_write", "[cdc_acm]")
|
||||
{
|
||||
nb_of_responses = 0;
|
||||
cdc_acm_dev_hdl_t cdc_dev = NULL;
|
||||
|
||||
test_install_cdc_driver();
|
||||
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = tx_buf,
|
||||
};
|
||||
|
||||
printf("Opening CDC-ACM device\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
cdc_acm_host_desc_print(cdc_dev);
|
||||
vTaskDelay(10);
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000));
|
||||
vTaskDelay(100); // Wait until responses are processed
|
||||
|
||||
// We sent two messages, should get two responses
|
||||
TEST_ASSERT_EQUAL(2, nb_of_responses);
|
||||
|
||||
cdc_acm_line_coding_t line_coding_get;
|
||||
const cdc_acm_line_coding_t line_coding_set = {
|
||||
.dwDTERate = 9600,
|
||||
.bDataBits = 7,
|
||||
.bParityType = 1,
|
||||
.bCharFormat = 1,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_line_coding_set(cdc_dev, &line_coding_set));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_line_coding_get(cdc_dev, &line_coding_get));
|
||||
TEST_ASSERT_EQUAL_MEMORY(&line_coding_set, &line_coding_get, sizeof(cdc_acm_line_coding_t));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_set_control_line_state(cdc_dev, true, false));
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
|
||||
vTaskDelay(20); //Short delay to allow task to be cleaned up
|
||||
}
|
||||
|
||||
/* Test communication with multiple CDC-ACM devices from one thread */
|
||||
TEST_CASE("multiple_devices", "[cdc_acm]")
|
||||
{
|
||||
nb_of_responses = 0;
|
||||
nb_of_responses2 = 0;
|
||||
|
||||
test_install_cdc_driver();
|
||||
|
||||
printf("Opening 2 CDC-ACM devices\n");
|
||||
cdc_acm_dev_hdl_t cdc_dev1, cdc_dev2;
|
||||
cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 1000,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = tx_buf,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev1)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
dev_config.data_cb = handle_rx2;
|
||||
dev_config.user_arg = tx_buf2;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 2, &dev_config, &cdc_dev2)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev1);
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev2);
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev1, tx_buf, sizeof(tx_buf), 1000));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev2, tx_buf2, sizeof(tx_buf2), 1000));
|
||||
|
||||
vTaskDelay(100); // Wait for RX callbacks
|
||||
|
||||
// We sent two messages, should get two responses
|
||||
TEST_ASSERT_EQUAL(1, nb_of_responses);
|
||||
TEST_ASSERT_EQUAL(1, nb_of_responses2);
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev1));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev2));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
|
||||
//Short delay to allow task to be cleaned up
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
#define MULTIPLE_THREADS_TRANSFERS_NUM 5
|
||||
#define MULTIPLE_THREADS_TASKS_NUM 4
|
||||
void tx_task(void *arg)
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev = (cdc_acm_dev_hdl_t) arg;
|
||||
// Send multiple transfers to make sure that some of them will run at the same time
|
||||
for (int i = 0; i < MULTIPLE_THREADS_TRANSFERS_NUM; i++) {
|
||||
// BULK endpoints
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000));
|
||||
|
||||
// CTRL endpoints
|
||||
cdc_acm_line_coding_t line_coding_get;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_line_coding_get(cdc_dev, &line_coding_get));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_set_control_line_state(cdc_dev, true, false));
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Multiple threads test
|
||||
*
|
||||
* In this test, one CDC device is accessed from multiple threads.
|
||||
* It has to be opened/closed just once, though.
|
||||
*/
|
||||
TEST_CASE("multiple_threads", "[cdc_acm]")
|
||||
{
|
||||
nb_of_responses = 0;
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
test_install_cdc_driver();
|
||||
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 5000,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = tx_buf,
|
||||
};
|
||||
|
||||
printf("Opening CDC-ACM device\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
// Create two tasks that will try to access cdc_dev
|
||||
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreate(tx_task, "CDC TX", 4096, cdc_dev, i + 3, NULL));
|
||||
}
|
||||
|
||||
// Wait until all tasks finish
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
TEST_ASSERT_EQUAL(MULTIPLE_THREADS_TASKS_NUM * MULTIPLE_THREADS_TRANSFERS_NUM, nb_of_responses);
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
/* Test CDC driver reaction to USB device sudden disconnection */
|
||||
TEST_CASE("sudden_disconnection", "[cdc_acm]")
|
||||
{
|
||||
test_install_cdc_driver();
|
||||
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 1000,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx
|
||||
};
|
||||
dev_config.user_arg = xTaskGetCurrentTaskHandle();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
force_conn_state(false, pdMS_TO_TICKS(10)); // Simulate device disconnection
|
||||
TEST_ASSERT_EQUAL(1, ulTaskNotifyTake(false, pdMS_TO_TICKS(100))); // Notify will succeed only if CDC_ACM_HOST_DEVICE_DISCONNECTED notification was generated
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20); //Short delay to allow task to be cleaned up
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM error handling test
|
||||
*
|
||||
* There are multiple erroneous scenarios checked in this test:
|
||||
*
|
||||
* -# Install CDC-ACM driver without USB Host
|
||||
* -# Open device without installed driver
|
||||
* -# Uninstall driver before installing it
|
||||
* -# Open non-existent device
|
||||
* -# Open the same device twice
|
||||
* -# Uninstall driver with open devices
|
||||
* -# Send data that is too large
|
||||
* -# Send unsupported CDC request
|
||||
* -# Write to read-only device
|
||||
*/
|
||||
TEST_CASE("error_handling", "[cdc_acm]")
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx
|
||||
};
|
||||
|
||||
// Install CDC-ACM driver without USB Host
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, cdc_acm_host_install(NULL));
|
||||
|
||||
// Open device without installed driver
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
|
||||
// Uninstall driver before installing it
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, cdc_acm_host_uninstall());
|
||||
|
||||
// Properly install USB and CDC drivers
|
||||
test_install_cdc_driver();
|
||||
|
||||
// Open non-existent device
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, cdc_acm_host_open(0x303A, 0x1234, 0, &dev_config, &cdc_dev)); // 0x303A:0x1234 this device is not connected to USB Host
|
||||
TEST_ASSERT_NULL(cdc_dev);
|
||||
|
||||
// Open regular device
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
// Open one CDC-ACM device twice
|
||||
cdc_acm_dev_hdl_t cdc_dev_test;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev_test));
|
||||
TEST_ASSERT_NULL(cdc_dev_test);
|
||||
|
||||
// Uninstall driver with open devices
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, cdc_acm_host_uninstall());
|
||||
|
||||
// Send data that is too large and NULL data
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_SIZE, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, 1024, 1000));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, cdc_acm_host_data_tx_blocking(cdc_dev, NULL, 10, 1000));
|
||||
|
||||
// Change mode to read-only and try to write to it
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
dev_config.out_buffer_size = 0; // Read-only device
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000));
|
||||
|
||||
// Send unsupported CDC request (TinyUSB accepts SendBreak command, even though it doesn't support it)
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_send_break(cdc_dev, 100));
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_command", "[cdc_acm]")
|
||||
{
|
||||
test_install_cdc_driver();
|
||||
|
||||
// Open device with only CTRL endpoint (endpoint no 0)
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 0,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = NULL
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
// Corresponds to command: Set Control Line State, DTR on, RTS off
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_send_custom_request(cdc_dev, 0x21, 34, 1, 0, 0, NULL));
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
TEST_CASE("new_device_connection_1", "[cdc_acm]")
|
||||
{
|
||||
// Create a task that will handle USB library events
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(usb_lib_task, "usb_lib", 4 * 4096, xTaskGetCurrentTaskHandle(), 10, NULL, 0));
|
||||
ulTaskNotifyTake(false, 1000);
|
||||
|
||||
// Option 1: Register callback during driver install
|
||||
printf("Installing CDC-ACM driver\n");
|
||||
cdc_acm_host_driver_config_t driver_config = {
|
||||
.driver_task_priority = 11,
|
||||
.driver_task_stack_size = 2048,
|
||||
.xCoreID = 0,
|
||||
.new_dev_cb = new_dev_cb,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_install(&driver_config));
|
||||
|
||||
vTaskDelay(50);
|
||||
TEST_ASSERT_TRUE_MESSAGE(new_dev_cb_called, "New device callback was not called\n");
|
||||
new_dev_cb_called = false;
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
TEST_CASE("new_device_connection_2", "[cdc_acm]")
|
||||
{
|
||||
test_install_cdc_driver();
|
||||
|
||||
// Option 2: Register callback after driver install
|
||||
force_conn_state(false, 0);
|
||||
vTaskDelay(50);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_register_new_dev_callback(new_dev_cb));
|
||||
force_conn_state(true, 0);
|
||||
vTaskDelay(50);
|
||||
TEST_ASSERT_TRUE_MESSAGE(new_dev_cb_called, "New device callback was not called\n");
|
||||
new_dev_cb_called = false;
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
TEST_CASE("rx_buffer", "[cdc_acm]")
|
||||
{
|
||||
test_install_cdc_driver();
|
||||
bool process_data = true; // This variable will determine return value of data_cb
|
||||
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.in_buffer_size = 512,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx_advanced,
|
||||
.user_arg = &process_data,
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
// 1. Send > in_buffer_size bytes of data in normal operation: Expect no error
|
||||
uint8_t tx_data[64] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
for (int i = 0; i < 10; i++) {
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_data, sizeof(tx_data), 1000));
|
||||
vTaskDelay(5);
|
||||
}
|
||||
TEST_ASSERT_FALSE_MESSAGE(rx_overflow, "RX overflowed");
|
||||
rx_overflow = false;
|
||||
|
||||
// 2. Send < (in_buffer_size - IN_MPS) bytes of data in 'not processed' mode: Expect no error
|
||||
process_data = false;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_data, sizeof(tx_data), 1000));
|
||||
vTaskDelay(5);
|
||||
}
|
||||
TEST_ASSERT_FALSE_MESSAGE(rx_overflow, "RX overflowed");
|
||||
rx_overflow = false;
|
||||
|
||||
// 3. Send >= (in_buffer_size - IN_MPS) bytes of data in 'not processed' mode: Expect error
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_data, sizeof(tx_data), 1000));
|
||||
vTaskDelay(5);
|
||||
TEST_ASSERT_TRUE_MESSAGE(rx_overflow, "RX did not overflow");
|
||||
rx_overflow = false;
|
||||
|
||||
// 4. Send more data to the EP: Expect no error
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_data, sizeof(tx_data), 1000));
|
||||
vTaskDelay(5);
|
||||
TEST_ASSERT_FALSE_MESSAGE(rx_overflow, "RX overflowed");
|
||||
rx_overflow = false;
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
TEST_CASE("functional_descriptor", "[cdc_acm]")
|
||||
{
|
||||
test_install_cdc_driver();
|
||||
|
||||
cdc_acm_dev_hdl_t cdc_dev;
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = NULL
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev));
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
|
||||
// Request various CDC functional descriptors
|
||||
// Following are present in the TinyUSB CDC device: Header, Call management, ACM, Union
|
||||
const cdc_header_desc_t *header_desc;
|
||||
const cdc_acm_call_desc_t *call_desc;
|
||||
const cdc_acm_acm_desc_t *acm_desc;
|
||||
const cdc_union_desc_t *union_desc;
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_HEADER, (const usb_standard_desc_t **)&header_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_CALL, (const usb_standard_desc_t **)&call_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_ACM, (const usb_standard_desc_t **)&acm_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_UNION, (const usb_standard_desc_t **)&union_desc));
|
||||
TEST_ASSERT_NOT_NULL(header_desc);
|
||||
TEST_ASSERT_NOT_NULL(call_desc);
|
||||
TEST_ASSERT_NOT_NULL(acm_desc);
|
||||
TEST_ASSERT_NOT_NULL(union_desc);
|
||||
TEST_ASSERT_EQUAL(USB_CDC_DESC_SUBTYPE_HEADER, header_desc->bDescriptorSubtype);
|
||||
TEST_ASSERT_EQUAL(USB_CDC_DESC_SUBTYPE_CALL, call_desc->bDescriptorSubtype);
|
||||
TEST_ASSERT_EQUAL(USB_CDC_DESC_SUBTYPE_ACM, acm_desc->bDescriptorSubtype);
|
||||
TEST_ASSERT_EQUAL(USB_CDC_DESC_SUBTYPE_UNION, union_desc->bDescriptorSubtype);
|
||||
|
||||
// Check few errors
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_OBEX, (const usb_standard_desc_t **)&header_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, cdc_acm_host_cdc_desc_get(cdc_dev, USB_CDC_DESC_SUBTYPE_MAX, (const usb_standard_desc_t **)&header_desc));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, cdc_acm_host_cdc_desc_get(NULL, USB_CDC_DESC_SUBTYPE_HEADER, (const usb_standard_desc_t **)&header_desc));
|
||||
|
||||
// Clean-up
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
vTaskDelay(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closing procedure test
|
||||
*
|
||||
* -# Close already closed device
|
||||
*/
|
||||
TEST_CASE("closing", "[cdc_acm]")
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev = NULL;
|
||||
|
||||
test_install_cdc_driver();
|
||||
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = tx_buf,
|
||||
};
|
||||
|
||||
printf("Opening CDC-ACM device\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
vTaskDelay(10);
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
printf("Closing already closed device \n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
|
||||
vTaskDelay(20); //Short delay to allow task to be cleaned up
|
||||
}
|
||||
|
||||
/* Basic test to check CDC driver reaction to TX timeout */
|
||||
TEST_CASE("tx_timeout", "[cdc_acm]")
|
||||
{
|
||||
cdc_acm_dev_hdl_t cdc_dev = NULL;
|
||||
|
||||
test_install_cdc_driver();
|
||||
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 500,
|
||||
.out_buffer_size = 64,
|
||||
.event_cb = notif_cb,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = tx_buf,
|
||||
};
|
||||
|
||||
printf("Opening CDC-ACM device\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device)
|
||||
TEST_ASSERT_NOT_NULL(cdc_dev);
|
||||
vTaskDelay(10);
|
||||
|
||||
// TX some data with timeout_ms=0. This will cause a timeout
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_TIMEOUT, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 0));
|
||||
vTaskDelay(100); // Wait before trying new TX
|
||||
|
||||
// TX some data again with greater timeout. This will check normal operation
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000));
|
||||
vTaskDelay(100);
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
|
||||
|
||||
vTaskDelay(20); //Short delay to allow task to be cleaned up
|
||||
}
|
||||
|
||||
/* Following test case implements dual CDC-ACM USB device that can be used as mock device for CDC-ACM Host tests */
|
||||
void run_usb_dual_cdc_device(void);
|
||||
TEST_CASE("mock_device_app", "[cdc_acm_device][ignore]")
|
||||
{
|
||||
run_usb_dual_cdc_device();
|
||||
while (1) {
|
||||
vTaskDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
static uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];
|
||||
static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
|
||||
{
|
||||
size_t rx_size = 0;
|
||||
/* read and write back */
|
||||
ESP_ERROR_CHECK(tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size));
|
||||
tinyusb_cdcacm_write_queue(itf, buf, rx_size);
|
||||
tinyusb_cdcacm_write_flush(itf, 0);
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
static const tusb_desc_device_t cdc_device_descriptor = {
|
||||
.bLength = sizeof(cdc_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = USB_ESPRESSIF_VID,
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN;
|
||||
static const uint8_t cdc_desc_configuration[] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 64),
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 64),
|
||||
};
|
||||
#endif
|
||||
|
||||
void run_usb_dual_cdc_device(void)
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
.device_descriptor = &cdc_device_descriptor,
|
||||
.configuration_descriptor = cdc_desc_configuration
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
tinyusb_config_cdcacm_t amc_cfg = {
|
||||
.usb_dev = TINYUSB_USBDEV_0,
|
||||
.cdc_port = TINYUSB_CDC_ACM_0,
|
||||
.callback_rx = &tinyusb_cdc_rx_callback,
|
||||
.callback_rx_wanted_char = NULL,
|
||||
.callback_line_state_changed = NULL,
|
||||
.callback_line_coding_changed = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
|
||||
#if (CONFIG_TINYUSB_CDC_COUNT > 1)
|
||||
amc_cfg.cdc_port = TINYUSB_CDC_ACM_1;
|
||||
ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
|
||||
#endif
|
||||
|
||||
printf("USB initialization DONE\n");
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.usb_host
|
||||
@pytest.mark.parametrize('count', [
|
||||
2,
|
||||
], indirect=True)
|
||||
def test_usb_host(dut: Tuple[IdfDut, IdfDut]) -> None:
|
||||
device = dut[0]
|
||||
host = dut[1]
|
||||
|
||||
# 1.1 Prepare USB device for CDC test
|
||||
device.expect_exact('Press ENTER to see the list of tests.')
|
||||
device.write('[cdc_acm_device]')
|
||||
device.expect_exact('USB initialization DONE')
|
||||
|
||||
# 1.2 Run CDC test
|
||||
host.run_all_single_board_cases(group='cdc_acm')
|
@ -1,19 +0,0 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB=y
|
||||
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=2
|
||||
CONFIG_TINYUSB_HID_COUNT=0
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
63
dependencies.lock
Normal file
63
dependencies.lock
Normal file
@ -0,0 +1,63 @@
|
||||
dependencies:
|
||||
espressif/esp-dsp:
|
||||
component_hash: fa7fe74305df6da25867437ebcd4213e047cbfc0556cf92067ab657fce537c6e
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.5.2
|
||||
espressif/esp_modem:
|
||||
component_hash: 681d7c8417ce0f2a11a562c6998b7b379a4847be41d84673c11c0c7a6b00e918
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.3.0
|
||||
espressif/mdns:
|
||||
component_hash: 4e21149422be01c24d4b1d4dec64fa07d136d8c5d234e931f3ebf375cbde51a0
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.5.2
|
||||
espressif/usb_host_cdc_acm:
|
||||
component_hash: f76e1283e7ef0e7970e8a708c4ee443ff0aa112572e25319d30b7ec555cc0aee
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 2.0.6
|
||||
espressif/usb_host_ch34x_vcp:
|
||||
component_hash: c7305154c452531950d8e4ee9838c474b5e4b84fdd12c40b2cae3f6f938752cb
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 2.0.0
|
||||
espressif/usb_host_cp210x_vcp:
|
||||
component_hash: 6a36fd6179b2264a7d8854aa643d872f0d6408dd8f67a23d96e8cb8e49dfd087
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 2.0.0
|
||||
espressif/usb_host_ftdi_vcp:
|
||||
component_hash: a24180724b8d7fdf01b920b6baebd01057d52d1a4ae5bf7ce009963cc24ebb42
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 2.0.0
|
||||
espressif/usb_host_vcp:
|
||||
component_hash: 99b3ad314fa966cb32970e468625672994e259c69c7c668d9c0a13d65993a0e7
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.0~5
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.1.4
|
||||
joltwallet/littlefs:
|
||||
component_hash: cc23c607cbc8671bc03b1b1b39ae13d8f5e8e23771e0b1c66599d04ecd0a3527
|
||||
source:
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.16.2
|
||||
manifest_hash: d59f1a31e1a9f7946c11e32fc4ec7bdda4ba5718dd49dcca5d2b59dfdd37483c
|
||||
target: esp32s3
|
||||
version: 1.0.0
|
@ -12,4 +12,5 @@
|
||||
platform = espressif32
|
||||
board = esp32-s3-devkitc-1
|
||||
framework = arduino, espidf
|
||||
monitor_speed = 115200
|
||||
; lib_deps = https://github.com/espressif/arduino-esp32#2f423afc4eb481bcc1e31c795643f009d184bf4f
|
||||
|
File diff suppressed because it is too large
Load Diff
1899
sdkconfig.esp32-s3-devkitc-1.old
Normal file
1899
sdkconfig.esp32-s3-devkitc-1.old
Normal file
File diff suppressed because it is too large
Load Diff
10
src/idf_component.yml
Normal file
10
src/idf_component.yml
Normal file
@ -0,0 +1,10 @@
|
||||
dependencies:
|
||||
usb_host_ch34x_vcp: "^2"
|
||||
usb_host_cp210x_vcp: "^2"
|
||||
usb_host_ftdi_vcp: "^2"
|
||||
usb_host_vcp: "^1"
|
||||
idf: ">=5.1.0"
|
||||
|
||||
# espressif/arduino-esp32:
|
||||
# pre_release: true
|
||||
# version: '*'
|
169
src/main.cpp
169
src/main.cpp
@ -1,17 +1,172 @@
|
||||
// #include "usb/vcp_cp210x.hpp"
|
||||
#include "Arduino.h"
|
||||
|
||||
// extern "C" void app_main() {
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// }
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "usb/cdc_acm_host.h"
|
||||
#include "usb/vcp_ch34x.hpp"
|
||||
#include "usb/vcp_cp210x.hpp"
|
||||
#include "usb/vcp_ftdi.hpp"
|
||||
#include "usb/vcp.hpp"
|
||||
#include "usb/usb_host.h"
|
||||
|
||||
void setup() {
|
||||
using namespace esp_usb;
|
||||
|
||||
// Change these values to match your needs
|
||||
#define EXAMPLE_BAUDRATE (115200)
|
||||
#define EXAMPLE_STOP_BITS (0) // 0: 1 stopbit, 1: 1.5 stopbits, 2: 2 stopbits
|
||||
#define EXAMPLE_PARITY (0) // 0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
|
||||
#define EXAMPLE_DATA_BITS (8)
|
||||
|
||||
|
||||
namespace {
|
||||
static const char *TAG = "VCP example";
|
||||
static SemaphoreHandle_t device_disconnected_sem;
|
||||
|
||||
/**
|
||||
* @brief Data received callback
|
||||
*
|
||||
* Just pass received data to stdout
|
||||
*
|
||||
* @param[in] data Pointer to received data
|
||||
* @param[in] data_len Length of received data in bytes
|
||||
* @param[in] arg Argument we passed to the device open function
|
||||
* @return
|
||||
* true: We have processed the received data
|
||||
* false: We expect more data
|
||||
*/
|
||||
static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
|
||||
{
|
||||
printf("%.*s", data_len, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Device event callback
|
||||
*
|
||||
* Apart from handling device disconnection it doesn't do anything useful
|
||||
*
|
||||
* @param[in] event Device event type and data
|
||||
* @param[in] user_ctx Argument we passed to the device open function
|
||||
*/
|
||||
static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
switch (event->type) {
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
ESP_LOGE(TAG, "CDC-ACM error has occurred, err_no = %d", event->data.error);
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Device suddenly disconnected");
|
||||
xSemaphoreGive(device_disconnected_sem);
|
||||
break;
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val);
|
||||
break;
|
||||
case CDC_ACM_HOST_NETWORK_CONNECTION:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Host library handling task
|
||||
*
|
||||
* @param arg Unused
|
||||
*/
|
||||
static void usb_lib_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
// Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
ESP_ERROR_CHECK(usb_host_device_free_all());
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
ESP_LOGI(TAG, "USB: All devices freed");
|
||||
// Continue handling USB events to allow device reconnection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
device_disconnected_sem = xSemaphoreCreateBinary();
|
||||
assert(device_disconnected_sem);
|
||||
|
||||
// Install USB Host driver. Should only be called once in entire application
|
||||
ESP_LOGI(TAG, "Installing USB Host");
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
|
||||
// Create a task that will handle USB library events
|
||||
BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, NULL, 10, NULL);
|
||||
assert(task_created == pdTRUE);
|
||||
|
||||
ESP_LOGI(TAG, "Installing CDC-ACM driver");
|
||||
ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
|
||||
|
||||
// Register VCP drivers to VCP service
|
||||
VCP::register_driver<FT23x>();
|
||||
VCP::register_driver<CP210x>();
|
||||
VCP::register_driver<CH34x>();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
const cdc_acm_host_device_config_t dev_config = {
|
||||
.connection_timeout_ms = 5000, // 5 seconds, enough time to plug the device in or experiment with timeout
|
||||
.out_buffer_size = 512,
|
||||
.in_buffer_size = 512,
|
||||
.event_cb = handle_event,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = NULL,
|
||||
};
|
||||
|
||||
// You don't need to know the device's VID and PID. Just plug in any device and the VCP service will load correct (already registered) driver for the device
|
||||
ESP_LOGI(TAG, "Opening any VCP device...");
|
||||
auto vcp = std::unique_ptr<CdcAcmDevice>(VCP::open(&dev_config));
|
||||
|
||||
if (vcp == nullptr) {
|
||||
ESP_LOGI(TAG, "Failed to open VCP device");
|
||||
return;
|
||||
// continue;
|
||||
}
|
||||
vTaskDelay(10);
|
||||
|
||||
ESP_LOGI(TAG, "Setting up line coding");
|
||||
cdc_acm_line_coding_t line_coding = {
|
||||
.dwDTERate = EXAMPLE_BAUDRATE,
|
||||
.bCharFormat = EXAMPLE_STOP_BITS,
|
||||
.bParityType = EXAMPLE_PARITY,
|
||||
.bDataBits = EXAMPLE_DATA_BITS,
|
||||
};
|
||||
ESP_ERROR_CHECK(vcp->line_coding_set(&line_coding));
|
||||
|
||||
/*
|
||||
Now the USB-to-UART converter is configured and receiving data.
|
||||
You can use standard CDC-ACM API to interact with it. E.g.
|
||||
|
||||
ESP_ERROR_CHECK(vcp->set_control_line_state(false, true));
|
||||
ESP_ERROR_CHECK(vcp->tx_blocking((uint8_t *)"Test string", 12));
|
||||
*/
|
||||
|
||||
// Send some dummy data
|
||||
ESP_LOGI(TAG, "Sending data through CdcAcmDevice");
|
||||
uint8_t data[] = "test_string";
|
||||
ESP_ERROR_CHECK(vcp->tx_blocking(data, sizeof(data)));
|
||||
ESP_ERROR_CHECK(vcp->set_control_line_state(true, true));
|
||||
|
||||
// We are done. Wait for device disconnection and start over
|
||||
ESP_LOGI(TAG, "Done. You can reconnect the VCP device to run again.");
|
||||
xSemaphoreTake(device_disconnected_sem, portMAX_DELAY);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user