Merge pull request #8645 from dhalbert/esp32s3-ble-fixes

ESP32-S3 BLE fixes
This commit is contained in:
Dan Halbert 2023-11-21 22:48:08 -05:00 committed by GitHub
commit b2c32cf42f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 20 deletions

View File

@ -284,15 +284,21 @@ STATIC void _new_connection(uint16_t conn_handle) {
esp_ble_tx_power_set(conn_handle, ESP_PWR_LVL_N0); esp_ble_tx_power_set(conn_handle, ESP_PWR_LVL_N0);
// Find an empty connection. One must always be available because the SD has the same // Find an empty connection. One should always be available because the SD has the same
// total connection limit. // total connection limit.
bleio_connection_internal_t *connection; bleio_connection_internal_t *connection = NULL;
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
connection = &bleio_connections[i]; connection = &bleio_connections[i];
if (connection->conn_handle == BLEIO_HANDLE_INVALID) { if (connection->conn_handle == BLEIO_HANDLE_INVALID) {
break; break;
} }
} }
// Shouldn't happen, but just return if no connection available.
if (!connection) {
return;
}
connection->conn_handle = conn_handle; connection->conn_handle = conn_handle;
connection->connection_obj = mp_const_none; connection->connection_obj = mp_const_none;
connection->pair_status = PAIR_NOT_PAIRED; connection->pair_status = PAIR_NOT_PAIRED;

View File

