ESPHome 2025.10.0-dev
Loading...
Searching...
No Matches
usb_uart.h
Go to the documentation of this file.
1#pragma once
2
3#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
10#include <atomic>
11
12namespace esphome {
13namespace usb_uart {
14class USBUartTypeCdcAcm;
15class USBUartComponent;
16class USBUartChannel;
17
18static const char *const TAG = "usb_uart";
19
20static constexpr uint8_t USB_CDC_SUBCLASS_ACM = 0x02;
21static constexpr uint8_t USB_SUBCLASS_COMMON = 0x02;
22static constexpr uint8_t USB_SUBCLASS_NULL = 0x00;
23static constexpr uint8_t USB_PROTOCOL_NULL = 0x00;
24static constexpr uint8_t USB_DEVICE_PROTOCOL_IAD = 0x01;
25static constexpr uint8_t USB_VENDOR_IFC = usb_host::USB_TYPE_VENDOR | usb_host::USB_RECIP_INTERFACE;
26static constexpr uint8_t USB_VENDOR_DEV = usb_host::USB_TYPE_VENDOR | usb_host::USB_RECIP_DEVICE;
27
28struct CdcEps {
29 const usb_ep_desc_t *notify_ep;
30 const usb_ep_desc_t *in_ep;
31 const usb_ep_desc_t *out_ep;
34};
35
43
49
50static const char *const PARITY_NAMES[] = {"NONE", "ODD", "EVEN", "MARK", "SPACE"};
51static const char *const STOP_BITS_NAMES[] = {"1", "1.5", "2"};
52
54 public:
55 RingBuffer(uint16_t buffer_size) : buffer_size_(buffer_size), buffer_(new uint8_t[buffer_size]) {}
56 bool is_empty() const { return this->read_pos_ == this->insert_pos_; }
57 size_t get_available() const {
58 return (this->insert_pos_ + this->buffer_size_ - this->read_pos_) % this->buffer_size_;
59 };
60 size_t get_free_space() const { return this->buffer_size_ - 1 - this->get_available(); }
61 uint8_t peek() const { return this->buffer_[this->read_pos_]; }
62 void push(uint8_t item);
63 void push(const uint8_t *data, size_t len);
64 uint8_t pop();
65 size_t pop(uint8_t *data, size_t len);
66 void clear() { this->read_pos_ = this->insert_pos_ = 0; }
67
68 protected:
69 uint16_t insert_pos_ = 0;
70 uint16_t read_pos_ = 0;
71 uint16_t buffer_size_;
72 uint8_t *buffer_;
73};
74
75// Structure for queuing received USB data chunks
77 static constexpr size_t MAX_CHUNK_SIZE = 64; // USB packet size
79 uint8_t length; // Max 64 bytes, so uint8_t is sufficient
81
82 // Required for EventPool - no cleanup needed for POD types
83 void release() {}
84};
85
86class USBUartChannel : public uart::UARTComponent, public Parented<USBUartComponent> {
87 friend class USBUartComponent;
88 friend class USBUartTypeCdcAcm;
89 friend class USBUartTypeCP210X;
90 friend class USBUartTypeCH34X;
91
92 public:
93 USBUartChannel(uint8_t index, uint16_t buffer_size)
94 : index_(index), input_buffer_(RingBuffer(buffer_size)), output_buffer_(RingBuffer(buffer_size)) {}
95 void write_array(const uint8_t *data, size_t len) override;
96 ;
97 bool peek_byte(uint8_t *data) override;
98 ;
99 bool read_array(uint8_t *data, size_t len) override;
100 int available() override { return static_cast<int>(this->input_buffer_.get_available()); }
101 void flush() override {}
102 void check_logger_conflict() override {}
103 void set_parity(UARTParityOptions parity) { this->parity_ = parity; }
104 void set_debug(bool debug) { this->debug_ = debug; }
105 void set_dummy_receiver(bool dummy_receiver) { this->dummy_receiver_ = dummy_receiver; }
106
107 protected:
108 // Larger structures first for better alignment
112 // Enum (likely 4 bytes)
114 // Group atomics together (each 1 byte)
115 std::atomic<bool> input_started_{true};
116 std::atomic<bool> output_started_{true};
117 std::atomic<bool> initialised_{false};
118 // Group regular bytes together to minimize padding
119 const uint8_t index_;
120 bool debug_{};
122};
123
125 public:
126 USBUartComponent(uint16_t vid, uint16_t pid) : usb_host::USBClient(vid, pid) {}
127 void setup() override;
128 void loop() override;
129 void dump_config() override;
130 std::vector<USBUartChannel *> get_channels() { return this->channels_; }
131
132 void add_channel(USBUartChannel *channel) { this->channels_.push_back(channel); }
133
134 void start_input(USBUartChannel *channel);
135 void start_output(USBUartChannel *channel);
136
137 // Lock-free data transfer from USB task to main loop
138 static constexpr int USB_DATA_QUEUE_SIZE = 32;
141
142 protected:
143 std::vector<USBUartChannel *> channels_{};
144};
145
147 public:
148 USBUartTypeCdcAcm(uint16_t vid, uint16_t pid) : USBUartComponent(vid, pid) {}
149
150 protected:
151 virtual std::vector<CdcEps> parse_descriptors(usb_device_handle_t dev_hdl);
152 void on_connected() override;
153 virtual void enable_channels();
154 void on_disconnected() override;
155};
156
158 public:
159 USBUartTypeCP210X(uint16_t vid, uint16_t pid) : USBUartTypeCdcAcm(vid, pid) {}
160
161 protected:
162 std::vector<CdcEps> parse_descriptors(usb_device_handle_t dev_hdl) override;
163 void enable_channels() override;
164};
166 public:
167 USBUartTypeCH34X(uint16_t vid, uint16_t pid) : USBUartTypeCdcAcm(vid, pid) {}
168
169 protected:
170 void enable_channels() override;
171};
172
173} // namespace usb_uart
174} // namespace esphome
175
176#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
Helper class to easily give an object a parent of type T.
Definition helpers.h:697
USBClient(uint16_t vid, uint16_t pid)
Definition usb_host.h:122
void push(uint8_t item)
Definition usb_uart.cpp:108
RingBuffer(uint16_t buffer_size)
Definition usb_uart.h:55
size_t get_free_space() const
Definition usb_uart.h:60
size_t get_available() const
Definition usb_uart.h:57
void set_dummy_receiver(bool dummy_receiver)
Definition usb_uart.h:105
std::atomic< bool > input_started_
Definition usb_uart.h:115
std::atomic< bool > initialised_
Definition usb_uart.h:117
bool peek_byte(uint8_t *data) override
Definition usb_uart.cpp:147
void set_parity(UARTParityOptions parity)
Definition usb_uart.h:103
void write_array(const uint8_t *data, size_t len) override
Definition usb_uart.cpp:132
void check_logger_conflict() override
Definition usb_uart.h:102
bool read_array(uint8_t *data, size_t len) override
Definition usb_uart.cpp:154
USBUartChannel(uint8_t index, uint16_t buffer_size)
Definition usb_uart.h:93
std::atomic< bool > output_started_
Definition usb_uart.h:116
void add_channel(USBUartChannel *channel)
Definition usb_uart.h:132
EventPool< UsbDataChunk, USB_DATA_QUEUE_SIZE > chunk_pool_
Definition usb_uart.h:140
USBUartComponent(uint16_t vid, uint16_t pid)
Definition usb_uart.h:126
std::vector< USBUartChannel * > channels_
Definition usb_uart.h:143
LockFreeQueue< UsbDataChunk, USB_DATA_QUEUE_SIZE > usb_data_queue_
Definition usb_uart.h:139
void start_output(USBUartChannel *channel)
Definition usb_uart.cpp:270
void start_input(USBUartChannel *channel)
Definition usb_uart.cpp:216
std::vector< USBUartChannel * > get_channels()
Definition usb_uart.h:130
static constexpr int USB_DATA_QUEUE_SIZE
Definition usb_uart.h:138
void enable_channels() override
CH34x.
Definition ch34x.cpp:16
USBUartTypeCH34X(uint16_t vid, uint16_t pid)
Definition usb_uart.h:167
USBUartTypeCP210X(uint16_t vid, uint16_t pid)
Definition usb_uart.h:159
std::vector< CdcEps > parse_descriptors(usb_device_handle_t dev_hdl) override
Definition cp210x.cpp:46
USBUartTypeCdcAcm(uint16_t vid, uint16_t pid)
Definition usb_uart.h:148
virtual std::vector< CdcEps > parse_descriptors(usb_device_handle_t dev_hdl)
Definition usb_uart.cpp:62
const char *const TAG
Definition spi.cpp:8
@ UART_CONFIG_STOP_BITS_1_5
Definition usb_uart.h:46
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:291
const usb_ep_desc_t * out_ep
Definition usb_uart.h:31
const usb_ep_desc_t * notify_ep
Definition usb_uart.h:29
const usb_ep_desc_t * in_ep
Definition usb_uart.h:30
uint8_t interrupt_interface_number
Definition usb_uart.h:33
uint8_t data[MAX_CHUNK_SIZE]
Definition usb_uart.h:78
static constexpr size_t MAX_CHUNK_SIZE
Definition usb_uart.h:77