From 019aecaa2035744738fe4a27c562a5dfe0ae1f44 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 26 Jan 2022 16:12:33 -0800 Subject: [PATCH] Support BLE advertising on ESP Services and characteristics still won't work. Progress on #5926 --- locale/circuitpython.pot | 28 ++ ports/espressif/Makefile | 2 + ports/espressif/common-hal/_bleio/Adapter.c | 257 ++++++++++++++++-- ports/espressif/common-hal/_bleio/Adapter.h | 5 - .../espressif/common-hal/_bleio/Connection.c | 32 +++ .../espressif/common-hal/_bleio/Connection.h | 4 + ports/espressif/common-hal/_bleio/UUID.c | 2 + ports/espressif/common-hal/_bleio/__init__.c | 32 +++ ports/espressif/common-hal/_bleio/__init__.h | 15 + 9 files changed, 349 insertions(+), 28 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index cfab5d02e2..a99a733595 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -446,6 +446,7 @@ msgstr "" msgid "All timers in use" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Already advertising." msgstr "" @@ -908,10 +909,12 @@ msgstr "" msgid "Data chunk must follow fmt chunk" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Data not supported with directed advertising" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Data too large for advertisement packet" msgstr "" @@ -992,6 +995,7 @@ msgstr "" msgid "Expected tuple of length %d, got %d" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Extended advertisements with scan response not supported." msgstr "" @@ -1045,6 +1049,7 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "" @@ -1276,6 +1281,7 @@ msgstr "" msgid "Invalid AuthMode" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c #: ports/nrf/common-hal/_bleio/__init__.c msgid "Invalid BLE parameter" msgstr "" @@ -1584,6 +1590,10 @@ msgstr "" msgid "Name too long" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "" + #: ports/nrf/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "" @@ -1731,6 +1741,7 @@ msgstr "" msgid "Not a valid IP string" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c #: ports/nrf/common-hal/_bleio/__init__.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" @@ -2110,6 +2121,7 @@ msgstr "" msgid "Scale dimensions must divide by 3" msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c msgid "Scan already in progess. Stop with stop_scan." msgstr "" @@ -2268,6 +2280,7 @@ msgstr "" msgid "Time is in the past." msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c #, c-format msgid "Timeout is too long: Maximum timeout length is %d seconds" @@ -2290,6 +2303,7 @@ msgstr "" msgid "Too many displays" msgstr "" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nrf/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -2421,11 +2435,21 @@ msgstr "" msgid "Unknown security error: 0x%04x" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "" + #: ports/nrf/common-hal/_bleio/__init__.c #, c-format msgid "Unknown system firmware error: %04x" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "" + #: shared-bindings/adafruit_pixelbuf/PixelBuf.c #, c-format msgid "Unmatched number of items on RHS (expected %d, got %d)." @@ -2463,11 +2487,13 @@ msgstr "" msgid "Update Failed" msgstr "" +#: ports/espressif/common-hal/_bleio/Descriptor.c #: ports/nrf/common-hal/_bleio/Characteristic.c #: ports/nrf/common-hal/_bleio/Descriptor.c msgid "Value length != required fixed length" msgstr "" +#: ports/espressif/common-hal/_bleio/Descriptor.c #: ports/nrf/common-hal/_bleio/Characteristic.c #: ports/nrf/common-hal/_bleio/Descriptor.c msgid "Value length > max_length" @@ -2525,6 +2551,7 @@ msgstr "" msgid "Woken up by alarm.\n" msgstr "" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nrf/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" @@ -3592,6 +3619,7 @@ msgstr "" msgid "matrix is not positive definite" msgstr "" +#: ports/espressif/common-hal/_bleio/Descriptor.c #: ports/nrf/common-hal/_bleio/Characteristic.c #: ports/nrf/common-hal/_bleio/Descriptor.c #, c-format diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 0febf307ff..d95812ad63 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -86,7 +86,9 @@ INC += \ -isystem esp-idf \ -isystem esp-idf/components/app_update/include \ -isystem esp-idf/components/bootloader_support/include \ + -isystem esp-idf/components/bt/include/$(IDF_TARGET)/include \ -isystem esp-idf/components/bt/host/nimble/esp-hci/include \ + -isystem esp-idf/components/bt/host/nimble/nimble/nimble/controller/include \ -isystem esp-idf/components/bt/host/nimble/nimble/nimble/host/include \ -isystem esp-idf/components/bt/host/nimble/nimble/nimble/host/services/gap/include \ -isystem esp-idf/components/bt/host/nimble/nimble/nimble/include \ diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index e388844f3c..1927d6da62 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -46,6 +46,7 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" +#include "controller/ble_ll_adv.h" #include "nimble/hci_common.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" @@ -53,12 +54,11 @@ #include "host/util/util.h" #include "services/gap/ble_svc_gap.h" +#include "common-hal/_bleio/Connection.h" + +#include "esp_bt.h" #include "esp_nimble_hci.h" -#include "esp_log.h" - -const char *TAG = "BLE adapter"; - bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; // static void bluetooth_adapter_background(void *data) { @@ -98,6 +98,13 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable // ble_hs_cfg.store_status_cb = ble_store_util_status_rr; ble_svc_gap_device_name_set("CIRCUITPY"); + // Clear all of the internal connection objects. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + // Reset connection. + connection->conn_handle = BLEIO_HANDLE_INVALID; + } + cp_task = xTaskGetCurrentTaskHandle(); nimble_port_freertos_init(nimble_host_task); @@ -158,7 +165,9 @@ static int _scan_event(struct ble_gap_event *event, void *scan_results_in) { } if (event->type != BLE_GAP_EVENT_DISC && event->type != BLE_GAP_EVENT_EXT_DISC) { - ESP_LOGI(TAG, "unsupported scan event %d", event->type); + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "Unsupported scan event %d\n", event->type); + #endif return 0; } @@ -208,16 +217,10 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t uint8_t own_addr_type; struct ble_gap_disc_params disc_params; - int rc; /* Figure out address to use while advertising (no privacy for now) */ int privacy = 0; - rc = ble_hs_id_infer_auto(privacy, &own_addr_type); - if (rc != 0) { - ESP_LOGE(TAG, "id error"); - // Error. TODO: Make function to translate into exceptions. - } - + CHECK_NIMBLE_ERROR(ble_hs_id_infer_auto(privacy, &own_addr_type)); disc_params.filter_duplicates = 0; disc_params.passive = !active; @@ -226,11 +229,8 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t disc_params.filter_policy = 0; disc_params.limited = 0; - rc = ble_gap_disc(own_addr_type, timeout * 1000, &disc_params, - _scan_event, self->scan_results); - if (rc != 0) { - ESP_LOGE(TAG, "scan error %d", rc); - } + CHECK_NIMBLE_ERROR(ble_gap_disc(own_addr_type, timeout * 1000, &disc_params, + _scan_event, self->scan_results)); return MP_OBJ_FROM_PTR(self->scan_results); } @@ -244,6 +244,36 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { self->scan_results = NULL; } +STATIC void _convert_address(const bleio_address_obj_t *address, ble_addr_t *nimble_address) { + nimble_address->type = address->type; + mp_buffer_info_t address_buf_info; + mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); + memcpy(nimble_address->val, (uint8_t *)address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); +} + +STATIC void _new_connection(uint16_t conn_handle) { + // Set the tx_power for the connection higher than the advertisement. + 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 + // total connection limit. + bleio_connection_internal_t *connection; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + connection = &bleio_connections[i]; + if (connection->conn_handle == BLEIO_HANDLE_INVALID) { + break; + } + } + connection->conn_handle = conn_handle; + connection->connection_obj = mp_const_none; + connection->pair_status = PAIR_NOT_PAIRED; + connection->mtu = 0; + + // Change the callback for the connection. + ble_gap_set_event_cb(conn_handle, bleio_connection_event_cb, connection); +} + mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { mp_raise_NotImplementedError(NULL); @@ -252,29 +282,210 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre return mp_const_none; } +typedef struct { + struct os_mbuf mbuf; + struct os_mbuf_pkthdr hdr; +} os_mbuf_t; + +STATIC void _wrap_in_mbuf(const uint8_t *data, uint16_t len, os_mbuf_t *buf) { + struct os_mbuf *mbuf = &buf->mbuf; + mbuf->om_data = (uint8_t *)data, + mbuf->om_flags = 0; + mbuf->om_pkthdr_len = 0; + mbuf->om_len = len; + mbuf->om_next.sle_next = NULL; + + buf->hdr.omp_len = len; + + // Setting the pool to NULL will cause frees to fail. Hopefully that failure + // is ignored. + mbuf->om_omp = NULL; +} + +static int _advertising_event(struct ble_gap_event *event, void *self_in) { + bleio_adapter_obj_t *self = (bleio_adapter_obj_t *)self_in; + + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "Advertising event: %d\n", event->type); + #endif + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + // Spurious connect events can happen. + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + if (event->adv_complete.reason == NIMBLE_OK) { + _new_connection(event->adv_complete.conn_handle); + // Set connections objs back to NULL since we have a new + // connection and need a new tuple. + self->connection_objs = NULL; + } + // Other statuses indicate timeout or preemption. + common_hal_bleio_adapter_stop_advertising(self); + break; + + default: + #if CIRCUITPY_VERBOSE_BLE + // For debugging. + mp_printf(&mp_plat_print, "Unhandled advertising event: %d\n", event->type); + #endif + break; + } + return 0; +} + uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, const uint8_t *advertising_data, uint16_t advertising_data_len, const uint8_t *scan_response_data, uint16_t scan_response_data_len, mp_int_t tx_power, const bleio_address_obj_t *directed_to) { - mp_raise_NotImplementedError(NULL); - return -1; + + if (ble_gap_adv_active() && !self->user_advertising) { + return BLE_HS_EBUSY; + } + + uint32_t rc; + bool extended = advertising_data_len > BLE_ADV_LEGACY_DATA_MAX_LEN || + scan_response_data_len > BLE_ADV_LEGACY_DATA_MAX_LEN; + + ble_addr_t peer; + if (directed_to != NULL) { + _convert_address(directed_to, &peer); + } + + uint8_t own_addr_type; + // Anonymous addresses are still resolvable. (Following what the NRF + // implementation does.) + rc = ble_hs_id_infer_auto(anonymous, &own_addr_type); + if (rc != NIMBLE_OK) { + return rc; + } + + bool high_duty_directed = directed_to != NULL && interval <= 3.5 && timeout <= 1.3; + + struct ble_gap_ext_adv_params adv_params = { + .connectable = connectable, + .scannable = scan_response_data_len > 0, + .directed = directed_to != NULL, + .high_duty_directed = high_duty_directed, + .legacy_pdu = !extended, + .anonymous = anonymous, + .include_tx_power = extended, + .scan_req_notif = false, + .itvl_min = SEC_TO_UNITS(interval, UNIT_0_625_MS) + 0.5f, + .itvl_max = SEC_TO_UNITS(interval, UNIT_0_625_MS) + 0.5f, + .channel_map = 0, + .own_addr_type = own_addr_type, + .peer = peer, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .primary_phy = BLE_HCI_LE_PHY_1M, + .secondary_phy = BLE_HCI_LE_PHY_1M, + .tx_power = tx_power, + .sid = 0, + }; + + // Configure must come before setting payloads. + rc = ble_gap_ext_adv_configure(0, + &adv_params, + NULL, + _advertising_event, self); + if (rc != NIMBLE_OK) { + return rc; + } + + os_mbuf_t buf; + _wrap_in_mbuf(advertising_data, advertising_data_len, &buf); + // This copies the advertising data into buffers to send to the controller. + // Therefore, we don't need to worry about the lifetime of our copy. + rc = ble_gap_ext_adv_set_data(0, &buf.mbuf); + if (rc != NIMBLE_OK) { + return rc; + } + + if (scan_response_data_len > 0) { + _wrap_in_mbuf(scan_response_data, scan_response_data_len, &buf); + // This copies the advertising data into buffers to send to the controller. + // Therefore, we don't need to worry about the lifetime of our copy. + rc = ble_gap_ext_adv_rsp_set_data(0, &buf.mbuf); + if (rc != NIMBLE_OK) { + return rc; + } + } + + rc = ble_gap_ext_adv_start(0, timeout / 10, 0); + if (rc != NIMBLE_OK) { + return rc; + } + + return NIMBLE_OK; } +STATIC void check_data_fit(size_t data_len, bool connectable) { + if (data_len > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) || + (connectable && data_len > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE))) { + mp_raise_ValueError(translate("Data too large for advertisement packet")); + } +} void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo, mp_int_t tx_power, const bleio_address_obj_t *directed_to) { - mp_raise_NotImplementedError(NULL); + if (self->user_advertising) { + mp_raise_bleio_BluetoothError(translate("Already advertising.")); + } else { + // If the user isn't advertising, then the background is. So, stop the + // background advertising so the user can. + common_hal_bleio_adapter_stop_advertising(self); + } + // interval value has already been validated. + + check_data_fit(advertising_data_bufinfo->len, connectable); + check_data_fit(scan_response_data_bufinfo->len, connectable); + + if (advertising_data_bufinfo->len > 31 && scan_response_data_bufinfo->len > 0) { + mp_raise_bleio_BluetoothError(translate("Extended advertisements with scan response not supported.")); + } + + + if (advertising_data_bufinfo->len > 0 && directed_to != NULL) { + mp_raise_bleio_BluetoothError(translate("Data not supported with directed advertising")); + } + + if (anonymous) { + mp_raise_NotImplementedError(NULL); + } + + if (!timeout) { + timeout = BLE_HS_FOREVER; + } else if (timeout > INT32_MAX) { + mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"), + INT32_MAX / 1000); + } + + CHECK_NIMBLE_ERROR(_common_hal_bleio_adapter_start_advertising(self, connectable, anonymous, timeout, interval, + advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len, + tx_power, + directed_to)); + self->user_advertising = true; } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { - mp_raise_NotImplementedError(NULL); + int err_code = ble_gap_ext_adv_stop(0); + self->user_advertising = false; + + if ((err_code != NIMBLE_OK) && + (err_code != BLE_HS_EALREADY) && + (err_code != BLE_HS_EINVAL)) { + CHECK_NIMBLE_ERROR(err_code); + } } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { - return self->current_advertising_data != NULL; + return ble_gap_adv_active(); } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { @@ -328,7 +539,7 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { common_hal_bleio_adapter_stop_scan(adapter); - if (adapter->current_advertising_data != NULL) { + if (common_hal_bleio_adapter_get_advertising(adapter)) { common_hal_bleio_adapter_stop_advertising(adapter); } diff --git a/ports/espressif/common-hal/_bleio/Adapter.h b/ports/espressif/common-hal/_bleio/Adapter.h index 906fc6d5fb..3534c79809 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.h +++ b/ports/espressif/common-hal/_bleio/Adapter.h @@ -47,11 +47,6 @@ extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUN typedef struct { mp_obj_base_t base; - // Pointer to buffers we maintain so that the data is long lived. - uint8_t *advertising_data; - uint8_t *scan_response_data; - // Pointer to current data. - const uint8_t *current_advertising_data; bleio_scanresults_obj_t *scan_results; mp_obj_t name; mp_obj_tuple_t *connection_objs; diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 2a96c2e189..a3668073a8 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -48,6 +48,38 @@ #include "host/ble_att.h" +int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) { + bleio_connection_internal_t *connection = (bleio_connection_internal_t *)connection_in; + + switch (event->type) { + case BLE_GAP_EVENT_DISCONNECT: { + connection->conn_handle = BLEIO_HANDLE_INVALID; + connection->pair_status = PAIR_NOT_PAIRED; + + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "disconnected %02x\n", event->disconnect.reason); + #endif + if (connection->connection_obj != mp_const_none) { + bleio_connection_obj_t *obj = connection->connection_obj; + obj->connection = NULL; + obj->disconnect_reason = event->disconnect.reason; + } + + break; + } + + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: { + break; + } + + default: + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "Unhandled connection event: %d\n", event->type); + #endif + return 0; + } + return 0; +} bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { if (self->connection == NULL) { diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index 2889694fbc..73bfeff19c 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -38,6 +38,8 @@ #include "shared-module/_bleio/Address.h" #include "common-hal/_bleio/Service.h" +#include "host/ble_gap.h" + typedef enum { PAIR_NOT_PAIRED, PAIR_WAITING, @@ -81,6 +83,8 @@ typedef struct { void bleio_connection_clear(bleio_connection_internal_t *self); +int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in); + uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/espressif/common-hal/_bleio/UUID.c b/ports/espressif/common-hal/_bleio/UUID.c index b49c5d3992..8f0866412c 100644 --- a/ports/espressif/common-hal/_bleio/UUID.c +++ b/ports/espressif/common-hal/_bleio/UUID.c @@ -42,6 +42,8 @@ void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, co ble_uuid_init_from_buf(&self->nimble_ble_uuid, (uint8_t *)&uuid16, 2); } else { ble_uuid_init_from_buf(&self->nimble_ble_uuid, uuid128, 16); + self->nimble_ble_uuid.u128.value[12] = uuid16 & 0xff; + self->nimble_ble_uuid.u128.value[13] = (uuid16 >> 8) & 0xff; } } diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index bc3f954f2f..bd10b0a519 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -65,3 +65,35 @@ void bleio_background(void) { void common_hal_bleio_gc_collect(void) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } + +void check_nimble_error(int rc, const char *file, size_t line) { + if (rc == NIMBLE_OK) { + return; + } + switch (rc) { + case BLE_HS_ENOMEM: + mp_raise_msg(&mp_type_MemoryError, translate("Nimble out of memory")); + return; + case BLE_HS_ETIMEOUT: + mp_raise_msg(&mp_type_TimeoutError, NULL); + return; + case BLE_HS_EINVAL: + mp_raise_ValueError(translate("Invalid BLE parameter")); + return; + case BLE_HS_ENOTCONN: + mp_raise_ConnectionError(translate("Not connected")); + return; + default: + #if CIRCUITPY_VERBOSE_BLE + if (file) { + mp_raise_bleio_BluetoothError(translate("Unknown system firmware error at %s:%d: %d"), file, line, rc); + } + #else + (void)file; + (void)line; + mp_raise_bleio_BluetoothError(translate("Unknown system firmware error: %d"), rc); + #endif + + break; + } +} diff --git a/ports/espressif/common-hal/_bleio/__init__.h b/ports/espressif/common-hal/_bleio/__init__.h index 965255907f..6c32bd5d4e 100644 --- a/ports/espressif/common-hal/_bleio/__init__.h +++ b/ports/espressif/common-hal/_bleio/__init__.h @@ -39,4 +39,19 @@ void bleio_background(void); // 20 bytes max (23 - 3). #define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) +#define NIMBLE_OK (0) + +void check_nimble_error(int rc, const char *file, size_t line); +#define CHECK_NIMBLE_ERROR(rc) check_nimble_error(rc, __FILE__, __LINE__) + +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) +#define SEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000000) / (RESOLUTION)) +#define UNITS_TO_SEC(TIME, RESOLUTION) (((TIME)*(RESOLUTION)) / 1000000) +// 0.625 msecs (625 usecs) +#define ADV_INTERVAL_UNIT_FLOAT_SECS (0.000625) +// Microseconds is the base unit. The macros above know that. +#define UNIT_0_625_MS (625) +#define UNIT_1_25_MS (1250) +#define UNIT_10_MS (10000) + #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_BLEIO_INIT_H