Merge pull request #93 from espressif/usb/virtual_com_port

USB: Virtual COM Ports drivers
This commit is contained in:
Tomas Rezucha 2022-11-30 10:50:37 +01:00 committed by GitHub
commit 47f0b00cae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1882 additions and 1 deletions

View File

@ -22,7 +22,7 @@ jobs:
IDF_TARGET: esp32
working-directory: test_app
run: |
${IDF_PATH}/tools/idf_tools.py --non-interactive install xtensa-clang
${IDF_PATH}/tools/idf_tools.py --non-interactive install esp-clang
. ${IDF_PATH}/export.sh
which -a clang-tidy || true
pip install pyclang~=0.2.0

View File

@ -21,6 +21,10 @@ jobs:
usb/usb_host_msc;
usb/usb_host_uvc;
usb/esp_modem_usb_dte;
usb/usb_host_vcp;
usb/usb_host_ch34x_vcp;
usb/usb_host_cp210x_vcp;
usb/usb_host_ftdi_vcp;
fmt;
namespace: "espressif"
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}

View File

@ -5,6 +5,10 @@ cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS ../usb_host_cdc_acm
../usb_host_msc
../usb_host_uvc
../usb_host_ch34x_vcp
../usb_host_cp210x_vcp
../usb_host_ftdi_vcp
../usb_host_vcp
../esp_modem_usb_dte
)

View File

@ -14,3 +14,5 @@ CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_COMPILER_CXX_EXCEPTIONS=y

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "usb_host_ch34x_vcp.cpp"
INCLUDE_DIRS "include")

View File

@ -0,0 +1,202 @@
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.

View File

