esphome 2025.9.3__py3-none-any.whl → 2025.10.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +87 -31
- esphome/address_cache.py +142 -0
- esphome/automation.py +130 -32
- esphome/build_gen/platformio.py +1 -3
- esphome/codegen.py +1 -0
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/api/__init__.py +166 -3
- esphome/components/api/api_connection.cpp +84 -41
- esphome/components/api/api_connection.h +22 -16
- esphome/components/api/api_frame_helper.cpp +33 -19
- esphome/components/api/api_frame_helper.h +19 -4
- esphome/components/api/api_frame_helper_noise.cpp +41 -53
- esphome/components/api/api_frame_helper_noise.h +1 -1
- esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
- esphome/components/api/api_frame_helper_plaintext.h +1 -1
- esphome/components/api/api_pb2.cpp +189 -15
- esphome/components/api/api_pb2.h +132 -20
- esphome/components/api/api_pb2_dump.cpp +97 -9
- esphome/components/api/api_pb2_service.cpp +118 -160
- esphome/components/api/api_pb2_service.h +31 -3
- esphome/components/api/api_server.cpp +68 -10
- esphome/components/api/api_server.h +32 -4
- esphome/components/api/custom_api_device.h +8 -8
- esphome/components/api/homeassistant_service.h +123 -6
- esphome/components/api/proto.h +6 -2
- esphome/components/api/user_services.h +2 -2
- esphome/components/as7341/sensor.py +1 -1
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio.cpp +1 -1
- esphome/components/audio/audio_decoder.cpp +9 -9
- esphome/components/bl0906/bl0906.cpp +2 -2
- esphome/components/bl0942/bl0942.cpp +2 -2
- esphome/components/ble_client/__init__.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +4 -30
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
- esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/camera_encoder/__init__.py +2 -4
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
- esphome/components/canbus/canbus.cpp +7 -5
- esphome/components/canbus/canbus.h +4 -4
- esphome/components/captive_portal/__init__.py +18 -1
- esphome/components/captive_portal/captive_portal.cpp +40 -46
- esphome/components/captive_portal/captive_portal.h +20 -22
- esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
- esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
- esphome/components/ccs811/ccs811.cpp +1 -1
- esphome/components/climate/climate.cpp +10 -7
- esphome/components/cm1106/cm1106.cpp +1 -1
- esphome/components/copy/lock/copy_lock.cpp +1 -1
- esphome/components/cover/cover.cpp +1 -0
- esphome/components/daikin_arc/daikin_arc.cpp +19 -12
- esphome/components/deep_sleep/__init__.py +9 -2
- esphome/components/deep_sleep/deep_sleep_component.h +11 -9
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
- esphome/components/ektf2232/touchscreen/__init__.py +8 -5
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
- esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
- esphome/components/epaper_spi/__init__.py +1 -0
- esphome/components/epaper_spi/display.py +80 -0
- esphome/components/epaper_spi/epaper_spi.cpp +227 -0
- esphome/components/epaper_spi/epaper_spi.h +93 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
- esphome/components/es7210/es7210.cpp +3 -3
- esphome/components/esp32/__init__.py +254 -339
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +159 -44
- esphome/components/esp32_ble/ble.cpp +47 -3
- esphome/components/esp32_ble/ble.h +18 -0
- esphome/components/esp32_ble/ble_advertising.cpp +7 -3
- esphome/components/esp32_ble/ble_advertising.h +4 -0
- esphome/components/esp32_ble/ble_uuid.cpp +16 -42
- esphome/components/esp32_ble_beacon/__init__.py +3 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
- esphome/components/esp32_ble_server/__init__.py +28 -14
- esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
- esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
- esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
- esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
- esphome/components/esp32_ble_server/ble_server.cpp +59 -24
- esphome/components/esp32_ble_server/ble_server.h +38 -20
- esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
- esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
- esphome/components/esp32_ble_tracker/__init__.py +25 -80
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
- esphome/components/esp32_camera/__init__.py +1 -3
- esphome/components/esp32_can/esp32_can.cpp +22 -4
- esphome/components/esp32_can/esp32_can.h +3 -0
- esphome/components/esp32_hosted/__init__.py +2 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
- esphome/components/esp32_improv/esp32_improv_component.h +6 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp8266/__init__.py +3 -3
- esphome/components/esphome/ota/__init__.py +21 -2
- esphome/components/esphome/ota/ota_esphome.cpp +455 -145
- esphome/components/esphome/ota/ota_esphome.h +49 -2
- esphome/components/ethernet/__init__.py +39 -22
- esphome/components/ethernet/ethernet_component.cpp +28 -5
- esphome/components/ethernet/ethernet_component.h +5 -1
- esphome/components/external_components/__init__.py +8 -6
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
- esphome/components/font/__init__.py +5 -5
- esphome/components/graph/graph.cpp +1 -1
- esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
- esphome/components/haier/hon_climate.cpp +2 -2
- esphome/components/haier/hon_climate.h +1 -1
- esphome/components/hdc1080/hdc1080.cpp +42 -34
- esphome/components/hdc1080/hdc1080.h +1 -3
- esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/http_request/__init__.py +3 -3
- esphome/components/htu21d/htu21d.cpp +13 -18
- esphome/components/htu21d/htu21d.h +1 -1
- esphome/components/i2s_audio/__init__.py +1 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
- esphome/components/improv_serial/improv_serial_component.cpp +12 -15
- esphome/components/improv_serial/improv_serial_component.h +6 -8
- esphome/components/json/json_util.cpp +35 -43
- esphome/components/json/json_util.h +57 -0
- esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
- esphome/components/key_collector/key_collector.h +4 -4
- esphome/components/libretiny/__init__.py +6 -6
- esphome/components/libretiny/preferences.cpp +23 -16
- esphome/components/light/light_call.cpp +98 -120
- esphome/components/light/light_call.h +17 -7
- esphome/components/lm75b/__init__.py +0 -0
- esphome/components/lm75b/lm75b.cpp +39 -0
- esphome/components/lm75b/lm75b.h +19 -0
- esphome/components/lm75b/sensor.py +34 -0
- esphome/components/lock/lock.h +12 -6
- esphome/components/logger/__init__.py +15 -27
- esphome/components/logger/logger.cpp +10 -20
- esphome/components/logger/logger.h +105 -62
- esphome/components/logger/logger_esp32.cpp +0 -48
- esphome/components/logger/logger_zephyr.cpp +2 -3
- esphome/components/logger/select/logger_level_select.cpp +6 -7
- esphome/components/logger/select/logger_level_select.h +7 -0
- esphome/components/ltr501/ltr501.cpp +7 -6
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
- esphome/components/matrix_keypad/matrix_keypad.h +4 -4
- esphome/components/max7219digit/max7219digit.cpp +1 -1
- esphome/components/mcp2515/mcp2515.cpp +31 -3
- esphome/components/mcp2515/mcp2515_defs.h +3 -1
- esphome/components/md5/md5.cpp +0 -26
- esphome/components/md5/md5.h +10 -20
- esphome/components/mdns/__init__.py +19 -6
- esphome/components/mdns/mdns_component.cpp +27 -59
- esphome/components/mdns/mdns_component.h +23 -10
- esphome/components/mdns/mdns_esp32.cpp +7 -7
- esphome/components/mdns/mdns_esp8266.cpp +6 -6
- esphome/components/mdns/mdns_libretiny.cpp +3 -3
- esphome/components/mdns/mdns_rp2040.cpp +3 -3
- esphome/components/mipi/__init__.py +1 -5
- esphome/components/mipi_spi/display.py +24 -8
- esphome/components/mipi_spi/mipi_spi.h +3 -3
- esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
- esphome/components/mmc5603/mmc5603.cpp +3 -3
- esphome/components/modbus/modbus.cpp +27 -13
- esphome/components/modbus/modbus.h +5 -3
- esphome/components/modbus/modbus_definitions.h +86 -0
- esphome/components/modbus_controller/__init__.py +29 -1
- esphome/components/modbus_controller/const.py +4 -0
- esphome/components/modbus_controller/modbus_controller.cpp +38 -13
- esphome/components/modbus_controller/modbus_controller.h +18 -29
- esphome/components/mpr121/mpr121.cpp +41 -42
- esphome/components/mpr121/mpr121.h +0 -1
- esphome/components/nau7802/nau7802.cpp +2 -2
- esphome/components/network/__init__.py +7 -3
- esphome/components/nextion/display.py +4 -4
- esphome/components/nextion/nextion.cpp +8 -8
- esphome/components/number/__init__.py +2 -0
- esphome/components/number/number_call.cpp +23 -12
- esphome/components/number/number_call.h +5 -0
- esphome/components/online_image/bmp_image.cpp +2 -1
- esphome/components/online_image/jpeg_image.cpp +4 -2
- esphome/components/openthread/openthread.cpp +6 -7
- esphome/components/openthread/openthread.h +0 -1
- esphome/components/ota/ota_backend.h +1 -0
- esphome/components/packages/__init__.py +10 -8
- esphome/components/packet_transport/packet_transport.cpp +2 -0
- esphome/components/pid/pid_controller.cpp +1 -1
- esphome/components/prometheus/prometheus_handler.cpp +239 -239
- esphome/components/psram/__init__.py +30 -28
- esphome/components/qmc5883l/qmc5883l.cpp +15 -0
- esphome/components/qmc5883l/qmc5883l.h +3 -0
- esphome/components/qmc5883l/sensor.py +31 -12
- esphome/components/remote_base/gobox_protocol.cpp +3 -3
- esphome/components/remote_receiver/__init__.py +14 -2
- esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
- esphome/components/remote_receiver/remote_receiver.h +4 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
- esphome/components/remote_transmitter/__init__.py +2 -2
- esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
- esphome/components/rp2040/__init__.py +11 -11
- esphome/components/rtttl/rtttl.cpp +2 -2
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/script/script.h +7 -7
- esphome/components/select/select.cpp +5 -4
- esphome/components/select/select_call.cpp +1 -1
- esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/sha256/__init__.py +22 -0
- esphome/components/sha256/sha256.cpp +116 -0
- esphome/components/sha256/sha256.h +60 -0
- esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
- esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
- esphome/components/spi/__init__.py +0 -3
- esphome/components/split_buffer/__init__.py +5 -0
- esphome/components/split_buffer/split_buffer.cpp +133 -0
- esphome/components/split_buffer/split_buffer.h +40 -0
- esphome/components/sps30/sps30.cpp +14 -10
- esphome/components/sps30/sps30.h +2 -0
- esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
- esphome/components/st7789v/st7789v.cpp +3 -2
- esphome/components/statsd/statsd.cpp +1 -1
- esphome/components/substitutions/__init__.py +3 -1
- esphome/components/substitutions/jinja.py +13 -3
- esphome/components/sx126x/__init__.py +16 -0
- esphome/components/sx126x/sx126x.cpp +15 -1
- esphome/components/sx126x/sx126x.h +9 -1
- esphome/components/sx126x/sx126x_reg.h +2 -0
- esphome/components/text_sensor/text_sensor.cpp +16 -0
- esphome/components/text_sensor/text_sensor.h +3 -10
- esphome/components/tormatic/tormatic_cover.cpp +1 -1
- esphome/components/tuya/select/tuya_select.cpp +1 -1
- esphome/components/tuya/tuya.cpp +29 -4
- esphome/components/uart/__init__.py +36 -26
- esphome/components/uart/uart.h +6 -0
- esphome/components/uart/uart_component.cpp +8 -0
- esphome/components/uart/uart_component.h +28 -0
- esphome/components/uart/uart_component_esp_idf.cpp +64 -10
- esphome/components/uart/uart_component_esp_idf.h +5 -2
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
- esphome/components/usb_host/__init__.py +2 -1
- esphome/components/usb_host/usb_host.h +82 -13
- esphome/components/usb_host/usb_host_client.cpp +180 -24
- esphome/components/usb_host/usb_host_component.cpp +1 -1
- esphome/components/usb_uart/__init__.py +0 -1
- esphome/components/usb_uart/ch34x.cpp +4 -4
- esphome/components/usb_uart/cp210x.cpp +3 -3
- esphome/components/usb_uart/usb_uart.cpp +88 -32
- esphome/components/usb_uart/usb_uart.h +30 -6
- esphome/components/valve/valve.cpp +1 -0
- esphome/components/veml7700/veml7700.cpp +7 -6
- esphome/components/version/version_text_sensor.cpp +2 -1
- esphome/components/voice_assistant/voice_assistant.cpp +3 -2
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
- esphome/components/web_server/list_entities.cpp +3 -4
- esphome/components/web_server/list_entities.h +8 -10
- esphome/components/web_server/ota/__init__.py +1 -1
- esphome/components/web_server/ota/ota_web_server.cpp +9 -3
- esphome/components/web_server/web_server.cpp +509 -404
- esphome/components/web_server/web_server.h +5 -6
- esphome/components/web_server/web_server_v1.cpp +21 -19
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.h +27 -7
- esphome/components/web_server_idf/__init__.py +1 -1
- esphome/components/web_server_idf/multipart.cpp +2 -2
- esphome/components/web_server_idf/multipart.h +2 -2
- esphome/components/web_server_idf/utils.cpp +2 -2
- esphome/components/web_server_idf/utils.h +2 -2
- esphome/components/web_server_idf/web_server_idf.cpp +118 -26
- esphome/components/web_server_idf/web_server_idf.h +12 -10
- esphome/components/wifi/__init__.py +13 -11
- esphome/components/wifi/wifi_component.cpp +73 -56
- esphome/components/wifi/wifi_component.h +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/wts01/__init__.py +0 -0
- esphome/components/wts01/sensor.py +41 -0
- esphome/components/wts01/wts01.cpp +91 -0
- esphome/components/wts01/wts01.h +27 -0
- esphome/components/zephyr/__init__.py +5 -5
- esphome/components/zwave_proxy/__init__.py +43 -0
- esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
- esphome/components/zwave_proxy/zwave_proxy.h +93 -0
- esphome/config.py +79 -24
- esphome/config_validation.py +13 -15
- esphome/const.py +9 -2
- esphome/core/__init__.py +31 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +19 -0
- esphome/core/hash_base.h +56 -0
- esphome/core/helpers.cpp +19 -3
- esphome/core/helpers.h +26 -0
- esphome/core/scheduler.cpp +5 -21
- esphome/core/scheduler.h +19 -8
- esphome/core/string_ref.h +1 -1
- esphome/core/time.cpp +5 -5
- esphome/cpp_generator.py +4 -29
- esphome/dashboard/const.py +21 -4
- esphome/dashboard/core.py +10 -8
- esphome/dashboard/dns.py +15 -0
- esphome/dashboard/entries.py +15 -21
- esphome/dashboard/models.py +76 -0
- esphome/dashboard/settings.py +7 -7
- esphome/dashboard/status/mdns.py +46 -2
- esphome/dashboard/web_server.py +367 -93
- esphome/espota2.py +111 -31
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/platformio_api.py +25 -18
- esphome/storage_json.py +26 -21
- esphome/types.py +30 -2
- esphome/util.py +32 -16
- esphome/vscode.py +8 -8
- esphome/wizard.py +10 -10
- esphome/writer.py +50 -15
- esphome/yaml_util.py +37 -31
- esphome/zeroconf.py +12 -3
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +332 -312
- esphome/components/event_emitter/__init__.py +0 -5
- esphome/components/event_emitter/event_emitter.cpp +0 -14
- esphome/components/event_emitter/event_emitter.h +0 -63
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
- esphome/components/uart/uart_component_esp32_arduino.h +0 -60
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
- esphome/core/string_ref.cpp +0 -12
- esphome/dashboard/util/file.py +0 -63
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -122,7 +122,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
|
|
122
122
|
|
123
123
|
// Decode packet payload data for easy access
|
124
124
|
UponorSmatrixData data[data_len];
|
125
|
-
for (
|
125
|
+
for (size_t i = 0; i < data_len; i++) {
|
126
126
|
data[i].id = packet[(i * 3) + 4];
|
127
127
|
data[i].value = encode_uint16(packet[(i * 3) + 5], packet[(i * 3) + 6]);
|
128
128
|
}
|
@@ -135,7 +135,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
|
|
135
135
|
// thermostat sending both room temperature and time information.
|
136
136
|
bool found_temperature = false;
|
137
137
|
bool found_time = false;
|
138
|
-
for (
|
138
|
+
for (size_t i = 0; i < data_len; i++) {
|
139
139
|
if (data[i].id == UPONOR_ID_ROOM_TEMP)
|
140
140
|
found_temperature = true;
|
141
141
|
if (data[i].id == UPONOR_ID_DATETIME1)
|
@@ -181,7 +181,7 @@ bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixDa
|
|
181
181
|
packet.push_back(device_address >> 8);
|
182
182
|
packet.push_back(device_address >> 0);
|
183
183
|
|
184
|
-
for (
|
184
|
+
for (size_t i = 0; i < data_len; i++) {
|
185
185
|
packet.push_back(data[i].id);
|
186
186
|
packet.push_back(data[i].value >> 8);
|
187
187
|
packet.push_back(data[i].value >> 0);
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components.esp32 import (
|
3
|
+
VARIANT_ESP32P4,
|
3
4
|
VARIANT_ESP32S2,
|
4
5
|
VARIANT_ESP32S3,
|
5
6
|
add_idf_sdkconfig_option,
|
@@ -47,7 +48,7 @@ CONFIG_SCHEMA = cv.All(
|
|
47
48
|
}
|
48
49
|
),
|
49
50
|
cv.only_with_esp_idf,
|
50
|
-
only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3]),
|
51
|
+
only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3, VARIANT_ESP32P4]),
|
51
52
|
)
|
52
53
|
|
53
54
|
|
@@ -1,18 +1,45 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
3
|
// Should not be needed, but it's required to pass CI clang-tidy checks
|
4
|
-
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
4
|
+
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
5
5
|
#include "esphome/core/component.h"
|
6
6
|
#include <vector>
|
7
7
|
#include "usb/usb_host.h"
|
8
|
-
|
9
|
-
#include <
|
8
|
+
#include <freertos/FreeRTOS.h>
|
9
|
+
#include <freertos/task.h>
|
10
|
+
#include "esphome/core/lock_free_queue.h"
|
11
|
+
#include "esphome/core/event_pool.h"
|
12
|
+
#include <atomic>
|
10
13
|
|
11
14
|
namespace esphome {
|
12
15
|
namespace usb_host {
|
13
16
|
|
17
|
+
// THREADING MODEL:
|
18
|
+
// This component uses a dedicated USB task for event processing to prevent data loss.
|
19
|
+
// - USB Task (high priority): Handles USB events, executes transfer callbacks
|
20
|
+
// - Main Loop Task: Initiates transfers, processes completion events
|
21
|
+
//
|
22
|
+
// Thread-safe communication:
|
23
|
+
// - Lock-free queues for USB task -> main loop events (SPSC pattern)
|
24
|
+
// - Lock-free TransferRequest pool using atomic bitmask (MCSP pattern)
|
25
|
+
//
|
26
|
+
// TransferRequest pool access pattern:
|
27
|
+
// - get_trq_() [allocate]: Called from BOTH USB task and main loop threads
|
28
|
+
// * USB task: via USB UART input callbacks that restart transfers immediately
|
29
|
+
// * Main loop: for output transfers and flow-controlled input restarts
|
30
|
+
// - release_trq() [deallocate]: Called from main loop thread only
|
31
|
+
//
|
32
|
+
// The multi-threaded allocation is intentional for performance:
|
33
|
+
// - USB task can immediately restart input transfers without context switching
|
34
|
+
// - Main loop controls backpressure by deciding when to restart after consuming data
|
35
|
+
// The atomic bitmask ensures thread-safe allocation without mutex blocking.
|
36
|
+
|
14
37
|
static const char *const TAG = "usb_host";
|
15
38
|
|
39
|
+
// Forward declarations
|
40
|
+
struct TransferRequest;
|
41
|
+
class USBClient;
|
42
|
+
|
16
43
|
// constants for setup packet type
|
17
44
|
static const uint8_t USB_RECIP_DEVICE = 0;
|
18
45
|
static const uint8_t USB_RECIP_INTERFACE = 1;
|
@@ -26,6 +53,10 @@ static const uint8_t USB_DIR_OUT = 0;
|
|
26
53
|
static const size_t SETUP_PACKET_SIZE = 8;
|
27
54
|
|
28
55
|
static const size_t MAX_REQUESTS = 16; // maximum number of outstanding requests possible.
|
56
|
+
static_assert(MAX_REQUESTS <= 16, "MAX_REQUESTS must be <= 16 to fit in uint16_t bitmask");
|
57
|
+
static constexpr size_t USB_EVENT_QUEUE_SIZE = 32; // Size of event queue between USB task and main loop
|
58
|
+
static constexpr size_t USB_TASK_STACK_SIZE = 4096; // Stack size for USB task (same as ESP-IDF USB examples)
|
59
|
+
static constexpr UBaseType_t USB_TASK_PRIORITY = 5; // Higher priority than main loop (tskIDLE_PRIORITY + 5)
|
29
60
|
|
30
61
|
// used to report a transfer status
|
31
62
|
struct TransferStatus {
|
@@ -49,6 +80,31 @@ struct TransferRequest {
|
|
49
80
|
USBClient *client;
|
50
81
|
};
|
51
82
|
|
83
|
+
enum EventType : uint8_t {
|
84
|
+
EVENT_DEVICE_NEW,
|
85
|
+
EVENT_DEVICE_GONE,
|
86
|
+
EVENT_TRANSFER_COMPLETE,
|
87
|
+
EVENT_CONTROL_COMPLETE,
|
88
|
+
};
|
89
|
+
|
90
|
+
struct UsbEvent {
|
91
|
+
EventType type;
|
92
|
+
union {
|
93
|
+
struct {
|
94
|
+
uint8_t address;
|
95
|
+
} device_new;
|
96
|
+
struct {
|
97
|
+
usb_device_handle_t handle;
|
98
|
+
} device_gone;
|
99
|
+
struct {
|
100
|
+
TransferRequest *trq;
|
101
|
+
} transfer;
|
102
|
+
} data;
|
103
|
+
|
104
|
+
// Required for EventPool - no cleanup needed for POD types
|
105
|
+
void release() {}
|
106
|
+
};
|
107
|
+
|
52
108
|
// callback function type.
|
53
109
|
|
54
110
|
enum ClientState {
|
@@ -63,13 +119,7 @@ class USBClient : public Component {
|
|
63
119
|
friend class USBHost;
|
64
120
|
|
65
121
|
public:
|
66
|
-
USBClient(uint16_t vid, uint16_t pid) : vid_(vid), pid_(pid)
|
67
|
-
|
68
|
-
void init_pool() {
|
69
|
-
this->trq_pool_.clear();
|
70
|
-
for (size_t i = 0; i != MAX_REQUESTS; i++)
|
71
|
-
this->trq_pool_.push_back(&this->requests_[i]);
|
72
|
-
}
|
122
|
+
USBClient(uint16_t vid, uint16_t pid) : vid_(vid), pid_(pid), trq_in_use_(0) {}
|
73
123
|
void setup() override;
|
74
124
|
void loop() override;
|
75
125
|
// setup must happen after the host bus has been setup
|
@@ -84,12 +134,26 @@ class USBClient : public Component {
|
|
84
134
|
bool control_transfer(uint8_t type, uint8_t request, uint16_t value, uint16_t index, const transfer_cb_t &callback,
|
85
135
|
const std::vector<uint8_t> &data = {});
|
86
136
|
|
137
|
+
// Lock-free event queue and pool for USB task to main loop communication
|
138
|
+
// Must be public for access from static callbacks
|
139
|
+
LockFreeQueue<UsbEvent, USB_EVENT_QUEUE_SIZE> event_queue;
|
140
|
+
EventPool<UsbEvent, USB_EVENT_QUEUE_SIZE> event_pool;
|
141
|
+
|
87
142
|
protected:
|
88
143
|
bool register_();
|
89
|
-
TransferRequest *get_trq_();
|
144
|
+
TransferRequest *get_trq_(); // Lock-free allocation using atomic bitmask (multi-consumer safe)
|
90
145
|
virtual void disconnect();
|
91
146
|
virtual void on_connected() {}
|
92
|
-
virtual void on_disconnected() {
|
147
|
+
virtual void on_disconnected() {
|
148
|
+
// Reset all requests to available (all bits to 0)
|
149
|
+
this->trq_in_use_.store(0);
|
150
|
+
}
|
151
|
+
|
152
|
+
// USB task management
|
153
|
+
static void usb_task_fn(void *arg);
|
154
|
+
void usb_task_loop();
|
155
|
+
|
156
|
+
TaskHandle_t usb_task_handle_{nullptr};
|
93
157
|
|
94
158
|
usb_host_client_handle_t handle_{};
|
95
159
|
usb_device_handle_t device_handle_{};
|
@@ -97,7 +161,12 @@ class USBClient : public Component {
|
|
97
161
|
int state_{USB_CLIENT_INIT};
|
98
162
|
uint16_t vid_{};
|
99
163
|
uint16_t pid_{};
|
100
|
-
|
164
|
+
// Lock-free pool management using atomic bitmask (no dynamic allocation)
|
165
|
+
// Bit i = 1: requests_[i] is in use, Bit i = 0: requests_[i] is available
|
166
|
+
// Supports multiple concurrent consumers (both threads can allocate)
|
167
|
+
// Single producer for deallocation (main loop only)
|
168
|
+
// Limited to 16 slots by uint16_t size (enforced by static_assert)
|
169
|
+
std::atomic<uint16_t> trq_in_use_;
|
101
170
|
TransferRequest requests_[MAX_REQUESTS]{};
|
102
171
|
};
|
103
172
|
class USBHost : public Component {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// Should not be needed, but it's required to pass CI clang-tidy checks
|
2
|
-
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
2
|
+
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
3
3
|
#include "usb_host.h"
|
4
4
|
#include "esphome/core/log.h"
|
5
5
|
#include "esphome/core/hal.h"
|
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
#include <cinttypes>
|
9
9
|
#include <cstring>
|
10
|
+
#include <atomic>
|
10
11
|
namespace esphome {
|
11
12
|
namespace usb_host {
|
12
13
|
|
@@ -139,24 +140,40 @@ static std::string get_descriptor_string(const usb_str_desc_t *desc) {
|
|
139
140
|
return {buffer};
|
140
141
|
}
|
141
142
|
|
143
|
+
// CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
|
142
144
|
static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *ptr) {
|
143
145
|
auto *client = static_cast<USBClient *>(ptr);
|
146
|
+
|
147
|
+
// Allocate event from pool
|
148
|
+
UsbEvent *event = client->event_pool.allocate();
|
149
|
+
if (event == nullptr) {
|
150
|
+
// No events available - increment counter for periodic logging
|
151
|
+
client->event_queue.increment_dropped_count();
|
152
|
+
return;
|
153
|
+
}
|
154
|
+
|
155
|
+
// Queue events to be processed in main loop
|
144
156
|
switch (event_msg->event) {
|
145
157
|
case USB_HOST_CLIENT_EVENT_NEW_DEV: {
|
146
|
-
auto addr = event_msg->new_dev.address;
|
147
158
|
ESP_LOGD(TAG, "New device %d", event_msg->new_dev.address);
|
148
|
-
|
159
|
+
event->type = EVENT_DEVICE_NEW;
|
160
|
+
event->data.device_new.address = event_msg->new_dev.address;
|
149
161
|
break;
|
150
162
|
}
|
151
163
|
case USB_HOST_CLIENT_EVENT_DEV_GONE: {
|
152
|
-
|
153
|
-
|
164
|
+
ESP_LOGD(TAG, "Device gone");
|
165
|
+
event->type = EVENT_DEVICE_GONE;
|
166
|
+
event->data.device_gone.handle = event_msg->dev_gone.dev_hdl;
|
154
167
|
break;
|
155
168
|
}
|
156
169
|
default:
|
157
170
|
ESP_LOGD(TAG, "Unknown event %d", event_msg->event);
|
158
|
-
|
171
|
+
client->event_pool.release(event);
|
172
|
+
return;
|
159
173
|
}
|
174
|
+
|
175
|
+
// Push to lock-free queue (always succeeds since pool size == queue size)
|
176
|
+
client->event_queue.push(event);
|
160
177
|
}
|
161
178
|
void USBClient::setup() {
|
162
179
|
usb_host_client_config_t config{.is_synchronous = false,
|
@@ -169,13 +186,65 @@ void USBClient::setup() {
|
|
169
186
|
this->mark_failed();
|
170
187
|
return;
|
171
188
|
}
|
172
|
-
for
|
173
|
-
|
174
|
-
|
189
|
+
// Pre-allocate USB transfer buffers for all slots at startup
|
190
|
+
// This avoids any dynamic allocation during runtime
|
191
|
+
for (size_t i = 0; i < MAX_REQUESTS; i++) {
|
192
|
+
usb_host_transfer_alloc(64, 0, &this->requests_[i].transfer);
|
193
|
+
this->requests_[i].client = this; // Set once, never changes
|
194
|
+
}
|
195
|
+
|
196
|
+
// Create and start USB task
|
197
|
+
xTaskCreate(usb_task_fn, "usb_task",
|
198
|
+
USB_TASK_STACK_SIZE, // Stack size
|
199
|
+
this, // Task parameter
|
200
|
+
USB_TASK_PRIORITY, // Priority (higher than main loop)
|
201
|
+
&this->usb_task_handle_);
|
202
|
+
|
203
|
+
if (this->usb_task_handle_ == nullptr) {
|
204
|
+
ESP_LOGE(TAG, "Failed to create USB task");
|
205
|
+
this->mark_failed();
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
void USBClient::usb_task_fn(void *arg) {
|
210
|
+
auto *client = static_cast<USBClient *>(arg);
|
211
|
+
client->usb_task_loop();
|
212
|
+
}
|
213
|
+
|
214
|
+
void USBClient::usb_task_loop() {
|
215
|
+
while (true) {
|
216
|
+
usb_host_client_handle_events(this->handle_, portMAX_DELAY);
|
175
217
|
}
|
176
218
|
}
|
177
219
|
|
178
220
|
void USBClient::loop() {
|
221
|
+
// Process any events from the USB task
|
222
|
+
UsbEvent *event;
|
223
|
+
while ((event = this->event_queue.pop()) != nullptr) {
|
224
|
+
switch (event->type) {
|
225
|
+
case EVENT_DEVICE_NEW:
|
226
|
+
this->on_opened(event->data.device_new.address);
|
227
|
+
break;
|
228
|
+
case EVENT_DEVICE_GONE:
|
229
|
+
this->on_removed(event->data.device_gone.handle);
|
230
|
+
break;
|
231
|
+
case EVENT_TRANSFER_COMPLETE:
|
232
|
+
case EVENT_CONTROL_COMPLETE: {
|
233
|
+
auto *trq = event->data.transfer.trq;
|
234
|
+
this->release_trq(trq);
|
235
|
+
break;
|
236
|
+
}
|
237
|
+
}
|
238
|
+
// Return event to pool for reuse
|
239
|
+
this->event_pool.release(event);
|
240
|
+
}
|
241
|
+
|
242
|
+
// Log dropped events periodically
|
243
|
+
uint16_t dropped = this->event_queue.get_and_reset_dropped_count();
|
244
|
+
if (dropped > 0) {
|
245
|
+
ESP_LOGW(TAG, "Dropped %u USB events due to queue overflow", dropped);
|
246
|
+
}
|
247
|
+
|
179
248
|
switch (this->state_) {
|
180
249
|
case USB_CLIENT_OPEN: {
|
181
250
|
int err;
|
@@ -228,7 +297,6 @@ void USBClient::loop() {
|
|
228
297
|
}
|
229
298
|
|
230
299
|
default:
|
231
|
-
usb_host_client_handle_events(this->handle_, 0);
|
232
300
|
break;
|
233
301
|
}
|
234
302
|
}
|
@@ -245,6 +313,26 @@ void USBClient::on_removed(usb_device_handle_t handle) {
|
|
245
313
|
}
|
246
314
|
}
|
247
315
|
|
316
|
+
// Helper to queue transfer cleanup to main loop
|
317
|
+
static void queue_transfer_cleanup(TransferRequest *trq, EventType type) {
|
318
|
+
auto *client = trq->client;
|
319
|
+
|
320
|
+
// Allocate event from pool
|
321
|
+
UsbEvent *event = client->event_pool.allocate();
|
322
|
+
if (event == nullptr) {
|
323
|
+
// No events available - increment counter for periodic logging
|
324
|
+
client->event_queue.increment_dropped_count();
|
325
|
+
return;
|
326
|
+
}
|
327
|
+
|
328
|
+
event->type = type;
|
329
|
+
event->data.transfer.trq = trq;
|
330
|
+
|
331
|
+
// Push to lock-free queue (always succeeds since pool size == queue size)
|
332
|
+
client->event_queue.push(event);
|
333
|
+
}
|
334
|
+
|
335
|
+
// CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
|
248
336
|
static void control_callback(const usb_transfer_t *xfer) {
|
249
337
|
auto *trq = static_cast<TransferRequest *>(xfer->context);
|
250
338
|
trq->status.error_code = xfer->status;
|
@@ -252,22 +340,54 @@ static void control_callback(const usb_transfer_t *xfer) {
|
|
252
340
|
trq->status.endpoint = xfer->bEndpointAddress;
|
253
341
|
trq->status.data = xfer->data_buffer;
|
254
342
|
trq->status.data_len = xfer->actual_num_bytes;
|
255
|
-
|
343
|
+
|
344
|
+
// Execute callback in USB task context
|
345
|
+
if (trq->callback != nullptr) {
|
256
346
|
trq->callback(trq->status);
|
257
|
-
|
347
|
+
}
|
348
|
+
|
349
|
+
// Queue cleanup to main loop
|
350
|
+
queue_transfer_cleanup(trq, EVENT_CONTROL_COMPLETE);
|
258
351
|
}
|
259
352
|
|
353
|
+
// THREAD CONTEXT: Called from both USB task and main loop threads (multi-consumer)
|
354
|
+
// - USB task: USB UART input callbacks restart transfers for immediate data reception
|
355
|
+
// - Main loop: Output transfers and flow-controlled input restarts after consuming data
|
356
|
+
//
|
357
|
+
// THREAD SAFETY: Lock-free using atomic compare-and-swap on bitmask
|
358
|
+
// This multi-threaded access is intentional for performance - USB task can
|
359
|
+
// immediately restart transfers without waiting for main loop scheduling.
|
260
360
|
TransferRequest *USBClient::get_trq_() {
|
261
|
-
|
262
|
-
|
263
|
-
|
361
|
+
uint16_t mask = this->trq_in_use_.load(std::memory_order_relaxed);
|
362
|
+
|
363
|
+
// Find first available slot (bit = 0) and try to claim it atomically
|
364
|
+
// We use a while loop to allow retrying the same slot after CAS failure
|
365
|
+
size_t i = 0;
|
366
|
+
while (i != MAX_REQUESTS) {
|
367
|
+
if (mask & (1U << i)) {
|
368
|
+
// Slot is in use, move to next slot
|
369
|
+
i++;
|
370
|
+
continue;
|
371
|
+
}
|
372
|
+
|
373
|
+
// Slot i appears available, try to claim it atomically
|
374
|
+
uint16_t desired = mask | (1U << i); // Set bit i to mark as in-use
|
375
|
+
|
376
|
+
if (this->trq_in_use_.compare_exchange_weak(mask, desired, std::memory_order_acquire, std::memory_order_relaxed)) {
|
377
|
+
// Successfully claimed slot i - prepare the TransferRequest
|
378
|
+
auto *trq = &this->requests_[i];
|
379
|
+
trq->transfer->context = trq;
|
380
|
+
trq->transfer->device_handle = this->device_handle_;
|
381
|
+
return trq;
|
382
|
+
}
|
383
|
+
// CAS failed - another thread modified the bitmask
|
384
|
+
// mask was already updated by compare_exchange_weak with the current value
|
385
|
+
// No need to reload - the CAS already did that for us
|
386
|
+
i = 0;
|
264
387
|
}
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
trq->transfer->context = trq;
|
269
|
-
trq->transfer->device_handle = this->device_handle_;
|
270
|
-
return trq;
|
388
|
+
|
389
|
+
ESP_LOGE(TAG, "All %d transfer slots in use", MAX_REQUESTS);
|
390
|
+
return nullptr;
|
271
391
|
}
|
272
392
|
void USBClient::disconnect() {
|
273
393
|
this->on_disconnected();
|
@@ -280,6 +400,8 @@ void USBClient::disconnect() {
|
|
280
400
|
this->device_addr_ = -1;
|
281
401
|
}
|
282
402
|
|
403
|
+
// THREAD CONTEXT: Called from main loop thread only
|
404
|
+
// - Used for device configuration and control operations
|
283
405
|
bool USBClient::control_transfer(uint8_t type, uint8_t request, uint16_t value, uint16_t index,
|
284
406
|
const transfer_cb_t &callback, const std::vector<uint8_t> &data) {
|
285
407
|
auto *trq = this->get_trq_();
|
@@ -315,6 +437,7 @@ bool USBClient::control_transfer(uint8_t type, uint8_t request, uint16_t value,
|
|
315
437
|
return true;
|
316
438
|
}
|
317
439
|
|
440
|
+
// CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
|
318
441
|
static void transfer_callback(usb_transfer_t *xfer) {
|
319
442
|
auto *trq = static_cast<TransferRequest *>(xfer->context);
|
320
443
|
trq->status.error_code = xfer->status;
|
@@ -322,12 +445,21 @@ static void transfer_callback(usb_transfer_t *xfer) {
|
|
322
445
|
trq->status.endpoint = xfer->bEndpointAddress;
|
323
446
|
trq->status.data = xfer->data_buffer;
|
324
447
|
trq->status.data_len = xfer->actual_num_bytes;
|
325
|
-
|
448
|
+
|
449
|
+
// Always execute callback in USB task context
|
450
|
+
// Callbacks should be fast and non-blocking (e.g., copy data to queue)
|
451
|
+
if (trq->callback != nullptr) {
|
326
452
|
trq->callback(trq->status);
|
327
|
-
|
453
|
+
}
|
454
|
+
|
455
|
+
// Queue cleanup to main loop
|
456
|
+
queue_transfer_cleanup(trq, EVENT_TRANSFER_COMPLETE);
|
328
457
|
}
|
329
458
|
/**
|
330
459
|
* Performs a transfer input operation.
|
460
|
+
* THREAD CONTEXT: Called from both USB task and main loop threads!
|
461
|
+
* - USB task: USB UART input callbacks call start_input() which calls this
|
462
|
+
* - Main loop: Initial setup and other components
|
331
463
|
*
|
332
464
|
* @param ep_address The endpoint address.
|
333
465
|
* @param callback The callback function to be called when the transfer is complete.
|
@@ -354,6 +486,9 @@ void USBClient::transfer_in(uint8_t ep_address, const transfer_cb_t &callback, u
|
|
354
486
|
|
355
487
|
/**
|
356
488
|
* Performs an output transfer operation.
|
489
|
+
* THREAD CONTEXT: Called from main loop thread only
|
490
|
+
* - USB UART output uses defer() to ensure main loop context
|
491
|
+
* - Modbus and other components call from loop()
|
357
492
|
*
|
358
493
|
* @param ep_address The endpoint address.
|
359
494
|
* @param callback The callback function to be called when the transfer is complete.
|
@@ -386,7 +521,28 @@ void USBClient::dump_config() {
|
|
386
521
|
" Product id %04X",
|
387
522
|
this->vid_, this->pid_);
|
388
523
|
}
|
389
|
-
|
524
|
+
// THREAD CONTEXT: Only called from main loop thread (single producer for deallocation)
|
525
|
+
// - Via event processing when handling EVENT_TRANSFER_COMPLETE/EVENT_CONTROL_COMPLETE
|
526
|
+
// - Directly when transfer submission fails
|
527
|
+
//
|
528
|
+
// THREAD SAFETY: Lock-free using atomic AND to clear bit
|
529
|
+
// Single-producer pattern makes this simpler than allocation
|
530
|
+
void USBClient::release_trq(TransferRequest *trq) {
|
531
|
+
if (trq == nullptr)
|
532
|
+
return;
|
533
|
+
|
534
|
+
// Calculate index from pointer arithmetic
|
535
|
+
size_t index = trq - this->requests_;
|
536
|
+
if (index >= MAX_REQUESTS) {
|
537
|
+
ESP_LOGE(TAG, "Invalid TransferRequest pointer");
|
538
|
+
return;
|
539
|
+
}
|
540
|
+
|
541
|
+
// Atomically clear bit i to mark slot as available
|
542
|
+
// fetch_and with inverted bitmask clears the bit atomically
|
543
|
+
uint16_t bit = 1U << index;
|
544
|
+
this->trq_in_use_.fetch_and(static_cast<uint16_t>(~bit), std::memory_order_release);
|
545
|
+
}
|
390
546
|
|
391
547
|
} // namespace usb_host
|
392
548
|
} // namespace esphome
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// Should not be needed, but it's required to pass CI clang-tidy checks
|
2
|
-
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
2
|
+
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
3
3
|
#include "usb_host.h"
|
4
4
|
#include <cinttypes>
|
5
5
|
#include "esphome/core/log.h"
|
@@ -24,7 +24,6 @@ usb_uart_ns = cg.esphome_ns.namespace("usb_uart")
|
|
24
24
|
USBUartComponent = usb_uart_ns.class_("USBUartComponent", Component)
|
25
25
|
USBUartChannel = usb_uart_ns.class_("USBUartChannel", UARTComponent)
|
26
26
|
|
27
|
-
|
28
27
|
UARTParityOptions = usb_uart_ns.enum("UARTParityOptions")
|
29
28
|
UART_PARITY_OPTIONS = {
|
30
29
|
"NONE": UARTParityOptions.UART_CONFIG_PARITY_NONE,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
1
|
+
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
2
2
|
#include "usb_uart.h"
|
3
3
|
#include "usb/usb_host.h"
|
4
4
|
#include "esphome/core/log.h"
|
@@ -16,12 +16,12 @@ using namespace bytebuffer;
|
|
16
16
|
void USBUartTypeCH34X::enable_channels() {
|
17
17
|
// enable the channels
|
18
18
|
for (auto channel : this->channels_) {
|
19
|
-
if (!channel->initialised_)
|
19
|
+
if (!channel->initialised_.load())
|
20
20
|
continue;
|
21
21
|
usb_host::transfer_cb_t callback = [=](const usb_host::TransferStatus &status) {
|
22
22
|
if (!status.success) {
|
23
23
|
ESP_LOGE(TAG, "Control transfer failed, status=%s", esp_err_to_name(status.error_code));
|
24
|
-
channel->initialised_
|
24
|
+
channel->initialised_.store(false);
|
25
25
|
}
|
26
26
|
};
|
27
27
|
|
@@ -48,7 +48,7 @@ void USBUartTypeCH34X::enable_channels() {
|
|
48
48
|
auto factor = static_cast<uint8_t>(clk / baud_rate);
|
49
49
|
if (factor == 0 || factor == 0xFF) {
|
50
50
|
ESP_LOGE(TAG, "Invalid baud rate %" PRIu32, baud_rate);
|
51
|
-
channel->initialised_
|
51
|
+
channel->initialised_.store(false);
|
52
52
|
continue;
|
53
53
|
}
|
54
54
|
if ((clk / factor - baud_rate) > (baud_rate - clk / (factor + 1)))
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
1
|
+
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
2
2
|
#include "usb_uart.h"
|
3
3
|
#include "usb/usb_host.h"
|
4
4
|
#include "esphome/core/log.h"
|
@@ -100,12 +100,12 @@ std::vector<CdcEps> USBUartTypeCP210X::parse_descriptors(usb_device_handle_t dev
|
|
100
100
|
void USBUartTypeCP210X::enable_channels() {
|
101
101
|
// enable the channels
|
102
102
|
for (auto channel : this->channels_) {
|
103
|
-
if (!channel->initialised_)
|
103
|
+
if (!channel->initialised_.load())
|
104
104
|
continue;
|
105
105
|
usb_host::transfer_cb_t callback = [=](const usb_host::TransferStatus &status) {
|
106
106
|
if (!status.success) {
|
107
107
|
ESP_LOGE(TAG, "Control transfer failed, status=%s", esp_err_to_name(status.error_code));
|
108
|
-
channel->initialised_
|
108
|
+
channel->initialised_.store(false);
|
109
109
|
}
|
110
110
|
};
|
111
111
|
this->control_transfer(USB_VENDOR_IFC | usb_host::USB_DIR_OUT, IFC_ENABLE, 1, channel->index_, callback);
|