diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index b09c370abd46d..92647c862d80b 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -765,3 +765,119 @@ Constructor - A 16-bit integer. e.g. ``0x2908``. - A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``. + + +HCI Commands +----------- + +Some ports optionally support direct access to the Bluetooth controller via Host Controller Interface (HCI) commands. +This is an advanced feature that allows for more direct manipulation of the Bluetooth stack. + +.. method:: BLE.hci_cmd(ogf, ocf, request_data, response_data, /) + + Send a raw HCI command to the Bluetooth controller and receive a response. + + This function is only available when the ``MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD`` + define is enabled during build. + + **Parameters:** + + - *ogf* (int): Opcode Group Field, indicating the command group. + - *ocf* (int): Opcode Command Field, indicating the specific command within the group. + - *request_data* (buffer): Data to send to the controller (must implement the buffer protocol). + - *response_data* (buffer): Buffer to receive the response into (must implement the buffer protocol). + + **Return Value:** + + Returns the HCI status code from the command (0 for success, or a specific error code). + + **Example:** + + .. code-block:: python + + import bluetooth + import struct + + # Initialize the BLE interface + ble = bluetooth.BLE() + ble.active(True) + + # Read Local Version Information + cmd_buf = bytearray(0) # Empty payload + resp_buf = bytearray(20) # Buffer for response + + # OGF=0x04 (Information Parameters) + # OCF=0x0001 (Read Local Version Information) + status = ble.hci_cmd(0x04, 0x0001, cmd_buf, resp_buf) + + if status == 0: + # Parse the response + hci_version = resp_buf[0] + hci_revision = struct.unpack(" BLE_ACK_TIMEOUT_MS) { @@ -513,8 +513,7 @@ static int tl_ble_wait_resp(void) { } // C2 set IPCC flag -- process the data, clear the flag, and re-enable IRQs. - tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, NULL); - return 0; + return tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, parse); } // Synchronously send a BLE command. @@ -522,7 +521,7 @@ static void tl_ble_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t len) // Poll for completion rather than wait for IRQ->scheduler. LL_C1_IPCC_DisableReceiveChannel(IPCC, IPCC_CH_BLE); tl_hci_cmd(ipcc_membuf_ble_cmd_buf, IPCC_CH_BLE, HCI_KIND_BT_CMD, opcode, buf, len); - tl_ble_wait_resp(); + tl_ble_wait_resp(NULL); } /******************************************************************************/ @@ -797,4 +796,49 @@ static mp_obj_t rfcore_sys_hci(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_sys_hci_obj, 3, 4, rfcore_sys_hci); +static void rfcore_ble_hci_response_to_buffer(void *env, const uint8_t *buf, size_t len) { + DEBUG_printf("rfcore_ble_hci_response_to_buffer len 0x%x\n", len); + mp_obj_t *rsp = (mp_obj_t *)env; + if (*rsp == mp_const_none) { + *rsp = mp_obj_new_bytes(buf, len); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(*rsp, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len < len) { + mp_raise_OSError(-len); + } + memcpy(bufinfo.buf, buf, len); + } +} + +static mp_obj_t rfcore_ble_hci(size_t n_args, const mp_obj_t *args) { + if (ipcc_mem_dev_info_tab.fus.table_state == MAGIC_IPCC_MEM_INCORRECT) { + mp_raise_OSError(MP_EINVAL); + } + mp_obj_t cmd = args[0]; + mp_obj_t rsp = mp_const_none; + bool return_len = false; + if (n_args == 2) { + rsp = args[1]; + // response buffer passed in, so return rsp length. + return_len = true; + } + + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(cmd, &bufinfo, MP_BUFFER_READ); + + // Poll for completion rather than wait for IRQ->scheduler. Is re-enabled in tl_check_msg. + LL_C1_IPCC_DisableReceiveChannel(IPCC, IPCC_CH_BLE); + + rfcore_ble_hci_cmd(bufinfo.len, bufinfo.buf); + + parse_hci_info_t parse = { rfcore_ble_hci_response_to_buffer, &rsp, false }; + size_t ret_len = tl_ble_wait_resp(&parse); + if (return_len) { + return MP_OBJ_NEW_SMALL_INT(ret_len); + } + return rsp; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_ble_hci_obj, 1, 2, rfcore_ble_hci); + #endif // defined(STM32WB) diff --git a/ports/stm32/rfcore.h b/ports/stm32/rfcore.h index 39267b325ec4d..bac14a843ffc4 100644 --- a/ports/stm32/rfcore.h +++ b/ports/stm32/rfcore.h @@ -44,5 +44,6 @@ void rfcore_end_flash_erase(void); MP_DECLARE_CONST_FUN_OBJ_0(rfcore_status_obj); MP_DECLARE_CONST_FUN_OBJ_1(rfcore_fw_version_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_sys_hci_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_ble_hci_obj); #endif // MICROPY_INCLUDED_STM32_RFCORE_H pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy