Skip to content

stm32/wb55: Add usb/bluetooth transparent mode to stm32wb55 via native module. #9046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions docs/library/bluetooth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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("<H", resp_buf[1:3])[0]
lmp_version = resp_buf[3]
manufacturer = struct.unpack("<H", resp_buf[4:6])[0]
lmp_subversion = struct.unpack("<H", resp_buf[6:8])[0]

print(f"HCI Version: {hci_version}")
print(f"HCI Revision: {hci_revision}")
print(f"LMP Version: {lmp_version}")
print(f"Manufacturer: {manufacturer}")
print(f"LMP Subversion: {lmp_subversion}")
else:
print(f"HCI command failed with status: {status}")

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("<H", resp_buf[1:3])[0]
lmp_version = resp_buf[3]
manufacturer = struct.unpack("<H", resp_buf[4:6])[0]
lmp_subversion = struct.unpack("<H", resp_buf[6:8])[0]

print(f"HCI Version: {hci_version}")
print(f"HCI Revision: {hci_revision}")
print(f"LMP Version: {lmp_version}")
print(f"Manufacturer: {manufacturer}")
print(f"LMP Subversion: {lmp_subversion}")
else:
print(f"HCI command failed with status: {status}")
11 changes: 11 additions & 0 deletions docs/library/stm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ the second CPU, the RF core.

Returns a bytes object with the result of the SYS command.

.. function:: rfcore_ble_hci(command[, response_buf])

Execute a HCI command on the BLE channel. The execution is synchronous.

Takes a *command* byte/bytearray with pre-formatted HCI packet.

Optionally takes a pre-allocated bytearray buffer for the response packet.

Returns response length if *response_buf* is provided, else a bytes object with the
response HCI packet.

Functions specific to STM32WLxx MCUs
------------------------------------

Expand Down
7 changes: 7 additions & 0 deletions extmod/nimble/nimble.mk
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,14 @@ INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/include
INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/transport/uart/include
INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/porting/nimble/include

# Compiler-specific warning flags for NimBLE
ifeq ($(shell uname -s),Darwin)
# macOS uses clang which has different warning flags
$(BUILD)/$(NIMBLE_LIB_DIR)/%.o: CFLAGS += -Wno-uninitialized -Wno-pointer-arith -Wno-unused-but-set-variable -Wno-format -Wno-sign-compare -Wno-float-conversion
else
# GCC-specific flags
$(BUILD)/$(NIMBLE_LIB_DIR)/%.o: CFLAGS += -Wno-maybe-uninitialized -Wno-pointer-arith -Wno-unused-but-set-variable -Wno-format -Wno-sign-compare -Wno-old-style-declaration
endif

endif

Expand Down
3 changes: 3 additions & 0 deletions extmod/nimble/syscfg/syscfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ void *nimble_realloc(void *ptr, size_t size);
#define realloc(ptr, size) nimble_realloc(ptr, size)

int nimble_sprintf(char *str, const char *fmt, ...);
#ifndef __APPLE__
// Don't redefine sprintf on macOS as it conflicts with system headers
#define sprintf(str, fmt, ...) nimble_sprintf(str, fmt, __VA_ARGS__)
#endif

#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x

Expand Down
1 change: 1 addition & 0 deletions ports/stm32/modstm.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static const mp_rom_map_elem_t stm_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_rfcore_status), MP_ROM_PTR(&rfcore_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_rfcore_fw_version), MP_ROM_PTR(&rfcore_fw_version_obj) },
{ MP_ROM_QSTR(MP_QSTR_rfcore_sys_hci), MP_ROM_PTR(&rfcore_sys_hci_obj) },
{ MP_ROM_QSTR(MP_QSTR_rfcore_ble_hci), MP_ROM_PTR(&rfcore_ble_hci_obj) },
#endif

#if defined(STM32WL)
Expand Down
52 changes: 48 additions & 4 deletions ports/stm32/rfcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ static ssize_t tl_sys_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t l
return tl_sys_wait_ack(ipcc_membuf_sys_cmd_buf, timeout_ms);
}

static int tl_ble_wait_resp(void) {
static size_t tl_ble_wait_resp(parse_hci_info_t *parse) {
uint32_t t0 = mp_hal_ticks_ms();
while (!LL_C2_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_BLE)) {
if (mp_hal_ticks_ms() - t0 > BLE_ACK_TIMEOUT_MS) {
Expand All @@ -513,16 +513,15 @@ 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.
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);
}

/******************************************************************************/
Expand Down Expand Up @@ -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)
1 change: 1 addition & 0 deletions ports/stm32/rfcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions ports/unix/mpbthciport.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define DEBUG_printf(...) // printf(__VA_ARGS__)

Expand Down Expand Up @@ -147,7 +148,12 @@ static int configure_uart(void) {
toptions.c_cflag |= CRTSCTS;

// 1Mbit (TODO: make this configurable).
#ifdef B1000000
speed_t brate = B1000000;
#else
// macOS doesn't have B1000000, use B230400 as fallback
speed_t brate = B230400;
#endif
cfsetospeed(&toptions, brate);
cfsetispeed(&toptions, brate);

Expand Down
Loading
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