@ -0,0 +1,6 @@
# CH34x USB-UART converter driver
Limited implementation only. The vendor does not provide full specification.
* CH340 and CH341 supported
* [Datasheet](http://www.wch-ic.com/downloads/CH341DS1_PDF.html)

View File

@ -0,0 +1,9 @@
## IDF Component Manager Manifest File
version: "1.0.0"
description: USB Host driver for CH34x series of chips
url: https://github.com/espressif/idf-extra-components/tree/master/usb/usb_host_ch34x_vcp
dependencies:
espressif/usb_host_cdc_acm:
version: "^1.0.4"
public: true
idf: ">=4.4"

View File

@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021 WCH
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <memory>
#include <vector>
#include "usb/cdc_acm_host.h"
#define NANJING_QINHENG_MICROE_VID (0x1A86)
#define CH340_PID (0x7522)
#define CH340_PID_1 (0x7523)
#define CH341_PID (0x5523)
namespace esp_usb {
class CH34x : public CdcAcmDevice {
public:
/**
* @brief Constructor for this CH34x driver
*
* @note USB Host library and CDC-ACM driver must be already installed
*
* @param[in] pid PID eg. CH340_PID
* @param[in] dev_config CDC device configuration
* @param[in] interface_idx Interface number
* @return CdcAcmDevice Pointer to created and opened CH34x device
*/
CH34x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx = 0);
/**
* @brief Set Line Coding method
*
* @note Overrides default implementation in CDC-ACM driver
* @param[in] line_coding Line Coding structure
* @return esp_err_t
*/
esp_err_t line_coding_set(cdc_acm_line_coding_t *line_coding);
/**
* @brief Set Control Line State method
*
* @note Overrides default implementation in CDC-ACM driver
* @note Both signals are active low
* @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 set_control_line_state(bool dtr, bool rts);
// List of supported VIDs and PIDs
static constexpr uint16_t vid = NANJING_QINHENG_MICROE_VID;
static constexpr std::array<uint16_t, 3> pids = {CH340_PID, CH340_PID_1, CH341_PID};
private:
const uint8_t intf;
// Make open functions from CdcAcmDevice class private
using CdcAcmDevice::open;
using CdcAcmDevice::open_vendor_specific;
using CdcAcmDevice::send_break; // Break is not supported by CH34x
using CdcAcmDevice::line_coding_get; // Manufacturer doesn't provide enough information to implement this
// This function comes from official Linux driver
static int calculate_baud_divisor(unsigned int baud_rate, unsigned char *factor, unsigned char *divisor);
};
} // namespace esp_usb

View File

@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021 WCH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usb/vcp_ch34x.hpp"
#include "usb/usb_types_ch9.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
#error This component requires C++ exceptions
#endif
#define CH34X_READ_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_RECIP_DEVICE | USB_BM_REQUEST_TYPE_DIR_IN)
#define CH34X_WRITE_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_RECIP_DEVICE | USB_BM_REQUEST_TYPE_DIR_OUT)
#define CH34X_CMD_READ_TYPE 0xC0
#define CH34X_CMD_READ 0x95
#define CH34X_CMD_WRITE 0x9A
#define CH34X_CMD_SERIAL_INIT 0xA1
#define CH34X_CMD_MODEM_OUT 0xA4
#define CH34X_CMD_VERSION 0x5F
// For CMD 0xA4
#define CH34X_UART_CTS 0x01
#define CH34X_UART_DSR 0x02
#define CH34X_UART_RING 0x04
#define CH34X_UART_DCD 0x08
#define CH34X_CONTROL_OUT 0x10
#define CH34X_CONTROL_DTR 0x20
#define CH34X_CONTROL_RTS 0x40
// Uart state
#define CH34X_UART_STATE 0x00
#define CH34X_UART_OVERRUN_ERROR 0x01
#define CH34X_UART_BREAK_ERROR // no define
#define CH34X_UART_PARITY_ERROR 0x02
#define CH34X_UART_FRAME_ERROR 0x06
#define CH34X_UART_RECV_ERROR 0x02
#define CH34X_UART_STATE_TRANSIENT_MASK 0x07
//CH34x Baud Rate
#define CH34x_BAUDRATE_FACTOR 1532620800
#define CH34x_BAUDRATE_DIVMAX 3
// Line Coding Register (LCR)
#define CH34x_REG_LCR 0x18
#define CH34x_LCR_ENABLE_RX 0x80
#define CH34x_LCR_ENABLE_TX 0x40
#define CH34x_LCR_MARK_SPACE 0x20
#define CH34x_LCR_PAR_EVEN 0x10
#define CH34x_LCR_ENABLE_PAR 0x08
#define CH34x_LCR_STOP_BITS_2 0x04
#define CH34x_LCR_CS8 0x03
#define CH34x_LCR_CS7 0x02
#define CH34x_LCR_CS6 0x01
#define CH34x_LCR_CS5 0x00
static const char *TAG = "CH34X";
namespace esp_usb {
CH34x::CH34x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
: intf(interface_idx)
{
const esp_err_t err = this->open_vendor_specific(vid, pid, this->intf, dev_config);
if (err != ESP_OK) {
throw (err);
}
};
esp_err_t CH34x::line_coding_set(cdc_acm_line_coding_t *line_coding)
{
assert(line_coding);
// Baudrate
if (line_coding->dwDTERate != 0) {
uint8_t factor, divisor;
if (calculate_baud_divisor(line_coding->dwDTERate, &factor, &divisor) != 0) {
return ESP_ERR_INVALID_ARG;
}
uint16_t baud_reg_val = (factor << 8) | divisor;
baud_reg_val |= BIT7;
ESP_RETURN_ON_ERROR(this->send_custom_request(CH34X_WRITE_REQ, CH34X_CMD_WRITE, 0x1312, baud_reg_val, 0, NULL), TAG, "Set baudrate failed");
}
// Line coding
if (line_coding->bDataBits != 0) {
uint8_t lcr = CH34x_LCR_ENABLE_RX | CH34x_LCR_ENABLE_TX;
switch (line_coding->bDataBits) {
case 5:
lcr |= CH34x_LCR_CS5;
break;
case 6:
lcr |= CH34x_LCR_CS6;
break;
case 7:
lcr |= CH34x_LCR_CS7;
break;
case 8:
lcr |= CH34x_LCR_CS8;
break;
default:
return ESP_ERR_INVALID_ARG;
}
switch (line_coding->bParityType) {
case 0:
break;
case 1:
lcr |= CH34x_LCR_ENABLE_PAR;
break;
case 2:
lcr |= CH34x_LCR_ENABLE_PAR | CH34x_LCR_PAR_EVEN;
break;
case 3: // Mark
case 4:
lcr |= CH34x_LCR_ENABLE_PAR | CH34x_LCR_MARK_SPACE;
break;
default:
return ESP_ERR_INVALID_ARG;
}
switch (line_coding->bCharFormat) {
case 0:
break; // 1 Stop bit
case 2:
lcr |= CH34x_LCR_STOP_BITS_2;
break;
default:
return ESP_ERR_INVALID_ARG; // 1.5 stop bits not supported
}
ESP_RETURN_ON_ERROR(this->send_custom_request(CH34X_WRITE_REQ, CH34X_CMD_WRITE, 0x2518, lcr, 0, NULL), TAG,
"Set line coding failed");
}
return ESP_OK;
}
esp_err_t CH34x::set_control_line_state(bool dtr, bool rts)
{
uint16_t wValue = 0;
if (dtr) {
wValue |= CH34X_CONTROL_DTR;
}
if (rts) {
wValue |= CH34X_CONTROL_RTS;
}
return this->send_custom_request(CH34X_WRITE_REQ, CH34X_CMD_MODEM_OUT, wValue, this->intf, 0, NULL);
}
int CH34x::calculate_baud_divisor(unsigned int baud_rate, unsigned char *factor, unsigned char *divisor)
{
unsigned char a;
unsigned char b;
unsigned long c;
assert(factor);
assert(divisor);
switch (baud_rate) {
case 921600:
a = 0xf3;
b = 7;
break;
case 307200:
a = 0xd9;
b = 7;
break;
default:
if (baud_rate > 6000000 / 255) {
b = 3;
c = 6000000;
} else if (baud_rate > 750000 / 255) {
b = 2;
c = 750000;
} else if (baud_rate > 93750 / 255) {
b = 1;
c = 93750;
} else {
b = 0;
c = 11719;
}
a = (unsigned char)(c / baud_rate);
if (a == 0 || a == 0xFF) {
return -1; // Can't set required baud rate
}
// Deal with integer division
const int delta_0 = c / a - baud_rate;
const int delta_1 = baud_rate - c / (a + 1);
if (delta_0 > delta_1) {
a++;
}
a = 256 - a;
break;
}
*factor = a;
*divisor = b;
return 0;
}
}

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "usb_host_cp210x_vcp.cpp"
INCLUDE_DIRS "include")

View File

@ -0,0 +1,202 @@
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.

View File

@ -0,0 +1,4 @@
# Silicon Labs CP210x USB-UART converter driver
* [Datasheet](https://www.silabs.com/documents/public/data-sheets/CP2102-9.pdf)
* [Application note](https://www.silabs.com/documents/public/application-notes/an197.pdf)

View File

@ -0,0 +1,9 @@
## IDF Component Manager Manifest File
version: "1.0.0"
description: USB Host driver for CP210x series of chips
url: https://github.com/espressif/idf-extra-components/tree/master/usb/usb_host_cp210x_vcp
dependencies:
espressif/usb_host_cdc_acm:
version: "^1.0.4"
public: true
idf: ">=4.4"

View File

@ -0,0 +1,117 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <memory>
#include <vector>
#include "usb/cdc_acm_host.h"
#define SILICON_LABS_VID (0x10C4)
#define CP210X_PID (0xEA60) // Single i.e. CP2101 - CP2104
#define CP2105_PID (0xEA70) // Dual
#define CP2108_PID (0xEA71) // Quad
// @see AN571: CP210x Virtual COM Port Interface, chapter 5
#define CP210X_CMD_IFC_ENABLE (0x00) // Enable or disable the interface
#define CP210X_CMD_SET_BAUDDIV (0x01) // Set the baud rate divisor
#define CP210X_CMD_GET_BAUDDIV (0x02) // Get the baud rate divisor
#define CP210X_CMD_SET_LINE_CTL (0x03) // Set the line control
#define CP210X_CMD_GET_LINE_CTL (0x04) // Get the line control
#define CP210X_CMD_SET_BREAK (0x05) // Set a BREAK
#define CP210X_CMD_IMM_CHAR (0x06) // Send character out of order
#define CP210X_CMD_SET_MHS (0x07) // Set modem handshaking
#define CP210X_CMD_GET_MDMSTS (0x08) // Get modem status
#define CP210X_CMD_SET_XON (0x09) // Emulate XON
#define CP210X_CMD_SET_XOFF (0x0A) // Emulate XOFF
#define CP210X_CMD_SET_EVENTMASK (0x0B) // Set the event mask
#define CP210X_CMD_GET_EVENTMASK (0x0C) // Get the event mask
#define CP210X_CMD_GET_EVENTSTATE (0x16) // Get the event state
#define CP210X_CMD_SET_RECEIVE (0x17) // Set receiver max timeout
#define CP210X_CMD_GET_RECEIVE (0x18) // Get receiver max timeout
#define CP210X_CMD_SET_CHAR (0x0D) // Set special character individually
#define CP210X_CMD_GET_CHARS (0x0E) // Get special characters
#define CP210X_CMD_GET_PROPS (0x0F) // Get properties
#define CP210X_CMD_GET_COMM_STATUS (0x10) // Get the serial status
#define CP210X_CMD_RESET (0x11) // Reset
#define CP210X_CMD_PURGE (0x12) // Purge
#define CP210X_CMD_SET_FLOW (0x13) // Set flow control
#define CP210X_CMD_GET_FLOW (0x14) // Get flow control
#define CP210X_CMD_EMBED_EVENTS (0x15) // Control embedding of events in the data stream
#define CP210X_CMD_GET_BAUDRATE (0x1D) // Get the baud rate
#define CP210X_CMD_SET_BAUDRATE (0x1E) // Set the baud rate
#define CP210X_CMD_SET_CHARS (0x19) // Set special characters
#define CP210X_CMD_VENDOR_SPECIFIC (0xFF) // Read/write latch values
namespace esp_usb {
class CP210x : public CdcAcmDevice {
public:
/**
* @brief Constructor for this CP210x driver
*
* @note USB Host library and CDC-ACM driver must be already installed
*
* @param[in] pid PID eg. CP210X_PID
* @param[in] dev_config CDC device configuration
* @param[in] interface_idx Interface number
* @return CdcAcmDevice Pointer to created and opened CP210x device
*/
CP210x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx = 0);
/**
* @brief Get Line Coding method
*
* @see AN571: CP210x Virtual COM Port Interface chapters 5.6 and 5.8
* @note Overrides default implementation in CDC-ACM driver
* @param[out] line_coding Line Coding structure
* @return esp_err_t
*/
esp_err_t line_coding_get(cdc_acm_line_coding_t *line_coding);
/**
* @brief Set Line Coding method
*
* @see AN571: CP210x Virtual COM Port Interface chapters 5.5 and 5.7
* @note Overrides default implementation in CDC-ACM driver
* @param[in] line_coding Line Coding structure
* @return esp_err_t
*/
esp_err_t line_coding_set(cdc_acm_line_coding_t *line_coding);
/**
* @brief Set Control Line State method
*
* @see AN571: CP210x Virtual COM Port Interface chapter 5.9
* @note Overrides default implementation in CDC-ACM driver
* @note Both signals are active low
* @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 set_control_line_state(bool dtr, bool rts);
/**
* @brief Send Break method
*
* @see AN571: CP210x Virtual COM Port Interface chapter 5.20
* @note Overrides default implementation in CDC-ACM driver
* @param[in] duration_ms Duration of the break condition in [ms]
* @return esp_err_t
*/
esp_err_t send_break(uint16_t duration_ms);
// List of supported VIDs and PIDs
static constexpr uint16_t vid = SILICON_LABS_VID;
static constexpr std::array<uint16_t, 3> pids = {CP210X_PID, CP2105_PID, CP2108_PID};
private:
const uint8_t intf;
// Make open functions from CdcAcmDevice class private
using CdcAcmDevice::open;
using CdcAcmDevice::open_vendor_specific;
};
} // namespace esp_usb

