Files
esphome-lsm6ds/esphome/components/usb_cdc_acm/usb_cdc_acm.h
T

135 lines
4.5 KiB
C++

#pragma once
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
#include "esphome/core/component.h"
#include "esphome/core/event_pool.h"
#include "esphome/core/lock_free_queue.h"
#include "esphome/components/uart/uart_component.h"
#include <functional>
#include "freertos/ringbuf.h"
#include "tinyusb_cdc_acm.h"
namespace esphome::usb_cdc_acm {
static const uint8_t EVENT_QUEUE_SIZE = 12;
// Callback types for line coding and line state changes
using LineCodingCallback = std::function<void(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits)>;
using LineStateCallback = std::function<void(bool dtr, bool rts)>;
// Event types
enum CDCEventType : uint8_t {
CDC_EVENT_LINE_STATE_CHANGED,
CDC_EVENT_LINE_CODING_CHANGED,
};
// Event structure for the queue
struct CDCEvent {
CDCEventType type;
union {
struct {
bool dtr;
bool rts;
} line_state;
struct {
uint32_t bit_rate;
uint8_t stop_bits;
uint8_t parity;
uint8_t data_bits;
} line_coding;
} data;
// Required by EventPool - called before returning to pool
void release() {
// No dynamic memory to clean up, data is stored inline
}
};
// Forward declaration
class USBCDCACMComponent;
/// Represents a single CDC ACM interface instance
class USBCDCACMInstance : public uart::UARTComponent, public Parented<USBCDCACMComponent> {
public:
void setup();
void loop();
void dump_config();
void set_interface_number(uint8_t itf) { this->itf_ = itf; }
// Get the CDC port number for this instance
uint8_t get_itf() const { return this->itf_; }
// Ring buffer accessors for bridge components
RingbufHandle_t get_tx_ringbuf() const { return this->usb_tx_ringbuf_; }
RingbufHandle_t get_rx_ringbuf() const { return this->usb_rx_ringbuf_; }
// Task handle accessor for notifying TX task
TaskHandle_t get_tx_task_handle() const { return this->usb_tx_task_handle_; }
// Callback registration for line coding and line state changes
void set_line_coding_callback(LineCodingCallback callback) { this->line_coding_callback_ = std::move(callback); }
void set_line_state_callback(LineStateCallback callback) { this->line_state_callback_ = std::move(callback); }
// Called from USB core task context queues event for processing in main loop
void queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity, uint8_t data_bits);
void queue_line_state_event(bool dtr, bool rts);
static void usb_tx_task_fn(void *arg);
void usb_tx_task();
// UARTComponent interface implementation
void write_array(const uint8_t *data, size_t len) override;
bool peek_byte(uint8_t *data) override;
bool read_array(uint8_t *data, size_t len) override;
size_t available() override;
uart::UARTFlushResult flush() override;
protected:
void check_logger_conflict() override;
// Process queued events and invoke callbacks (called from main loop)
void process_events_();
TaskHandle_t usb_tx_task_handle_{nullptr};
RingbufHandle_t usb_tx_ringbuf_{nullptr};
RingbufHandle_t usb_rx_ringbuf_{nullptr};
// RX buffer for peek functionality
uint8_t peek_buffer_{0};
bool has_peek_{false};
uint8_t itf_{0};
// User-registered callbacks (called from main loop)
LineCodingCallback line_coding_callback_{nullptr};
LineStateCallback line_state_callback_{nullptr};
// Lock-free queue and event pool for cross-task event passing
// Pool sized to queue capacity (SIZE-1) because LockFreeQueue<T,N> is a ring
// buffer that holds N-1 elements. This guarantees allocate() returns nullptr
// before push() can fail, preventing both a pool slot leak and an SPSC
// violation on the pool's internal free list.
EventPool<CDCEvent, EVENT_QUEUE_SIZE - 1> event_pool_;
LockFreeQueue<CDCEvent, EVENT_QUEUE_SIZE> event_queue_;
};
/// Main USB CDC ACM component that manages the USB device and all CDC interfaces
class USBCDCACMComponent : public Component {
public:
USBCDCACMComponent();
void setup() override;
void loop() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::IO; }
// Interface management
void add_interface(USBCDCACMInstance *interface);
USBCDCACMInstance *get_interface_by_number(uint8_t itf);
protected:
std::array<USBCDCACMInstance *, ESPHOME_MAX_USB_CDC_INSTANCES> interfaces_{};
};
extern USBCDCACMComponent *global_usb_cdc_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace esphome::usb_cdc_acm
#endif