ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
usb_cdc_acm.h
Go to the documentation of this file.
1#pragma once
2#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
3 defined(USE_ESP32_VARIANT_ESP32S31) || defined(USE_ESP32_VARIANT_ESP32H4)
4
9
10#include <functional>
11#include "freertos/ringbuf.h"
12#include "tinyusb_cdc_acm.h"
13
14namespace esphome::usb_cdc_acm {
15
16static const uint8_t EVENT_QUEUE_SIZE = 12;
17
18// Callback types for line coding and line state changes
19using LineCodingCallback = std::function<void(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits)>;
20using LineStateCallback = std::function<void(bool dtr, bool rts)>;
21
22// Event types
27
28// Event structure for the queue
29struct CDCEvent {
31 union {
32 struct {
33 bool dtr;
34 bool rts;
36 struct {
38 uint8_t stop_bits;
39 uint8_t parity;
40 uint8_t data_bits;
43
44 // Required by EventPool - called before returning to pool
45 void release() {
46 // No dynamic memory to clean up, data is stored inline
47 }
48};
49
50// Forward declaration
51class USBCDCACMComponent;
52
54class USBCDCACMInstance final : public uart::UARTComponent, public Parented<USBCDCACMComponent> {
55 public:
56 void setup();
57 void loop();
58 void dump_config();
59
60 void set_interface_number(uint8_t itf) { this->itf_ = itf; }
61 // Get the CDC port number for this instance
62 uint8_t get_itf() const { return this->itf_; }
63 // Ring buffer accessors for bridge components
64 RingbufHandle_t get_tx_ringbuf() const { return this->usb_tx_ringbuf_; }
65 RingbufHandle_t get_rx_ringbuf() const { return this->usb_rx_ringbuf_; }
66
67 // Task handle accessor for notifying TX task
68 TaskHandle_t get_tx_task_handle() const { return this->usb_tx_task_handle_; }
69
70 // Callback registration for line coding and line state changes
71 void set_line_coding_callback(LineCodingCallback callback) { this->line_coding_callback_ = std::move(callback); }
72 void set_line_state_callback(LineStateCallback callback) { this->line_state_callback_ = std::move(callback); }
73
74 // Called from USB core task context queues event for processing in main loop
75 void queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits);
76 void queue_line_state_event(bool dtr, bool rts);
77
78 static void usb_tx_task_fn(void *arg);
79 void usb_tx_task();
80
81 // UARTComponent interface implementation
82 void write_array(const uint8_t *data, size_t len) override;
83 bool peek_byte(uint8_t *data) override;
84 bool read_array(uint8_t *data, size_t len) override;
85 size_t available() override;
87#if defined(USE_ESP8266) || defined(USE_ESP32)
88 // No-op: in CDC ACM device mode the host dictates the line coding, so there are no
89 // local UART settings to (re)apply.
90 void load_settings(bool dump_config) override {}
91 using UARTComponent::load_settings; // also bring in the no-arg overload for convenience
92#endif
93
94 protected:
95 void check_logger_conflict() override;
96
97 // Process queued events and invoke callbacks (called from main loop)
98 void process_events_();
99 TaskHandle_t usb_tx_task_handle_{nullptr};
100
101 RingbufHandle_t usb_tx_ringbuf_{nullptr};
102 RingbufHandle_t usb_rx_ringbuf_{nullptr};
103 // RX buffer for peek functionality
104 uint8_t peek_buffer_{0};
105 bool has_peek_{false};
106 uint8_t itf_{0};
107 // User-registered callbacks (called from main loop)
110
111 // Lock-free queue and event pool for cross-task event passing
112 // Pool sized to queue capacity (SIZE-1) because LockFreeQueue<T,N> is a ring
113 // buffer that holds N-1 elements. This guarantees allocate() returns nullptr
114 // before push() can fail, preventing both a pool slot leak and an SPSC
115 // violation on the pool's internal free list.
116 EventPool<CDCEvent, EVENT_QUEUE_SIZE - 1> event_pool_;
118};
119
121class USBCDCACMComponent final : public Component {
122 public:
124
125 void setup() override;
126 void loop() override;
127 void dump_config() override;
128 float get_setup_priority() const override { return setup_priority::IO; }
129
130 // Interface management
131 void add_interface(USBCDCACMInstance *interface);
133
134 protected:
135 std::array<USBCDCACMInstance *, ESPHOME_MAX_USB_CDC_INSTANCES> interfaces_{};
136};
137
138extern USBCDCACMComponent *global_usb_cdc_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
139
140} // namespace esphome::usb_cdc_acm
141#endif
Helper class to easily give an object a parent of type T.
Definition helpers.h:1875
Main USB CDC ACM component that manages the USB device and all CDC interfaces.
void add_interface(USBCDCACMInstance *interface)
std::array< USBCDCACMInstance *, ESPHOME_MAX_USB_CDC_INSTANCES > interfaces_
USBCDCACMInstance * get_interface_by_number(uint8_t itf)
float get_setup_priority() const override
Represents a single CDC ACM interface instance.
Definition usb_cdc_acm.h:54
RingbufHandle_t get_rx_ringbuf() const
Definition usb_cdc_acm.h:65
EventPool< CDCEvent, EVENT_QUEUE_SIZE - 1 > event_pool_
bool read_array(uint8_t *data, size_t len) override
RingbufHandle_t get_tx_ringbuf() const
Definition usb_cdc_acm.h:64
void set_line_state_callback(LineStateCallback callback)
Definition usb_cdc_acm.h:72
uart::UARTFlushResult flush() override
LockFreeQueue< CDCEvent, EVENT_QUEUE_SIZE > event_queue_
void queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits)
TaskHandle_t get_tx_task_handle() const
Definition usb_cdc_acm.h:68
void set_line_coding_callback(LineCodingCallback callback)
Definition usb_cdc_acm.h:71
void load_settings(bool dump_config) override
Definition usb_cdc_acm.h:90
void write_array(const uint8_t *data, size_t len) override
void queue_line_state_event(bool dtr, bool rts)
constexpr float IO
For components that represent GPIO pins like PCF8573.
Definition component.h:41
UARTFlushResult
Result of a flush() call.
std::function< void(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits)> LineCodingCallback
Definition usb_cdc_acm.h:19
USBCDCACMComponent * global_usb_cdc_component
std::function< void(bool dtr, bool rts)> LineStateCallback
Definition usb_cdc_acm.h:20
const void size_t len
Definition hal.h:64
static void uint32_t
union esphome::usb_cdc_acm::CDCEvent::@175 data
struct esphome::usb_cdc_acm::CDCEvent::@175::@177 line_coding
struct esphome::usb_cdc_acm::CDCEvent::@175::@176 line_state