View File

@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usb/vcp_cp210x.hpp"
#include "usb/usb_types_ch9.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
#error This component requires C++ exceptions
#endif
#define CP210X_READ_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_RECIP_INTERFACE | USB_BM_REQUEST_TYPE_DIR_IN)
#define CP210X_WRITE_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_RECIP_INTERFACE | USB_BM_REQUEST_TYPE_DIR_OUT)
namespace esp_usb {
CP210x::CP210x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
: intf(interface_idx)
{
esp_err_t err;
err = this->open_vendor_specific(vid, pid, this->intf, dev_config);
if (err != ESP_OK) {
throw (err);
}
// CP210X interfaces must be explicitly enabled
err = this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_IFC_ENABLE, 1, this->intf, 0, NULL);
if (err != ESP_OK) {
throw (err);
}
};
esp_err_t CP210x::line_coding_get(cdc_acm_line_coding_t *line_coding)
{
assert(line_coding);
ESP_RETURN_ON_ERROR(this->send_custom_request(CP210X_READ_REQ, CP210X_CMD_GET_BAUDRATE, 0, this->intf, sizeof(line_coding->dwDTERate), (uint8_t *)&line_coding->dwDTERate), "CP210X",);
uint8_t temp_data[2];
ESP_RETURN_ON_ERROR(this->send_custom_request(CP210X_READ_REQ, CP210X_CMD_GET_LINE_CTL, 0, this->intf, 2, temp_data), "CP210X",);
line_coding->bCharFormat = temp_data[0] & 0x0F;
line_coding->bParityType = (temp_data[0] & 0xF0) >> 4;
line_coding->bDataBits = temp_data[1];
return ESP_OK;
}
esp_err_t CP210x::line_coding_set(cdc_acm_line_coding_t *line_coding)
{
assert(line_coding);
if (line_coding->dwDTERate != 0) {
ESP_RETURN_ON_ERROR(this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_SET_BAUDRATE, 0, this->intf, sizeof(line_coding->dwDTERate), (uint8_t *)&line_coding->dwDTERate), "CP210X",);
}
if (line_coding->bDataBits != 0) {
const uint16_t wValue = line_coding->bCharFormat | (line_coding->bParityType << 4) | (line_coding->bDataBits << 8);
return this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_SET_LINE_CTL, wValue, this->intf, 0, NULL);
}
return ESP_OK;
}
esp_err_t CP210x::set_control_line_state(bool dtr, bool rts)
{
const uint16_t wValue = (uint16_t)dtr | ((uint16_t)rts << 1) | 0x0300;
return this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_SET_MHS, wValue, this->intf, 0, NULL);
}
esp_err_t CP210x::send_break(uint16_t duration_ms)
{
ESP_RETURN_ON_ERROR(this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_SET_BREAK, 1, this->intf, 0, NULL), "CP210x",);
vTaskDelay(pdMS_TO_TICKS(duration_ms));
return this->send_custom_request(CP210X_WRITE_REQ, CP210X_CMD_SET_BREAK, 0, this->intf, 0, NULL);
}
}

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "usb_host_ftdi_vcp.cpp"
INCLUDE_DIRS "include")

