extmod/modbluetooth: Add support for changing the GAP device name.
This commit allows the user to set/get the GAP device name used by service 0x1800, characteristic 0x2a00. The usage is: BLE.config(gap_name="myname") print(BLE.config("gap_name")) As part of this change the compile-time setting MICROPY_PY_BLUETOOTH_DEFAULT_NAME is renamed to MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME to emphasise its link to GAP and this new "gap_name" config value. And the default value of this for the NimBLE bindings is changed from "PYBD" to "MPY NIMBLE" to be more generic.
This commit is contained in:
parent
f385b7bfa8
commit
3b6c9119eb
|
@ -51,6 +51,10 @@ Configuration
|
|||
Note: on some ports, accessing this value requires that the interface is
|
||||
active (so that the MAC address can be queried from the controller).
|
||||
|
||||
- ``'gap_name'``: Get/set the GAP device name used by service 0x1800,
|
||||
characteristic 0x2a00. This can be set at any time and changed multiple
|
||||
times.
|
||||
|
||||
- ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store
|
||||
incoming events. This buffer is global to the entire BLE driver and so
|
||||
handles incoming data for all events, including all characteristics.
|
||||
|
|
|
@ -37,10 +37,20 @@
|
|||
|
||||
#define DEBUG_EVENT_printf(...) //printf(__VA_ARGS__)
|
||||
|
||||
#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME
|
||||
#define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME "MPY BTSTACK"
|
||||
#endif
|
||||
|
||||
// How long to wait for a controller to init/deinit.
|
||||
// Some controllers can take up to 5-6 seconds in normal operation.
|
||||
STATIC const uint32_t BTSTACK_INIT_DEINIT_TIMEOUT_MS = 15000;
|
||||
|
||||
// We need to know the attribute handle for the GAP device name (see GAP_DEVICE_NAME_UUID)
|
||||
// so it can be put into the gatts_db before registering the services, and accessed
|
||||
// efficiently when requesting an attribute in att_read_callback. Because this is the
|
||||
// first characteristic of the first service, it always has a handle value of 3.
|
||||
STATIC const uint16_t BTSTACK_GAP_DEVICE_NAME_HANDLE = 3;
|
||||
|
||||
volatile int mp_bluetooth_btstack_state = MP_BLUETOOTH_BTSTACK_STATE_OFF;
|
||||
|
||||
STATIC btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
@ -250,6 +260,12 @@ int mp_bluetooth_init(void) {
|
|||
MP_STATE_PORT(bluetooth_btstack_root_pointers) = m_new0(mp_bluetooth_btstack_root_pointers_t, 1);
|
||||
mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db);
|
||||
|
||||
// Set the default GAP device name.
|
||||
const char *gap_name = MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME;
|
||||
size_t gap_len = strlen(gap_name);
|
||||
mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, BTSTACK_GAP_DEVICE_NAME_HANDLE, gap_len);
|
||||
mp_bluetooth_gap_set_device_name((const uint8_t *)gap_name, gap_len);
|
||||
|
||||
mp_bluetooth_btstack_port_init();
|
||||
mp_bluetooth_btstack_state = MP_BLUETOOTH_BTSTACK_STATE_STARTING;
|
||||
|
||||
|
@ -344,6 +360,19 @@ void mp_bluetooth_get_device_addr(uint8_t *addr) {
|
|||
mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr);
|
||||
}
|
||||
|
||||
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
|
||||
uint8_t *value = NULL;
|
||||
size_t value_len = 0;
|
||||
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, BTSTACK_GAP_DEVICE_NAME_HANDLE, &value, &value_len);
|
||||
*buf = value;
|
||||
return value_len;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len) {
|
||||
mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, BTSTACK_GAP_DEVICE_NAME_HANDLE, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) {
|
||||
DEBUG_EVENT_printf("mp_bluetooth_gap_advertise_start\n");
|
||||
uint16_t adv_int_min = interval_us / 625;
|
||||
|
@ -396,7 +425,9 @@ int mp_bluetooth_gatts_register_service_begin(bool append) {
|
|||
att_db_util_init();
|
||||
|
||||
att_db_util_add_service_uuid16(GAP_SERVICE_UUID);
|
||||
att_db_util_add_characteristic_uuid16(GAP_DEVICE_NAME_UUID, ATT_PROPERTY_READ, ATT_SECURITY_NONE, ATT_SECURITY_NONE, (uint8_t *)"MPY BTSTACK", 11);
|
||||
uint16_t handle = att_db_util_add_characteristic_uuid16(GAP_DEVICE_NAME_UUID, ATT_PROPERTY_READ | ATT_PROPERTY_DYNAMIC, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0);
|
||||
assert(handle == BTSTACK_GAP_DEVICE_NAME_HANDLE);
|
||||
(void)handle;
|
||||
|
||||
att_db_util_add_service_uuid16(0x1801);
|
||||
att_db_util_add_characteristic_uuid16(0x2a05, ATT_PROPERTY_READ, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0);
|
||||
|
|
|
@ -295,6 +295,11 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|||
}
|
||||
|
||||
switch (mp_obj_str_get_qstr(args[1])) {
|
||||
case MP_QSTR_gap_name: {
|
||||
const uint8_t *buf;
|
||||
size_t len = mp_bluetooth_gap_get_device_name(&buf);
|
||||
return mp_obj_new_bytes(buf, len);
|
||||
}
|
||||
case MP_QSTR_mac: {
|
||||
uint8_t addr[6];
|
||||
mp_bluetooth_get_device_addr(addr);
|
||||
|
@ -315,6 +320,13 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|||
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
|
||||
mp_map_elem_t *e = &kwargs->table[i];
|
||||
switch (mp_obj_str_get_qstr(e->key)) {
|
||||
case MP_QSTR_gap_name: {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(e->value, &bufinfo, MP_BUFFER_READ);
|
||||
int ret = mp_bluetooth_gap_set_device_name(bufinfo.buf, bufinfo.len);
|
||||
bluetooth_handle_errno(ret);
|
||||
break;
|
||||
}
|
||||
case MP_QSTR_rxbuf: {
|
||||
// Determine new buffer sizes
|
||||
mp_int_t ringbuf_alloc = mp_obj_get_int(e->value);
|
||||
|
|
|
@ -171,6 +171,10 @@ bool mp_bluetooth_is_active(void);
|
|||
// Gets the MAC addr of this device in big-endian format.
|
||||
void mp_bluetooth_get_device_addr(uint8_t *addr);
|
||||
|
||||
// Get or set the GAP device name that will be used by service 0x1800, characteristic 0x2a00.
|
||||
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf);
|
||||
int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len);
|
||||
|
||||
// Start advertisement. Will re-start advertisement when already enabled.
|
||||
// Returns errno on failure.
|
||||
int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len);
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
#include "nimble/nimble_port.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_NAME
|
||||
#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME "PYBD"
|
||||
#ifndef MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME
|
||||
#define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME "MPY NIMBLE"
|
||||
#endif
|
||||
|
||||
#define DEBUG_EVENT_printf(...) //printf(__VA_ARGS__)
|
||||
|
@ -191,7 +191,7 @@ STATIC void sync_cb(void) {
|
|||
assert(rc == 0);
|
||||
}
|
||||
|
||||
ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_NAME);
|
||||
ble_svc_gap_device_name_set(MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME);
|
||||
|
||||
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE;
|
||||
}
|
||||
|
@ -352,6 +352,22 @@ void mp_bluetooth_get_device_addr(uint8_t *addr) {
|
|||
#endif
|
||||
}
|
||||
|
||||
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
|
||||
const char *name = ble_svc_gap_device_name();
|
||||
*buf = (const uint8_t *)name;
|
||||
return strlen(name);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len) {
|
||||
char tmp_buf[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH) + 1];
|
||||
if (len + 1 > sizeof(tmp_buf)) {
|
||||
return MP_EINVAL;
|
||||
}
|
||||
memcpy(tmp_buf, buf, len);
|
||||
tmp_buf[len] = '\0';
|
||||
return ble_hs_err_to_errno(ble_svc_gap_device_name_set(tmp_buf));
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL)
|
||||
#define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1)
|
||||
#define MICROPY_PY_BLUETOOTH_DEFAULT_NAME ("ESP32")
|
||||
#define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32")
|
||||
|
||||
// fatfs configuration
|
||||
#define MICROPY_FATFS_ENABLE_LFN (1)
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
# Test BLE GAP device name get/set
|
||||
|
||||
from micropython import const
|
||||
import time, machine, bluetooth
|
||||
|
||||
TIMEOUT_MS = 5000
|
||||
|
||||
_IRQ_CENTRAL_CONNECT = const(1 << 0)
|
||||
_IRQ_CENTRAL_DISCONNECT = const(1 << 1)
|
||||
_IRQ_PERIPHERAL_CONNECT = const(1 << 6)
|
||||
_IRQ_PERIPHERAL_DISCONNECT = const(1 << 7)
|
||||
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9)
|
||||
_IRQ_GATTC_READ_RESULT = const(1 << 11)
|
||||
|
||||
GAP_DEVICE_NAME_UUID = bluetooth.UUID(0x2A00)
|
||||
|
||||
last_event = None
|
||||
last_data = None
|
||||
value_handle = 0
|
||||
|
||||
|
||||
def irq(event, data):
|
||||
global last_event, last_data, value_handle
|
||||
last_event = event
|
||||
last_data = data
|
||||
if event == _IRQ_CENTRAL_CONNECT:
|
||||
print("_IRQ_CENTRAL_CONNECT")
|
||||
elif event == _IRQ_CENTRAL_DISCONNECT:
|
||||
print("_IRQ_CENTRAL_DISCONNECT")
|
||||
elif event == _IRQ_PERIPHERAL_CONNECT:
|
||||
print("_IRQ_PERIPHERAL_CONNECT")
|
||||
elif event == _IRQ_PERIPHERAL_DISCONNECT:
|
||||
print("_IRQ_PERIPHERAL_DISCONNECT")
|
||||
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
|
||||
if data[-1] == GAP_DEVICE_NAME_UUID:
|
||||
print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
|
||||
value_handle = data[2]
|
||||
elif event == _IRQ_GATTC_READ_RESULT:
|
||||
print("_IRQ_GATTC_READ_RESULT", data[-1])
|
||||
|
||||
|
||||
def wait_for_event(event, timeout_ms):
|
||||
t0 = time.ticks_ms()
|
||||
while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms:
|
||||
if isinstance(event, int):
|
||||
if last_event == event:
|
||||
break
|
||||
elif event():
|
||||
break
|
||||
machine.idle()
|
||||
|
||||
|
||||
# Acting in peripheral role.
|
||||
def instance0():
|
||||
multitest.globals(BDADDR=ble.config("mac"))
|
||||
|
||||
# Test setting and getting the GAP device name before registering services.
|
||||
ble.config(gap_name="GAP_NAME")
|
||||
print(ble.config("gap_name"))
|
||||
|
||||
# Create an empty service and start advertising.
|
||||
ble.gatts_register_services([])
|
||||
print("gap_advertise")
|
||||
multitest.next()
|
||||
|
||||
try:
|
||||
# Do multiple iterations to test changing the name.
|
||||
for iteration in range(2):
|
||||
# Set the GAP device name and start advertising.
|
||||
ble.config(gap_name="GAP_NAME{}".format(iteration))
|
||||
print(ble.config("gap_name"))
|
||||
ble.gap_advertise(20_000)
|
||||
|
||||
# Wait for central to connect, then wait for it to disconnect.
|
||||
wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS)
|
||||
wait_for_event(_IRQ_CENTRAL_DISCONNECT, 4 * TIMEOUT_MS)
|
||||
if last_event != _IRQ_CENTRAL_DISCONNECT:
|
||||
return
|
||||
finally:
|
||||
ble.active(0)
|
||||
|
||||
|
||||
# Acting in central role.
|
||||
def instance1():
|
||||
multitest.next()
|
||||
try:
|
||||
for iteration in range(2):
|
||||
# Wait for peripheral to start advertising.
|
||||
time.sleep_ms(500)
|
||||
|
||||
# Connect to peripheral.
|
||||
print("gap_connect")
|
||||
ble.gap_connect(0, BDADDR)
|
||||
wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS)
|
||||
if last_event != _IRQ_PERIPHERAL_CONNECT:
|
||||
return
|
||||
conn_handle, _, _ = last_data
|
||||
|
||||
if iteration == 0:
|
||||
print("gattc_discover_characteristics")
|
||||
ble.gattc_discover_characteristics(conn_handle, 1, 65535)
|
||||
wait_for_event(lambda: value_handle, TIMEOUT_MS)
|
||||
|
||||
# Wait for all characteristic results to come in (there should be an event for it).
|
||||
time.sleep_ms(500)
|
||||
|
||||
# Read the peripheral's GAP device name.
|
||||
print("gattc_read")
|
||||
ble.gattc_read(conn_handle, value_handle)
|
||||
wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS)
|
||||
|
||||
# Disconnect from peripheral.
|
||||
print("gap_disconnect:", ble.gap_disconnect(conn_handle))
|
||||
wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS)
|
||||
if last_event != _IRQ_PERIPHERAL_DISCONNECT:
|
||||
return
|
||||
finally:
|
||||
ble.active(0)
|
||||
|
||||
|
||||
ble = bluetooth.BLE()
|
||||
ble.active(1)
|
||||
ble.irq(irq)
|
|
@ -0,0 +1,24 @@
|
|||
--- instance0 ---
|
||||
b'GAP_NAME'
|
||||
gap_advertise
|
||||
b'GAP_NAME0'
|
||||
_IRQ_CENTRAL_CONNECT
|
||||
_IRQ_CENTRAL_DISCONNECT
|
||||
b'GAP_NAME1'
|
||||
_IRQ_CENTRAL_CONNECT
|
||||
_IRQ_CENTRAL_DISCONNECT
|
||||
--- instance1 ---
|
||||
gap_connect
|
||||
_IRQ_PERIPHERAL_CONNECT
|
||||
gattc_discover_characteristics
|
||||
_IRQ_GATTC_CHARACTERISTIC_RESULT UUID16(0x2a00)
|
||||
gattc_read
|
||||
_IRQ_GATTC_READ_RESULT b'GAP_NAME0'
|
||||
gap_disconnect: True
|
||||
_IRQ_PERIPHERAL_DISCONNECT
|
||||
gap_connect
|
||||
_IRQ_PERIPHERAL_CONNECT
|
||||
gattc_read
|
||||
_IRQ_GATTC_READ_RESULT b'GAP_NAME1'
|
||||
gap_disconnect: True
|
||||
_IRQ_PERIPHERAL_DISCONNECT
|
Loading…
Reference in New Issue