usb: Add Virtual COM Port drivers
This commit is contained in:
parent
f4338a8141
commit
7a7c1dbff8
|
@ -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 }}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
idf_component_register(SRCS "usb_host_ch34x_vcp.cpp"
|
||||
INCLUDE_DIRS "include")
|
|
@ -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.
|
|
@ -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)
|
|
@ -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"
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
idf_component_register(SRCS "usb_host_cp210x_vcp.cpp"
|
||||
INCLUDE_DIRS "include")
|
|
@ -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.
|
|
@ -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)
|
|
@ -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"
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
idf_component_register(SRCS "usb_host_ftdi_vcp.cpp"
|
||||
INCLUDE_DIRS "include")
|
|
@ -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.
|
|
@ -0,0 +1,5 @@
|
|||
# FTDI UART-USB converters driver
|
||||
|
||||
Supported devices:
|
||||
* FT231
|
||||
* FT232
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
|
@ -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.
|
|
@ -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"
|
|
@ -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 ¶m) = delete;
|
||||
bool operator!= (const VCP ¶m) = 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
|
|
@ -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
|
Loading…
Reference in New Issue