View File

@ -0,0 +1,202 @@
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.

View File

@ -0,0 +1,5 @@
# FTDI UART-USB converters driver
Supported devices:
* FT231
* FT232

View File

@ -0,0 +1,9 @@
## IDF Component Manager Manifest File
version: "1.0.0"
description: USB Host driver for FTDI USB<->UART converters series of chips
url: https://github.com/espressif/idf-extra-components/tree/master/usb/usb_host_ftdi_vcp
dependencies:
espressif/usb_host_cdc_acm:
version: "^1.0.4"
public: true
idf: ">=4.4"

View File

@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <memory>
#include <vector>
#include "usb/cdc_acm_host.h"
#define FTDI_VID (0x0403)
#define FT232_PID (0x6001)
#define FT231_PID (0x6015)
#define FTDI_CMD_RESET (0x00)
#define FTDI_CMD_SET_FLOW (0x01)
#define FTDI_CMD_SET_MHS (0x02) // Modem handshaking
#define FTDI_CMD_SET_BAUDRATE (0x03)
#define FTDI_CMD_SET_LINE_CTL (0x04)
#define FTDI_CMD_GET_MDMSTS (0x05) // Modem status
namespace esp_usb {
class FT23x : public CdcAcmDevice {
public:
/**
* @brief Constructor for this FTDI driver
*
* @note USB Host library and CDC-ACM driver must be already installed
*
* @param[in] pid PID eg. FTDI_FT232_PID
* @param[in] dev_config CDC device configuration
* @param[in] interface_idx Interface number
* @return CdcAcmDevice Pointer to created and opened FTDI device
*/
FT23x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx = 0);
/**
* @brief Set Line Coding method
*
* @note Overrides default implementation in CDC-ACM driver
* @param[in] line_coding Line Coding structure
* @return esp_err_t
*/
esp_err_t line_coding_set(cdc_acm_line_coding_t *line_coding);
/**
* @brief Set Control Line State method
*
* @note Overrides default implementation in CDC-ACM driver
* @note Both signals are active low
* @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 set_control_line_state(bool dtr, bool rts);
// List of supported VIDs and PIDs
static constexpr uint16_t vid = FTDI_VID;
static constexpr std::array<uint16_t, 2> pids = {FT232_PID, FT231_PID};
private:
const uint8_t intf;
const cdc_acm_data_callback_t user_data_cb;
const cdc_acm_host_dev_callback_t user_event_cb;
void *user_arg;
uint16_t uart_state;
/**
* @brief FT23x's RX data handler
*
* First two bytes are status bytes, the RX data start at data[2].
* Coding of status bytes:
* Byte 0:
* Bit 0: Full Speed packet
* Bit 1: High Speed packet
* Bit 4: CTS
* Bit 5: DSR
* Bit 6: RI
* Bit 7: DCD
* Byte 1:
* Bit 1: RX overflow
* Bit 2: Parity error
* Bit 3: Framing error
* Bit 4: Break received
* Bit 5: Transmitter holding register empty
* Bit 6: Transmitter empty
*
* @todo When CTS is asserted, this driver should stop sending data.
*
* @param[in] data Received data
* @param[in] data_len Received data length
* @param[in] user_arg Pointer to FT23x class
*/
static void ftdi_rx(uint8_t *data, size_t data_len, void *user_arg);
// Just a wrapper to recover user's argument
static void ftdi_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx);
/**
* @brief Construct a new calculate baudrate object
*
* A Baud rate for the FT232R, FT2232 (UART mode) or FT232B is generated using the chips
* internal 48MHz clock. This is input to Baud rate generator circuitry where it is then divided by 16
* and fed into a prescaler as a 3MHz reference clock. This 3MHz reference clock is then divided
* down to provide the required Baud rate for the device's on chip UART. The value of the Baud rate
* divisor is an integer plus a sub-integer prescaler.
* Allowed values for the Baud rate divisor are:
* Divisor = n + 0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875; where n is an integer between 2 and
* 16384 (214).
*
* Note: Divisor = 1 and Divisor = 0 are special cases. A divisor of 0 will give 3 MBaud, and a divisor
* of 1 will give 2 MBaud. Sub-integer divisors between 0 and 2 are not allowed.
* Therefore the value of the divisor needed for a given Baud rate is found by dividing 3000000 by the
* required Baud rate.
*
* @see FTDI AN232B-05 Configuring FT232R, FT2232 and FT232B Baud Rates
* @param[in] baudrate
* @param[out] wValue
* @param[out] wIndex
*/
static int calculate_baudrate(uint32_t baudrate, uint16_t *wValue, uint16_t *wIndex);
// Make open functions from CdcAcmDevice class private
using CdcAcmDevice::open;
using CdcAcmDevice::open_vendor_specific;
using CdcAcmDevice::line_coding_get; // Not implemented
using CdcAcmDevice::send_break; // Not implemented
};
} // namespace esp_usb

