mirror of
https://github.com/esphome/esphome.git
synced 2026-01-10 20:20:56 -07:00
3.3 KiB
3.3 KiB
USB Host Component - Callback Execution Contexts
Overview
After the refactoring to use a dedicated USB task, all USB callbacks now execute in the USB task context, NOT in the main loop. This prevents race conditions and data corruption.
USB Task Architecture
// USB Task (runs on Core 1, priority 5)
void USBClient::usb_task_loop() {
while (usb_task_running_) {
// This handles ALL USB events and triggers callbacks
usb_host_client_handle_events(handle_, pdMS_TO_TICKS(10));
}
}
Callback Execution Contexts
1. client_event_cb (Device Connect/Disconnect)
- Context: USB task
- Triggered by: USB device connection/disconnection events
- What it does: Queues events to main loop via FreeRTOS queue
- Data flow: USB hardware → USB task → Queue → Main loop
2. control_callback (Control Transfers)
- Context: USB task
- Triggered by: Completion of USB control transfers
- What it does: Queues callback execution to main loop
- Data flow: USB hardware → USB task → Queue → Main loop
3. transfer_callback (Bulk Transfers)
- Context: USB task
- Triggered by: Completion of bulk IN/OUT transfers
- What it does: Queues callback execution to main loop
- Data flow: USB hardware → USB task → Queue → Main loop
4. USBUartComponent Input Callback (Data Reception)
- Context: USB task (lambda passed to transfer_in)
- Called from: transfer_callback in USB task
- What it does:
- Copies received data to temporary buffer
- Queues data processing to main loop via defer()
- Main loop then safely pushes to ring buffer
- Data flow: USB hardware → USB task → Copy data → Queue → Main loop → Ring buffer
5. USBUartComponent Output Callback (Data Transmission)
- Context: USB task (lambda passed to transfer_out)
- Called from: transfer_callback in USB task
- What it does:
- Marks output as not started
- Queues next transfer start to main loop via defer()
- Data flow: Main loop reads ring buffer → Start transfer → USB task → Queue restart → Main loop
Thread Safety Summary
Safe Operations (Main Loop Only):
- Ring buffer push (incoming data)
- Ring buffer pop (outgoing data)
- Component state changes
- Transfer initiation
USB Task Operations:
- USB event handling
- Transfer completion detection
- Event queueing to main loop
Communication Mechanism:
- FreeRTOS Queue: For USB events and callbacks
- defer(): For component-specific operations
Why This Architecture?
- Prevents data loss: USB events are handled promptly even when main loop is busy
- Thread safety: Ring buffer is only accessed from main loop
- No race conditions: Data structures aren't shared between tasks
- Maintains responsiveness: USB hardware FIFOs don't overflow
Key Changes from Original Implementation
Before (Problematic):
usb_host_client_handle_events()called in main loop- Callbacks executed in main loop context
- USB events dropped when main loop was busy
- Ring buffer corruption when data arrived during slow processing
After (Fixed):
usb_host_client_handle_events()runs in dedicated task- Callbacks execute in USB task, queue work to main loop
- USB events always handled promptly
- Ring buffer only accessed from main loop (thread-safe)