From b2dbd56db2a76efd326bbea2a5d65804488da7f3 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sun, 23 Aug 2026 09:17:44 -0700 Subject: [PATCH] zephyr-cp/_bleio: don't let an unsupported Tx power command block advertising common_hal_bleio_adapter_start_advertising() called set_tx_power() unconditionally before bt_le_adv_start(). That sends BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL (0xfc0e), a Zephyr vendor-specific command rather than a Bluetooth spec one. Controllers that do not implement Zephyr's VS extensions reject it, and the resulting error aborted start_advertising() before advertising was ever started, so those controllers could not advertise at all. On a SiWx917-DK2605A, which has its own vendor command at 0xfc06 for RF power: bt_hci_core: opcode 0xfc0e status 0x01 (Unknown HCI Command) OSError: [Errno 5] Input/output error Split the command into a non-raising _try_set_tx_power(). The public common_hal_bleio_adapter_set_tx_power() still raises, so an explicit adapter.tx_power assignment fails loudly, but start_advertising() treats it as best-effort and continues. --- ports/zephyr-cp/common-hal/_bleio/Adapter.c | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index ac2b1948eb7..cfa3c82dc96 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -328,13 +328,16 @@ mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { return power; } -void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { +// Returns a Zephyr error code rather than raising, so callers can treat setting +// Tx power as best-effort. BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL is a Zephyr +// vendor-specific command that not every controller implements. +static int _try_set_tx_power(mp_int_t tx_power) { struct bt_hci_cp_vs_write_tx_power_level *cp; struct net_buf *buf, *rsp = NULL; buf = bt_hci_cmd_alloc(K_MSEC(3000)); if (!buf) { - mp_raise_msg(&mp_type_MemoryError, NULL); + return -ENOMEM; } cp = net_buf_add(buf, sizeof(*cp)); cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; @@ -343,10 +346,19 @@ void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t t int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp); if (err) { - raise_zephyr_error(err); + return err; } net_buf_unref(rsp); + return 0; +} + +void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { + int err = _try_set_tx_power(tx_power); + if (err == -ENOMEM) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + raise_zephyr_error(err); } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { @@ -454,7 +466,10 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, NULL); } - common_hal_bleio_adapter_set_tx_power(self, tx_power); + // Best-effort: a controller that does not implement Zephyr's vendor-specific + // Tx power command must still be able to advertise. tx_power defaults to 0, + // so reporting the rejection here would print on every start_advertising(). + _try_set_tx_power(tx_power); raise_zephyr_error(bt_le_adv_start(&adv_params, adv_data,