View File

@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <inttypes.h>
#include "usb/vcp_ftdi.hpp"
#include "usb/usb_types_ch9.h"
#include "esp_log.h"
#include "esp_check.h"
#include "sdkconfig.h"
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
#error This component requires C++ exceptions
#endif
#define FTDI_READ_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_DIR_IN)
#define FTDI_WRITE_REQ (USB_BM_REQUEST_TYPE_TYPE_VENDOR | USB_BM_REQUEST_TYPE_DIR_OUT)
namespace esp_usb {
FT23x::FT23x(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
: intf(interface_idx), user_data_cb(dev_config->data_cb), user_event_cb(dev_config->event_cb),
user_arg(dev_config->user_arg), uart_state(0)
{
cdc_acm_host_device_config_t ftdi_config;
memcpy(&ftdi_config, dev_config, sizeof(cdc_acm_host_device_config_t));
// FT23x reports modem status in first two bytes of RX data
// so here we override the RX handler with our own
if (dev_config->data_cb) {
ftdi_config.data_cb = ftdi_rx;
ftdi_config.user_arg = this;
}
if (dev_config->event_cb) {
ftdi_config.event_cb = ftdi_event;
ftdi_config.user_arg = this;
}
esp_err_t err;
err = this->open_vendor_specific(vid, pid, this->intf, &ftdi_config);
if (err != ESP_OK) {
throw (err);
}
// FT23x interface must be first reset and configured (115200 8N1)
err = this->send_custom_request(FTDI_WRITE_REQ, FTDI_CMD_RESET, 0, this->intf + 1, 0, NULL);
if (err != ESP_OK) {
throw (err);
}
cdc_acm_line_coding_t line_coding = {
.dwDTERate = 115200,
.bCharFormat = 0,
.bParityType = 0,
.bDataBits = 8,
};
err = this->line_coding_set(&line_coding);
if (err != ESP_OK) {
throw (err);
}
};
esp_err_t FT23x::line_coding_set(cdc_acm_line_coding_t *line_coding)
{
assert(line_coding);
if (line_coding->dwDTERate != 0) {
uint16_t wIndex, wValue;
calculate_baudrate(line_coding->dwDTERate, &wValue, &wIndex);
ESP_RETURN_ON_ERROR(this->send_custom_request(FTDI_WRITE_REQ, FTDI_CMD_SET_BAUDRATE, wValue, wIndex, 0, NULL), "FT23x",);
}
if (line_coding->bDataBits != 0) {
const uint16_t wValue = (line_coding->bDataBits) | (line_coding->bParityType << 8) | (line_coding->bCharFormat << 11);
return this->send_custom_request(FTDI_WRITE_REQ, FTDI_CMD_SET_LINE_CTL, wValue, this->intf, 0, NULL);
}
return ESP_OK;
}
esp_err_t FT23x::set_control_line_state(bool dtr, bool rts)
{
ESP_RETURN_ON_ERROR(this->send_custom_request(FTDI_WRITE_REQ, FTDI_CMD_SET_MHS, dtr ? 0x11 : 0x10, this->intf, 0, NULL), "FT23x",); // DTR
return this->send_custom_request(FTDI_WRITE_REQ, FTDI_CMD_SET_MHS, rts ? 0x21 : 0x20, this->intf, 0, NULL); // RTS
}
void FT23x::ftdi_rx(uint8_t *data, size_t data_len, void *user_arg)
{
FT23x *this_ftdi = (FT23x *)user_arg;
// Dispatch serial state if it has changed
if (this_ftdi->user_event_cb) {
cdc_acm_uart_state_t new_state;
new_state.val = 0;
new_state.bRxCarrier = data[0] & 0x80; // DCD
new_state.bTxCarrier = data[0] & 0x20; // DSR
new_state.bBreak = data[1] & 0x10;
new_state.bRingSignal = data[0] & 0x40;
new_state.bFraming = data[1] & 0x08;
new_state.bParity = data[1] & 0x04;
new_state.bOverRun = data[1] & 0x02;
if (this_ftdi->uart_state != new_state.val) {
cdc_acm_host_dev_event_data_t serial_event;
serial_event.type = CDC_ACM_HOST_SERIAL_STATE;
serial_event.data.serial_state = new_state;
this_ftdi->user_event_cb(&serial_event, this_ftdi->user_arg);
this_ftdi->uart_state = new_state.val;
}
}
// Dispatch data if any
if (data_len > 2) {
this_ftdi->user_data_cb(&data[2], data_len - 2, this_ftdi->user_arg);
}
}
void FT23x::ftdi_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
{
FT23x *this_ftdi = (FT23x *)user_ctx;
this_ftdi->user_event_cb(event, this_ftdi->user_arg);
}
int FT23x::calculate_baudrate(uint32_t baudrate, uint16_t *wValue, uint16_t *wIndex)
{
#define FTDI_BASE_CLK (3000000)
int baudrate_real;
if (baudrate > 2000000) {
// set to 3000000
*wValue = 0;
*wIndex = 0;
baudrate_real = 3000000;
} else if (baudrate >= 1000000) {
// set to 1000000
*wValue = 1;
*wIndex = 0;
baudrate_real = 1000000;
} else {
const float ftdi_fractal[] = {0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1};
const uint8_t ftdi_fractal_bits[] = {0, 0x03, 0x02, 0x04, 0x01, 0x05, 0x06, 0x07};
uint16_t divider_n = FTDI_BASE_CLK / baudrate; // integer value
int ftdi_fractal_idx = 0;
float divider = FTDI_BASE_CLK / (float)baudrate; // float value
float divider_fractal = divider - (float)divider_n;
// Find closest bigger FT23x fractal divider
for (ftdi_fractal_idx = 0; ftdi_fractal[ftdi_fractal_idx] <= divider_fractal; ftdi_fractal_idx++) {};
// Calculate baudrate errors for two closest fractal divisors
int diff1 = baudrate - (int)(FTDI_BASE_CLK / (divider_n + ftdi_fractal[ftdi_fractal_idx])); // Greater than required baudrate
int diff2 = (int)(FTDI_BASE_CLK / (divider_n + ftdi_fractal[ftdi_fractal_idx - 1])) - baudrate; // Lesser than required baudrate
// Chose divider and fractal divider with smallest error
if (diff2 < diff1) {
ftdi_fractal_idx--;
} else {
if (ftdi_fractal_idx == 8) {
ftdi_fractal_idx = 0;
divider_n++;
}
}
baudrate_real = FTDI_BASE_CLK / (float)((float)divider_n + ftdi_fractal[ftdi_fractal_idx]);
*wValue = ((0x3FFFF) & divider_n) | (ftdi_fractal_bits[ftdi_fractal_idx] << 14);
*wIndex = ftdi_fractal_bits[ftdi_fractal_idx] >> 2;
}
ESP_LOGD("FT23x", "wValue: 0x%04X wIndex: 0x%04X", *wValue, *wIndex);
ESP_LOGI("FT23x", "Baudrate required: %" PRIu32", set: %d", baudrate, baudrate_real);
return baudrate_real;
}
} // esp_usb

View File

@ -0,0 +1,8 @@
idf_component_register(SRCS "usb_host_vcp.cpp"
INCLUDE_DIRS "include")
set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
)
target_compile_options(${COMPONENT_LIB} PRIVATE -fconcepts)

