ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
cdc_acm_uart_bridge.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)
6
7#include <array>
8#include <atomic>
9#include "sdkconfig.h"
10
11namespace esphome::cdc_acm_uart {
12
13class CDCACMUARTBridge final : public Component {
14 public:
15 // Upper bound on the RX task's blocking read, so pause() takes effect without
16 // aborting the read. Arriving bytes still unblock it immediately.
17 static constexpr uint32_t UART_RX_WAIT_MS = 250;
18
20 : uart_parent_(uart_parent), usb_cdc_parent_(usb_cdc_parent) {}
21
22 void setup() override;
23 void loop() override;
24 void dump_config() override;
25 void on_shutdown() override;
26 float get_setup_priority() const override { return setup_priority::HARDWARE; }
27
28 void set_dtr_pin(GPIOPin *dtr_pin) { this->dtr_pin_ = dtr_pin; }
29 void set_rts_pin(GPIOPin *rts_pin) { this->rts_pin_ = rts_pin; }
30
31 void set_line_coding();
32 void set_line_state(bool dtr, bool rts);
34
45 void pause();
51 void resume();
54 bool is_paused() const {
55 return this->state_ == MainState::MAIN_STATE_PAUSED &&
56 (this->uart_rx_task_handle_ == nullptr || this->rx_parked_ != 0);
57 }
58
59 protected:
60 static void uart_rx_task_fn(void *arg);
61 static void uart_tx_task_fn(void *arg);
62 void uart_rx_task_();
63 void uart_tx_task_();
65 // True when the TX task has no write in flight and the UART TX FIFO has drained.
66 bool tx_idle_();
67 void finish_resume_();
68 void drive_line_state_();
69 // Copy the host's line coding onto the UART settings; true if anything changed.
70 bool sync_host_framing_();
71
72 TaskHandle_t uart_rx_task_handle_{nullptr};
73 TaskHandle_t uart_tx_task_handle_{nullptr};
74
75 GPIOPin *dtr_pin_{nullptr};
76 GPIOPin *rts_pin_{nullptr};
77
79
80 // Worker staging, each sized to the CDC ring buffer it feeds or drains.
81 std::array<uint8_t, CONFIG_TINYUSB_CDC_TX_BUFSIZE> uart_rx_buffer_{};
82 std::array<uint8_t, CONFIG_TINYUSB_CDC_RX_BUFSIZE> uart_tx_buffer_{};
83
86
87 // YAML framing, captured at setup; the host's line coding overwrites the UART's
88 // settings, so pause() needs the original to restore.
93
94 // Written on the main loop, read by both worker tasks. uint8_t rather than bool:
95 // GCC on Xtensa emits an out-of-line call for atomic<bool>.
96 std::atomic<uint8_t> paused_{0};
97 // Raised by the RX task while parked and by the TX task around each UART write, so
98 // the pause hand-off knows when the bus is actually free.
99 std::atomic<uint8_t> rx_parked_{0};
100 std::atomic<uint8_t> tx_busy_{0};
101 // Main-loop state; paused_ mirrors it for the worker tasks.
102 enum class MainState : uint8_t {
104 MAIN_STATE_RELOAD_PENDING, // host line coding debounced, forwarding continues
105 MAIN_STATE_PAUSING, // waiting for TX idle to restore the configured framing
107 MAIN_STATE_RESUMING, // resume() requested while a host write still drains
108 };
110 // Host line state, recorded even while paused so resume() can re-drive the pins.
111 bool host_dtr_{false};
112 bool host_rts_{false};
113 // True once the host has sent any line coding; resume() then re-syncs to it.
114 bool host_coding_seen_{false};
115};
116
117} // namespace esphome::cdc_acm_uart
118#endif
std::array< uint8_t, CONFIG_TINYUSB_CDC_RX_BUFSIZE > uart_tx_buffer_
uart::IDFUARTComponent * get_uart_parent() const
void resume()
Re-apply the host's line coding and line state, then resume forwarding.
usb_cdc_acm::USBCDCACMInstance * usb_cdc_parent_
bool is_paused() const
True once both worker tasks are off the bus and the configured framing is restored.
void pause()
Stop forwarding in both directions and hand the UART back to its configured framing,...
CDCACMUARTBridge(uart::IDFUARTComponent *uart_parent, usb_cdc_acm::USBCDCACMInstance *usb_cdc_parent)
std::array< uint8_t, CONFIG_TINYUSB_CDC_TX_BUFSIZE > uart_rx_buffer_
ESP-IDF UART driver wrapper.
Represents a single CDC ACM interface instance.
Definition usb_cdc_acm.h:87
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.h:43
static void uint32_t