@ -50,7 +50,25 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
self->props = props; self->props = props;
self->read_perm = read_perm; self->read_perm = read_perm;
self->write_perm = write_perm; self->write_perm = write_perm;
common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo);
if (initial_value_bufinfo != NULL) {
// Copy the initial value if it's on the heap. Otherwise it's internal and we may not be able
// to allocate.
self->current_value_len = initial_value_bufinfo->len;
if (gc_alloc_possible()) {
if (gc_nbytes(initial_value_bufinfo->buf) > 0) {
uint8_t *initial_value = m_malloc(self->current_value_len);
self->current_value_alloc = self->current_value_len;
memcpy(initial_value, initial_value_bufinfo->buf, self->current_value_len);
self->current_value = initial_value;
} else {
self->current_value_alloc = 0;
self->current_value = initial_value_bufinfo->buf;
}
} else {
self->current_value = initial_value_bufinfo->buf;
}
}
if (gc_alloc_possible()) { if (gc_alloc_possible()) {
self->descriptor_list = mp_obj_new_list(0, NULL); self->descriptor_list = mp_obj_new_list(0, NULL);

View File

@ -63,7 +63,7 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in)
connection->pair_status = PAIR_NOT_PAIRED; connection->pair_status = PAIR_NOT_PAIRED;
#if CIRCUITPY_VERBOSE_BLE #if CIRCUITPY_VERBOSE_BLE
mp_printf(&mp_plat_print, "disconnected %02x\n", event->disconnect.reason); mp_printf(&mp_plat_print, "event->disconnect.reason: 0x%x\n", event->disconnect.reason);
#endif #endif
if (connection->connection_obj != mp_const_none) { if (connection->connection_obj != mp_const_none) {
bleio_connection_obj_t *obj = connection->connection_obj; bleio_connection_obj_t *obj = connection->connection_obj;
@ -128,6 +128,7 @@ bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) {
} }
void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) {
// Second argument is an HCI reason, not an HS error code.
ble_gap_terminate(self->conn_handle, BLE_ERR_REM_USER_CONN_TERM); ble_gap_terminate(self->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
} }
@ -162,9 +163,9 @@ STATIC int _discovered_service_cb(uint16_t conn_handle,
void *arg) { void *arg) {
bleio_connection_internal_t *self = (bleio_connection_internal_t *)arg; bleio_connection_internal_t *self = (bleio_connection_internal_t *)arg;
if (error->status != BLE_ERR_SUCCESS) { if (error->status != 0) {
// Keep the first error in case it's due to memory. // Keep the first error in case it's due to memory.
if (_last_discovery_status == BLE_ERR_SUCCESS) { if (_last_discovery_status == 0) {
_last_discovery_status = error->status; _last_discovery_status = error->status;
xTaskNotifyGive(discovery_task); xTaskNotifyGive(discovery_task);
} }
@ -173,7 +174,7 @@ STATIC int _discovered_service_cb(uint16_t conn_handle,
// If any of these memory allocations fail, we set _last_discovery_status // If any of these memory allocations fail, we set _last_discovery_status
// and let the process continue. // and let the process continue.
if (_last_discovery_status != BLE_ERR_SUCCESS) { if (_last_discovery_status != 0) {
return 0; return 0;
} }
bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type); bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type);
@ -202,16 +203,17 @@ STATIC int _discovered_characteristic_cb(uint16_t conn_handle,
void *arg) { void *arg) {
bleio_service_obj_t *service = (bleio_service_obj_t *)arg; bleio_service_obj_t *service = (bleio_service_obj_t *)arg;
if (error->status != BLE_ERR_SUCCESS) { if (error->status != 0) {
// Keep the first error in case it's due to memory. // Keep the first error in case it's due to memory.
if (_last_discovery_status == BLE_ERR_SUCCESS) { if (_last_discovery_status == 0) {
_last_discovery_status = error->status; _last_discovery_status = error->status;
xTaskNotifyGive(discovery_task); xTaskNotifyGive(discovery_task);
} }
return 0;
} }
// If any of these memory allocations fail, we set _last_discovery_status // If any of these memory allocations fail, we set _last_discovery_status
// and let the process continue. // and let the process continue.
if (_last_discovery_status != BLE_ERR_SUCCESS) { if (_last_discovery_status != 0) {
return 0; return 0;
} }
@ -232,11 +234,14 @@ STATIC int _discovered_characteristic_cb(uint16_t conn_handle,
((chr->properties & BLE_GATT_CHR_PROP_WRITE_NO_RSP) != 0 ? CHAR_PROP_WRITE_NO_RESPONSE : 0); ((chr->properties & BLE_GATT_CHR_PROP_WRITE_NO_RSP) != 0 ? CHAR_PROP_WRITE_NO_RESPONSE : 0);
// Call common_hal_bleio_characteristic_construct() to initialize some fields and set up evt handler. // Call common_hal_bleio_characteristic_construct() to initialize some fields and set up evt handler.
mp_buffer_info_t mp_const_empty_bytes_bufinfo;
mp_get_buffer_raise(mp_const_empty_bytes, &mp_const_empty_bytes_bufinfo, MP_BUFFER_READ);
common_hal_bleio_characteristic_construct( common_hal_bleio_characteristic_construct(
characteristic, service, chr->val_handle, uuid, characteristic, service, chr->val_handle, uuid,
props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN,
0, false, // max_length, fixed_length: values don't matter for gattc 0, false, // max_length, fixed_length: values don't matter for gattc
mp_const_empty_bytes, &mp_const_empty_bytes_bufinfo,
NULL); NULL);
// Set def_handle directly since it is only used in discovery. // Set def_handle directly since it is only used in discovery.
characteristic->def_handle = chr->def_handle; characteristic->def_handle = chr->def_handle;
@ -253,16 +258,17 @@ STATIC int _discovered_descriptor_cb(uint16_t conn_handle,
void *arg) { void *arg) {
bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg; bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg;
if (error->status != BLE_ERR_SUCCESS) { if (error->status != 0) {
// Keep the first error in case it's due to memory. // Keep the first error in case it's due to memory.
if (_last_discovery_status == BLE_ERR_SUCCESS) { if (_last_discovery_status == 0) {
_last_discovery_status = error->status; _last_discovery_status = error->status;
} }
xTaskNotifyGive(discovery_task); xTaskNotifyGive(discovery_task);
return 0;
} }
// If any of these memory allocations fail, we set _last_discovery_status // If any of these memory allocations fail, we set _last_discovery_status
// and let the process continue. // and let the process continue.
if (_last_discovery_status != BLE_ERR_SUCCESS) { if (_last_discovery_status != 0) {
return 0; return 0;
} }
@ -306,7 +312,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
discovery_task = xTaskGetCurrentTaskHandle(); discovery_task = xTaskGetCurrentTaskHandle();
if (service_uuids_whitelist == mp_const_none) { if (service_uuids_whitelist == mp_const_none) {
_last_discovery_status = BLE_ERR_SUCCESS; _last_discovery_status = 0;
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self));
// Wait for sync. // Wait for sync.
@ -324,7 +330,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
} }
bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj);
_last_discovery_status = BLE_ERR_SUCCESS; _last_discovery_status = 0;
// Make sure we start with a clean notification state // Make sure we start with a clean notification state
ulTaskNotifyValueClear(discovery_task, 0xffffffff); ulTaskNotifyValueClear(discovery_task, 0xffffffff);
CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u,
@ -340,7 +346,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
for (size_t i = 0; i < self->remote_service_list->len; i++) { for (size_t i = 0; i < self->remote_service_list->len; i++) {
bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]);
_last_discovery_status = BLE_ERR_SUCCESS; _last_discovery_status = 0;
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle,
service->start_handle, service->start_handle,
service->end_handle, service->end_handle,
@ -375,7 +381,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
continue; continue;
} }
_last_discovery_status = BLE_ERR_SUCCESS; _last_discovery_status = 0;
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle, CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle,
end_handle, end_handle,
_discovered_descriptor_cb, characteristic)); _discovered_descriptor_cb, characteristic));

