diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index f1c1ee986c..a5cf3da6ac 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -284,15 +284,21 @@ STATIC void _new_connection(uint16_t conn_handle) { 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. - bleio_connection_internal_t *connection; + bleio_connection_internal_t *connection = NULL; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { connection = &bleio_connections[i]; if (connection->conn_handle == BLEIO_HANDLE_INVALID) { break; } } + + // Shouldn't happen, but just return if no connection available. + if (!connection) { + return; + } + connection->conn_handle = conn_handle; connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index f639b75edf..0a787c017d 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -50,7 +50,25 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->props = props; self->read_perm = read_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()) { self->descriptor_list = mp_obj_new_list(0, NULL); diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 575d8d0894..2d10300bac 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -63,7 +63,7 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) connection->pair_status = PAIR_NOT_PAIRED; #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 if (connection->connection_obj != mp_const_none) { 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) { + // Second argument is an HCI reason, not an HS error code. 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) { 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. - if (_last_discovery_status == BLE_ERR_SUCCESS) { + if (_last_discovery_status == 0) { _last_discovery_status = error->status; 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 // and let the process continue. - if (_last_discovery_status != BLE_ERR_SUCCESS) { + if (_last_discovery_status != 0) { return 0; } 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) { 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. - if (_last_discovery_status == BLE_ERR_SUCCESS) { + if (_last_discovery_status == 0) { _last_discovery_status = error->status; xTaskNotifyGive(discovery_task); } + return 0; } // If any of these memory allocations fail, we set _last_discovery_status // and let the process continue. - if (_last_discovery_status != BLE_ERR_SUCCESS) { + if (_last_discovery_status != 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); // 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( characteristic, service, chr->val_handle, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, 0, false, // max_length, fixed_length: values don't matter for gattc - mp_const_empty_bytes, + &mp_const_empty_bytes_bufinfo, NULL); // Set def_handle directly since it is only used in discovery. characteristic->def_handle = chr->def_handle; @@ -253,16 +258,17 @@ STATIC int _discovered_descriptor_cb(uint16_t conn_handle, void *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. - if (_last_discovery_status == BLE_ERR_SUCCESS) { + if (_last_discovery_status == 0) { _last_discovery_status = error->status; } xTaskNotifyGive(discovery_task); + return 0; } // If any of these memory allocations fail, we set _last_discovery_status // and let the process continue. - if (_last_discovery_status != BLE_ERR_SUCCESS) { + if (_last_discovery_status != 0) { return 0; } @@ -306,7 +312,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t discovery_task = xTaskGetCurrentTaskHandle(); 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)); // 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); - _last_discovery_status = BLE_ERR_SUCCESS; + _last_discovery_status = 0; // Make sure we start with a clean notification state ulTaskNotifyValueClear(discovery_task, 0xffffffff); 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++) { 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, service->start_handle, service->end_handle, @@ -375,7 +381,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t continue; } - _last_discovery_status = BLE_ERR_SUCCESS; + _last_discovery_status = 0; CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle, end_handle, _discovered_descriptor_cb, characteristic)); diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index f6ac17012d..338f576f69 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -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) { - if (error_code == BLE_ERR_SUCCESS) { + // 0 means success. For BLE_HS_* codes, there is no defined "SUCCESS" value. + if (error_code == 0) { return; } switch (error_code) { diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index f94fd1ce0c..1a97d1b6de 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -28,6 +28,9 @@ #ifndef 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_USE_INTERNAL_PRINTF (0) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index b962f3892d..30f3101a38 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -470,7 +470,9 @@ void background_callback_run_all(void); #error "boot counter requires CIRCUITPY_NVM enabled" #endif +#ifndef CIRCUITPY_VERBOSE_BLE #define CIRCUITPY_VERBOSE_BLE 0 +#endif // Display the Blinka logo in the REPL on displayio displays. #ifndef CIRCUITPY_REPL_LOGO diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 43d146434b..005f30f8b3 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -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; if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) { 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")); } }