202
usb/usb_host_vcp/LICENSE Normal file
View File

@ -0,0 +1,202 @@
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.

View File

@ -0,0 +1,7 @@
# Virtual COM Port Service
Virtual COM Port (VCP) service manages drivers to connected VCP devices - typically USB <-> UART converters.
In practice, you rarely care about specifics of the devices; you only want uniform interface for them all.
VCP service does just that, after you register drivers for various VCP devices, you can just call VCP::open
and the service will load proper driver for device that was just plugged into USB port.

View File

@ -0,0 +1,9 @@
## IDF Component Manager Manifest File
version: "1.0.0"
description: USB Host Virtual COM Port Service
url: https://github.com/espressif/idf-extra-components/tree/master/usb/usb_host_vcp
dependencies:
espressif/usb_host_cdc_acm:
version: "^1.0.4"
public: true
idf: ">=4.4"

View File

@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <memory>
#include <vector>
#include "usb/cdc_acm_host.h"
namespace esp_usb {
/**
* @brief Virtual COM Port Service Class
*
* Virtual COM Port (VCP) service manages drivers to connected VCP devices - typically USB <-> UART converters.
* In practice, you rarely care about specifics of the devices; you only want uniform interface for them all.
* VCP service does just that, after you register drivers for various VCP devices, you can just call VCP::open
* and the service will load proper driver for device that was just plugged into USB port.
*
* Example usage:
* \code{.cpp}
* VCP::register_driver<FT23x>();
* VCP::register_driver<CP210x>();
* VCP::register_driver<CH34x>();
* auto vcp = VCP::open(&dev_config);
* \endcode
*
* The example code assumes that you have USB Host Lib already installed.
*/
class VCP {
public:
/**
* @brief Register VCP driver to VCP service
*
* To fully leverage from VCP service functionalities, you must register VCP drivers first.
* The driver must contain the following public members/methods;
* #. vid: Supported VID
* #. pids: Array of supported PIDs
* # Constructor with (uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx) input parameters
*
* @tparam T VCP driver type
*/
template<class T> static void
register_driver(void)
{
static_assert(T::pids.begin() != nullptr, "Every VCP driver must contain array of supported PIDs in 'pids' array");
static_assert(T::vid != 0, "Every VCP driver must contain supported VID in'vid' integer");
std::vector<uint16_t> pids(T::pids.begin(), T::pids.end()); // Convert array to vector
vcp_driver new_driver = vcp_driver([](uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx) {
return static_cast<CdcAcmDevice *> (new T(pid, dev_config, interface_idx)); // Lambda function: Open factory method
}, T::vid, pids);
drivers.push_back(new_driver);
}
/**
* @brief VCP factory with VID and PID
*
* Use this function if you know VID and PID of the device.
* The VCP service will look for correct (already registered) driver and load it.
*
* @attention USB Host Library must be installed before calling this function!
*
* @param[in] _vid VID of the device
* @param[in] _pid PID of the device
* @param[in] dev_config Configuration of the device
* @param[in] interface_idx USB interface to use
* @return std::shared_ptr<CdcAcmDevice>
*/
static CdcAcmDevice *
open(uint16_t _vid, uint16_t _pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx = 0);
/**
* @brief VCP factory
*
* Use this function when you want the VCP service to open any connected VCP device.
* The VCP service will look for correct (already registered) driver and load it.
*
* This function will block until a valid VCP device is found or
* until dev_config->connection_timeout_ms expires. Set timeout to 0 to wait forever.
*
* @note If there are more USB devices connected, the VCP service will return first successfully opened device
* @attention USB Host Library must be installed before calling this function!
*
* @param[in] dev_config Configuration of the device
* @param[in] interface_idx USB interface to use
* @return std::shared_ptr<CdcAcmDevice>
*/
static CdcAcmDevice *
open(const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx = 0);
private:
// Default operators
VCP() = delete; // This driver acts as a service, you can't instantiate it
VCP(const VCP &) = delete;
VCP &operator=(VCP &) = delete;
bool operator== (const VCP &param) = delete;
bool operator!= (const VCP &param) = delete;
/**
* @brief VCP driver structure
*/
typedef struct vcp_driver {
CdcAcmDevice *(*open)(uint16_t pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx); /*!< Factory method of this driver */
uint16_t vid; /*!< VID this driver supports */
std::vector<uint16_t> pids; /*!< List of PIDs this driver supports */
vcp_driver(auto open_func, const uint16_t _vid, const std::vector<uint16_t> &_pids): open(open_func), vid(_vid), pids(_pids) {};
} vcp_driver;
/**
* @brief List of registered VCP drivers
*/
static std::vector<vcp_driver> drivers;
}; // VCP class
} // namespace esp_usb