View File

@ -112,7 +112,8 @@ void check_nimble_error(int rc, const char *file, size_t line) {
} }
void check_ble_error(int error_code, const char *file, size_t line) { void check_ble_error(int error_code, const char *file, size_t line) {
if (error_code == BLE_ERR_SUCCESS) { // 0 means success. For BLE_HS_* codes, there is no defined "SUCCESS" value.
if (error_code == 0) {
return; return;
} }
switch (error_code) { switch (error_code) {

View File

@ -28,6 +28,9 @@
#ifndef MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H #ifndef MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H
#define MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H #define MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H
// Enable for debugging.
// #define CIRCUITPY_VERBOSE_BLE (1)
#define MICROPY_NLR_THUMB (0) #define MICROPY_NLR_THUMB (0)
#define MICROPY_USE_INTERNAL_PRINTF (0) #define MICROPY_USE_INTERNAL_PRINTF (0)

View File

@ -470,7 +470,9 @@ void background_callback_run_all(void);
#error "boot counter requires CIRCUITPY_NVM enabled" #error "boot counter requires CIRCUITPY_NVM enabled"
#endif #endif
#ifndef CIRCUITPY_VERBOSE_BLE
#define CIRCUITPY_VERBOSE_BLE 0 #define CIRCUITPY_VERBOSE_BLE 0
#endif
// Display the Blinka logo in the REPL on displayio displays. // Display the Blinka logo in the REPL on displayio displays.
#ifndef CIRCUITPY_REPL_LOGO #ifndef CIRCUITPY_REPL_LOGO

View File

@ -353,7 +353,8 @@ STATIC mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args
prefix_bufinfo.len = 0; prefix_bufinfo.len = 0;
if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) { if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) {
mp_get_buffer_raise(args[ARG_prefixes].u_obj, &prefix_bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(args[ARG_prefixes].u_obj, &prefix_bufinfo, MP_BUFFER_READ);
if (gc_nbytes(prefix_bufinfo.buf) == 0) { // An empty buffer may not be on the heap, but that doesn't matter.
if (prefix_bufinfo.len > 0 && gc_nbytes(prefix_bufinfo.buf) == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("Prefix buffer must be on the heap")); mp_raise_ValueError(MP_ERROR_TEXT("Prefix buffer must be on the heap"));
} }
} }