summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extmod/btstack/modbluetooth_btstack.c122
-rw-r--r--extmod/modbluetooth.c11
-rw-r--r--extmod/modbluetooth.h21
-rw-r--r--extmod/nimble/modbluetooth_nimble.c127
-rw-r--r--ports/unix/mpbtstackport_common.c3
5 files changed, 222 insertions, 62 deletions
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c
index 03ec12b73..b028a5d1a 100644
--- a/extmod/btstack/modbluetooth_btstack.c
+++ b/extmod/btstack/modbluetooth_btstack.c
@@ -271,6 +271,14 @@ STATIC void btstack_packet_handler_att_server(uint8_t packet_type, uint16_t chan
}
}
+#if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
+// During startup, the controller (e.g. Zephyr) might give us a static address that we can use.
+STATIC uint8_t controller_static_addr[6] = {0};
+STATIC bool controller_static_addr_available = false;
+
+STATIC const uint8_t read_static_address_command_complete_prefix[] = { 0x0e, 0x1b, 0x01, 0x09, 0xfc };
+#endif
+
STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t irq) {
DEBUG_printf("btstack_packet_handler(packet_type=%u, packet=%p)\n", packet_type, packet);
if (packet_type != HCI_EVENT_PACKET) {
@@ -313,6 +321,13 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
DEBUG_printf(" --> hci transport packet sent\n");
} else if (event_type == HCI_EVENT_COMMAND_COMPLETE) {
DEBUG_printf(" --> hci command complete\n");
+ #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
+ if (memcmp(packet, read_static_address_command_complete_prefix, sizeof(read_static_address_command_complete_prefix)) == 0) {
+ DEBUG_printf(" --> static address available\n");
+ reverse_48(&packet[7], controller_static_addr);
+ controller_static_addr_available = true;
+ }
+ #endif // MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
} else if (event_type == HCI_EVENT_COMMAND_STATUS) {
DEBUG_printf(" --> hci command status\n");
} else if (event_type == HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS) {
@@ -493,6 +508,60 @@ STATIC void btstack_init_deinit_timeout_handler(btstack_timer_source_t *ds) {
mp_bluetooth_btstack_state = MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT;
}
+STATIC void btstack_static_address_ready(void *arg) {
+ DEBUG_printf("btstack_static_address_ready.\n");
+ *(volatile bool *)arg = true;
+}
+
+STATIC bool set_public_address(void) {
+ bd_addr_t local_addr;
+ gap_local_bd_addr(local_addr);
+ bd_addr_t null_addr = {0};
+ if (memcmp(local_addr, null_addr, 6) == 0) {
+ DEBUG_printf("set_public_address: No public address available.\n");
+ return false;
+ }
+ DEBUG_printf("set_public_address: Using controller's public address.\n");
+ gap_random_address_set_mode(GAP_RANDOM_ADDRESS_TYPE_OFF);
+ return true;
+}
+
+STATIC void set_random_address(void) {
+ #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
+ if (controller_static_addr_available) {
+ DEBUG_printf("set_random_address: Using static address supplied by controller.\n");
+ gap_random_address_set(controller_static_addr);
+ } else
+ #endif // MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
+ {
+ DEBUG_printf("set_random_address: Generating random static address.\n");
+ btstack_crypto_random_t sm_crypto_random_request;
+ bd_addr_t static_addr;
+ volatile bool ready = false;
+ btstack_crypto_random_generate(&sm_crypto_random_request, static_addr, 6, &btstack_static_address_ready, (void *)&ready);
+ while (!ready) {
+ MICROPY_EVENT_POLL_HOOK
+ }
+ DEBUG_printf("set_random_address: Address generated.\n");
+ gap_random_address_set(static_addr);
+ }
+
+ // Wait for the controller to accept this address.
+ while (true) {
+ uint8_t addr_type;
+ bd_addr_t addr;
+ gap_le_get_own_address(&addr_type, addr);
+
+ bd_addr_t null_addr = {0};
+ if (memcmp(addr, null_addr, 6) != 0) {
+ break;
+ }
+
+ MICROPY_EVENT_POLL_HOOK
+ }
+ DEBUG_printf("set_random_address: Address loaded by controller\n");
+}
+
int mp_bluetooth_init(void) {
DEBUG_printf("mp_bluetooth_init\n");
@@ -505,6 +574,10 @@ int mp_bluetooth_init(void) {
btstack_memory_init();
+ #if MICROPY_BLUETOOTH_BTSTACK_ZEPHYR_STATIC_ADDRESS
+ controller_static_addr_available = false;
+ #endif
+
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);
@@ -563,9 +636,23 @@ int mp_bluetooth_init(void) {
// Clean up.
MP_STATE_PORT(bluetooth_btstack_root_pointers) = NULL;
+
return MP_ETIMEDOUT;
}
+ DEBUG_printf("mp_bluetooth_init: stack startup complete\n");
+
+ // At this point if the controller has its own public address, btstack will know this.
+ // However, if this is not available, then attempt to get a static address:
+ // - For a Zephyr controller on nRF, a static address will be available during startup.
+ // - Otherwise we ask the controller to generate a static address for us.
+ // In either case, calling gap_random_address_set will set the mode to STATIC, and then
+ // immediately set the address on the controller. We then wait until this address becomes available.
+
+ if (!set_public_address()) {
+ set_random_address();
+ }
+
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
// Enable GATT_EVENT_NOTIFICATION/GATT_EVENT_INDICATION for all connections and handles.
gatt_client_listen_for_characteristic_value_updates(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->notification, &btstack_packet_handler_generic, GATT_CLIENT_ANY_CONNECTION, NULL);
@@ -612,8 +699,39 @@ bool mp_bluetooth_is_active(void) {
return mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE;
}
-void mp_bluetooth_get_device_addr(uint8_t *addr) {
- mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr);
+void mp_bluetooth_get_current_address(uint8_t *addr_type, uint8_t *addr) {
+ if (!mp_bluetooth_is_active()) {
+ mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
+ }
+
+ DEBUG_printf("mp_bluetooth_get_current_address\n");
+ gap_le_get_own_address(addr_type, addr);
+}
+
+void mp_bluetooth_set_address_mode(uint8_t addr_mode) {
+ if (!mp_bluetooth_is_active()) {
+ mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
+ }
+
+ switch (addr_mode) {
+ case MP_BLUETOOTH_ADDRESS_MODE_PUBLIC: {
+ DEBUG_printf("mp_bluetooth_set_address_mode: public\n");
+ if (!set_public_address()) {
+ // No public address available.
+ mp_raise_OSError(MP_EINVAL);
+ }
+ break;
+ }
+ case MP_BLUETOOTH_ADDRESS_MODE_RANDOM: {
+ DEBUG_printf("mp_bluetooth_set_address_mode: random\n");
+ set_random_address();
+ break;
+ }
+ case MP_BLUETOOTH_ADDRESS_MODE_RPA:
+ case MP_BLUETOOTH_ADDRESS_MODE_NRPA:
+ // Not yet supported.
+ mp_raise_OSError(MP_EINVAL);
+ }
}
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index 82efe4938..a8a762ce3 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -308,9 +308,11 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
return mp_obj_new_bytes(buf, len);
}
case MP_QSTR_mac: {
+ uint8_t addr_type;
uint8_t addr[6];
- mp_bluetooth_get_device_addr(addr);
- return mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr));
+ mp_bluetooth_get_current_address(&addr_type, addr);
+ mp_obj_t items[] = { MP_OBJ_NEW_SMALL_INT(addr_type), mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)) };
+ return mp_obj_new_tuple(2, items);
}
case MP_QSTR_rxbuf:
return mp_obj_new_int(self->ringbuf.size);
@@ -366,6 +368,11 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
m_del(uint8_t, old_irq_data_buf, old_irq_data_alloc);
break;
}
+ case MP_QSTR_addr_mode: {
+ mp_int_t addr_mode = mp_obj_get_int(e->value);
+ mp_bluetooth_set_address_mode(addr_mode);
+ break;
+ }
default:
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
}
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index 2c0768312..23ff97bc6 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -79,15 +79,6 @@
#define MP_BLUETOOTH_UUID_TYPE_32 (4)
#define MP_BLUETOOTH_UUID_TYPE_128 (16)
-// Address types (for the addr_type params).
-// Ports will need to map these to their own values.
-#define MP_BLUETOOTH_ADDR_PUBLIC (0x00) // Public (identity) address. (Same as NimBLE and NRF SD)
-#define MP_BLUETOOTH_ADDR_RANDOM_STATIC (0x01) // Random static (identity) address. (Same as NimBLE and NRF SD)
-#define MP_BLUETOOTH_ADDR_PUBLIC_ID (0x02) // (Same as NimBLE)
-#define MP_BLUETOOTH_ADDR_RANDOM_ID (0x03) // (Same as NimBLE)
-#define MP_BLUETOOTH_ADDR_RANDOM_PRIVATE_RESOLVABLE (0x12) // Random private resolvable address. (NRF SD 0x02)
-#define MP_BLUETOOTH_ADDR_RANDOM_PRIVATE_NON_RESOLVABLE (0x13) // Random private non-resolvable address. (NRF SD 0x03)
-
// Event codes for the IRQ handler.
#define MP_BLUETOOTH_IRQ_CENTRAL_CONNECT (1)
#define MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT (2)
@@ -110,6 +101,11 @@
#define MP_BLUETOOTH_IRQ_GATTC_INDICATE (19)
#define MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE (20)
+#define MP_BLUETOOTH_ADDRESS_MODE_PUBLIC (0)
+#define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1)
+#define MP_BLUETOOTH_ADDRESS_MODE_RPA (2)
+#define MP_BLUETOOTH_ADDRESS_MODE_NRPA (3)
+
/*
These aren't included in the module for space reasons, but can be used
in your Python code if necessary.
@@ -173,8 +169,11 @@ void mp_bluetooth_deinit(void);
// Returns true when the Bluetooth stack is active.
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);
+// Gets the current address of this device in big-endian format.
+void mp_bluetooth_get_current_address(uint8_t *addr_type, uint8_t *addr);
+
+// Sets the addressing mode to use.
+void mp_bluetooth_set_address_mode(uint8_t addr_mode);
// 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);
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index 61ba3a3ab..1c782943a 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -50,6 +50,8 @@
#define ERRNO_BLUETOOTH_NOT_ACTIVE MP_ENODEV
+STATIC uint8_t nimble_address_mode = BLE_OWN_ADDR_RANDOM;
+
// Any BLE_HS_xxx code not in this table will default to MP_EIO.
STATIC int8_t ble_hs_err_to_errno_table[] = {
[BLE_HS_EAGAIN] = MP_EAGAIN,
@@ -148,9 +150,26 @@ STATIC void reset_cb(int reason) {
(void)reason;
}
-STATIC void sync_cb(void) {
+STATIC bool has_public_address(void) {
+ return ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, NULL, NULL) == 0;
+}
+
+STATIC void set_random_address(bool nrpa) {
int rc;
+ (void)rc;
+ DEBUG_printf("sync_cb: Generating random static address\n");
ble_addr_t addr;
+ rc = ble_hs_id_gen_rnd(nrpa ? 1 : 0, &addr);
+ assert(rc == 0);
+ rc = ble_hs_id_set_rnd(addr.val);
+ assert(rc == 0);
+ rc = ble_hs_util_ensure_addr(1);
+ assert(rc == 0);
+}
+
+STATIC void sync_cb(void) {
+ int rc;
+ (void)rc;
DEBUG_printf("sync_cb: state=%d\n", mp_bluetooth_nimble_ble_state);
@@ -158,25 +177,11 @@ STATIC void sync_cb(void) {
return;
}
- rc = ble_hs_util_ensure_addr(0); // prefer public address
- if (rc != 0) {
- // https://mynewt.apache.org/latest/tutorials/ble/eddystone.html#configure-the-nimble-stack-with-an-address
- #if MICROPY_PY_BLUETOOTH_RANDOM_ADDR
- rc = ble_hs_id_gen_rnd(1, &addr);
- assert(rc == 0);
- rc = ble_hs_id_set_rnd(addr.val);
- assert(rc == 0);
- #else
- uint8_t addr_be[6];
- mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr_be);
- reverse_addr_byte_order(addr.val, addr_be);
- // ble_hs_id_set_pub(addr.val);
- rc = ble_hs_id_set_rnd(addr.val);
- assert(rc == 0);
- #endif
-
- rc = ble_hs_util_ensure_addr(0); // prefer public address
- assert(rc == 0);
+ if (has_public_address()) {
+ nimble_address_mode = BLE_OWN_ADDR_PUBLIC;
+ } else {
+ nimble_address_mode = BLE_OWN_ADDR_RANDOM;
+ set_random_address(false);
}
if (MP_BLUETOOTH_DEFAULT_ATTR_LEN > 20) {
@@ -412,19 +417,65 @@ bool mp_bluetooth_is_active(void) {
return mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE;
}
-void mp_bluetooth_get_device_addr(uint8_t *addr) {
- #if MICROPY_PY_BLUETOOTH_RANDOM_ADDR
+void mp_bluetooth_get_current_address(uint8_t *addr_type, uint8_t *addr) {
+ if (!mp_bluetooth_is_active()) {
+ mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
+ }
+
uint8_t addr_le[6];
- int rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr_le, NULL);
+
+ switch (nimble_address_mode) {
+ case BLE_OWN_ADDR_PUBLIC:
+ *addr_type = BLE_ADDR_PUBLIC;
+ break;
+ case BLE_OWN_ADDR_RANDOM:
+ *addr_type = BLE_ADDR_RANDOM;
+ break;
+ case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
+ case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
+ default:
+ // TODO: If RPA/NRPA in use, get the current value.
+ // Is this even possible in NimBLE?
+ mp_raise_OSError(MP_EINVAL);
+ }
+
+ int rc = ble_hs_id_copy_addr(*addr_type, addr_le, NULL);
if (rc != 0) {
- // Even with MICROPY_PY_BLUETOOTH_RANDOM_ADDR enabled the public address may
- // be used instead, in which case there is no random address.
- ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr_le, NULL);
+ mp_raise_OSError(MP_EINVAL);
}
reverse_addr_byte_order(addr, addr_le);
- #else
- mp_hal_get_mac(MP_HAL_MAC_BDADDR, addr);
- #endif
+}
+
+void mp_bluetooth_set_address_mode(uint8_t addr_mode) {
+ switch (addr_mode) {
+ case MP_BLUETOOTH_ADDRESS_MODE_PUBLIC:
+ if (!has_public_address()) {
+ // No public address available.
+ mp_raise_OSError(MP_EINVAL);
+ }
+ nimble_address_mode = BLE_OWN_ADDR_PUBLIC;
+ break;
+ case MP_BLUETOOTH_ADDRESS_MODE_RANDOM:
+ // Generate an static random address.
+ set_random_address(false);
+ nimble_address_mode = BLE_OWN_ADDR_RANDOM;
+ break;
+ case MP_BLUETOOTH_ADDRESS_MODE_RPA:
+ if (has_public_address()) {
+ nimble_address_mode = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT;
+ } else {
+ // Generate an static random address to use as the identity address.
+ set_random_address(false);
+ nimble_address_mode = BLE_OWN_ADDR_RPA_RANDOM_DEFAULT;
+ }
+ break;
+ case MP_BLUETOOTH_ADDRESS_MODE_NRPA:
+ // Generate an NRPA.
+ set_random_address(true);
+ // In NimBLE, NRPA is treated like a static random address that happens to be an NRPA.
+ nimble_address_mode = BLE_OWN_ADDR_RANDOM;
+ break;
+ }
}
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
@@ -473,19 +524,7 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons
.channel_map = 7, // all 3 channels.
};
- ret = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL);
- if (ret == 0) {
- return 0;
- }
- ret = ble_gap_adv_start(BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL);
- if (ret == 0) {
- return 0;
- }
- ret = ble_gap_adv_start(BLE_OWN_ADDR_RPA_RANDOM_DEFAULT, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL);
- if (ret == 0) {
- return 0;
- }
- ret = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL);
+ ret = ble_gap_adv_start(nimble_address_mode, NULL, BLE_HS_FOREVER, &adv_params, gap_event_cb, NULL);
if (ret == 0) {
return 0;
}
@@ -756,7 +795,7 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_
.passive = active_scan ? 0 : 1,
.filter_duplicates = 0,
};
- int err = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, duration_ms, &discover_params, gap_scan_cb, NULL);
+ int err = ble_gap_disc(nimble_address_mode, duration_ms, &discover_params, gap_scan_cb, NULL);
return ble_hs_err_to_errno(err);
}
@@ -847,7 +886,7 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
};
ble_addr_t addr_nimble = create_nimble_addr(addr_type, addr);
- int err = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &addr_nimble, duration_ms, &params, &peripheral_gap_event_cb, NULL);
+ int err = ble_gap_connect(nimble_address_mode, &addr_nimble, duration_ms, &params, &peripheral_gap_event_cb, NULL);
return ble_hs_err_to_errno(err);
}
diff --git a/ports/unix/mpbtstackport_common.c b/ports/unix/mpbtstackport_common.c
index eb1b1c9c8..621e661f9 100644
--- a/ports/unix/mpbtstackport_common.c
+++ b/ports/unix/mpbtstackport_common.c
@@ -93,7 +93,4 @@ void mp_bluetooth_btstack_port_init(void) {
#endif
}
-void mp_hal_get_mac(int idx, uint8_t buf[6]) {
-}
-
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK