1#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
2 defined(USE_ESP32_VARIANT_ESP32S31) || defined(USE_ESP32_VARIANT_ESP32H4)
4#include "usb/usb_host.h"
14using namespace bytebuffer;
19static constexpr uint8_t IFC_ENABLE = 0x00;
20static constexpr uint8_t SET_BAUDDIV = 0x01;
21static constexpr uint8_t GET_BAUDDIV = 0x02;
22static constexpr uint8_t SET_LINE_CTL = 0x03;
23static constexpr uint8_t GET_LINE_CTL = 0x04;
24static constexpr uint8_t SET_BREAK = 0x05;
25static constexpr uint8_t IMM_CHAR = 0x06;
26static constexpr uint8_t SET_MHS = 0x07;
27static constexpr uint8_t GET_MDMSTS = 0x08;
28static constexpr uint8_t SET_XON = 0x09;
29static constexpr uint8_t SET_XOFF = 0x0A;
30static constexpr uint8_t SET_EVENTMASK = 0x0B;
31static constexpr uint8_t GET_EVENTMASK = 0x0C;
32static constexpr uint8_t GET_EVENTSTATE = 0x16;
33static constexpr uint8_t SET_RECEIVE = 0x17;
34static constexpr uint8_t GET_RECEIVE = 0x18;
35static constexpr uint8_t SET_CHAR = 0x0D;
36static constexpr uint8_t GET_CHARS = 0x0E;
37static constexpr uint8_t GET_PROPS = 0x0F;
38static constexpr uint8_t GET_COMM_STATUS = 0x10;
39static constexpr uint8_t
RESET = 0x11;
40static constexpr uint8_t PURGE = 0x12;
41static constexpr uint8_t SET_FLOW = 0x13;
42static constexpr uint8_t GET_FLOW = 0x14;
43static constexpr uint8_t EMBED_EVENTS = 0x15;
44static constexpr uint8_t GET_BAUDRATE = 0x1D;
45static constexpr uint8_t SET_BAUDRATE = 0x1E;
46static constexpr uint8_t SET_CHARS = 0x19;
47static constexpr uint8_t VENDOR_SPECIFIC = 0xFF;
50static constexpr uint16_t GET_FW_VER_2N = 0x0010;
51static constexpr uint16_t GET_PARTNUM = 0x370B;
53static constexpr uint8_t PARTNUM_CP2102N_QFN28 = 0x20;
54static constexpr uint8_t PARTNUM_CP2102N_QFN24 = 0x21;
55static constexpr uint8_t PARTNUM_CP2102N_QFN20 = 0x22;
58static constexpr uint32_t CP2102N_LAST_FW_WITHOUT_FLOW_CONTROL = 0x010004;
61static constexpr uint16_t CONTROL_DTR = 0x0001;
62static constexpr uint16_t CONTROL_RTS = 0x0002;
63static constexpr uint16_t CONTROL_WRITE_DTR = 0x0100;
64static constexpr uint16_t CONTROL_WRITE_RTS = 0x0200;
67static constexpr uint32_t SERIAL_DTR_MASK = 0x03;
68static constexpr uint32_t SERIAL_DTR_INACTIVE = 0x00;
69static constexpr uint32_t SERIAL_DTR_ACTIVE = 0x01;
70static constexpr uint32_t SERIAL_CTS_HANDSHAKE = 1 << 3;
71static constexpr uint32_t SERIAL_DSR_HANDSHAKE = 1 << 4;
72static constexpr uint32_t SERIAL_DCD_HANDSHAKE = 1 << 5;
73static constexpr uint32_t SERIAL_DSR_SENSITIVITY = 1 << 6;
76static constexpr uint32_t SERIAL_AUTO_TRANSMIT = 1 << 0;
77static constexpr uint32_t SERIAL_AUTO_RECEIVE = 1 << 1;
78static constexpr uint32_t SERIAL_RTS_MASK = 0xC0;
79static constexpr uint32_t SERIAL_RTS_INACTIVE = 0x00;
80static constexpr uint32_t SERIAL_RTS_ACTIVE = 0x40;
81static constexpr uint32_t SERIAL_RTS_FLOW_CTL = 0x80;
84static constexpr uint32_t XON_XOFF_LIMIT = 128;
87static constexpr uint8_t SPECIAL_CHARS[] = {0, 0, 0, 0, 0x11, 0x13};
90static void set_block_modem_lines(CP210xFlowBlock &block,
bool dtr,
bool rts) {
91 block.control_handshake =
92 (block.control_handshake & ~SERIAL_DTR_MASK) | (dtr ? SERIAL_DTR_ACTIVE : SERIAL_DTR_INACTIVE);
93 uint32_t rts_bits = SERIAL_RTS_INACTIVE;
95 rts_bits = (block.control_handshake & SERIAL_CTS_HANDSHAKE) ? SERIAL_RTS_FLOW_CTL : SERIAL_RTS_ACTIVE;
96 block.flow_replace = (block.flow_replace & ~SERIAL_RTS_MASK) | rts_bits;
100 const usb_config_desc_t *config_desc;
101 const usb_device_desc_t *device_desc;
102 int conf_offset = 0, ep_offset;
103 std::vector<CdcEps> cdc_devs{};
106 if (usb_host_get_device_descriptor(dev_hdl, &device_desc) != ESP_OK) {
107 ESP_LOGE(TAG,
"get_device_descriptor failed");
110 if (usb_host_get_active_config_descriptor(dev_hdl, &config_desc) != ESP_OK) {
111 ESP_LOGE(TAG,
"get_active_config_descriptor failed");
114 ESP_LOGD(TAG,
"bDeviceClass: %u, bDeviceSubClass: %u, bNumInterfaces: %u", device_desc->bDeviceClass,
115 device_desc->bDeviceSubClass, config_desc->bNumInterfaces);
116 if (device_desc->bDeviceClass != 0) {
117 ESP_LOGE(TAG,
"bDeviceClass != 0");
121 for (uint8_t i = 0; i != config_desc->bNumInterfaces; i++) {
122 const auto *data_desc = usb_parse_interface_descriptor(config_desc, i, 0, &conf_offset);
124 ESP_LOGE(TAG,
"data_desc: usb_parse_interface_descriptor failed");
127 if (data_desc->bNumEndpoints != 2 || data_desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
128 ESP_LOGE(TAG,
"data_desc: bInterfaceClass == %u, bInterfaceSubClass == %u, bNumEndpoints == %u",
129 data_desc->bInterfaceClass, data_desc->bInterfaceSubClass, data_desc->bNumEndpoints);
132 ep_offset = conf_offset;
133 const auto *out_ep = usb_parse_endpoint_descriptor_by_index(data_desc, 0, config_desc->wTotalLength, &ep_offset);
135 ESP_LOGE(TAG,
"out_ep: usb_parse_endpoint_descriptor_by_index failed");
138 ep_offset = conf_offset;
139 const auto *in_ep = usb_parse_endpoint_descriptor_by_index(data_desc, 1, config_desc->wTotalLength, &ep_offset);
141 ESP_LOGE(TAG,
"in_ep: usb_parse_endpoint_descriptor_by_index failed");
144 CdcEps eps = in_ep->bEndpointAddress & usb_host::USB_DIR_IN
145 ?
CdcEps{
nullptr, in_ep, out_ep, data_desc->bInterfaceNumber}
146 :
CdcEps{
nullptr, out_ep, in_ep, data_desc->bInterfaceNumber};
148 cdc_devs.push_back(eps);
159 this->
config_transfer_(USB_VENDOR_DEV | usb_host::USB_DIR_IN, VENDOR_SPECIFIC, GET_PARTNUM, 0,
165 ESP_LOGD(TAG,
"Part number 0x%02X", response[0]);
166 if (response[0] != PARTNUM_CP2102N_QFN28 && response[0] != PARTNUM_CP2102N_QFN24 &&
167 response[0] != PARTNUM_CP2102N_QFN20)
169 this->
config_transfer_(USB_VENDOR_DEV | usb_host::USB_DIR_IN, VENDOR_SPECIFIC, GET_FW_VER_2N, 0,
175 const uint32_t version = (response[0] << 16) | (response[1] << 8) | response[2];
176 ESP_LOGD(TAG,
"CP2102N firmware %u.%u.%u", response[0], response[1], response[2]);
179 ESP_LOGW(TAG,
"CP2102N firmware 1.0.4 and older cannot do flow control (erratum E104), using none");
189 const uint8_t *response) {
199 }
else if (!xon_xoff) {
209 uint16_t line_control =
static_cast<uint8_t
>(channel->
line_stop_bits_());
210 line_control |=
static_cast<uint8_t
>(channel->
line_parity_()) << 4;
212 ESP_LOGD(TAG,
"Line control value 0x%X", line_control);
213 this->
config_transfer_(USB_VENDOR_IFC | usb_host::USB_DIR_OUT, SET_LINE_CTL, line_control, channel->
index_);
218 this->
config_transfer_(USB_VENDOR_IFC | usb_host::USB_DIR_OUT, SET_BAUDRATE, 0, channel->
index_, baud.get_data());
223 std::vector<uint8_t>(std::begin(SPECIAL_CHARS), std::end(SPECIAL_CHARS)));
229 reinterpret_cast<uint8_t *
>(&this->flow_blocks_[channel->
index_]));
236 block.control_handshake &=
237 ~(SERIAL_DSR_HANDSHAKE | SERIAL_DCD_HANDSHAKE | SERIAL_DSR_SENSITIVITY | SERIAL_CTS_HANDSHAKE);
239 block.control_handshake |= SERIAL_CTS_HANDSHAKE;
240 assign_bits(block.flow_replace, SERIAL_AUTO_TRANSMIT | SERIAL_AUTO_RECEIVE, xon_xoff);
242 block.xon_limit = XON_XOFF_LIMIT;
243 block.xoff_limit = XON_XOFF_LIMIT;
245 set_block_modem_lines(block, channel->
dtr_, channel->
rts_);
263 if (block.control_handshake & SERIAL_CTS_HANDSHAKE) {
264 set_block_modem_lines(block, channel->
dtr_, channel->
rts_);
268 const uint16_t value =
269 CONTROL_WRITE_DTR | CONTROL_WRITE_RTS | (channel->
dtr_ ? CONTROL_DTR : 0) | (channel->
rts_ ? CONTROL_RTS : 0);
270 ESP_LOGD(TAG,
"SET_MHS: DTR=%s RTS=%s", ONOFF(channel->
dtr_), ONOFF(channel->
rts_));
276 ESP_LOGD(TAG,
"SET_FLOW: control handshake 0x%02" PRIX32
", flow replace 0x%02" PRIX32, block.control_handshake,
278 const auto *bytes =
reinterpret_cast<const uint8_t *
>(&block);
280 std::vector<uint8_t>(bytes, bytes +
sizeof(block)));
static ByteBuffer wrap(T value, Endian endianness=LITTLE)
UARTFlowControl flow_control_
LineParity line_parity_() const
LineStopBits line_stop_bits_() const
void config_transfer_(uint8_t type, uint8_t request, uint16_t value, uint16_t index, const std::vector< uint8_t > &data={}, uint8_t *dest=nullptr)
void modem_control_transfer(USBUartChannelBase *channel) override
bool config_device_step(uint8_t step, bool ok, const uint8_t *response) override
void set_flow_transfer_(USBUartChannelBase *channel)
std::vector< CdcEps > parse_descriptors(usb_device_handle_t dev_hdl) override
bool config_step(USBUartChannelBase *channel, uint8_t step, bool reload, bool ok, const uint8_t *response) override
std::array< CP210xFlowBlock, MAX_CHANNELS > flow_blocks_
@ UART_FLOW_CONTROL_RTS_CTS
@ UART_FLOW_CONTROL_XON_XOFF
ESPHOME_ALWAYS_INLINE constexpr void assign_bits(T &value, std::type_identity_t< T > mask, bool on)
Set the bits of mask in value when on is true, clear them otherwise.
uint8_t bulk_interface_class