mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 18:18:43 +00:00
[usb_uart] Add claim_comm_interface option (#18969)
This commit is contained in:
@@ -44,6 +44,7 @@ UART_STOP_BITS_OPTIONS = {
|
||||
}
|
||||
|
||||
DEFAULT_BAUD_RATE = 9600
|
||||
CONF_CLAIM_COMM_INTERFACE = "claim_comm_interface"
|
||||
|
||||
|
||||
class Type:
|
||||
@@ -56,6 +57,7 @@ class Type:
|
||||
max_channels: int = 1,
|
||||
baud_rate_required: bool = True,
|
||||
max_baud: int = 1_000_000,
|
||||
has_comm_interface: bool = False,
|
||||
) -> None:
|
||||
self.name = name
|
||||
cls = cls or name
|
||||
@@ -65,6 +67,9 @@ class Type:
|
||||
self._max_channels = max_channels
|
||||
self.baud_rate_required = baud_rate_required
|
||||
self.max_baud = max_baud
|
||||
# True for types that claim the CDC comm (interrupt) interface; only these
|
||||
# accept the claim_comm_interface option.
|
||||
self.has_comm_interface = has_comm_interface
|
||||
|
||||
@property
|
||||
def max_channels(self) -> int:
|
||||
@@ -80,11 +85,21 @@ class Type:
|
||||
|
||||
|
||||
uart_types = (
|
||||
Type("CDC_ACM", 0, 0, "CdcAcm", 1, baud_rate_required=False),
|
||||
Type(
|
||||
"CDC_ACM", 0, 0, "CdcAcm", 1, baud_rate_required=False, has_comm_interface=True
|
||||
),
|
||||
Type("CH34X", 0x1A86, 0x55D5, "CH34X", 4, max_baud=2_000_000),
|
||||
Type("CH340", 0x1A86, 0x7523, "CH34X", 1, max_baud=2_000_000),
|
||||
Type("CP210X", 0x10C4, 0xEA60, "CP210X", 3, max_baud=2_000_000),
|
||||
Type("ESP_JTAG", 0x303A, 0x1001, "CdcAcm", 1, baud_rate_required=False),
|
||||
Type(
|
||||
"ESP_JTAG",
|
||||
0x303A,
|
||||
0x1001,
|
||||
"CdcAcm",
|
||||
1,
|
||||
baud_rate_required=False,
|
||||
has_comm_interface=True,
|
||||
),
|
||||
Type("FT232", 0x0403, 0x6001, "FT23XX", 1, max_baud=3_000_000),
|
||||
Type("FT2232", 0x0403, 0x6010, "FT23XX", 2, max_baud=12_000_000),
|
||||
Type("FT4232", 0x0403, 0x6011, "FT23XX", 4, max_baud=12_000_000),
|
||||
@@ -95,12 +110,20 @@ uart_types = (
|
||||
Type("PL2303GL", 0x067B, 0x23D3, "PL2303", 1, max_baud=6_000_000),
|
||||
Type("PL2303GS", 0x067B, 0x23F3, "PL2303", 1, max_baud=6_000_000),
|
||||
Type("PL2303GT", 0x067B, 0x23C3, "PL2303", 1, max_baud=6_000_000),
|
||||
Type("STM32_VCP", 0x0483, 0x5740, "CdcAcm", 1, baud_rate_required=False),
|
||||
Type(
|
||||
"STM32_VCP",
|
||||
0x0483,
|
||||
0x5740,
|
||||
"CdcAcm",
|
||||
1,
|
||||
baud_rate_required=False,
|
||||
has_comm_interface=True,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def channel_schema(type_: "Type") -> cv.Schema:
|
||||
return cv.Schema(
|
||||
schema = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_CHANNELS): cv.All(
|
||||
cv.ensure_list(
|
||||
@@ -139,9 +162,26 @@ def channel_schema(type_: "Type") -> cv.Schema:
|
||||
max=type_.max_channels,
|
||||
msg=f"Device type {type_.name} supports a maximum of {type_.max_channels} channels",
|
||||
),
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
if type_.has_comm_interface:
|
||||
# The comm (interrupt) interface pins a host hardware channel per device;
|
||||
# disable to save one on channel-poor hosts (some devices may need it
|
||||
# claimed before enabling data flow).
|
||||
schema = schema.extend(
|
||||
{cv.Optional(CONF_CLAIM_COMM_INTERFACE, default=True): cv.boolean}
|
||||
)
|
||||
else:
|
||||
schema = schema.extend(
|
||||
{
|
||||
cv.Optional(CONF_CLAIM_COMM_INTERFACE): cv.invalid(
|
||||
f"'{CONF_CLAIM_COMM_INTERFACE}' is only supported on device types "
|
||||
f"that claim the CDC comm interface; {type_.name} never claims it"
|
||||
)
|
||||
}
|
||||
)
|
||||
return schema
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.ensure_list(
|
||||
@@ -172,6 +212,9 @@ async def to_code(config: list[ConfigType]) -> None:
|
||||
|
||||
for device in config:
|
||||
var = await register_usb_client(device)
|
||||
# The C++ default is true; only emit the override
|
||||
if not device.get(CONF_CLAIM_COMM_INTERFACE, True):
|
||||
cg.add(var.set_claim_comm_interface(False))
|
||||
for index, channel in enumerate(device[CONF_CHANNELS]):
|
||||
chvar = cg.new_Pvariable(channel[CONF_ID], index, channel[CONF_BUFFER_SIZE])
|
||||
await cg.register_parented(chvar, var)
|
||||
|
||||
@@ -431,15 +431,20 @@ void USBUartTypeCdcAcm::on_connected() {
|
||||
// they enable data flow on the bulk endpoints.
|
||||
if (channel->cdc_dev_.interrupt_interface_number != 0xFF &&
|
||||
channel->cdc_dev_.interrupt_interface_number != channel->cdc_dev_.bulk_interface_number) {
|
||||
auto err_comm = usb_host_interface_claim(this->handle_, this->device_handle_,
|
||||
channel->cdc_dev_.interrupt_interface_number, 0);
|
||||
if (err_comm != ESP_OK) {
|
||||
// Continue anyway: the interface number stays valid for CDC request addressing
|
||||
ESP_LOGW(TAG, "Could not claim comm interface %d: %s", channel->cdc_dev_.interrupt_interface_number,
|
||||
esp_err_to_name(err_comm));
|
||||
if (!this->claim_comm_interface_) {
|
||||
ESP_LOGD(TAG, "Skipping comm interface %d (claim_comm_interface: false)",
|
||||
channel->cdc_dev_.interrupt_interface_number);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Claimed comm interface %d", channel->cdc_dev_.interrupt_interface_number);
|
||||
channel->cdc_dev_.interrupt_interface_claimed = true;
|
||||
auto err_comm = usb_host_interface_claim(this->handle_, this->device_handle_,
|
||||
channel->cdc_dev_.interrupt_interface_number, 0);
|
||||
if (err_comm != ESP_OK) {
|
||||
// Continue anyway: the interface number stays valid for CDC request addressing
|
||||
ESP_LOGW(TAG, "Could not claim comm interface %d: %s", channel->cdc_dev_.interrupt_interface_number,
|
||||
esp_err_to_name(err_comm));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Claimed comm interface %d", channel->cdc_dev_.interrupt_interface_number);
|
||||
channel->cdc_dev_.interrupt_interface_claimed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto err =
|
||||
|
||||
@@ -271,12 +271,16 @@ class USBUartComponent : public usb_host::USBClient {
|
||||
class USBUartTypeCdcAcm : public USBUartComponent {
|
||||
public:
|
||||
USBUartTypeCdcAcm(uint16_t vid, uint16_t pid) : USBUartComponent(vid, pid) {}
|
||||
void set_claim_comm_interface(bool claim) { this->claim_comm_interface_ = claim; }
|
||||
|
||||
protected:
|
||||
virtual std::vector<CdcEps> parse_descriptors(usb_device_handle_t dev_hdl);
|
||||
void on_connected() override;
|
||||
void on_disconnected() override;
|
||||
bool config_step(USBUartChannelBase *channel, uint8_t step, bool reload, bool ok, const uint8_t *response) override;
|
||||
// Each claimed interface pins one host hardware channel per endpoint; skipping
|
||||
// the comm (interrupt) interface frees one on channel-poor hosts (ESP32-S3: 8).
|
||||
bool claim_comm_interface_{true};
|
||||
};
|
||||
|
||||
class USBUartTypeCP210X : public USBUartTypeCdcAcm {
|
||||
|
||||
@@ -6,6 +6,7 @@ usb_uart:
|
||||
type: cdc_acm
|
||||
vid: 0x1234
|
||||
pid: 0x5678
|
||||
claim_comm_interface: false
|
||||
channels:
|
||||
- id: channel_0_1
|
||||
- id: uart_1
|
||||
|
||||
Reference in New Issue
Block a user