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"
11static constexpr uint8_t SET_LINE_REQUEST_TYPE = 0x21;
12static constexpr uint8_t SET_LINE_REQUEST = 0x20;
14static constexpr uint8_t SET_CONTROL_REQUEST_TYPE = 0x21;
15static constexpr uint8_t SET_CONTROL_REQUEST = 0x22;
16static constexpr uint8_t CONTROL_DTR = 0x01;
17static constexpr uint8_t CONTROL_RTS = 0x02;
19static constexpr uint8_t VENDOR_WRITE_REQUEST_TYPE = 0x40;
20static constexpr uint8_t VENDOR_WRITE_REQUEST = 0x01;
22static constexpr uint8_t VENDOR_READ_REQUEST_TYPE = 0xc0;
23static constexpr uint8_t VENDOR_READ_REQUEST = 0x01;
26static const uint32_t SUPPORTED_BAUD_RATES[] = {
27 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200,
28 28800, 38400, 57600, 115200, 230400, 460800, 614400, 921600, 1228800, 2457600, 3000000, 6000000,
44 return "G/HXN (newer)";
52 size_t n =
sizeof(SUPPORTED_BAUD_RATES) /
sizeof(SUPPORTED_BAUD_RATES[0]);
53 for (
size_t i = 0; i < n; i++) {
54 if (SUPPORTED_BAUD_RATES[i] > baud) {
56 return SUPPORTED_BAUD_RATES[0];
57 uint32_t lower = SUPPORTED_BAUD_RATES[i - 1];
58 uint32_t upper = SUPPORTED_BAUD_RATES[i];
59 return (upper - baud) > (baud - lower) ? lower : upper;
62 return SUPPORTED_BAUD_RATES[n - 1];
66static void encode_baud_direct(uint8_t buf[4],
uint32_t baud) {
68 buf[1] = (baud >> 8) & 0xFF;
69 buf[2] = (baud >> 16) & 0xFF;
70 buf[3] = (baud >> 24) & 0xFF;
74static void encode_baud_divisor(uint8_t buf[4],
uint32_t baud) {
80 while (mantissa >= 512) {
91 buf[1] = (exponent << 1) | (mantissa >> 8);
92 buf[0] = mantissa & 0xFF;
96static void encode_baud_divisor_alt(uint8_t buf[4],
uint32_t baud) {
101 uint8_t exponent = 0;
102 while (mantissa >= 2048) {
112 buf[2] = exponent & 0x01;
113 buf[1] = ((exponent & ~0x01) << 4) | (mantissa >> 8);
114 buf[0] = mantissa & 0xFF;
118 const usb_config_desc_t *config_desc;
119 const usb_device_desc_t *device_desc;
120 std::vector<CdcEps> cdc_devs{};
122 if (usb_host_get_device_descriptor(dev_hdl, &device_desc) != ESP_OK) {
123 ESP_LOGE(TAG,
"PL2303: get_device_descriptor failed");
126 if (usb_host_get_active_config_descriptor(dev_hdl, &config_desc) != ESP_OK) {
127 ESP_LOGE(TAG,
"PL2303: get_active_config_descriptor failed");
132 uint16_t bcd_device = device_desc->bcdDevice;
133 uint16_t bcd_usb = device_desc->bcdUSB;
134 uint8_t bmax_packet = device_desc->bMaxPacketSize0;
135 uint8_t bdev_class = device_desc->bDeviceClass;
137 if (bdev_class == 0x02 || bmax_packet != 0x40) {
147 if (bcd_device == 0x0300) {
149 }
else if (bcd_device == 0x0500) {
158 ESP_LOGI(TAG,
"PL2303 chip type: %s (bcdUSB=0x%04X bcdDevice=0x%04X bMaxPkt=%u)", pl2303_type_name(this->
chip_type_),
159 bcd_usb, bcd_device, bmax_packet);
163 for (uint8_t i = 0; i < config_desc->bNumInterfaces; i++) {
164 int ep_offset = conf_offset;
165 const auto *intf = usb_parse_interface_descriptor(config_desc, i, 0, &conf_offset);
168 if (intf->bNumEndpoints < 2)
171 const usb_ep_desc_t *in_ep =
nullptr;
172 const usb_ep_desc_t *out_ep =
nullptr;
173 const usb_ep_desc_t *notify_ep =
nullptr;
175 for (uint8_t e = 0; e < intf->bNumEndpoints; e++) {
176 ep_offset = conf_offset;
177 const auto *ep = usb_parse_endpoint_descriptor_by_index(intf, e, config_desc->wTotalLength, &ep_offset);
180 if (ep->bmAttributes == USB_BM_ATTRIBUTES_XFER_BULK) {
181 if (ep->bEndpointAddress & usb_host::USB_DIR_IN) {
186 }
else if (ep->bmAttributes == USB_BM_ATTRIBUTES_XFER_INT) {
191 if (in_ep && out_ep) {
192 cdc_devs.push_back(
CdcEps{notify_ep, in_ep, out_ep, intf->bInterfaceNumber, intf->bInterfaceNumber});
197 if (cdc_devs.empty())
198 ESP_LOGE(TAG,
"PL2303: failed to find bulk IN+OUT endpoints");
207struct Pl2303InitStep {
214static const Pl2303InitStep PL2303_INIT[] = {
215 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0,
true},
216 {VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0,
false},
217 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0,
true},
218 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0,
true},
219 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0,
true},
220 {VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1,
false},
221 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0,
true},
222 {VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0,
true},
223 {VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1,
false},
224 {VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0,
false},
225 {VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0,
false},
227static constexpr uint8_t PL2303_INIT_COUNT =
sizeof(PL2303_INIT) /
sizeof(PL2303_INIT[0]);
230 const uint8_t *response) {
235 uint8_t init_count = (!reload && !is_hxn) ? PL2303_INIT_COUNT : 0;
236 if (step < init_count) {
237 const auto &e = PL2303_INIT[step];
238 uint16_t index = (step == PL2303_INIT_COUNT - 1) ? (is_legacy ? 0x24 : 0x44) : e.index;
240 e.read ? std::vector<uint8_t>{0} : std::vector<uint8_t>{});
250 uint8_t line_coding[7] = {};
254 uint32_t nearest = nearest_supported_baud(baud);
256 encode_baud_direct(line_coding, baud);
258 encode_baud_divisor_alt(line_coding, baud);
260 encode_baud_divisor(line_coding, baud);
295 ESP_LOGD(TAG,
"PL2303: SET_LINE_REQUEST baud=%u stop=%u parity=%u data=%u", baud, line_coding[4], line_coding[5],
298 std::vector<uint8_t> lc_vec(line_coding, line_coding + 7);
299 this->
config_transfer_(SET_LINE_REQUEST_TYPE, SET_LINE_REQUEST, 0, iface, lc_vec);
306 this->
config_transfer_(SET_CONTROL_REQUEST_TYPE, SET_CONTROL_REQUEST, CONTROL_DTR | CONTROL_RTS, iface);
uint8_t get_data_bits() const
uint8_t get_stop_bits() const
uint32_t get_baud_rate() const
UARTParityOptions parity_
void config_transfer_(uint8_t type, uint8_t request, uint16_t value, uint16_t index, const std::vector< uint8_t > &data={})
std::vector< CdcEps > parse_descriptors(usb_device_handle_t dev_hdl) override
Pl2303ChipType chip_type_
bool config_step(USBUartChannel *channel, uint8_t step, bool reload, bool ok, const uint8_t *response) override
@ UART_CONFIG_PARITY_SPACE
@ UART_CONFIG_PARITY_MARK
@ UART_CONFIG_PARITY_EVEN
uint8_t bulk_interface_number