ESPHome 2026.1.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
8
9#include <functional>
10#include "freertos/ringbuf.h"
11#include "tusb_cdc_acm.h"
12
13namespace esphome::usb_cdc_acm {
14
15static const uint8_t EVENT_QUEUE_SIZE = 12;
16static const uint8_t MAX_USB_CDC_INSTANCES = 2;
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 {
37 uint32_t bit_rate;
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 : public uart::UARTComponent, public Parented<USBCDCACMComponent> {
55 public:
56 void set_interface_number(uint8_t itf) { this->itf_ = static_cast<tinyusb_cdcacm_itf_t>(itf); }
57
58 void setup();
59 void loop();
60
61 // Get the CDC port number for this instance
62 tinyusb_cdcacm_itf_t get_itf() const { return this->itf_; }
63
64 // Ring buffer accessors for bridge components
65 RingbufHandle_t get_tx_ringbuf() const { return this->usb_tx_ringbuf_; }
66 RingbufHandle_t get_rx_ringbuf() const { return this->usb_rx_ringbuf_; }
67
68 // Task handle accessor for notifying TX task
69 TaskHandle_t get_tx_task_handle() const { return this->usb_tx_task_handle_; }
70
71 // Callback registration for line coding and line state changes
72 void set_line_coding_callback(LineCodingCallback callback) { this->line_coding_callback_ = std::move(callback); }
73 void set_line_state_callback(LineStateCallback callback) { this->line_state_callback_ = std::move(callback); }
74
75 // Called from TinyUSB task context (SPSC producer) - queues event for processing in main loop
76 void queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits);
77 void queue_line_state_event(bool dtr, bool rts);
78
79 static void usb_tx_task_fn(void *arg);
80 void usb_tx_task();
81
82 // UARTComponent interface implementation
83 void write_array(const uint8_t *data, size_t len) override;
84 bool peek_byte(uint8_t *data) override;
85 bool read_array(uint8_t *data, size_t len) override;
86 int available() override;
87 void flush() override;
88
89 protected:
90 void check_logger_conflict() override {}
91
92 // Process queued events and invoke callbacks (called from main loop)
93 void process_events_();
94
95 TaskHandle_t usb_tx_task_handle_{nullptr};
96 tinyusb_cdcacm_itf_t itf_{TINYUSB_CDC_ACM_0};
97
98 RingbufHandle_t usb_tx_ringbuf_{nullptr};
99 RingbufHandle_t usb_rx_ringbuf_{nullptr};
100
101 // User-registered callbacks (called from main loop)
104
105 // Lock-free queue and event pool for cross-task event passing
108
109 // RX buffer for peek functionality
110 uint8_t peek_buffer_{0};
111 bool has_peek_{false};
112};
113
116 public:
118
119 void setup() override;
120 void loop() override;
121 void dump_config() override;
122 float get_setup_priority() const override { return setup_priority::IO; }
123
124 // Interface management
125 void add_interface(USBCDCACMInstance *interface);
127
128 protected:
129 std::array<USBCDCACMInstance *, MAX_USB_CDC_INSTANCES> interfaces_{nullptr, nullptr};
130};
131
132extern USBCDCACMComponent *global_usb_cdc_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
133
134} // namespace esphome::usb_cdc_acm
135#endif
Helper class to easily give an object a parent of type T.
Definition helpers.h:958
Main USB CDC ACM component that manages the USB device and all CDC interfaces.
void add_interface(USBCDCACMInstance *interface)
USBCDCACMInstance * get_interface_by_number(uint8_t itf)
std::array< USBCDCACMInstance *, MAX_USB_CDC_INSTANCES > interfaces_
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:66
bool read_array(uint8_t *data, size_t len) override
EventPool< CDCEvent, EVENT_QUEUE_SIZE > event_pool_
bool peek_byte(uint8_t *data) override
RingbufHandle_t get_tx_ringbuf() const
Definition usb_cdc_acm.h:65
void set_line_state_callback(LineStateCallback callback)
Definition usb_cdc_acm.h:73
tinyusb_cdcacm_itf_t get_itf() const
Definition usb_cdc_acm.h:62
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:69
void set_line_coding_callback(LineCodingCallback callback)
Definition usb_cdc_acm.h:72
void write_array(const uint8_t *data, size_t len) override
void queue_line_state_event(bool dtr, bool rts)
const float IO
For components that represent GPIO pins like PCF8573.
Definition component.cpp:79
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
std::string size_t len
Definition helpers.h:518
union esphome::usb_cdc_acm::CDCEvent::@159 data
struct esphome::usb_cdc_acm::CDCEvent::@159::@160 line_state
struct esphome::usb_cdc_acm::CDCEvent::@159::@161 line_coding