View File

@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdexcept>
#include "usb/vcp.hpp"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "VCP service";
namespace esp_usb {
std::vector<VCP::vcp_driver> VCP::drivers;
CdcAcmDevice *VCP::open(uint16_t _vid, uint16_t _pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
{
// In case user didn't install CDC-ACM driver, we try to install it here.
const esp_err_t err = cdc_acm_host_install(NULL);
switch (err) {
case ESP_OK: ESP_LOGD(TAG, "CDC-ACM driver installed"); break;
case ESP_ERR_INVALID_STATE: ESP_LOGD(TAG, "CDC-ACM driver already installed"); break;
default: ESP_LOGE(TAG, "Failed to install CDC-ACM driver"); return nullptr;
}
for (vcp_driver drv : drivers) {
if (drv.vid == _vid) {
for (uint16_t p : drv.pids) {
if (p == _pid) {
try {
return drv.open(_pid, dev_config, interface_idx);
} catch (esp_err_t &e) {
switch (e) {
case ESP_ERR_NO_MEM: throw std::bad_alloc();
case ESP_ERR_NOT_FOUND: // fallthrough
default: return nullptr;
}
}
}
}
}
}
return nullptr;
}
CdcAcmDevice *VCP::open(const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
{
// Setup this function timeout
TickType_t timeout_ticks = (dev_config->connection_timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(dev_config->connection_timeout_ms);
TimeOut_t connection_timeout;
vTaskSetTimeOutState(&connection_timeout);
// In case user didn't install CDC-ACM driver, we try to install it here.
esp_err_t err = cdc_acm_host_install(NULL);
switch (err) {
case ESP_OK: ESP_LOGD(TAG, "CDC-ACM driver installed"); break;
case ESP_ERR_INVALID_STATE: ESP_LOGD(TAG, "CDC-ACM driver already installed"); break;
default: ESP_LOGE(TAG, "Failed to install CDC-ACM driver"); return nullptr;
}
// dev_config->connection_timeout_ms is normally meant for 1 device,
// but here it is a timeout for the whole function call
cdc_acm_host_device_config_t _config = {
.connection_timeout_ms = 1,
.out_buffer_size = dev_config->out_buffer_size,
.event_cb = dev_config->event_cb,
.data_cb = dev_config->data_cb,
.user_arg = dev_config->user_arg,
};
// Try opening all registered devices, return on first success
do {
for (vcp_driver drv : drivers) {
for (uint16_t pid : drv.pids) {
try {
return drv.open(pid, &_config, interface_idx);
} catch (esp_err_t &e) {
switch (e) {
case ESP_ERR_NOT_FOUND: break;
case ESP_ERR_NO_MEM: throw std::bad_alloc();
default: return nullptr;
}
}
}
}
vTaskDelay(pdMS_TO_TICKS(50));
} while (xTaskCheckForTimeOut(&connection_timeout, &timeout_ticks) == pdFALSE);
return nullptr;
}
} // namespace esp_usb