From 345334aaf13dabbbb5fbfc1778fc34ed78907f42 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Tue, 17 Jul 2018 11:44:55 +0200 Subject: bleio: Add a new Address class Use the new in the Adapter singleton. --- shared-module/bleio/Address.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 shared-module/bleio/Address.h (limited to 'shared-module') diff --git a/shared-module/bleio/Address.h b/shared-module/bleio/Address.h new file mode 100644 index 000000000..a520b8dd6 --- /dev/null +++ b/shared-module/bleio/Address.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H + +#include "shared-bindings/bleio/AddressType.h" + +#define BLEIO_ADDRESS_BYTES 6 + +typedef struct { + mp_obj_base_t base; + bleio_address_type_t type; + uint8_t value[BLEIO_ADDRESS_BYTES]; +} bleio_address_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H -- cgit v1.2.3 From 7390dc7dab2c5ccd34a1fa5a33e1e5241b8f9bd7 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Tue, 17 Jul 2018 17:00:37 +0200 Subject: bleio: Move ScanEntry to shared module and add a new AdvertisementData class --- ports/nrf/Makefile | 3 +- ports/nrf/drivers/bluetooth/ble_drv.c | 12 + ports/nrf/drivers/bluetooth/ble_drv.h | 2 + ports/nrf/modules/ubluepy/modubluepy.c | 2 - ports/nrf/modules/ubluepy/modubluepy.h | 10 - ports/nrf/modules/ubluepy/ubluepy_constants.c | 47 ---- ports/nrf/modules/ubluepy/ubluepy_scan_entry.c | 146 ------------ ports/nrf/modules/ubluepy/ubluepy_scanner.c | 26 +-- shared-bindings/bleio/AdvertisementData.c | 92 ++++++++ shared-bindings/bleio/AdvertisementData.h | 34 +++ shared-bindings/bleio/ScanEntry.c | 307 +++++++++++++++++++++++++ shared-bindings/bleio/ScanEntry.h | 44 ++++ shared-bindings/bleio/__init__.c | 20 +- shared-module/bleio/AdvertisementData.h | 76 ++++++ 14 files changed, 592 insertions(+), 229 deletions(-) delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_scan_entry.c create mode 100644 shared-bindings/bleio/AdvertisementData.c create mode 100644 shared-bindings/bleio/AdvertisementData.h create mode 100644 shared-bindings/bleio/ScanEntry.c create mode 100644 shared-bindings/bleio/ScanEntry.h create mode 100644 shared-module/bleio/AdvertisementData.h (limited to 'shared-module') diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 2de7f24bd..c5e0df02f 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -135,7 +135,6 @@ DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/ubluepy_delegate.c \ ubluepy/ubluepy_constants.c \ ubluepy/ubluepy_scanner.c \ - ubluepy/ubluepy_scan_entry.c \ ) SRC_COMMON_HAL += \ @@ -187,6 +186,8 @@ ifneq ($(SD), ) SRC_BINDINGS_ENUMS += \ bleio/Address.c \ bleio/AddressType.c \ + bleio/AdvertisementData.c \ + bleio/ScanEntry.c \ bleio/UUIDType.c endif diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index 81d2a8ece..766660828 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -785,6 +785,18 @@ void ble_drv_scan_start(void) { } } +void ble_drv_scan_continue(void) { + SD_TEST_OR_ENABLE(); + +#if (BLUETOOTH_SD == 140) + uint32_t err_code; + if ((err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not continue scanning. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +#endif +} + void ble_drv_scan_stop(void) { sd_ble_gap_scan_stop(); } diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index d8b715467..ca9a38fdd 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -108,6 +108,8 @@ void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, u void ble_drv_scan_start(void); +void ble_drv_scan_continue(void); + void ble_drv_scan_stop(void); void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler); diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c index 0c02b22f2..034cc806c 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ b/ports/nrf/modules/ubluepy/modubluepy.c @@ -34,7 +34,6 @@ extern const mp_obj_type_t ubluepy_characteristic_type; extern const mp_obj_type_t ubluepy_delegate_type; extern const mp_obj_type_t ubluepy_constants_type; extern const mp_obj_type_t ubluepy_scanner_type; -extern const mp_obj_type_t ubluepy_scan_entry_type; STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluepy) }, @@ -46,7 +45,6 @@ STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { #endif #if MICROPY_PY_UBLUEPY_CENTRAL { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&ubluepy_scanner_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&ubluepy_scan_entry_type) }, #endif { MP_ROM_QSTR(MP_QSTR_DefaultDelegate), MP_ROM_PTR(&ubluepy_delegate_type) }, { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, diff --git a/ports/nrf/modules/ubluepy/modubluepy.h b/ports/nrf/modules/ubluepy/modubluepy.h index c5fd7b6f8..8fb9fadd0 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ b/ports/nrf/modules/ubluepy/modubluepy.h @@ -78,7 +78,6 @@ extern const mp_obj_type_t ubluepy_service_type; extern const mp_obj_type_t ubluepy_characteristic_type; extern const mp_obj_type_t ubluepy_peripheral_type; extern const mp_obj_type_t ubluepy_scanner_type; -extern const mp_obj_type_t ubluepy_scan_entry_type; extern const mp_obj_type_t ubluepy_constants_type; extern const mp_obj_type_t ubluepy_constants_ad_types_type; @@ -153,15 +152,6 @@ typedef struct _ubluepy_scanner_obj_t { mp_obj_t adv_reports; } ubluepy_scanner_obj_t; -typedef struct _ubluepy_scan_entry_obj_t { - mp_obj_base_t base; - mp_obj_t addr; - uint8_t addr_type; - bool connectable; - int8_t rssi; - mp_obj_t data; -} ubluepy_scan_entry_obj_t; - typedef enum _ubluepy_prop_t { UBLUEPY_PROP_BROADCAST = 0x01, UBLUEPY_PROP_READ = 0x02, diff --git a/ports/nrf/modules/ubluepy/ubluepy_constants.c b/ports/nrf/modules/ubluepy/ubluepy_constants.c index e53a6f068..b28bd3828 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_constants.c +++ b/ports/nrf/modules/ubluepy/ubluepy_constants.c @@ -31,58 +31,11 @@ #include "modubluepy.h" -STATIC const mp_rom_map_elem_t ubluepy_constants_ad_types_locals_dict_table[] = { - // GAP AD Types - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_FLAGS), MP_ROM_INT(0x01) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x02) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x03) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x04) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x05) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x06) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x07) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SHORT_LOCAL_NAME), MP_ROM_INT(0x08) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_COMPLETE_LOCAL_NAME), MP_ROM_INT(0x09) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_TX_POWER_LEVEL), MP_ROM_INT(0x0A) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_CLASS_OF_DEVICE), MP_ROM_INT(0x0D) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_HASH_C), MP_ROM_INT(0x0E) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R), MP_ROM_INT(0x0F) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SECURITY_MANAGER_TK_VALUE), MP_ROM_INT(0x10) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS), MP_ROM_INT(0x11) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE), MP_ROM_INT(0x12) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT), MP_ROM_INT(0x14) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT), MP_ROM_INT(0x15) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA), MP_ROM_INT(0x16) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_PUBLIC_TARGET_ADDRESS), MP_ROM_INT(0x17) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_RANDOM_TARGET_ADDRESS), MP_ROM_INT(0x18) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_APPEARANCE), MP_ROM_INT(0x19) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_ADVERTISING_INTERVAL), MP_ROM_INT(0x1A) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS), MP_ROM_INT(0x1B) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_LE_ROLE), MP_ROM_INT(0x1C) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_HASH_C256), MP_ROM_INT(0x1D) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256), MP_ROM_INT(0x1E) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA_32BIT_UUID), MP_ROM_INT(0x20) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA_128BIT_UUID), MP_ROM_INT(0x21) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_URI), MP_ROM_INT(0x24) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_3D_INFORMATION_DATA), MP_ROM_INT(0x3D) }, - { MP_ROM_QSTR(MP_QSTR_AD_TYPE_MANUFACTURER_SPECIFIC_DATA), MP_ROM_INT(0xFF) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_constants_ad_types_locals_dict, ubluepy_constants_ad_types_locals_dict_table); - -const mp_obj_type_t ubluepy_constants_ad_types_type = { - { &mp_type_type }, - .name = MP_QSTR_ad_types, - .locals_dict = (mp_obj_dict_t*)&ubluepy_constants_ad_types_locals_dict -}; - STATIC const mp_rom_map_elem_t ubluepy_constants_locals_dict_table[] = { // GAP events { MP_ROM_QSTR(MP_QSTR_EVT_GAP_CONNECTED), MP_ROM_INT(16) }, { MP_ROM_QSTR(MP_QSTR_EVT_GAP_DISCONNECTED), MP_ROM_INT(17) }, { MP_ROM_QSTR(MP_QSTR_EVT_GATTS_WRITE), MP_ROM_INT(80) }, - { MP_ROM_QSTR(MP_QSTR_UUID_CCCD), MP_ROM_INT(0x2902) }, - - { MP_ROM_QSTR(MP_QSTR_ad_types), MP_ROM_PTR(&ubluepy_constants_ad_types_type) }, }; STATIC MP_DEFINE_CONST_DICT(ubluepy_constants_locals_dict, ubluepy_constants_locals_dict_table); diff --git a/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c b/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c deleted file mode 100644 index 773070b08..000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include "py/obj.h" -#include "py/runtime.h" -#include "py/objstr.h" -#include "py/objlist.h" -#include "py/objarray.h" -#include "py/objtuple.h" -#include "py/qstr.h" - -#if MICROPY_PY_UBLUEPY_CENTRAL - -#include "ble_drv.h" - -STATIC void ubluepy_scan_entry_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_scan_entry_obj_t * self = (ubluepy_scan_entry_obj_t *)o; - (void)self; - mp_printf(print, "ScanEntry"); -} - -/// \method addr() -/// Return address as text string. -/// -STATIC mp_obj_t scan_entry_get_addr(mp_obj_t self_in) { - ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return self->addr; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_addr_obj, scan_entry_get_addr); - -/// \method addr_type() -/// Return address type value. -/// -STATIC mp_obj_t scan_entry_get_addr_type(mp_obj_t self_in) { - ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(self->addr_type); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_addr_type_obj, scan_entry_get_addr_type); - -/// \method rssi() -/// Return RSSI value. -/// -STATIC mp_obj_t scan_entry_get_rssi(mp_obj_t self_in) { - ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(self->rssi); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_rssi_obj, scan_entry_get_rssi); - -/// \method getScanData() -/// Return list of the scan data tupples (ad_type, description, value) -/// -STATIC mp_obj_t scan_entry_get_scan_data(mp_obj_t self_in) { - ubluepy_scan_entry_obj_t * self = MP_OBJ_TO_PTR(self_in); - - mp_obj_t retval_list = mp_obj_new_list(0, NULL); - - // TODO: check if self->data is set - mp_obj_array_t * data = MP_OBJ_TO_PTR(self->data); - - uint16_t byte_index = 0; - - while (byte_index < data->len) { - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - - uint8_t adv_item_len = ((uint8_t * )data->items)[byte_index]; - uint8_t adv_item_type = ((uint8_t * )data->items)[byte_index + 1]; - - mp_obj_t description = mp_const_none; - - mp_map_t *constant_map = mp_obj_dict_get_map(ubluepy_constants_ad_types_type.locals_dict); - mp_map_elem_t *ad_types_table = MP_OBJ_TO_PTR(constant_map->table); - - uint16_t num_of_elements = constant_map->used; - - for (uint16_t i = 0; i < num_of_elements; i++) { - mp_map_elem_t element = (mp_map_elem_t)*ad_types_table; - ad_types_table++; - uint16_t element_value = mp_obj_get_int(element.value); - - if (adv_item_type == element_value) { - qstr key_qstr = MP_OBJ_QSTR_VALUE(element.key); - const char * text = qstr_str(key_qstr); - size_t len = qstr_len(key_qstr); - - vstr_t vstr; - vstr_init(&vstr, len); - vstr_printf(&vstr, "%s", text); - description = mp_obj_new_str(vstr.buf, vstr.len); - vstr_clear(&vstr); - } - } - - t->items[0] = MP_OBJ_NEW_SMALL_INT(adv_item_type); - t->items[1] = description; - t->items[2] = mp_obj_new_bytearray(adv_item_len - 1, - &((uint8_t * )data->items)[byte_index + 2]); - mp_obj_list_append(retval_list, MP_OBJ_FROM_PTR(t)); - - byte_index += adv_item_len + 1; - } - - return retval_list; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_scan_entry_get_scan_data_obj, scan_entry_get_scan_data); - -STATIC const mp_rom_map_elem_t ubluepy_scan_entry_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&bluepy_scan_entry_get_addr_obj) }, - { MP_ROM_QSTR(MP_QSTR_addr_type), MP_ROM_PTR(&bluepy_scan_entry_get_addr_type_obj) }, - { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bluepy_scan_entry_get_rssi_obj) }, - { MP_ROM_QSTR(MP_QSTR_getScanData), MP_ROM_PTR(&ubluepy_scan_entry_get_scan_data_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_scan_entry_locals_dict, ubluepy_scan_entry_locals_dict_table); - -const mp_obj_type_t ubluepy_scan_entry_type = { - { &mp_type_type }, - .name = MP_QSTR_ScanEntry, - .print = ubluepy_scan_entry_print, - .locals_dict = (mp_obj_dict_t*)&ubluepy_scan_entry_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY_CENTRAL diff --git a/ports/nrf/modules/ubluepy/ubluepy_scanner.c b/ports/nrf/modules/ubluepy/ubluepy_scanner.c index 1cde3d551..9d15037a5 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_scanner.c +++ b/ports/nrf/modules/ubluepy/ubluepy_scanner.c @@ -33,31 +33,25 @@ #if MICROPY_PY_UBLUEPY_CENTRAL +#include "shared-bindings/bleio/ScanEntry.h" #include "ble_drv.h" STATIC void adv_event_handler(mp_obj_t self_in, uint16_t event_id, ble_drv_adv_data_t * data) { ubluepy_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - ubluepy_scan_entry_obj_t * item = m_new_obj(ubluepy_scan_entry_obj_t); - item->base.type = &ubluepy_scan_entry_type; + // TODO: Don't add new entry for each item, group by address and update + bleio_scanentry_obj_t *item = m_new_obj(bleio_scanentry_obj_t); + item->base.type = &bleio_scanentry_type; - vstr_t vstr; - vstr_init(&vstr, 17); + item->rssi = data->rssi; + item->data = mp_obj_new_bytearray(data->data_len, data->p_data); - vstr_printf(&vstr, ""HEX2_FMT":"HEX2_FMT":"HEX2_FMT":" \ - HEX2_FMT":"HEX2_FMT":"HEX2_FMT"", - data->p_peer_addr[5], data->p_peer_addr[4], data->p_peer_addr[3], - data->p_peer_addr[2], data->p_peer_addr[1], data->p_peer_addr[0]); - - item->addr = mp_obj_new_str(vstr.buf, vstr.len); - - vstr_clear(&vstr); - - item->addr_type = data->addr_type; - item->rssi = data->rssi; - item->data = mp_obj_new_bytearray(data->data_len, data->p_data); + item->address.type = data->addr_type; + memcpy(item->address.value, data->p_peer_addr, BLEIO_ADDRESS_BYTES); mp_obj_list_append(self->adv_reports, item); + + ble_drv_scan_continue(); } STATIC void ubluepy_scanner_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { diff --git a/shared-bindings/bleio/AdvertisementData.c b/shared-bindings/bleio/AdvertisementData.c new file mode 100644 index 000000000..545dd5c51 --- /dev/null +++ b/shared-bindings/bleio/AdvertisementData.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "shared-module/bleio/AdvertisementData.h" + +//| .. currentmodule:: bleio +//| +//| :class:`AdvertisementData` -- data used during BLE advertising +//| ============================================================== +//| +//| Represents the data to be broadcast during BLE advertising. +//| + +// TODO: Implement constructor and methods + +STATIC const mp_rom_map_elem_t bleio_advertisementdata_locals_dict_table[] = { + // Static variables + { MP_ROM_QSTR(MP_QSTR_FLAGS), MP_ROM_INT(AdFlags) }, + { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_16BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf16BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_16BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf16BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_32BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf32BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_32BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf32BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_128BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf128BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_128BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf128BitServiceClassUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_SHORTENED_LOCAL_NAME), MP_ROM_INT(AdShortenedLocalName) }, + { MP_ROM_QSTR(MP_QSTR_COMPLETE_LOCAL_NAME), MP_ROM_INT(AdCompleteLocalName) }, + { MP_ROM_QSTR(MP_QSTR_TX_POWER_LEVEL), MP_ROM_INT(AdTxPowerLevel) }, + { MP_ROM_QSTR(MP_QSTR_CLASS_OF_DEVICE), MP_ROM_INT(AdClassOfDevice) }, + { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_HASH_C), MP_ROM_INT(AdSimplePairingHashC) }, + { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_RANDOMIZER_R), MP_ROM_INT(AdSimplePairingRandomizerR) }, + { MP_ROM_QSTR(MP_QSTR_SECURITY_MANAGER_TK_VALUE), MP_ROM_INT(AdSecurityManagerTKValue) }, + { MP_ROM_QSTR(MP_QSTR_SECURITY_MANAGER_OOB_FLAGS), MP_ROM_INT(AdSecurityManagerOOBFlags) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE_CONNECTION_INTERVAL_RANGE), MP_ROM_INT(AdSlaveConnectionIntervalRange) }, + { MP_ROM_QSTR(MP_QSTR_LIST_OF_16BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf16BitServiceSolicitationUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_LIST_OF_128BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf128BitServiceSolicitationUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA), MP_ROM_INT(AdServiceData) }, + { MP_ROM_QSTR(MP_QSTR_PUBLIC_TARGET_ADDRESS), MP_ROM_INT(AdPublicTargetAddress) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_TARGET_ADDRESS), MP_ROM_INT(AdRandomTargetAddress) }, + { MP_ROM_QSTR(MP_QSTR_APPEARANCE), MP_ROM_INT(AdAppearance) }, + { MP_ROM_QSTR(MP_QSTR_ADVERTISING_INTERNAL), MP_ROM_INT(AdAdvertisingInterval) }, + { MP_ROM_QSTR(MP_QSTR_LE_BLUETOOTH_DEVICE_ADDRESS), MP_ROM_INT(AdLEBluetoothDeviceAddress) }, + { MP_ROM_QSTR(MP_QSTR_LE_ROLE), MP_ROM_INT(AdLERole) }, + { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_HASH_C256), MP_ROM_INT(AdSimplePairingHashC256) }, + { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_RANDOMIZER_R256), MP_ROM_INT(AdSimplePairingRandomizerR256) }, + { MP_ROM_QSTR(MP_QSTR_LIST_OF_32BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf32BitServiceSolicitationUUIDs) }, + { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA_32BIT_UUID), MP_ROM_INT(AdServiceData32BitUUID) }, + { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA_128BIT_UUID), MP_ROM_INT(AdServiceData128BitUUID) }, + { MP_ROM_QSTR(MP_QSTR_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE), MP_ROM_INT(AdLESecureConnectionsConfirmationValue) }, + { MP_ROM_QSTR(MP_QSTR_LE_SECURE_CONNECTIONS_RANDOM_VALUE), MP_ROM_INT(AdLESecureConnectionsRandomValue) }, + { MP_ROM_QSTR(MP_QSTR_URI), MP_ROM_INT(AdURI) }, + { MP_ROM_QSTR(MP_QSTR_INDOOR_POSITIONING), MP_ROM_INT(AdIndoorPositioning) }, + { MP_ROM_QSTR(MP_QSTR_TRANSPORT_DISCOVERY_DATA), MP_ROM_INT(AdTransportDiscoveryData) }, + { MP_ROM_QSTR(MP_QSTR_LE_SUPPORTED_FEATURES), MP_ROM_INT(AdLESupportedFeatures) }, + { MP_ROM_QSTR(MP_QSTR_CHANNEL_MAP_UPDATE_INDICATION), MP_ROM_INT(AdChannelMapUpdateIndication) }, + { MP_ROM_QSTR(MP_QSTR_PB_ADV), MP_ROM_INT(AdPBADV) }, + { MP_ROM_QSTR(MP_QSTR_MESH_MESSAGE), MP_ROM_INT(AdMeshMessage) }, + { MP_ROM_QSTR(MP_QSTR_MESH_BEACON), MP_ROM_INT(AdMeshBeacon) }, + { MP_ROM_QSTR(MP_QSTR_3D_INFORMATION_DATA), MP_ROM_INT(Ad3DInformationData) }, + { MP_ROM_QSTR(MP_QSTR_MANUFACTURER_SPECIFIC_DATA), MP_ROM_INT(AdManufacturerSpecificData) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_advertisementdata_locals_dict, bleio_advertisementdata_locals_dict_table); + +const mp_obj_type_t bleio_advertisementdata_type = { + { &mp_type_type }, + .name = MP_QSTR_AdvertisementData, + .locals_dict = (mp_obj_dict_t*)&bleio_advertisementdata_locals_dict +}; diff --git a/shared-bindings/bleio/AdvertisementData.h b/shared-bindings/bleio/AdvertisementData.h new file mode 100644 index 000000000..05b5a2c8d --- /dev/null +++ b/shared-bindings/bleio/AdvertisementData.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H + +#include "py/obj.h" + +extern const mp_obj_type_t bleio_advertisementdata_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H diff --git a/shared-bindings/bleio/ScanEntry.c b/shared-bindings/bleio/ScanEntry.c new file mode 100644 index 000000000..f41665581 --- /dev/null +++ b/shared-bindings/bleio/ScanEntry.c @@ -0,0 +1,307 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objarray.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "shared-bindings/bleio/Address.h" +#include "shared-module/bleio/AdvertisementData.h" +#include "shared-bindings/bleio/UUID.h" +#include "shared-bindings/bleio/ScanEntry.h" + +//| .. currentmodule:: bleio +//| +//| :class:`ScanEntry` -- BLE scan response entry +//| ========================================================= +//| +//| Encapsulates information about a device that was received as a +//| response to a BLE scan request. +//| + +//| .. attribute:: address +//| +//| The address of the device. (read-only) +//| This attribute is of type `bleio:Address`. +//| + +//| .. attribute:: manufacturer_specific_data +//| +//| The manufacturer-specific data present in the advertisement packet. (read-only) +//| + +//| .. attribute:: name +//| +//| The name of the device. (read-only) +//| This attribute might be `None` if the data was missing from the advertisement packet. +//| + +//| .. attribute:: raw_data +//| +//| All the advertisement data present in the packet. (read-only) +//| + +//| .. attribute:: rssi +//| +//| The signal strength of the device at the time of the scan. (read-only) +//| + +//| .. attribute:: service_uuids +//| +//| The address of the device. (read-only) +//| This attribute is a list of `bleio:UUID`. +//| This attribute might be empty or incomplete, depending on the advertisement packet. +//| Currently only 16-bit UUIDS are listed. +//| + +//| .. attribute:: tx_power_level +//| +//| The transmit power level of the device. (read-only) +//| This attribute might be `None` if the data was missing from the advertisement packet. +//| +static uint8_t find_data_item(mp_obj_array_t *data_in, uint8_t type, uint8_t **data_out) { + uint16_t i = 0; + while (i < data_in->len) { + const uint8_t item_len = ((uint8_t*)data_in->items)[i]; + const uint8_t item_type = ((uint8_t*)data_in->items)[i + 1]; + if (item_type != type) { + i += (item_len + 1); + continue; + } + + *data_out = &((uint8_t*)data_in->items)[i + 2]; + + return item_len; + } + + return 0; +} + +STATIC mp_obj_t scanentry_get_name(mp_obj_t self_in); + +STATIC void bleio_scanentry_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_scanentry_obj_t *self = (bleio_scanentry_obj_t *)self_in; + mp_printf(print, "ScanEntry(address: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT"", + self->address.value[5], self->address.value[4], self->address.value[3], + self->address.value[1], self->address.value[1], self->address.value[0]); + + const mp_obj_t name_obj = scanentry_get_name(self_in); + if (name_obj != mp_const_none) { + mp_obj_str_t *str = MP_OBJ_TO_PTR(name_obj); + mp_printf(print, " name: %s", str->data); + } + + mp_print_str(print, ")"); +} + +STATIC mp_obj_t bleio_scanentry_get_address(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_obj_t obj = bleio_address_type.make_new(&bleio_address_type, 1, 0, (mp_obj_t)&mp_const_none_obj); + bleio_address_obj_t *address = MP_OBJ_TO_PTR(obj); + + address->type = self->address.type; + memcpy(address->value, self->address.value, BLEIO_ADDRESS_BYTES); + + return obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_address_obj, bleio_scanentry_get_address); + +const mp_obj_property_t bleio_scanentry_address_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bluepy_scanentry_get_address_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_manufacturer_specific_data(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); + uint8_t *manuf_data; + + const uint8_t manuf_data_len = find_data_item(data, AdManufacturerSpecificData, &manuf_data); + if (manuf_data_len == 0) { + return mp_const_none; + } + + return mp_obj_new_bytearray_by_ref(manuf_data_len, manuf_data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_manufacturer_specific_data_obj, scanentry_get_manufacturer_specific_data); + +const mp_obj_property_t bleio_scanentry_manufacturer_specific_data_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&scanentry_get_manufacturer_specific_data_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_name(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); + uint8_t *name; + + // Try for Complete but settle for Shortened + uint8_t name_len = find_data_item(data, AdCompleteLocalName, &name); + if (name_len == 0) { + name_len = find_data_item(data, AdShortenedLocalName, &name); + } + + if (name_len == 0) { + return mp_const_none; + } + + return mp_obj_new_str((const char*)name, name_len - 1, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_name_obj, scanentry_get_name); + +const mp_obj_property_t bleio_scanentry_name_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bluepy_scanentry_get_name_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_raw_data(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_obj_t entries = mp_obj_new_list(0, NULL); + + mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); + + uint16_t i = 0; + while (i < data->len) { + mp_obj_tuple_t *entry = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + + const uint8_t item_len = ((uint8_t*)data->items)[i]; + const uint8_t item_type = ((uint8_t*)data->items)[i + 1]; + + entry->items[0] = MP_OBJ_NEW_SMALL_INT(item_type); + entry->items[1] = mp_obj_new_bytearray(item_len - 1, &((uint8_t*)data->items)[i + 2]); + mp_obj_list_append(entries, MP_OBJ_FROM_PTR(entry)); + + i += (item_len + 1); + } + + return entries; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_raw_data_obj, scanentry_get_raw_data); + +const mp_obj_property_t bleio_scanentry_raw_data_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanentry_get_raw_data_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_rssi(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_int(self->rssi); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_rssi_obj, scanentry_get_rssi); + +const mp_obj_property_t bleio_scanentry_rssi_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bluepy_scanentry_get_rssi_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_service_uuids(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); + uint8_t *uuids; + + // Try for Complete but settle for Incomplete + uint8_t uuids_len = find_data_item(data, AdCompleteListOf16BitServiceClassUUIDs, &uuids); + if (uuids_len == 0) { + uuids_len = find_data_item(data, AdIncompleteListOf16BitServiceClassUUIDs, &uuids); + } + + mp_obj_t entries = mp_obj_new_list(0, NULL); + for (size_t i = 0; i < uuids_len / sizeof(uint16_t); ++i) { + const mp_obj_t uuid_int = mp_obj_new_int(uuids[sizeof(uint16_t) * i] | (uuids[sizeof(uint16_t) * i + 1] << 8)); + const mp_obj_t uuid_obj = bleio_uuid_type.make_new(&bleio_uuid_type, 1, 0, &uuid_int); + + mp_obj_list_append(entries, uuid_obj); + } + + // TODO: 32-bit UUIDs + // TODO: 128-bit UUIDs + + return entries; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_service_uuids_obj, scanentry_get_service_uuids); + +const mp_obj_property_t bleio_scanentry_service_uuids_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&scanentry_get_service_uuids_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanentry_get_tx_power_level(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); + uint8_t *tx_power; + + const uint8_t tx_power_len = find_data_item(data, AdTxPowerLevel, &tx_power); + if (tx_power_len == 0) { + return mp_const_none; + } + + return mp_obj_new_int((int8_t)(*tx_power)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_tx_power_level_obj, scanentry_get_tx_power_level); + +const mp_obj_property_t bleio_scanentry_tx_power_level_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&scanentry_get_tx_power_level_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_manufacturer_specific_data), MP_ROM_PTR(&bleio_scanentry_manufacturer_specific_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_scanentry_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_raw_data), MP_ROM_PTR(&bleio_scanentry_raw_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) }, + { MP_ROM_QSTR(MP_QSTR_service_uuids), MP_ROM_PTR(&bleio_scanentry_service_uuids_obj) }, + { MP_ROM_QSTR(MP_QSTR_tx_power_level), MP_ROM_PTR(&bleio_scanentry_tx_power_level_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table); + +const mp_obj_type_t bleio_scanentry_type = { + { &mp_type_type }, + .name = MP_QSTR_ScanEntry, + .print = bleio_scanentry_print, + .locals_dict = (mp_obj_dict_t*)&bleio_scanentry_locals_dict +}; diff --git a/shared-bindings/bleio/ScanEntry.h b/shared-bindings/bleio/ScanEntry.h new file mode 100644 index 000000000..4a201124e --- /dev/null +++ b/shared-bindings/bleio/ScanEntry.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H + +#include "shared-module/bleio/Address.h" +#include "py/objtype.h" + +typedef struct { + mp_obj_base_t base; + bleio_address_obj_t address; + bool connectable; + int8_t rssi; + mp_obj_t data; +} bleio_scanentry_obj_t; + +extern const mp_obj_type_t bleio_scanentry_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 570b71798..315b2c32c 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -29,7 +29,9 @@ #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/AddressType.h" +#include "shared-bindings/bleio/AdvertisementData.h" #include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/UUID.h" #include "shared-bindings/bleio/UUIDType.h" @@ -49,8 +51,10 @@ //| //| Address //| AddressType +//| AdvertisementData //| Adapter //| Descriptor +//| ScanEntry //| UUID //| UUIDType //| @@ -62,17 +66,19 @@ //| STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, - { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, - { MP_ROM_QSTR(MP_QSTR_AddressType), MP_ROM_PTR(&bleio_addresstype_type) }, - { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, - { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, + { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_AdvertisementData), MP_ROM_PTR(&bleio_advertisementdata_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, // Properties - { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, + { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, // Enum-like Classes. - { MP_ROM_QSTR(MP_QSTR_UUIDType), MP_ROM_PTR(&bleio_uuidtype_type) }, + { MP_ROM_QSTR(MP_QSTR_AddressType), MP_ROM_PTR(&bleio_addresstype_type) }, + { MP_ROM_QSTR(MP_QSTR_UUIDType), MP_ROM_PTR(&bleio_uuidtype_type) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); diff --git a/shared-module/bleio/AdvertisementData.h b/shared-module/bleio/AdvertisementData.h new file mode 100644 index 000000000..0ebc48ea7 --- /dev/null +++ b/shared-module/bleio/AdvertisementData.h @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H + +// Taken from https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile +enum { + AdFlags = 0x01, + AdIncompleteListOf16BitServiceClassUUIDs = 0x02, + AdCompleteListOf16BitServiceClassUUIDs = 0x03, + AdIncompleteListOf32BitServiceClassUUIDs = 0x04, + AdCompleteListOf32BitServiceClassUUIDs = 0x05, + AdIncompleteListOf128BitServiceClassUUIDs = 0x06, + AdCompleteListOf128BitServiceClassUUIDs = 0x07, + AdShortenedLocalName = 0x08, + AdCompleteLocalName = 0x09, + AdTxPowerLevel = 0x0A, + AdClassOfDevice = 0x0D, + AdSimplePairingHashC = 0x0E, + AdSimplePairingRandomizerR = 0x0F, + AdSecurityManagerTKValue = 0x10, + AdSecurityManagerOOBFlags = 0x11, + AdSlaveConnectionIntervalRange = 0x12, + AdListOf16BitServiceSolicitationUUIDs = 0x14, + AdListOf128BitServiceSolicitationUUIDs = 0x15, + AdServiceData = 0x16, + AdPublicTargetAddress = 0x17, + AdRandomTargetAddress = 0x18, + AdAppearance = 0x19, + AdAdvertisingInterval = 0x1A, + AdLEBluetoothDeviceAddress = 0x1B, + AdLERole = 0x1C, + AdSimplePairingHashC256 = 0x1D, + AdSimplePairingRandomizerR256 = 0x1E, + AdListOf32BitServiceSolicitationUUIDs = 0x1F, + AdServiceData32BitUUID = 0x20, + AdServiceData128BitUUID = 0x21, + AdLESecureConnectionsConfirmationValue = 0x22, + AdLESecureConnectionsRandomValue = 0x23, + AdURI = 0x24, + AdIndoorPositioning = 0x25, + AdTransportDiscoveryData = 0x26, + AdLESupportedFeatures = 0x27, + AdChannelMapUpdateIndication = 0x28, + AdPBADV = 0x29, + AdMeshMessage = 0x2A, + AdMeshBeacon = 0x2B, + Ad3DInformationData = 0x3D, + AdManufacturerSpecificData = 0xFF, +}; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H -- cgit v1.2.3 From 1c6bf9a15061d64ea097a024d73ad0a6da8f8e2b Mon Sep 17 00:00:00 2001 From: arturo182 Date: Wed, 18 Jul 2018 10:22:11 +0200 Subject: bleio: Move the Scanner class to a shared module --- ports/nrf/Makefile | 2 +- ports/nrf/common-hal/bleio/Scanner.c | 59 ++++++++++ ports/nrf/drivers/bluetooth/ble_drv.c | 19 ++-- ports/nrf/drivers/bluetooth/ble_drv.h | 8 +- ports/nrf/modules/ubluepy/modubluepy.c | 4 - ports/nrf/modules/ubluepy/modubluepy.h | 6 -- ports/nrf/modules/ubluepy/ubluepy_scanner.c | 118 -------------------- shared-bindings/bleio/ScanEntry.c | 4 +- shared-bindings/bleio/Scanner.c | 161 ++++++++++++++++++++++++++++ shared-bindings/bleio/Scanner.h | 38 +++++++ shared-bindings/bleio/__init__.c | 3 + shared-module/bleio/Scanner.h | 39 +++++++ 12 files changed, 317 insertions(+), 144 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Scanner.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_scanner.c create mode 100644 shared-bindings/bleio/Scanner.c create mode 100644 shared-bindings/bleio/Scanner.h create mode 100644 shared-module/bleio/Scanner.h (limited to 'shared-module') diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index c5e0df02f..3873f2cbc 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -134,7 +134,6 @@ DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/ubluepy_characteristic.c \ ubluepy/ubluepy_delegate.c \ ubluepy/ubluepy_constants.c \ - ubluepy/ubluepy_scanner.c \ ) SRC_COMMON_HAL += \ @@ -167,6 +166,7 @@ SRC_COMMON_HAL += \ bleio/__init__.c \ bleio/Adapter.c \ bleio/Descriptor.c \ + bleio/Scanner.c \ bleio/UUID.c endif diff --git a/ports/nrf/common-hal/bleio/Scanner.c b/ports/nrf/common-hal/bleio/Scanner.c new file mode 100644 index 000000000..ed1987144 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Scanner.c @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "ble_drv.h" +#include "py/mphal.h" +#include "shared-bindings/bleio/Scanner.h" +#include "shared-bindings/bleio/ScanEntry.h" + +STATIC void adv_event_handler(bleio_scanner_obj_t *self, ble_drv_adv_data_t *data) { + // TODO: Don't add new entry for each item, group by address and update + bleio_scanentry_obj_t *item = m_new_obj(bleio_scanentry_obj_t); + item->base.type = &bleio_scanentry_type; + + item->rssi = data->rssi; + item->data = mp_obj_new_bytearray(data->data_len, data->p_data); + + item->address.type = data->addr_type; + memcpy(item->address.value, data->p_peer_addr, BLEIO_ADDRESS_BYTES); + + mp_obj_list_append(self->adv_reports, item); + + ble_drv_scan_continue(); +} + +void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_int_t timeout) { + ble_drv_adv_report_handler_set(self, adv_event_handler); + + ble_drv_scan_start(self->interval, self->window); + + mp_hal_delay_ms(timeout); + + ble_drv_scan_stop(); +} diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index 766660828..1d67842ef 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -94,7 +94,7 @@ static volatile ble_drv_disc_add_service_callback_t disc_add_service_handler; static volatile ble_drv_disc_add_char_callback_t disc_add_char_handler; static volatile ble_drv_gattc_char_data_callback_t gattc_char_data_handle; -static mp_obj_t mp_adv_observer; +static bleio_scanner_obj_t *mp_adv_observer; static mp_obj_t mp_gattc_observer; static mp_obj_t mp_gattc_disc_service_observer; static mp_obj_t mp_gattc_disc_char_observer; @@ -707,8 +707,8 @@ void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t gattc_event_handler = evt_handler; } -void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler) { - mp_adv_observer = obj; +void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_callback_t evt_handler) { + mp_adv_observer = self; adv_event_handler = evt_handler; } @@ -760,15 +760,15 @@ void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, u ; } } -void ble_drv_scan_start(void) { +void ble_drv_scan_start(uint16_t interval, uint16_t window) { SD_TEST_OR_ENABLE(); ble_gap_scan_params_t scan_params; memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); scan_params.active = 1; - scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); - scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.interval = MSEC_TO_UNITS(interval, UNIT_0_625_MS); + scan_params.window = MSEC_TO_UNITS(window, UNIT_0_625_MS); #if (BLUETOOTH_SD == 140) scan_params.scan_phys = BLE_GAP_PHY_1MBPS; #endif @@ -1003,10 +1003,9 @@ static void ble_evt_handler(ble_evt_t * p_ble_evt) { #endif }; - // TODO: Fix unsafe callback to possible undefined callback... - adv_event_handler(mp_adv_observer, - p_ble_evt->header.evt_id, - &adv_data); + if (adv_event_handler != NULL) { + adv_event_handler(mp_adv_observer, &adv_data); + } break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index ca9a38fdd..d344e2690 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -32,6 +32,8 @@ #include #include +#include "shared-module/bleio/Scanner.h" + #include "modubluepy.h" typedef struct { @@ -67,7 +69,7 @@ typedef struct { typedef void (*ble_drv_gap_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data); typedef void (*ble_drv_gatts_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); typedef void (*ble_drv_gattc_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_adv_evt_callback_t)(mp_obj_t self, uint16_t event_id, ble_drv_adv_data_t * data); +typedef void (*ble_drv_adv_evt_callback_t)(bleio_scanner_obj_t *self, ble_drv_adv_data_t *data); typedef void (*ble_drv_disc_add_service_callback_t)(mp_obj_t self, ble_drv_service_data_t * p_service_data); typedef void (*ble_drv_disc_add_char_callback_t)(mp_obj_t self, ble_drv_char_data_t * p_desc_data); typedef void (*ble_drv_gattc_char_data_callback_t)(mp_obj_t self, uint16_t length, uint8_t * p_data); @@ -106,13 +108,13 @@ void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response); -void ble_drv_scan_start(void); +void ble_drv_scan_start(uint16_t interval, uint16_t window); void ble_drv_scan_continue(void); void ble_drv_scan_stop(void); -void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler); +void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_callback_t evt_handler); void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type); diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c index 034cc806c..e817983fa 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ b/ports/nrf/modules/ubluepy/modubluepy.c @@ -33,7 +33,6 @@ extern const mp_obj_type_t ubluepy_service_type; extern const mp_obj_type_t ubluepy_characteristic_type; extern const mp_obj_type_t ubluepy_delegate_type; extern const mp_obj_type_t ubluepy_constants_type; -extern const mp_obj_type_t ubluepy_scanner_type; STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluepy) }, @@ -42,9 +41,6 @@ STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { #endif #if 0 // MICROPY_PY_UBLUEPY_CENTRAL { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&ubluepy_central_type) }, -#endif -#if MICROPY_PY_UBLUEPY_CENTRAL - { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&ubluepy_scanner_type) }, #endif { MP_ROM_QSTR(MP_QSTR_DefaultDelegate), MP_ROM_PTR(&ubluepy_delegate_type) }, { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, diff --git a/ports/nrf/modules/ubluepy/modubluepy.h b/ports/nrf/modules/ubluepy/modubluepy.h index 8fb9fadd0..f51cc9e87 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ b/ports/nrf/modules/ubluepy/modubluepy.h @@ -77,7 +77,6 @@ p.advertise(device_name="micr", services=[s]) extern const mp_obj_type_t ubluepy_service_type; extern const mp_obj_type_t ubluepy_characteristic_type; extern const mp_obj_type_t ubluepy_peripheral_type; -extern const mp_obj_type_t ubluepy_scanner_type; extern const mp_obj_type_t ubluepy_constants_type; extern const mp_obj_type_t ubluepy_constants_ad_types_type; @@ -147,11 +146,6 @@ typedef struct _ubluepy_advertise_data_t { bool connectable; } ubluepy_advertise_data_t; -typedef struct _ubluepy_scanner_obj_t { - mp_obj_base_t base; - mp_obj_t adv_reports; -} ubluepy_scanner_obj_t; - typedef enum _ubluepy_prop_t { UBLUEPY_PROP_BROADCAST = 0x01, UBLUEPY_PROP_READ = 0x02, diff --git a/ports/nrf/modules/ubluepy/ubluepy_scanner.c b/ports/nrf/modules/ubluepy/ubluepy_scanner.c deleted file mode 100644 index 9d15037a5..000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_scanner.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include "py/obj.h" -#include "py/runtime.h" -#include "py/objstr.h" -#include "py/objlist.h" -#include "py/mphal.h" - -#if MICROPY_PY_UBLUEPY_CENTRAL - -#include "shared-bindings/bleio/ScanEntry.h" -#include "ble_drv.h" - -STATIC void adv_event_handler(mp_obj_t self_in, uint16_t event_id, ble_drv_adv_data_t * data) { - ubluepy_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - // TODO: Don't add new entry for each item, group by address and update - bleio_scanentry_obj_t *item = m_new_obj(bleio_scanentry_obj_t); - item->base.type = &bleio_scanentry_type; - - item->rssi = data->rssi; - item->data = mp_obj_new_bytearray(data->data_len, data->p_data); - - item->address.type = data->addr_type; - memcpy(item->address.value, data->p_peer_addr, BLEIO_ADDRESS_BYTES); - - mp_obj_list_append(self->adv_reports, item); - - ble_drv_scan_continue(); -} - -STATIC void ubluepy_scanner_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_scanner_obj_t * self = (ubluepy_scanner_obj_t *)o; - (void)self; - mp_printf(print, "Scanner"); -} - -STATIC mp_obj_t ubluepy_scanner_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - static const mp_arg_t allowed_args[] = { - - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - ubluepy_scanner_obj_t * s = m_new_obj(ubluepy_scanner_obj_t); - s->base.type = type; - - return MP_OBJ_FROM_PTR(s); -} - -/// \method scan(timeout) -/// Scan for devices. Timeout is in milliseconds and will set the duration -/// of the scanning. -/// -STATIC mp_obj_t scanner_scan(mp_obj_t self_in, mp_obj_t timeout_in) { - ubluepy_scanner_obj_t * self = MP_OBJ_TO_PTR(self_in); - mp_int_t timeout = mp_obj_get_int(timeout_in); - - self->adv_reports = mp_obj_new_list(0, NULL); - - ble_drv_adv_report_handler_set(MP_OBJ_FROM_PTR(self), adv_event_handler); - - // start - ble_drv_scan_start(); - - // sleep - mp_hal_delay_ms(timeout); - - // stop - ble_drv_scan_stop(); - - return self->adv_reports; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_scanner_scan_obj, scanner_scan); - -STATIC const mp_rom_map_elem_t ubluepy_scanner_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&ubluepy_scanner_scan_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_scanner_locals_dict, ubluepy_scanner_locals_dict_table); - - -const mp_obj_type_t ubluepy_scanner_type = { - { &mp_type_type }, - .name = MP_QSTR_Scanner, - .print = ubluepy_scanner_print, - .make_new = ubluepy_scanner_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_scanner_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY_CENTRAL diff --git a/shared-bindings/bleio/ScanEntry.c b/shared-bindings/bleio/ScanEntry.c index f41665581..e38a08909 100644 --- a/shared-bindings/bleio/ScanEntry.c +++ b/shared-bindings/bleio/ScanEntry.c @@ -48,7 +48,7 @@ //| .. attribute:: address //| //| The address of the device. (read-only) -//| This attribute is of type `bleio:Address`. +//| This attribute is of type `bleio.Address`. //| //| .. attribute:: manufacturer_specific_data @@ -75,7 +75,7 @@ //| .. attribute:: service_uuids //| //| The address of the device. (read-only) -//| This attribute is a list of `bleio:UUID`. +//| This attribute is a list of `bleio.UUID`. //| This attribute might be empty or incomplete, depending on the advertisement packet. //| Currently only 16-bit UUIDS are listed. //| diff --git a/shared-bindings/bleio/Scanner.c b/shared-bindings/bleio/Scanner.c new file mode 100644 index 000000000..00e29d9d5 --- /dev/null +++ b/shared-bindings/bleio/Scanner.c @@ -0,0 +1,161 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objproperty.h" +#include "shared-bindings/bleio/ScanEntry.h" +#include "shared-bindings/bleio/Scanner.h" + +#define DEFAULT_INTERVAL 100 +#define DEFAULT_WINDOW 100 + +//| .. currentmodule:: bleio +//| +//| :class:`Scanner` -- scan for nearby BLE devices +//| ========================================================= +//| +//| Allows scanning for nearby BLE devices. +//| +//| Usage:: +//| +//| import bleio +//| scanner = bleio.Scanner() +//| entries = scanner.scan(2500) +//| print(entries) +//| + +//| .. class:: Scanner() +//| +//| Create a new Scanner object. +//| + +//| .. attribute:: interval +//| +//| The interval (in ms) between the start of two consecutive scan windows. +//| Allowed values are between 10ms and 10.24 sec. +//| + +//| .. attribute:: window +//| +//| The duration (in ms) in which a single BLE channel is scanned. +//| Allowed values are between 10ms and 10.24 sec. +//| + +//| .. method:: scan(timeout) +//| +//| Performs a BLE scan lasting :py:data:`timeout` ms. +//| +//| :returns: advertising packets found +//| :rtype: list of :py:class:`bleio.ScanEntry` +//| +STATIC void bleio_scanner_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_printf(print, "Scanner(interval: %d window: %d)", self->interval, self->window); +} + +STATIC mp_obj_t bleio_scanner_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + bleio_scanner_obj_t *self = m_new_obj(bleio_scanner_obj_t); + self->base.type = type; + + self->interval = DEFAULT_INTERVAL; + self->window = DEFAULT_WINDOW; + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t bleio_scanner_get_interval(mp_obj_t self_in) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_int(self->interval); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanner_get_interval_obj, bleio_scanner_get_interval); + +static mp_obj_t bleio_scanner_set_interval(mp_obj_t self_in, mp_obj_t value) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->interval = mp_obj_get_int(value); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_set_interval_obj, bleio_scanner_set_interval); + +const mp_obj_property_t bleio_scanner_interval_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanner_get_interval_obj, + (mp_obj_t)&bleio_scanner_set_interval_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t scanner_scan(mp_obj_t self_in, mp_obj_t timeout_in) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + const mp_int_t timeout = mp_obj_get_int(timeout_in); + + self->adv_reports = mp_obj_new_list(0, NULL); + + common_hal_bleio_scanner_scan(self, timeout); + + return self->adv_reports; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_scan_obj, scanner_scan); + +STATIC mp_obj_t bleio_scanner_get_window(mp_obj_t self_in) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_int(self->window); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanner_get_window_obj, bleio_scanner_get_window); + +static mp_obj_t bleio_scanner_set_window(mp_obj_t self_in, mp_obj_t value) { + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->window = mp_obj_get_int(value); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_set_window_obj, bleio_scanner_set_window); + +const mp_obj_property_t bleio_scanner_window_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanner_get_window_obj, + (mp_obj_t)&bleio_scanner_set_window_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_scanner_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_interval), MP_ROM_PTR(&bleio_scanner_interval_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bleio_scanner_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_window), MP_ROM_PTR(&bleio_scanner_window_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict_table); + +const mp_obj_type_t bleio_scanner_type = { + { &mp_type_type }, + .name = MP_QSTR_Scanner, + .print = bleio_scanner_print, + .make_new = bleio_scanner_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_scanner_locals_dict +}; diff --git a/shared-bindings/bleio/Scanner.h b/shared-bindings/bleio/Scanner.h new file mode 100644 index 000000000..03db5cd8b --- /dev/null +++ b/shared-bindings/bleio/Scanner.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H + +#include "py/objtype.h" +#include "shared-module/bleio/Scanner.h" + +extern const mp_obj_type_t bleio_scanner_type; + +extern void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_int_t timeout); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 315b2c32c..4ad858ac9 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -32,6 +32,7 @@ #include "shared-bindings/bleio/AdvertisementData.h" #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/ScanEntry.h" +#include "shared-bindings/bleio/Scanner.h" #include "shared-bindings/bleio/UUID.h" #include "shared-bindings/bleio/UUIDType.h" @@ -55,6 +56,7 @@ //| Adapter //| Descriptor //| ScanEntry +//| Scanner //| UUID //| UUIDType //| @@ -71,6 +73,7 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_AdvertisementData), MP_ROM_PTR(&bleio_advertisementdata_type) }, { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, // Properties diff --git a/shared-module/bleio/Scanner.h b/shared-module/bleio/Scanner.h new file mode 100644 index 000000000..f1159adfe --- /dev/null +++ b/shared-module/bleio/Scanner.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t adv_reports; + uint16_t interval; + uint16_t window; +} bleio_scanner_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H -- cgit v1.2.3 From fb422ccf5e4dcf644a4c99fe4843af2838a23907 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Wed, 18 Jul 2018 10:47:58 +0200 Subject: bleio: Remove SAMD mention in include guard Damn copy-paste! --- shared-module/bleio/Address.h | 6 +++--- shared-module/bleio/AdvertisementData.h | 6 +++--- shared-module/bleio/Scanner.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'shared-module') diff --git a/shared-module/bleio/Address.h b/shared-module/bleio/Address.h index a520b8dd6..f0998c163 100644 --- a/shared-module/bleio/Address.h +++ b/shared-module/bleio/Address.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H #include "shared-bindings/bleio/AddressType.h" @@ -37,4 +37,4 @@ typedef struct { uint8_t value[BLEIO_ADDRESS_BYTES]; } bleio_address_obj_t; -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADDRESS_H +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H diff --git a/shared-module/bleio/AdvertisementData.h b/shared-module/bleio/AdvertisementData.h index 0ebc48ea7..2a9addf57 100644 --- a/shared-module/bleio/AdvertisementData.h +++ b/shared-module/bleio/AdvertisementData.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H // Taken from https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile enum { @@ -73,4 +73,4 @@ enum { AdManufacturerSpecificData = 0xFF, }; -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H diff --git a/shared-module/bleio/Scanner.h b/shared-module/bleio/Scanner.h index f1159adfe..76f5e5866 100644 --- a/shared-module/bleio/Scanner.h +++ b/shared-module/bleio/Scanner.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANNER_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANNER_H #include "py/obj.h" @@ -36,4 +36,4 @@ typedef struct { uint16_t window; } bleio_scanner_obj_t; -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BLEIO_SCANNER_H +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANNER_H -- cgit v1.2.3 From cc782492269f2311995269507ff1411d3bbb8a2f Mon Sep 17 00:00:00 2001 From: arturo182 Date: Wed, 18 Jul 2018 23:47:06 +0200 Subject: nrf: Move the Characteristic class from ubluepy to the shared bleio module --- ports/nrf/Makefile | 2 +- ports/nrf/common-hal/bleio/Characteristic.c | 53 ++++ ports/nrf/common-hal/bleio/UUID.h | 1 - ports/nrf/drivers/bluetooth/ble_drv.c | 151 +++++----- ports/nrf/drivers/bluetooth/ble_drv.h | 22 +- ports/nrf/modules/ubluepy/modubluepy.c | 2 - ports/nrf/modules/ubluepy/modubluepy.h | 15 - ports/nrf/modules/ubluepy/ubluepy_characteristic.c | 224 -------------- ports/nrf/modules/ubluepy/ubluepy_peripheral.c | 18 +- ports/nrf/modules/ubluepy/ubluepy_service.c | 11 +- shared-bindings/bleio/Characteristic.c | 330 +++++++++++++++++++++ shared-bindings/bleio/Characteristic.h | 37 +++ shared-bindings/bleio/__init__.c | 3 + shared-module/bleio/Characteristic.h | 52 ++++ 14 files changed, 578 insertions(+), 343 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Characteristic.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_characteristic.c create mode 100644 shared-bindings/bleio/Characteristic.c create mode 100644 shared-bindings/bleio/Characteristic.h create mode 100644 shared-module/bleio/Characteristic.h (limited to 'shared-module') diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 8a4454a0a..6ed2d3054 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -131,7 +131,6 @@ DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/modubluepy.c \ ubluepy/ubluepy_peripheral.c \ ubluepy/ubluepy_service.c \ - ubluepy/ubluepy_characteristic.c \ ) SRC_COMMON_HAL += \ @@ -163,6 +162,7 @@ ifneq ($(SD), ) SRC_COMMON_HAL += \ bleio/__init__.c \ bleio/Adapter.c \ + bleio/Characteristic.c \ bleio/Descriptor.c \ bleio/Scanner.c \ bleio/UUID.c diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c new file mode 100644 index 000000000..3087b6707 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "ble_drv.h" +#include "shared-module/bleio/Characteristic.h" + +void data_callback(bleio_characteristic_obj_t *self, uint16_t length, uint8_t *data) { + self->value_data = mp_obj_new_bytearray(length, data); +} + +void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self) { + ble_drv_attr_c_read(self, data_callback); +} + +void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(self->service); + ubluepy_role_type_t role = service->p_periph->role; + + if (role == UBLUEPY_ROLE_PERIPHERAL) { + // TODO: Add indications + if (self->props.notify) { + ble_drv_attr_s_notify(self, bufinfo); + } else { + ble_drv_attr_s_write(self, bufinfo); + } + } else { + ble_drv_attr_c_write(self, bufinfo); + } + +} diff --git a/ports/nrf/common-hal/bleio/UUID.h b/ports/nrf/common-hal/bleio/UUID.h index b919fec28..cb0fddcfd 100644 --- a/ports/nrf/common-hal/bleio/UUID.h +++ b/ports/nrf/common-hal/bleio/UUID.h @@ -28,7 +28,6 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H -#include "py/obj.h" #include "shared-bindings/bleio/UUIDType.h" typedef struct { diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index 1d67842ef..6240a18e4 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -98,7 +98,7 @@ static bleio_scanner_obj_t *mp_adv_observer; static mp_obj_t mp_gattc_observer; static mp_obj_t mp_gattc_disc_service_observer; static mp_obj_t mp_gattc_disc_char_observer; -static mp_obj_t mp_gattc_char_data_observer; +static bleio_characteristic_obj_t *mp_gattc_char_data_observer; #if (BLUETOOTH_SD == 140) static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; @@ -270,38 +270,26 @@ bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) { bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj) { SD_TEST_OR_ENABLE(); - if (p_service_obj->p_uuid->type > BLE_UUID_TYPE_BLE) { + ble_uuid_t uuid; + uuid.type = BLE_UUID_TYPE_BLE; + uuid.uuid = p_service_obj->p_uuid->value[0] | (p_service_obj->p_uuid->value[1] << 8); - ble_uuid_t uuid; + if (p_service_obj->p_uuid->type == UUID_TYPE_128BIT) { uuid.type = p_service_obj->p_uuid->uuid_vs_idx; - uuid.uuid = p_service_obj->p_uuid->value[0]; - uuid.uuid += p_service_obj->p_uuid->value[1] << 8; - - if (sd_ble_gatts_service_add(p_service_obj->type, - &uuid, - &p_service_obj->handle) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Service."))); - } - } else if (p_service_obj->p_uuid->type == BLE_UUID_TYPE_BLE) { - BLE_DRIVER_LOG("adding service\n"); - - ble_uuid_t uuid; - uuid.type = p_service_obj->p_uuid->type; - uuid.uuid = p_service_obj->p_uuid->value[0]; - uuid.uuid += p_service_obj->p_uuid->value[1] << 8; + } - if (sd_ble_gatts_service_add(p_service_obj->type, - &uuid, - &p_service_obj->handle) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Service."))); - } + uint32_t err_code = sd_ble_gatts_service_add(p_service_obj->type, + &uuid, + &p_service_obj->handle); + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + translate("Can not add Service. status: 0x%08lX"), err_code)); } + return true; } -bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { +bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic) { ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; @@ -310,24 +298,19 @@ bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { memset(&char_md, 0, sizeof(char_md)); - char_md.char_props.broadcast = (p_char_obj->props & UBLUEPY_PROP_BROADCAST) ? 1 : 0; - char_md.char_props.read = (p_char_obj->props & UBLUEPY_PROP_READ) ? 1 : 0; - char_md.char_props.write_wo_resp = (p_char_obj->props & UBLUEPY_PROP_WRITE_WO_RESP) ? 1 : 0; - char_md.char_props.write = (p_char_obj->props & UBLUEPY_PROP_WRITE) ? 1 : 0; - char_md.char_props.notify = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0; - char_md.char_props.indicate = (p_char_obj->props & UBLUEPY_PROP_INDICATE) ? 1 : 0; -#if 0 - char_md.char_props.auth_signed_wr = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0; -#endif - + char_md.char_props.broadcast = characteristic->props.broadcast; + char_md.char_props.read = characteristic->props.read; + char_md.char_props.write_wo_resp = characteristic->props.write_wo_resp; + char_md.char_props.write = characteristic->props.write; + char_md.char_props.notify = characteristic->props.notify; + char_md.char_props.indicate = characteristic->props.indicate; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_sccd_md = NULL; - // if cccd - if (p_char_obj->attrs & UBLUEPY_ATTR_CCCD) { + if (characteristic->props.notify || characteristic->props.notify) { memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); @@ -337,9 +320,12 @@ bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { char_md.p_cccd_md = NULL; } - uuid.type = p_char_obj->p_uuid->type; - uuid.uuid = p_char_obj->p_uuid->value[0]; - uuid.uuid += p_char_obj->p_uuid->value[1] << 8; + uuid.type = BLE_UUID_TYPE_BLE; + if (characteristic->uuid->type == UUID_TYPE_128BIT) + uuid.type = characteristic->uuid->uuid_vs_idx; + + uuid.uuid = characteristic->uuid->value[0]; + uuid.uuid += characteristic->uuid->value[1] << 8; memset(&attr_md, 0, sizeof(attr_md)); @@ -365,19 +351,20 @@ bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { ble_gatts_char_handles_t handles; - if (sd_ble_gatts_characteristic_add(p_char_obj->service_handle, - &char_md, - &attr_char_value, - &handles) != 0) { + uint32_t err_code = sd_ble_gatts_characteristic_add(characteristic->service_handle, + &char_md, + &attr_char_value, + &handles); + if (err_code != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Characteristic."))); + translate("Can not add Characteristic. status: 0x%08lX"), err_code)); } // apply handles to object instance - p_char_obj->handle = handles.value_handle; - p_char_obj->user_desc_handle = handles.user_desc_handle; - p_char_obj->cccd_handle = handles.cccd_handle; - p_char_obj->sccd_handle = handles.sccd_handle; + characteristic->handle = handles.value_handle; + characteristic->user_desc_handle = handles.user_desc_handle; + characteristic->cccd_handle = handles.cccd_handle; + characteristic->sccd_handle = handles.sccd_handle; return true; } @@ -652,15 +639,18 @@ void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, ui } -void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { +void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); + uint16_t conn_handle = service->p_periph->conn_handle; ble_gatts_value_t gatts_value; + memset(&gatts_value, 0, sizeof(gatts_value)); - gatts_value.len = len; + gatts_value.len = bufinfo->len; gatts_value.offset = 0; - gatts_value.p_value = p_data; + gatts_value.p_value = bufinfo->buf; - uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value); + uint32_t err_code = sd_ble_gatts_value_set(conn_handle, characteristic->handle, &gatts_value); if (err_code != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, @@ -668,17 +658,19 @@ void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, u } } -void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { - uint16_t hvx_len = len; +void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); + uint16_t conn_handle = service->p_periph->conn_handle; ble_gatts_hvx_params_t hvx_params; + uint16_t hvx_len = bufinfo->len; memset(&hvx_params, 0, sizeof(hvx_params)); - hvx_params.handle = handle; + hvx_params.handle = characteristic->handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &hvx_len; - hvx_params.p_data = p_data; + hvx_params.p_data = bufinfo->buf; while (m_tx_in_progress) { ; @@ -713,13 +705,13 @@ void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_c } -void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, ble_drv_gattc_char_data_callback_t cb) { - - mp_gattc_char_data_observer = obj; +void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic, ble_drv_gattc_char_data_callback_t cb) { + ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); + mp_gattc_char_data_observer = characteristic; gattc_char_data_handle = cb; - uint32_t err_code = sd_ble_gattc_read(conn_handle, - handle, + const uint32_t err_code = sd_ble_gattc_read(service->p_periph->conn_handle, + characteristic->handle, 0); if (err_code != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, @@ -731,26 +723,26 @@ void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, bl } } -void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response) { +void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); + uint16_t conn_handle = service->p_periph->conn_handle; ble_gattc_write_params_t write_params; + write_params.write_op = BLE_GATT_OP_WRITE_REQ; - if (w_response) { - write_params.write_op = BLE_GATT_OP_WRITE_REQ; - } else { + if (characteristic->props.write_wo_resp) { write_params.write_op = BLE_GATT_OP_WRITE_CMD; } write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL; - write_params.handle = handle; + write_params.handle = characteristic->handle; write_params.offset = 0; - write_params.len = len; - write_params.p_value = p_data; + write_params.len = bufinfo->len; + write_params.p_value = bufinfo->buf; - m_write_done = !w_response; + m_write_done = (write_params.write_op == BLE_GATT_OP_WRITE_CMD); uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not write attribute value. status: 0x%02x"), (uint16_t)err_code)); @@ -1053,15 +1045,12 @@ static void ble_evt_handler(ble_evt_t * p_ble_evt) { char_data.decl_handle = p_char->handle_decl; char_data.value_handle = p_char->handle_value; - char_data.props |= (p_char->char_props.broadcast) ? UBLUEPY_PROP_BROADCAST : 0; - char_data.props |= (p_char->char_props.read) ? UBLUEPY_PROP_READ : 0; - char_data.props |= (p_char->char_props.write_wo_resp) ? UBLUEPY_PROP_WRITE_WO_RESP : 0; - char_data.props |= (p_char->char_props.write) ? UBLUEPY_PROP_WRITE : 0; - char_data.props |= (p_char->char_props.notify) ? UBLUEPY_PROP_NOTIFY : 0; - char_data.props |= (p_char->char_props.indicate) ? UBLUEPY_PROP_INDICATE : 0; - #if 0 - char_data.props |= (p_char->char_props.auth_signed_wr) ? UBLUEPY_PROP_NOTIFY : 0; - #endif + char_data.props.broadcast = p_char->char_props.broadcast; + char_data.props.read = p_char->char_props.read; + char_data.props.write_wo_resp = p_char->char_props.write_wo_resp; + char_data.props.write = p_char->char_props.write; + char_data.props.notify = p_char->char_props.notify; + char_data.props.indicate = p_char->char_props.indicate; disc_add_char_handler(mp_gattc_disc_char_observer, &char_data); } diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index d344e2690..7283dbfce 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -32,6 +32,7 @@ #include #include +#include "shared-module/bleio/Characteristic.h" #include "shared-module/bleio/Scanner.h" #include "modubluepy.h" @@ -61,7 +62,14 @@ typedef struct { typedef struct { uint16_t uuid; uint8_t uuid_type; - uint8_t props; + struct { + bool broadcast : 1; + bool read : 1; + bool write_wo_resp : 1; + bool write : 1; + bool notify : 1; + bool indicate : 1; + } props; uint16_t decl_handle; uint16_t value_handle; } ble_drv_char_data_t; @@ -72,7 +80,7 @@ typedef void (*ble_drv_gattc_evt_callback_t)(mp_obj_t self, uint16_t event_id, u typedef void (*ble_drv_adv_evt_callback_t)(bleio_scanner_obj_t *self, ble_drv_adv_data_t *data); typedef void (*ble_drv_disc_add_service_callback_t)(mp_obj_t self, ble_drv_service_data_t * p_service_data); typedef void (*ble_drv_disc_add_char_callback_t)(mp_obj_t self, ble_drv_char_data_t * p_desc_data); -typedef void (*ble_drv_gattc_char_data_callback_t)(mp_obj_t self, uint16_t length, uint8_t * p_data); +typedef void (*ble_drv_gattc_char_data_callback_t)(bleio_characteristic_obj_t *self, uint16_t length, uint8_t * p_data); uint32_t ble_drv_stack_enable(void); @@ -86,7 +94,7 @@ bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx); bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj); -bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj); +bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic); bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params); @@ -100,13 +108,13 @@ void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); -void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, ble_drv_gattc_char_data_callback_t cb); +void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic, ble_drv_gattc_char_data_callback_t cb); -void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); +void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); -void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); +void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); -void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response); +void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); void ble_drv_scan_start(uint16_t interval, uint16_t window); diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c index 1470f4a37..2d1a6a550 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ b/ports/nrf/modules/ubluepy/modubluepy.c @@ -30,7 +30,6 @@ extern const mp_obj_type_t ubluepy_peripheral_type; extern const mp_obj_type_t ubluepy_service_type; -extern const mp_obj_type_t ubluepy_characteristic_type; STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluepy) }, @@ -38,7 +37,6 @@ STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&ubluepy_peripheral_type) }, #endif { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&ubluepy_characteristic_type) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_ubluepy_globals, mp_module_ubluepy_globals_table); diff --git a/ports/nrf/modules/ubluepy/modubluepy.h b/ports/nrf/modules/ubluepy/modubluepy.h index 5d80e3536..ad33001cb 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ b/ports/nrf/modules/ubluepy/modubluepy.h @@ -75,7 +75,6 @@ p.advertise(device_name="micr", services=[s]) #include "py/obj.h" extern const mp_obj_type_t ubluepy_service_type; -extern const mp_obj_type_t ubluepy_characteristic_type; extern const mp_obj_type_t ubluepy_peripheral_type; typedef enum { @@ -116,20 +115,6 @@ typedef struct _ubluepy_service_obj_t { uint16_t end_handle; } ubluepy_service_obj_t; -typedef struct _ubluepy_characteristic_obj_t { - mp_obj_base_t base; - uint16_t handle; - bleio_uuid_obj_t * p_uuid; - uint16_t service_handle; - uint16_t user_desc_handle; - uint16_t cccd_handle; - uint16_t sccd_handle; - uint8_t props; - uint8_t attrs; - ubluepy_service_obj_t * p_service; - mp_obj_t value_data; -} ubluepy_characteristic_obj_t; - typedef struct _ubluepy_advertise_data_t { uint8_t * p_device_name; uint8_t device_name_len; diff --git a/ports/nrf/modules/ubluepy/ubluepy_characteristic.c b/ports/nrf/modules/ubluepy/ubluepy_characteristic.c deleted file mode 100644 index e0259fb06..000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_characteristic.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/obj.h" -#include "py/runtime.h" -#include "supervisor/shared/translate.h" - -#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL - -#include "modubluepy.h" -#include "ble_drv.h" -#include "shared-bindings/bleio/UUID.h" - -STATIC void ubluepy_characteristic_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_characteristic_obj_t * self = (ubluepy_characteristic_obj_t *)o; - - mp_printf(print, "Characteristic(handle: 0x" HEX2_FMT ", conn_handle: " HEX2_FMT ")", - self->handle, self->p_service->p_periph->conn_handle); -} - -STATIC mp_obj_t ubluepy_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_uuid, MP_ARG_REQUIRED| MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_props, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UBLUEPY_PROP_READ | UBLUEPY_PROP_WRITE} }, - { MP_QSTR_attrs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - ubluepy_characteristic_obj_t *s = m_new_obj(ubluepy_characteristic_obj_t); - s->base.type = type; - - mp_obj_t uuid_obj = args[0].u_obj; - - if (uuid_obj == mp_const_none) { - return MP_OBJ_FROM_PTR(s); - } - - if (MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); - // (void)sd_characterstic_add(s); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Invalid UUID parameter"))); - } - - if (args[1].u_int > 0) { - s->props = (uint8_t)args[1].u_int; - } - - if (args[2].u_int > 0) { - s->attrs = (uint8_t)args[2].u_int; - } - - // clear pointer to service - s->p_service = NULL; - - // clear pointer to char value data - s->value_data = NULL; - - return MP_OBJ_FROM_PTR(s); -} - -void char_data_callback(mp_obj_t self_in, uint16_t length, uint8_t * p_data) { - ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); - self->value_data = mp_obj_new_bytearray(length, p_data); -} - -/// \method read() -/// Read Characteristic value. -/// -STATIC mp_obj_t char_read(mp_obj_t self_in) { - ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); - -#if MICROPY_PY_UBLUEPY_CENTRAL - // TODO: free any previous allocation of value_data - - ble_drv_attr_c_read(self->p_service->p_periph->conn_handle, - self->handle, - self_in, - char_data_callback); - - return self->value_data; -#else - (void)self; - return mp_const_none; -#endif -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_read_obj, char_read); - -/// \method write(data, [with_response=False]) -/// Write Characteristic value. -/// -STATIC mp_obj_t char_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - ubluepy_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_obj_t data = pos_args[1]; - - static const mp_arg_t allowed_args[] = { - { MP_QSTR_with_response, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false } }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); - - // figure out mode of the Peripheral - ubluepy_role_type_t role = self->p_service->p_periph->role; - - if (role == UBLUEPY_ROLE_PERIPHERAL) { - if (self->props & UBLUEPY_PROP_NOTIFY) { - ble_drv_attr_s_notify(self->p_service->p_periph->conn_handle, - self->handle, - bufinfo.len, - bufinfo.buf); - } else { - ble_drv_attr_s_write(self->p_service->p_periph->conn_handle, - self->handle, - bufinfo.len, - bufinfo.buf); - } - } else { -#if MICROPY_PY_UBLUEPY_CENTRAL - bool with_response = args[0].u_bool; - - ble_drv_attr_c_write(self->p_service->p_periph->conn_handle, - self->handle, - bufinfo.len, - bufinfo.buf, - with_response); -#endif - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_characteristic_write_obj, 2, char_write); - -/// \method properties() -/// Read Characteristic value properties. -/// -STATIC mp_obj_t char_properties(mp_obj_t self_in) { - ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(self->props); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_get_properties_obj, char_properties); - -/// \method uuid() -/// Get UUID instance of the characteristic. -/// -STATIC mp_obj_t char_uuid(mp_obj_t self_in) { - ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->p_uuid); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_get_uuid_obj, char_uuid); - - -STATIC const mp_rom_map_elem_t ubluepy_characteristic_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&ubluepy_characteristic_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&ubluepy_characteristic_write_obj) }, -#if 0 - { MP_ROM_QSTR(MP_QSTR_supportsRead), MP_ROM_PTR(&ubluepy_characteristic_supports_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_propertiesToString), MP_ROM_PTR(&ubluepy_characteristic_properties_to_str_obj) }, - { MP_ROM_QSTR(MP_QSTR_getHandle), MP_ROM_PTR(&ubluepy_characteristic_get_handle_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_characteristic_get_peripheral_obj) }, -#endif - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_characteristic_get_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&ubluepy_characteristic_get_properties_obj) }, - - { MP_ROM_QSTR(MP_QSTR_PROP_BROADCAST), MP_ROM_INT(UBLUEPY_PROP_BROADCAST) }, - { MP_ROM_QSTR(MP_QSTR_PROP_READ), MP_ROM_INT(UBLUEPY_PROP_READ) }, - { MP_ROM_QSTR(MP_QSTR_PROP_WRITE_WO_RESP), MP_ROM_INT(UBLUEPY_PROP_WRITE_WO_RESP) }, - { MP_ROM_QSTR(MP_QSTR_PROP_WRITE), MP_ROM_INT(UBLUEPY_PROP_WRITE) }, - { MP_ROM_QSTR(MP_QSTR_PROP_NOTIFY), MP_ROM_INT(UBLUEPY_PROP_NOTIFY) }, - { MP_ROM_QSTR(MP_QSTR_PROP_INDICATE), MP_ROM_INT(UBLUEPY_PROP_INDICATE) }, - { MP_ROM_QSTR(MP_QSTR_PROP_AUTH_SIGNED_WR), MP_ROM_INT(UBLUEPY_PROP_AUTH_SIGNED_WR) }, - -#if MICROPY_PY_UBLUEPY_PERIPHERAL - { MP_ROM_QSTR(MP_QSTR_ATTR_CCCD), MP_ROM_INT(UBLUEPY_ATTR_CCCD) }, -#endif - -#if MICROPY_PY_UBLUEPY_CENTRAL - { MP_ROM_QSTR(MP_QSTR_PROP_AUTH_SIGNED_WR), MP_ROM_INT(UBLUEPY_ATTR_SCCD) }, -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_characteristic_locals_dict, ubluepy_characteristic_locals_dict_table); - -const mp_obj_type_t ubluepy_characteristic_type = { - { &mp_type_type }, - .name = MP_QSTR_Characteristic, - .print = ubluepy_characteristic_print, - .make_new = ubluepy_characteristic_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_characteristic_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c index 6fced1695..2a826db4d 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c @@ -34,6 +34,7 @@ #include "ble_drv.h" #include "common-hal/bleio/UUID.h" +#include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/UUID.h" STATIC void ubluepy_peripheral_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { @@ -316,26 +317,31 @@ void static disc_add_service(mp_obj_t self, ble_drv_service_data_t * p_service_d void static disc_add_char(mp_obj_t service_in, ble_drv_char_data_t * p_desc_data) { ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service_in); - ubluepy_characteristic_obj_t * p_char = m_new_obj(ubluepy_characteristic_obj_t); - p_char->base.type = &ubluepy_characteristic_type; + bleio_characteristic_obj_t * p_char = m_new_obj(bleio_characteristic_obj_t); + p_char->base.type = &bleio_characteristic_type; bleio_uuid_obj_t * p_uuid = m_new_obj(bleio_uuid_obj_t); p_uuid->base.type = &bleio_uuid_type; - p_char->p_uuid = p_uuid; + p_char->uuid = p_uuid; p_uuid->type = p_desc_data->uuid_type; p_uuid->value[0] = p_desc_data->uuid & 0xFF; p_uuid->value[1] = p_desc_data->uuid >> 8; // add characteristic specific data from discovery - p_char->props = p_desc_data->props; + p_char->props.broadcast = p_desc_data->props.broadcast; + p_char->props.indicate = p_desc_data->props.indicate; + p_char->props.notify = p_desc_data->props.notify; + p_char->props.read = p_desc_data->props.read; + p_char->props.write = p_desc_data->props.write; + p_char->props.write_wo_resp = p_desc_data->props.write_wo_resp; p_char->handle = p_desc_data->value_handle; // equivalent to ubluepy_service.c - service_add_characteristic() // except the registration of the characteristic towards the bluetooth stack p_char->service_handle = p_service->handle; - p_char->p_service = p_service; + p_char->service = p_service; mp_obj_list_append(p_service->char_list, MP_OBJ_FROM_PTR(p_char)); } @@ -430,7 +436,7 @@ STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, m mp_uint_t num_chars; mp_obj_get_array(p_service->char_list, &num_chars, &characteristics); - ubluepy_characteristic_obj_t * p_char = (ubluepy_characteristic_obj_t *)characteristics[num_chars - 1]; + bleio_characteristic_obj_t * p_char = (bleio_characteristic_obj_t *)characteristics[num_chars - 1]; uint16_t next_handle = p_char->handle + 1; if ((next_handle) < p_service->end_handle) { char_disc_retval = ble_drv_discover_characteristic(p_service, diff --git a/ports/nrf/modules/ubluepy/ubluepy_service.c b/ports/nrf/modules/ubluepy/ubluepy_service.c index 69d98bb7e..3834c61de 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_service.c +++ b/ports/nrf/modules/ubluepy/ubluepy_service.c @@ -94,14 +94,13 @@ STATIC mp_obj_t ubluepy_service_make_new(const mp_obj_type_t *type, size_t n_arg /// STATIC mp_obj_t service_add_characteristic(mp_obj_t self_in, mp_obj_t characteristic) { ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); - ubluepy_characteristic_obj_t * p_char = MP_OBJ_TO_PTR(characteristic); + bleio_characteristic_obj_t * p_char = MP_OBJ_TO_PTR(characteristic); p_char->service_handle = self->handle; bool retval = ble_drv_characteristic_add(p_char); - if (retval) { - p_char->p_service = self; + p_char->service = self_in; } mp_obj_list_append(self->char_list, characteristic); @@ -139,10 +138,10 @@ STATIC mp_obj_t service_get_characteristic(mp_obj_t self_in, mp_obj_t uuid) { mp_obj_get_array(self->char_list, &num_chars, &chars); for (uint8_t i = 0; i < num_chars; i++) { - ubluepy_characteristic_obj_t * p_char = (ubluepy_characteristic_obj_t *)chars[i]; + bleio_characteristic_obj_t * p_char = (bleio_characteristic_obj_t *)chars[i]; - bool type_match = p_char->p_uuid->type == p_uuid->type; - bool uuid_match = ((uint16_t)(*(uint16_t *)&p_char->p_uuid->value[0]) == + bool type_match = p_char->uuid->type == p_uuid->type; + bool uuid_match = ((uint16_t)(*(uint16_t *)&p_char->uuid->value[0]) == (uint16_t)(*(uint16_t *)&p_uuid->value[0])); if (type_match && uuid_match) { diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c new file mode 100644 index 000000000..fb96be703 --- /dev/null +++ b/shared-bindings/bleio/Characteristic.c @@ -0,0 +1,330 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/UUID.h" + +//| .. currentmodule:: bleio +//| +//| :class:`Characteristic` -- BLE service characteristic +//| ========================================================= +//| +//| Stores information about a BLE service characteristic and allows to read +//| and write the characteristic's value. +//| + +//| .. class:: Characteristic(uuid) +//| +//| Create a new Characteristic object identified by the specified UUID. +//| +//| :param uuid: The uuid of the characteristic +//| + +//| .. attribute:: broadcast +//| +//| A `bool` specifying if the characteristic allows broadcasting its value. +//| + +//| .. attribute:: indicate +//| +//| A `bool` specifying if the characteristic allows indicating its value. +//| + +//| .. attribute:: notify +//| +//| A `bool` specifying if the characteristic allows notifying its value. +//| + +//| .. attribute:: read +//| +//| A `bool` specifying if the characteristic allows reading its value. +//| + +//| .. attribute:: uuid +//| +//| The UUID of this characteristic. (read-only) +//| + +//| .. attribute:: value +//| +//| The value of this characteristic. The value can be written to if the `write` property allows it. +//| If the `read` property allows it, the value can be read. If the `notify` property is set, writting +//| to the value will generate a BLE notification. +//| + +//| .. attribute:: write +//| +//| A `bool` specifying if the characteristic allows writting to its value. +//| + +//| .. attribute:: write_no_resp +//| +//| A `bool` specifying if the characteristic allows writting to its value without response. +//| +STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_printf(print, "Characteristic(uuid: 0x"HEX2_FMT""HEX2_FMT" handle: 0x" HEX2_FMT ")", + self->uuid->value[0], self->uuid->value[1], self->handle); +} + +STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 1, 1, true); + bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); + self->base.type = &bleio_characteristic_type; + self->service = mp_const_none; + self->value_data = NULL; + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + + enum { ARG_uuid }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_REQUIRED| MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t uuid = args[ARG_uuid].u_obj; + + if (uuid == mp_const_none) { + return MP_OBJ_FROM_PTR(self); + } + + if (MP_OBJ_IS_TYPE(uuid, &bleio_uuid_type)) { + self->uuid = MP_OBJ_TO_PTR(uuid); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Invalid UUID parameter")); + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t bleio_characteristic_get_broadcast(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.broadcast); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_broadcast_obj, bleio_characteristic_get_broadcast); + +STATIC mp_obj_t bleio_characteristic_set_broadcast(mp_obj_t self_in, mp_obj_t broadcast_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.broadcast = mp_obj_is_true(broadcast_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_broadcast_obj, bleio_characteristic_set_broadcast); + +const mp_obj_property_t bleio_characteristic_broadcast_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_broadcast_obj, + (mp_obj_t)&bleio_characteristic_set_broadcast_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_indicate(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.indicate); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_indicate_obj, bleio_characteristic_get_indicate); + +STATIC mp_obj_t bleio_characteristic_set_indicate(mp_obj_t self_in, mp_obj_t indicate_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.indicate = mp_obj_is_true(indicate_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_indicate_obj, bleio_characteristic_set_indicate); + +const mp_obj_property_t bleio_characteristic_indicate_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_indicate_obj, + (mp_obj_t)&bleio_characteristic_set_indicate_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_notify(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.notify); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_notify_obj, bleio_characteristic_get_notify); + +STATIC mp_obj_t bleio_characteristic_set_notify(mp_obj_t self_in, mp_obj_t notify_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.notify = mp_obj_is_true(notify_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_notify_obj, bleio_characteristic_set_notify); + +const mp_obj_property_t bleio_characteristic_notify_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_notify_obj, + (mp_obj_t)&bleio_characteristic_set_notify_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_read(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.read); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_read_obj, bleio_characteristic_get_read); + +STATIC mp_obj_t bleio_characteristic_set_read(mp_obj_t self_in, mp_obj_t read_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.read = mp_obj_is_true(read_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_read_obj, bleio_characteristic_set_read); + +const mp_obj_property_t bleio_characteristic_read_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_read_obj, + (mp_obj_t)&bleio_characteristic_set_read_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_write(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.write); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_obj, bleio_characteristic_get_write); + +STATIC mp_obj_t bleio_characteristic_set_write(mp_obj_t self_in, mp_obj_t write_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.write = mp_obj_is_true(write_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_write_obj, bleio_characteristic_set_write); + +const mp_obj_property_t bleio_characteristic_write_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_write_obj, + (mp_obj_t)&bleio_characteristic_set_write_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_write_wo_resp(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(self->props.write_wo_resp); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_wo_resp_obj, bleio_characteristic_get_write_wo_resp); + +STATIC mp_obj_t bleio_characteristic_set_write_wo_resp(mp_obj_t self_in, mp_obj_t write_wo_resp_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->props.write_wo_resp = mp_obj_is_true(write_wo_resp_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_write_wo_resp_obj, bleio_characteristic_set_write_wo_resp); + +const mp_obj_property_t bleio_characteristic_write_wo_resp_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_write_wo_resp_obj, + (mp_obj_t)&bleio_characteristic_set_write_wo_resp_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_FROM_PTR(self->uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_uuid_obj, bleio_characteristic_get_uuid); + +const mp_obj_property_t bleio_characteristic_uuid_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_uuid_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_characteristic_read_value(self); + + return self->value_data; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value); + +STATIC mp_obj_t bleio_characteristic_set_value(mp_obj_t self_in, mp_obj_t value_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ); + + common_hal_bleio_characteristic_write_value(self, &bufinfo); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_value_obj, bleio_characteristic_set_value); + +const mp_obj_property_t bleio_characteristic_value_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_value_obj, + (mp_obj_t)&bleio_characteristic_set_value_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_broadcast), MP_ROM_PTR(&bleio_characteristic_broadcast_obj) }, + { MP_ROM_QSTR(MP_QSTR_indicate), MP_ROM_PTR(&bleio_characteristic_indicate_obj) }, + { MP_ROM_QSTR(MP_QSTR_notify), MP_ROM_PTR(&bleio_characteristic_notify_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&bleio_characteristic_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&bleio_characteristic_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_wo_resp), MP_ROM_PTR(&bleio_characteristic_write_wo_resp_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table); + +const mp_obj_type_t bleio_characteristic_type = { + { &mp_type_type }, + .name = MP_QSTR_Characteristic, + .print = bleio_characteristic_print, + .make_new = bleio_characteristic_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict +}; diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h new file mode 100644 index 000000000..dd67170d9 --- /dev/null +++ b/shared-bindings/bleio/Characteristic.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H + +#include "shared-module/bleio/Characteristic.h" + +extern const mp_obj_type_t bleio_characteristic_type; + +extern void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self); +extern void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 4ad858ac9..f96abc449 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -30,6 +30,7 @@ #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/AddressType.h" #include "shared-bindings/bleio/AdvertisementData.h" +#include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" @@ -54,6 +55,7 @@ //| AddressType //| AdvertisementData //| Adapter +//| Characteristic //| Descriptor //| ScanEntry //| Scanner @@ -71,6 +73,7 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, { MP_ROM_QSTR(MP_QSTR_AdvertisementData), MP_ROM_PTR(&bleio_advertisementdata_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h new file mode 100644 index 000000000..aa313afd3 --- /dev/null +++ b/shared-module/bleio/Characteristic.h @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H + +#include "common-hal/bleio/UUID.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t service; + uint16_t service_handle; + bleio_uuid_obj_t *uuid; + mp_obj_t value_data; + uint16_t handle; + struct { + bool broadcast : 1; + bool read : 1; + bool write_wo_resp : 1; + bool write : 1; + bool notify : 1; + bool indicate : 1; + } props; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; +} bleio_characteristic_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -- cgit v1.2.3 From bda734223e75382be048d47fa9331afd7e9cfdce Mon Sep 17 00:00:00 2001 From: arturo182 Date: Thu, 19 Jul 2018 01:01:41 +0200 Subject: nrf: Move the Service class from ubluepy to the shared bleio module --- ports/nrf/Makefile | 2 +- ports/nrf/common-hal/bleio/Characteristic.c | 4 +- ports/nrf/common-hal/bleio/Service.c | 38 +++++ ports/nrf/drivers/bluetooth/ble_drv.c | 71 +++++----- ports/nrf/drivers/bluetooth/ble_drv.h | 3 +- ports/nrf/modules/ubluepy/modubluepy.c | 1 - ports/nrf/modules/ubluepy/modubluepy.h | 17 --- ports/nrf/modules/ubluepy/ubluepy_peripheral.c | 17 +-- ports/nrf/modules/ubluepy/ubluepy_service.c | 188 ------------------------- shared-bindings/bleio/Characteristic.c | 4 +- shared-bindings/bleio/Service.c | 167 ++++++++++++++++++++++ shared-bindings/bleio/Service.h | 38 +++++ shared-bindings/bleio/__init__.c | 4 +- shared-module/bleio/Characteristic.h | 3 +- shared-module/bleio/Service.h | 44 ++++++ 15 files changed, 346 insertions(+), 255 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Service.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_service.c create mode 100644 shared-bindings/bleio/Service.c create mode 100644 shared-bindings/bleio/Service.h create mode 100644 shared-module/bleio/Service.h (limited to 'shared-module') diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 6ed2d3054..6112678f5 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -130,7 +130,6 @@ SRC_C += \ DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/modubluepy.c \ ubluepy/ubluepy_peripheral.c \ - ubluepy/ubluepy_service.c \ ) SRC_COMMON_HAL += \ @@ -165,6 +164,7 @@ SRC_COMMON_HAL += \ bleio/Characteristic.c \ bleio/Descriptor.c \ bleio/Scanner.c \ + bleio/Service.c \ bleio/UUID.c endif diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 3087b6707..56afc52c5 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -36,8 +36,8 @@ void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self } void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(self->service); - ubluepy_role_type_t role = service->p_periph->role; + ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(self->service->periph); + ubluepy_role_type_t role = peripheral->role; if (role == UBLUEPY_ROLE_PERIPHERAL) { // TODO: Add indications diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c new file mode 100644 index 000000000..b6e0595b1 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Service.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "ble_drv.h" +#include "shared-module/bleio/Service.h" + +void common_hal_bleio_service_construct(bleio_service_obj_t *self) { + ble_drv_service_add(self); +} + +void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic) { + if (ble_drv_characteristic_add(characteristic)) { + characteristic->service = self; + } +} diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index 6240a18e4..e421036ae 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -267,26 +267,29 @@ bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) { return true; } -bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj) { +void ble_drv_service_add(bleio_service_obj_t *service) { SD_TEST_OR_ENABLE(); - ble_uuid_t uuid; - uuid.type = BLE_UUID_TYPE_BLE; - uuid.uuid = p_service_obj->p_uuid->value[0] | (p_service_obj->p_uuid->value[1] << 8); + ble_uuid_t uuid = { + .type = BLE_UUID_TYPE_BLE, + .uuid = service->uuid->value[0] | (service->uuid->value[1] << 8) + }; - if (p_service_obj->p_uuid->type == UUID_TYPE_128BIT) { - uuid.type = p_service_obj->p_uuid->uuid_vs_idx; + if (service->uuid->type == UUID_TYPE_128BIT) { + uuid.type = service->uuid->uuid_vs_idx; } - uint32_t err_code = sd_ble_gatts_service_add(p_service_obj->type, - &uuid, - &p_service_obj->handle); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Service. status: 0x%08lX"), err_code)); + uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; + if (service->is_secondary) { + service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; } - return true; + if (sd_ble_gatts_service_add(service_type, + &uuid, + &service->handle) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + translate("Can not add Service."))); + } } bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic) { @@ -320,7 +323,7 @@ bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic) { char_md.p_cccd_md = NULL; } - uuid.type = BLE_UUID_TYPE_BLE; + uuid.type = BLE_UUID_TYPE_BLE; if (characteristic->uuid->type == UUID_TYPE_128BIT) uuid.type = characteristic->uuid->uuid_vs_idx; @@ -416,12 +419,12 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { bool type_128bit_present = false; for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; - if (p_service->p_uuid->type == UUID_TYPE_16BIT) { + bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; + if (p_service->uuid->type == UUID_TYPE_16BIT) { type_16bit_present = true; } - if (p_service->p_uuid->type == UUID_TYPE_128BIT) { + if (p_service->uuid->type == UUID_TYPE_128BIT) { type_128bit_present = true; } } @@ -439,12 +442,12 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { uint8_t encoded_size = 0; for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; + bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; ble_uuid_t uuid; - uuid.type = p_service->p_uuid->type; - uuid.uuid = p_service->p_uuid->value[0]; - uuid.uuid += p_service->p_uuid->value[1] << 8; + uuid.type = p_service->uuid->type; + uuid.uuid = p_service->uuid->value[0]; + uuid.uuid += p_service->uuid->value[1] << 8; // calculate total size of uuids if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, @@ -488,12 +491,12 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { uint8_t encoded_size = 0; for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; + bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; ble_uuid_t uuid; - uuid.type = p_service->p_uuid->uuid_vs_idx; - uuid.uuid = p_service->p_uuid->value[0]; - uuid.uuid += p_service->p_uuid->value[1] << 8; + uuid.type = p_service->uuid->uuid_vs_idx; + uuid.uuid = p_service->uuid->value[0]; + uuid.uuid += p_service->uuid->value[1] << 8; // calculate total size of uuids if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { @@ -640,8 +643,8 @@ void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, ui } void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); - uint16_t conn_handle = service->p_periph->conn_handle; + ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); + uint16_t conn_handle = peripheral->conn_handle; ble_gatts_value_t gatts_value; memset(&gatts_value, 0, sizeof(gatts_value)); @@ -659,8 +662,8 @@ void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_ } void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); - uint16_t conn_handle = service->p_periph->conn_handle; + ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); + uint16_t conn_handle = peripheral->conn_handle; ble_gatts_hvx_params_t hvx_params; uint16_t hvx_len = bufinfo->len; @@ -706,11 +709,13 @@ void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_c void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic, ble_drv_gattc_char_data_callback_t cb) { - ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); + bleio_service_obj_t *service = characteristic->service; + ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(service->periph); + mp_gattc_char_data_observer = characteristic; gattc_char_data_handle = cb; - const uint32_t err_code = sd_ble_gattc_read(service->p_periph->conn_handle, + const uint32_t err_code = sd_ble_gattc_read(peripheral->conn_handle, characteristic->handle, 0); if (err_code != 0) { @@ -724,8 +729,8 @@ void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic, ble_drv_gat } void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_service_obj_t *service = MP_OBJ_TO_PTR(characteristic->service); - uint16_t conn_handle = service->p_periph->conn_handle; + ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); + uint16_t conn_handle = peripheral->conn_handle; ble_gattc_write_params_t write_params; write_params.write_op = BLE_GATT_OP_WRITE_REQ; diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index 7283dbfce..8c6bd6ce3 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -34,6 +34,7 @@ #include "shared-module/bleio/Characteristic.h" #include "shared-module/bleio/Scanner.h" +#include "shared-module/bleio/Service.h" #include "modubluepy.h" @@ -92,7 +93,7 @@ void ble_drv_address_get(ble_drv_addr_t * p_addr); bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx); -bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj); +void ble_drv_service_add(bleio_service_obj_t *service); bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic); diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c index 2d1a6a550..f8266a82d 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ b/ports/nrf/modules/ubluepy/modubluepy.c @@ -36,7 +36,6 @@ STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { #if MICROPY_PY_UBLUEPY_PERIPHERAL { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&ubluepy_peripheral_type) }, #endif - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_ubluepy_globals, mp_module_ubluepy_globals_table); diff --git a/ports/nrf/modules/ubluepy/modubluepy.h b/ports/nrf/modules/ubluepy/modubluepy.h index ad33001cb..e301f0476 100644 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ b/ports/nrf/modules/ubluepy/modubluepy.h @@ -74,14 +74,8 @@ p.advertise(device_name="micr", services=[s]) #include "common-hal/bleio/UUID.h" #include "py/obj.h" -extern const mp_obj_type_t ubluepy_service_type; extern const mp_obj_type_t ubluepy_peripheral_type; -typedef enum { - UBLUEPY_SERVICE_PRIMARY = 1, - UBLUEPY_SERVICE_SECONDARY = 2 -} ubluepy_service_type_t; - typedef enum { UBLUEPY_ADDR_TYPE_PUBLIC = 0, UBLUEPY_ADDR_TYPE_RANDOM_STATIC = 1, @@ -104,17 +98,6 @@ typedef struct _ubluepy_peripheral_obj_t { mp_obj_t service_list; } ubluepy_peripheral_obj_t; -typedef struct _ubluepy_service_obj_t { - mp_obj_base_t base; - uint16_t handle; - uint8_t type; - bleio_uuid_obj_t * p_uuid; - ubluepy_peripheral_obj_t * p_periph; - mp_obj_t char_list; - uint16_t start_handle; - uint16_t end_handle; -} ubluepy_service_obj_t; - typedef struct _ubluepy_advertise_data_t { uint8_t * p_device_name; uint8_t device_name_len; diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c index 2a826db4d..3b1a0d279 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c @@ -35,6 +35,7 @@ #include "ble_drv.h" #include "common-hal/bleio/UUID.h" #include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" STATIC void ubluepy_peripheral_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { @@ -271,9 +272,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_disconnect_obj, peripheral_d /// STATIC mp_obj_t peripheral_add_service(mp_obj_t self_in, mp_obj_t service) { ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); - ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service); + bleio_service_obj_t * p_service = MP_OBJ_TO_PTR(service); - p_service->p_periph = self; + p_service->periph = self_in; mp_obj_list_append(self->service_list, service); @@ -294,13 +295,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_get_services_obj, peripheral #if MICROPY_PY_UBLUEPY_CENTRAL void static disc_add_service(mp_obj_t self, ble_drv_service_data_t * p_service_data) { - ubluepy_service_obj_t * p_service = m_new_obj(ubluepy_service_obj_t); - p_service->base.type = &ubluepy_service_type; + bleio_service_obj_t * p_service = m_new_obj(bleio_service_obj_t); + p_service->base.type = &bleio_service_type; bleio_uuid_obj_t * p_uuid = m_new_obj(bleio_uuid_obj_t); p_uuid->base.type = &bleio_uuid_type; - p_service->p_uuid = p_uuid; + p_service->uuid = p_uuid; p_uuid->type = p_service_data->uuid_type; p_uuid->value[0] = p_service_data->uuid & 0xFF; @@ -316,7 +317,7 @@ void static disc_add_service(mp_obj_t self, ble_drv_service_data_t * p_service_d } void static disc_add_char(mp_obj_t service_in, ble_drv_char_data_t * p_desc_data) { - ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service_in); + bleio_service_obj_t * p_service = MP_OBJ_TO_PTR(service_in); bleio_characteristic_obj_t * p_char = m_new_obj(bleio_characteristic_obj_t); p_char->base.type = &bleio_characteristic_type; @@ -410,7 +411,7 @@ STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, m mp_uint_t num_services; mp_obj_get_array(self->service_list, &num_services, &services); - ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)services[num_services - 1]; + bleio_service_obj_t * p_service = (bleio_service_obj_t *)services[num_services - 1]; service_disc_retval = ble_drv_discover_services(self, self->conn_handle, @@ -424,7 +425,7 @@ STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, m mp_obj_get_array(self->service_list, &num_services, &services); for (uint16_t s = 0; s < num_services; s++) { - ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)services[s]; + bleio_service_obj_t * p_service = (bleio_service_obj_t *)services[s]; bool char_disc_retval = ble_drv_discover_characteristic(p_service, self->conn_handle, p_service->start_handle, diff --git a/ports/nrf/modules/ubluepy/ubluepy_service.c b/ports/nrf/modules/ubluepy/ubluepy_service.c deleted file mode 100644 index 3834c61de..000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_service.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/obj.h" -#include "py/runtime.h" -#include "py/objlist.h" -#include "supervisor/shared/translate.h" - -#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL - -#include "modubluepy.h" -#include "ble_drv.h" -#include "common-hal/bleio/UUID.h" -#include "shared-bindings/bleio/UUID.h" - -STATIC void ubluepy_service_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_service_obj_t * self = (ubluepy_service_obj_t *)o; - - mp_printf(print, "Service(handle: 0x" HEX2_FMT ")", self->handle); -} - -STATIC mp_obj_t ubluepy_service_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - - enum { ARG_NEW_UUID, ARG_NEW_TYPE }; - - static const mp_arg_t allowed_args[] = { - { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { ARG_NEW_TYPE, MP_ARG_INT, {.u_int = UBLUEPY_SERVICE_PRIMARY} }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - ubluepy_service_obj_t *s = m_new_obj(ubluepy_service_obj_t); - s->base.type = type; - - mp_obj_t uuid_obj = args[ARG_NEW_UUID].u_obj; - - if (uuid_obj == MP_OBJ_NULL) { - return MP_OBJ_FROM_PTR(s); - } - - if (MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); - - uint8_t type = args[ARG_NEW_TYPE].u_int; - if (type > 0 && type <= UBLUEPY_SERVICE_PRIMARY) { - s->type = type; - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Invalid Service type"))); - } - - (void)ble_drv_service_add(s); - - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Invalid UUID parameter"))); - } - - // clear reference to peripheral - s->p_periph = NULL; - s->char_list = mp_obj_new_list(0, NULL); - - return MP_OBJ_FROM_PTR(s); -} - -/// \method addCharacteristic(Characteristic) -/// Add Characteristic to the Service. -/// -STATIC mp_obj_t service_add_characteristic(mp_obj_t self_in, mp_obj_t characteristic) { - ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); - bleio_characteristic_obj_t * p_char = MP_OBJ_TO_PTR(characteristic); - - p_char->service_handle = self->handle; - - bool retval = ble_drv_characteristic_add(p_char); - if (retval) { - p_char->service = self_in; - } - - mp_obj_list_append(self->char_list, characteristic); - - // return mp_obj_new_bool(retval); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_service_add_char_obj, service_add_characteristic); - -/// \method getCharacteristics() -/// Return list with all characteristics registered in the Service. -/// -STATIC mp_obj_t service_get_chars(mp_obj_t self_in) { - ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); - - return self->char_list; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_service_get_chars_obj, service_get_chars); - -/// \method getCharacteristic(UUID) -/// Return Characteristic with the given UUID. -/// -STATIC mp_obj_t service_get_characteristic(mp_obj_t self_in, mp_obj_t uuid) { - ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); - bleio_uuid_obj_t * p_uuid = MP_OBJ_TO_PTR(uuid); - - // validate that there is an UUID object passed in as parameter - if (!(MP_OBJ_IS_TYPE(uuid, &bleio_uuid_type))) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Invalid UUID parameter"))); - } - - mp_obj_t * chars = NULL; - mp_uint_t num_chars = 0; - mp_obj_get_array(self->char_list, &num_chars, &chars); - - for (uint8_t i = 0; i < num_chars; i++) { - bleio_characteristic_obj_t * p_char = (bleio_characteristic_obj_t *)chars[i]; - - bool type_match = p_char->uuid->type == p_uuid->type; - bool uuid_match = ((uint16_t)(*(uint16_t *)&p_char->uuid->value[0]) == - (uint16_t)(*(uint16_t *)&p_uuid->value[0])); - - if (type_match && uuid_match) { - return MP_OBJ_FROM_PTR(p_char); - } - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_service_get_char_obj, service_get_characteristic); - -/// \method uuid() -/// Get UUID instance of the Service. -/// -STATIC mp_obj_t service_uuid(mp_obj_t self_in) { - ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->p_uuid); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_service_get_uuid_obj, service_uuid); - -STATIC const mp_rom_map_elem_t ubluepy_service_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_getCharacteristic), MP_ROM_PTR(&ubluepy_service_get_char_obj) }, - { MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_service_add_char_obj) }, - { MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_service_get_chars_obj) }, -#if 0 - // Properties - { MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_service_get_peripheral_obj) }, -#endif - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_service_get_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_PRIMARY), MP_ROM_INT(UBLUEPY_SERVICE_PRIMARY) }, - { MP_ROM_QSTR(MP_QSTR_SECONDARY), MP_ROM_INT(UBLUEPY_SERVICE_SECONDARY) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_service_locals_dict, ubluepy_service_locals_dict_table); - -const mp_obj_type_t ubluepy_service_type = { - { &mp_type_type }, - .name = MP_QSTR_Service, - .print = ubluepy_service_print, - .make_new = ubluepy_service_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_service_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index fb96be703..97aed679e 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -91,14 +91,14 @@ STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "Characteristic(uuid: 0x"HEX2_FMT""HEX2_FMT" handle: 0x" HEX2_FMT ")", - self->uuid->value[0], self->uuid->value[1], self->handle); + self->uuid->value[1], self->uuid->value[0], self->handle); } STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { mp_arg_check_num(n_args, n_kw, 1, 1, true); bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); self->base.type = &bleio_characteristic_type; - self->service = mp_const_none; + self->service = NULL; self->value_data = NULL; mp_map_t kw_args; diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c new file mode 100644 index 000000000..6451991e9 --- /dev/null +++ b/shared-bindings/bleio/Service.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" + +//| .. currentmodule:: bleio +//| +//| :class:`Service` -- BLE service +//| ========================================================= +//| +//| Stores information about a BLE service and its characteristics. +//| + +//| .. class:: Service(uuid, secondary=False) +//| +//| Create a new Service object identified by the specified UUID. +//| To mark the service as secondary, pass `True` as :py:data:`secondary`. +//| +//| :param uuid: The uuid of the service +//| + +//| .. method:: add_characteristic(characteristic) +//| +//| Appends the :py:data:`characteristic` to the list of this service's characteristics. +//| +//| :param bleio.Characteristic characteristic: the characteristic to append +//| + +//| .. attribute:: characteristics +//| +//| A `list` of `bleio.Characteristic` that are offered by this service. (read-only) +//| + +//| .. attribute:: uuid +//| +//| The UUID of this service. (read-only) +//| +STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_printf(print, "Service(uuid: 0x"HEX2_FMT""HEX2_FMT")", + self->uuid->value[1], self->uuid->value[0]); +} + +STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 1, 1, true); + bleio_service_obj_t *self = m_new_obj(bleio_service_obj_t); + self->base.type = &bleio_service_type; + self->periph = mp_const_none; + self->char_list = mp_obj_new_list(0, NULL); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + + enum { ARG_uuid, ARG_secondary }; + static const mp_arg_t allowed_args[] = { + { ARG_uuid, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self->is_secondary = args[ARG_secondary].u_bool; + + const mp_obj_t uuid = args[ARG_uuid].u_obj; + + if (uuid == MP_OBJ_NULL) { + return MP_OBJ_FROM_PTR(self); + } + + if (MP_OBJ_IS_TYPE(uuid, &bleio_uuid_type)) { + self->uuid = MP_OBJ_TO_PTR(uuid); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Invalid UUID parameter")); + } + + common_hal_bleio_service_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t bleio_service_add_characteristic(mp_obj_t self_in, mp_obj_t characteristic_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(characteristic_in); + + characteristic->service_handle = self->handle; + + common_hal_bleio_service_add_characteristic(self, characteristic); + + mp_obj_list_append(self->char_list, characteristic); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_service_add_characteristic_obj, bleio_service_add_characteristic); + +STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return self->char_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics); + +const mp_obj_property_t bleio_service_characteristics_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_characteristics_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_FROM_PTR(self->uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_uuid_obj, bleio_service_get_uuid); + +const mp_obj_property_t bleio_service_uuid_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_uuid_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add_characteristic), MP_ROM_PTR(&bleio_service_add_characteristic_obj) }, + { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table); + +const mp_obj_type_t bleio_service_type = { + { &mp_type_type }, + .name = MP_QSTR_Service, + .print = bleio_service_print, + .make_new = bleio_service_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict +}; diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h new file mode 100644 index 000000000..6e3079cf9 --- /dev/null +++ b/shared-bindings/bleio/Service.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H + +#include "shared-module/bleio/Characteristic.h" +#include "shared-module/bleio/Service.h" + +const mp_obj_type_t bleio_service_type; + +extern void common_hal_bleio_service_construct(bleio_service_obj_t *self); +extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index f96abc449..9f5a8f8f2 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -25,7 +25,6 @@ * THE SOFTWARE. */ -#include "py/obj.h" #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/AddressType.h" @@ -34,6 +33,7 @@ #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" +#include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" #include "shared-bindings/bleio/UUIDType.h" @@ -59,6 +59,7 @@ //| Descriptor //| ScanEntry //| Scanner +//| Service //| UUID //| UUIDType //| @@ -77,6 +78,7 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, // Properties diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index aa313afd3..2347c9c30 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -27,11 +27,12 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H +#include "shared-module/bleio/Service.h" #include "common-hal/bleio/UUID.h" typedef struct { mp_obj_base_t base; - mp_obj_t service; + bleio_service_obj_t *service; uint16_t service_handle; bleio_uuid_obj_t *uuid; mp_obj_t value_data; diff --git a/shared-module/bleio/Service.h b/shared-module/bleio/Service.h new file mode 100644 index 000000000..bd359a41d --- /dev/null +++ b/shared-module/bleio/Service.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H + +#include "modubluepy.h" +#include "common-hal/bleio/UUID.h" + +typedef struct { + mp_obj_base_t base; + uint16_t handle; + bool is_secondary; + bleio_uuid_obj_t *uuid; + mp_obj_t periph; + mp_obj_t char_list; + uint16_t start_handle; + uint16_t end_handle; +} bleio_service_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H -- cgit v1.2.3 From 3bd65fbae5d0150139c0ffd4cf02f8c9f547bbf5 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Thu, 19 Jul 2018 20:33:24 +0200 Subject: nrf: Move the Peripheral class to bleio as Device This was the last class from ubluepy and so that module is now gone. The Device class offers both Peripheral and Central functionality. See the inline docs for more info. --- ports/nrf/Makefile | 5 +- ports/nrf/common-hal/bleio/Characteristic.c | 6 +- ports/nrf/common-hal/bleio/Device.c | 166 ++++++++ ports/nrf/common-hal/bleio/Scanner.c | 3 +- ports/nrf/drivers/bluetooth/ble_drv.c | 396 +++++++++---------- ports/nrf/drivers/bluetooth/ble_drv.h | 36 +- ports/nrf/drivers/bluetooth/ble_uart.h | 1 - ports/nrf/modules/ubluepy/modubluepy.c | 48 --- ports/nrf/modules/ubluepy/modubluepy.h | 126 ------ ports/nrf/modules/ubluepy/ubluepy_peripheral.c | 507 ------------------------- ports/nrf/mpconfigport.h | 33 +- shared-bindings/bleio/Device.c | 348 +++++++++++++++++ shared-bindings/bleio/Device.h | 40 ++ shared-bindings/bleio/ScanEntry.c | 5 +- shared-bindings/bleio/ScanEntry.h | 11 +- shared-bindings/bleio/Service.c | 6 +- shared-bindings/bleio/__init__.c | 3 + shared-module/bleio/AdvertisementData.h | 9 + shared-module/bleio/Device.h | 45 +++ shared-module/bleio/ScanEntry.h | 40 ++ shared-module/bleio/Service.h | 3 +- 21 files changed, 860 insertions(+), 977 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Device.c delete mode 100644 ports/nrf/modules/ubluepy/modubluepy.c delete mode 100644 ports/nrf/modules/ubluepy/modubluepy.h delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_peripheral.c create mode 100644 shared-bindings/bleio/Device.c create mode 100644 shared-bindings/bleio/Device.h create mode 100644 shared-module/bleio/Device.h create mode 100644 shared-module/bleio/ScanEntry.h (limited to 'shared-module') diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 6112678f5..b059569ab 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -127,10 +127,6 @@ SRC_C += \ peripherals/nrf/timers.c \ supervisor/shared/memory.c -DRIVERS_SRC_C += $(addprefix modules/,\ - ubluepy/modubluepy.c \ - ubluepy/ubluepy_peripheral.c \ - ) SRC_COMMON_HAL += \ analogio/AnalogIn.c \ @@ -163,6 +159,7 @@ SRC_COMMON_HAL += \ bleio/Adapter.c \ bleio/Characteristic.c \ bleio/Descriptor.c \ + bleio/Device.c \ bleio/Scanner.c \ bleio/Service.c \ bleio/UUID.c diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 56afc52c5..938289f2d 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -26,6 +26,7 @@ #include "ble_drv.h" #include "shared-module/bleio/Characteristic.h" +#include "shared-module/bleio/Device.h" void data_callback(bleio_characteristic_obj_t *self, uint16_t length, uint8_t *data) { self->value_data = mp_obj_new_bytearray(length, data); @@ -36,10 +37,9 @@ void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self } void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(self->service->periph); - ubluepy_role_type_t role = peripheral->role; + const bleio_device_obj_t *device = MP_OBJ_TO_PTR(self->service->device); - if (role == UBLUEPY_ROLE_PERIPHERAL) { + if (device->is_peripheral) { // TODO: Add indications if (self->props.notify) { ble_drv_attr_s_notify(self, bufinfo); diff --git a/ports/nrf/common-hal/bleio/Device.c b/ports/nrf/common-hal/bleio/Device.c new file mode 100644 index 000000000..ab2898e72 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Device.c @@ -0,0 +1,166 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "ble_drv.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_types.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Device.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" + +static volatile bool m_disc_evt_received; + +STATIC void gap_event_handler(bleio_device_obj_t *device, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) { + if (event_id == BLE_GAP_EVT_CONNECTED) { + device->conn_handle = conn_handle; + } else if (event_id == BLE_GAP_EVT_DISCONNECTED) { + device->conn_handle = BLE_CONN_HANDLE_INVALID; + } +} + +STATIC void gatts_event_handler(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { + +} + +STATIC void gattc_event_handler(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { + m_disc_evt_received = true; +} + +STATIC void disc_add_service(bleio_device_obj_t *device, ble_drv_service_data_t * service_data) { + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + uuid->type = (service_data->uuid_type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT; + uuid->value[0] = service_data->uuid & 0xFF; + uuid->value[1] = service_data->uuid >> 8; + + service->char_list = mp_obj_new_list(0, NULL); + service->uuid = uuid; + service->device = device; + service->handle = service_data->start_handle; + service->start_handle = service_data->start_handle; + service->end_handle = service_data->end_handle; + + mp_obj_list_append(device->service_list, service); +} + +STATIC void disc_add_char(bleio_service_obj_t *service, ble_drv_char_data_t *chara_data) { + bleio_characteristic_obj_t *chara = m_new_obj(bleio_characteristic_obj_t); + chara->base.type = &bleio_characteristic_type; + + bleio_uuid_obj_t * p_uuid = m_new_obj(bleio_uuid_obj_t); + p_uuid->base.type = &bleio_uuid_type; + + chara->uuid = p_uuid; + + p_uuid->type = chara_data->uuid_type; + p_uuid->value[0] = chara_data->uuid & 0xFF; + p_uuid->value[1] = chara_data->uuid >> 8; + + // add characteristic specific data from discovery + chara->props.broadcast = chara_data->props.broadcast; + chara->props.indicate = chara_data->props.indicate; + chara->props.notify = chara_data->props.notify; + chara->props.read = chara_data->props.read; + chara->props.write = chara_data->props.write; + chara->props.write_wo_resp = chara_data->props.write_wo_resp; + chara->handle = chara_data->value_handle; + + chara->service_handle = service->handle; + chara->service = service; + + mp_obj_list_append(service->char_list, MP_OBJ_FROM_PTR(chara)); +} + + +void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bleio_advertisement_data_t *adv_data) { + if (adv_data->connectable) { + ble_drv_gap_event_handler_set(device, gap_event_handler); + ble_drv_gatts_event_handler_set(device, gatts_event_handler); + } + + ble_drv_advertise_data(adv_data); +} + +void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device) { + (void)device; + + ble_drv_advertise_stop(); +} + +void common_hal_bleio_device_connect(bleio_device_obj_t *device) { + ble_drv_gap_event_handler_set(device, gap_event_handler); + + ble_drv_connect(device); + + while (device->conn_handle == BLE_CONN_HANDLE_INVALID) { + run_background_tasks(); +// __asm volatile ("wfi"); + } + + ble_drv_gattc_event_handler_set(device, gattc_event_handler); + + // TODO: read name + + // find services + bool found_service = ble_drv_discover_services(device, BLE_GATT_HANDLE_START, disc_add_service); + while (found_service) { + const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(device->service_list); + const bleio_service_obj_t *service = service_list->items[service_list->len - 1]; + + found_service = ble_drv_discover_services(device, service->end_handle + 1, disc_add_service); + } + + // find characteristics in each service + const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(device->service_list); + for (size_t i = 0; i < service_list->len; ++i) { + bleio_service_obj_t *service = service_list->items[i]; + + bool found_char = ble_drv_discover_characteristic(device, service, service->start_handle, disc_add_char); + while (found_char) { + const mp_obj_list_t *char_list = MP_OBJ_TO_PTR(service->char_list); + const bleio_characteristic_obj_t *characteristic = char_list->items[char_list->len - 1]; + + const uint16_t next_handle = characteristic->handle + 1; + if (next_handle >= service->end_handle) { + break; + } + + found_char = ble_drv_discover_characteristic(device, service, next_handle, disc_add_char); + } + } +} + +void common_hal_bleio_device_disconnect(bleio_device_obj_t *device) { + ble_drv_disconnect(device); +} diff --git a/ports/nrf/common-hal/bleio/Scanner.c b/ports/nrf/common-hal/bleio/Scanner.c index ed1987144..0eb50a1f6 100644 --- a/ports/nrf/common-hal/bleio/Scanner.c +++ b/ports/nrf/common-hal/bleio/Scanner.c @@ -29,8 +29,9 @@ #include "ble_drv.h" #include "py/mphal.h" -#include "shared-bindings/bleio/Scanner.h" #include "shared-bindings/bleio/ScanEntry.h" +#include "shared-bindings/bleio/Scanner.h" +#include "shared-module/bleio/ScanEntry.h" STATIC void adv_event_handler(bleio_scanner_obj_t *self, ble_drv_adv_data_t *data) { // TODO: Don't add new entry for each item, group by address and update diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index e421036ae..1ab1d9337 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +35,8 @@ #define NRF52 // Needed for SD132 v2 #endif +#include "shared-module/bleio/Device.h" +#include "py/objstr.h" #include "py/runtime.h" #include "supervisor/shared/translate.h" #include "ble_drv.h" @@ -41,15 +44,10 @@ #include "nrf_sdm.h" #include "nrfx_power.h" #include "ble_gap.h" +#include "ble_hci.h" #include "ble.h" // sd_ble_uuid_encode - -#define BLE_DRIVER_VERBOSE 0 -#if BLE_DRIVER_VERBOSE #define BLE_DRIVER_LOG printf -#else -#define BLE_DRIVER_LOG(...) -#endif #define BLE_ADV_LENGTH_FIELD_SIZE 1 #define BLE_ADV_AD_TYPE_FIELD_SIZE 1 @@ -61,8 +59,8 @@ #define APP_CFG_NON_CONN_ADV_TIMEOUT 0 // Disable timeout. #define NON_CONNECTABLE_ADV_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS) -#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS) -#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS) +#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) #define BLE_SLAVE_LATENCY 0 #define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) @@ -81,8 +79,8 @@ static volatile bool m_tx_in_progress; static ble_drv_gap_evt_callback_t gap_event_handler; static ble_drv_gatts_evt_callback_t gatts_event_handler; -static mp_obj_t mp_gap_observer; -static mp_obj_t mp_gatts_observer; +static bleio_device_obj_t *mp_gap_observer; +static bleio_device_obj_t *mp_gatts_observer; static volatile bool m_primary_service_found; static volatile bool m_characteristic_found; @@ -95,10 +93,11 @@ static volatile ble_drv_disc_add_char_callback_t disc_add_char_handler; static volatile ble_drv_gattc_char_data_callback_t gattc_char_data_handle; static bleio_scanner_obj_t *mp_adv_observer; -static mp_obj_t mp_gattc_observer; -static mp_obj_t mp_gattc_disc_service_observer; -static mp_obj_t mp_gattc_disc_char_observer; +static bleio_device_obj_t *mp_gattc_observer; +static bleio_device_obj_t *mp_gattc_disc_service_observer; +static bleio_service_obj_t *mp_gattc_disc_char_observer; static bleio_characteristic_obj_t *mp_gattc_char_data_observer; +static bleio_address_obj_t *mp_connect_address; #if (BLUETOOTH_SD == 140) static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; @@ -123,18 +122,6 @@ uint32_t ble_drv_stack_enable(void) { m_adv_in_progress = false; m_tx_in_progress = false; -#if BLUETOOTH_LFCLK_RC - nrf_clock_lf_cfg_t clock_config = { - .source = NRF_CLOCK_LF_SRC_RC, - .rc_ctiv = 16, - .rc_temp_ctiv = 2, -#if (BLE_API_VERSION == 4) - .accuracy = 0 -#else - .xtal_accuracy = 0 -#endif - }; -#else nrf_clock_lf_cfg_t clock_config = { .source = NRF_CLOCK_LF_SRC_XTAL, .rc_ctiv = 0, @@ -145,23 +132,22 @@ uint32_t ble_drv_stack_enable(void) { .xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM #endif }; -#endif #if (BLUETOOTH_SD == 140) // The SD takes over the POWER IRQ and will fail if the IRQ is already in use nrfx_power_uninit(); #endif - uint32_t err_code = sd_softdevice_enable(&clock_config, - softdevice_assert_handler); - - BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code); + uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler); + if (err_code != NRF_SUCCESS) + BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code); - err_code = sd_nvic_EnableIRQ(SWI2_EGU2_IRQn); - - BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code); + err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); + if (err_code != NRF_SUCCESS) + BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code); // Enable BLE stack. + uint32_t app_ram_start; #if (BLE_API_VERSION == 2) ble_enable_params_t ble_enable_params; memset(&ble_enable_params, 0x00, sizeof(ble_enable_params)); @@ -169,48 +155,17 @@ uint32_t ble_drv_stack_enable(void) { ble_enable_params.gatts_enable_params.service_changed = 0; ble_enable_params.gap_enable_params.periph_conn_count = 1; ble_enable_params.gap_enable_params.central_conn_count = 1; -#endif -#if (BLE_API_VERSION == 2) - uint32_t app_ram_start = 0x200039c0; + app_ram_start = 0x200039c0; err_code = sd_ble_enable(&ble_enable_params, &app_ram_start); // 8K SD headroom from linker script. - BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start); #else - uint32_t app_ram_start = 0x20004000; + app_ram_start = 0x20004000; err_code = sd_ble_enable(&app_ram_start); - BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start); #endif - - BLE_DRIVER_LOG("BLE enable status: " UINT_FMT "\n", (uint16_t)err_code); - - // set up security mode - ble_gap_conn_params_t gap_conn_params; - ble_gap_conn_sec_mode_t sec_mode; - - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); - - const char device_name[] = "micr"; - - if ((err_code = sd_ble_gap_device_name_set(&sec_mode, - (const uint8_t *)device_name, - strlen(device_name))) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Cannot apply GAP parameters."))); - } - - // set connection parameters - memset(&gap_conn_params, 0, sizeof(gap_conn_params)); - - gap_conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL; - gap_conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL; - gap_conn_params.slave_latency = BLE_SLAVE_LATENCY; - gap_conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT; - - if (sd_ble_gap_ppcp_set(&gap_conn_params) != 0) { - - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Cannot set PPCP parameters."))); + if (err_code != NRF_SUCCESS) { + BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start); + BLE_DRIVER_LOG("BLE enable status: " UINT_FMT "\n", (uint16_t)err_code); } return err_code; @@ -223,9 +178,10 @@ void ble_drv_stack_disable(void) { uint8_t ble_drv_stack_enabled(void) { uint8_t is_enabled; uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); - (void)err_code; - BLE_DRIVER_LOG("Is enabled status: " UINT_FMT "\n", (uint16_t)err_code); + if (err_code != NRF_SUCCESS) { + BLE_DRIVER_LOG("Is enabled status: " UINT_FMT "\n", (uint16_t)err_code); + } return is_enabled; } @@ -256,10 +212,10 @@ void ble_drv_address_get(ble_drv_addr_t * p_addr) { memcpy(p_addr->addr, local_ble_addr.addr, 6); } -bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) { +bool ble_drv_uuid_add_vs(uint8_t *uuid, uint8_t *idx) { SD_TEST_OR_ENABLE(); - if (sd_ble_uuid_vs_add((ble_uuid128_t const *)p_uuid, idx) != 0) { + if (sd_ble_uuid_vs_add((ble_uuid128_t const *)uuid, idx) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not add Vendor Specific 128-bit UUID."))); } @@ -284,9 +240,7 @@ void ble_drv_service_add(bleio_service_obj_t *service) { service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; } - if (sd_ble_gatts_service_add(service_type, - &uuid, - &service->handle) != 0) { + if (sd_ble_gatts_service_add(service_type, &uuid, &service->handle) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not add Service."))); } @@ -372,59 +326,66 @@ bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic) { return true; } -bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { +// TODO: Replace with just bleio_device_obj_t + data +bool ble_drv_advertise_data(bleio_advertisement_data_t *adv_params) { SD_TEST_OR_ENABLE(); uint8_t byte_pos = 0; uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; - if (p_adv_params->device_name_len > 0) { - ble_gap_conn_sec_mode_t sec_mode; + GET_STR_DATA_LEN(adv_params->device_name, name_data, name_len); + if (name_len > 0) { + ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); if (sd_ble_gap_device_name_set(&sec_mode, - p_adv_params->p_device_name, - p_adv_params->device_name_len) != 0) { + name_data, + name_len) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not apply device name in the stack."))); } - BLE_DRIVER_LOG("Device name applied\n"); - - adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + p_adv_params->device_name_len); + adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + name_len); byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + + // TODO: Shorten if too long adv_data[byte_pos] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; - memcpy(&adv_data[byte_pos], p_adv_params->p_device_name, p_adv_params->device_name_len); - // increment position counter to see if it fits, and in case more content should - // follow in this adv packet. - byte_pos += p_adv_params->device_name_len; + + memcpy(&adv_data[byte_pos], name_data, name_len); + + byte_pos += name_len; } - // Add FLAGS only if manually controlled data has not been used. - if (p_adv_params->data_len == 0) { - // set flags, default to disc mode + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(adv_params->data, &bufinfo, MP_BUFFER_WRITE); + + // set flags, default to disc mode + if (bufinfo.len == 0) { adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + BLE_AD_TYPE_FLAGS_DATA_SIZE); byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + adv_data[byte_pos] = BLE_GAP_AD_TYPE_FLAGS; byte_pos += BLE_AD_TYPE_FLAGS_DATA_SIZE; + adv_data[byte_pos] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; byte_pos += 1; } - if (p_adv_params->num_of_services > 0) { - + const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(adv_params->services); + if (service_list->len > 0) { bool type_16bit_present = false; bool type_128bit_present = false; - for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; - if (p_service->uuid->type == UUID_TYPE_16BIT) { + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + + if (service->uuid->type == UUID_TYPE_16BIT) { type_16bit_present = true; } - if (p_service->uuid->type == UUID_TYPE_128BIT) { + if (service->uuid->type == UUID_TYPE_128BIT) { type_128bit_present = true; } } @@ -441,13 +402,17 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { uint8_t uuid_total_size = 0; uint8_t encoded_size = 0; - for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + + if (service->uuid->type != UUID_TYPE_16BIT) { + continue; + } ble_uuid_t uuid; - uuid.type = p_service->uuid->type; - uuid.uuid = p_service->uuid->value[0]; - uuid.uuid += p_service->uuid->value[1] << 8; + uuid.type = BLE_UUID_TYPE_BLE; + uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); + // calculate total size of uuids if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, @@ -460,19 +425,8 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { translate("Can encode UUID into the advertisement packet."))); } - BLE_DRIVER_LOG("encoded uuid for service %u: ", 0); - for (uint8_t j = 0; j < encoded_size; j++) { - BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]); - } - BLE_DRIVER_LOG("\n"); - uuid_total_size += encoded_size; // size of entry byte_pos += encoded_size; // relative to adv data packet - BLE_DRIVER_LOG("ADV: uuid size: %u, type: %u, uuid: %x%x, vs_idx: %u\n", - encoded_size, p_service->p_uuid->type, - p_service->p_uuid->value[1], - p_service->p_uuid->value[0], - p_service->p_uuid->uuid_vs_idx); } adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); @@ -490,13 +444,16 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { uint8_t uuid_total_size = 0; uint8_t encoded_size = 0; - for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { - bleio_service_obj_t * p_service = (bleio_service_obj_t *)p_adv_params->p_services[i]; + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + + if (service->uuid->type != UUID_TYPE_128BIT) { + continue; + } ble_uuid_t uuid; - uuid.type = p_service->uuid->uuid_vs_idx; - uuid.uuid = p_service->uuid->value[0]; - uuid.uuid += p_service->uuid->value[1] << 8; + uuid.type = service->uuid->uuid_vs_idx; + uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); // calculate total size of uuids if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { @@ -510,51 +467,37 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { translate("Can encode UUID into the advertisement packet."))); } - BLE_DRIVER_LOG("encoded uuid for service %u: ", 0); - for (uint8_t j = 0; j < encoded_size; j++) { - BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]); - } - BLE_DRIVER_LOG("\n"); - uuid_total_size += encoded_size; // size of entry byte_pos += encoded_size; // relative to adv data packet - BLE_DRIVER_LOG("ADV: uuid size: %u, type: %x%x, uuid: %u, vs_idx: %u\n", - encoded_size, p_service->p_uuid->type, - p_service->p_uuid->value[1], - p_service->p_uuid->value[0], - p_service->p_uuid->uuid_vs_idx); } adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); } } - if ((p_adv_params->data_len > 0) && (p_adv_params->p_data != NULL)) { - if (p_adv_params->data_len + byte_pos > BLE_GAP_ADV_MAX_SIZE) { + if (bufinfo.len > 0) { + if (byte_pos + bufinfo.len > BLE_GAP_ADV_MAX_SIZE) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not fit data into the advertisement packet."))); } - memcpy(adv_data, p_adv_params->p_data, p_adv_params->data_len); - byte_pos += p_adv_params->data_len; + memcpy(adv_data, bufinfo.buf, bufinfo.len); + byte_pos += bufinfo.len; } - // scan response data not set uint32_t err_code; #if (BLUETOOTH_SD == 132) if ((err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not apply advertisement data. status: 0x%02x"), (uint16_t)err_code)); } - BLE_DRIVER_LOG("Set Adv data size: " UINT_FMT "\n", byte_pos); #endif static ble_gap_adv_params_t m_adv_params; // initialize advertising params memset(&m_adv_params, 0, sizeof(m_adv_params)); - if (p_adv_params->connectable) { + if (adv_params->connectable) { #if (BLUETOOTH_SD == 140) m_adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; #else @@ -643,8 +586,8 @@ void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, ui } void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); - uint16_t conn_handle = peripheral->conn_handle; + bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); + uint16_t conn_handle = device->conn_handle; ble_gatts_value_t gatts_value; memset(&gatts_value, 0, sizeof(gatts_value)); @@ -662,8 +605,8 @@ void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_ } void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); - uint16_t conn_handle = peripheral->conn_handle; + bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); + uint16_t conn_handle = device->conn_handle; ble_gatts_hvx_params_t hvx_params; uint16_t hvx_len = bufinfo->len; @@ -676,7 +619,9 @@ void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer hvx_params.p_data = bufinfo->buf; while (m_tx_in_progress) { - ; +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif } m_tx_in_progress = true; @@ -687,50 +632,49 @@ void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer } } -void ble_drv_gap_event_handler_set(mp_obj_t obj, ble_drv_gap_evt_callback_t evt_handler) { - mp_gap_observer = obj; +void ble_drv_gap_event_handler_set(bleio_device_obj_t *device, ble_drv_gap_evt_callback_t evt_handler) { + mp_gap_observer = device; gap_event_handler = evt_handler; } -void ble_drv_gatts_event_handler_set(mp_obj_t obj, ble_drv_gatts_evt_callback_t evt_handler) { - mp_gatts_observer = obj; +void ble_drv_gatts_event_handler_set(bleio_device_obj_t *device, ble_drv_gatts_evt_callback_t evt_handler) { + mp_gatts_observer = device; gatts_event_handler = evt_handler; } -void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler) { - mp_gattc_observer = obj; +void ble_drv_gattc_event_handler_set(bleio_device_obj_t *device, ble_drv_gattc_evt_callback_t evt_handler) { + mp_gattc_observer = device; gattc_event_handler = evt_handler; } -void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_callback_t evt_handler) { - mp_adv_observer = self; +void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *device, ble_drv_adv_evt_callback_t evt_handler) { + mp_adv_observer = device; adv_event_handler = evt_handler; } - void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic, ble_drv_gattc_char_data_callback_t cb) { bleio_service_obj_t *service = characteristic->service; - ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(service->periph); + bleio_device_obj_t *device = MP_OBJ_TO_PTR(service->device); mp_gattc_char_data_observer = characteristic; gattc_char_data_handle = cb; - const uint32_t err_code = sd_ble_gattc_read(peripheral->conn_handle, - characteristic->handle, - 0); + const uint32_t err_code = sd_ble_gattc_read(device->conn_handle, characteristic->handle, 0); if (err_code != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, translate("Can not read attribute value. status: 0x%02x"), (uint16_t)err_code)); } while (gattc_char_data_handle != NULL) { - ; +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif } } void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - ubluepy_peripheral_obj_t *peripheral = MP_OBJ_TO_PTR(characteristic->service->periph); - uint16_t conn_handle = peripheral->conn_handle; + bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); + uint16_t conn_handle = device->conn_handle; ble_gattc_write_params_t write_params; write_params.write_op = BLE_GATT_OP_WRITE_REQ; @@ -753,10 +697,13 @@ void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_ translate("Can not write attribute value. status: 0x%02x"), (uint16_t)err_code)); } - while (m_write_done != true) { - ; + while (m_write_done != true) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif } } + void ble_drv_scan_start(uint16_t interval, uint16_t window) { SD_TEST_OR_ENABLE(); @@ -798,109 +745,108 @@ void ble_drv_scan_stop(void) { sd_ble_gap_scan_stop(); } -void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type) { - SD_TEST_OR_ENABLE(); +STATIC void ble_drv_connect_scan_callback(bleio_scanner_obj_t *scanner, ble_drv_adv_data_t *data) { + if (memcmp(data->p_peer_addr, mp_connect_address->value, BLEIO_ADDRESS_BYTES) == 0) { + ble_drv_adv_report_handler_set(NULL, NULL); - ble_gap_scan_params_t scan_params; - scan_params.active = 1; - scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); - scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); - scan_params.timeout = 0; // Infinite + ble_gap_scan_params_t scan_params; + memset(&scan_params, 0, sizeof(scan_params)); - ble_gap_addr_t addr; - memset(&addr, 0, sizeof(addr)); + scan_params.active = 1; + scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.timeout = 0; - addr.addr_type = addr_type; - memcpy(addr.addr, p_addr, 6); + ble_gap_addr_t addr; + memset(&addr, 0, sizeof(addr)); - BLE_DRIVER_LOG("GAP CONNECTING: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT", type: %d\n", - addr.addr[0], addr.addr[1], addr.addr[2], addr.addr[3], addr.addr[4], addr.addr[5], addr.addr_type); + addr.addr_type = data->addr_type; + memcpy(addr.addr, data->p_peer_addr, BLEIO_ADDRESS_BYTES); - ble_gap_conn_params_t conn_params; + BLE_DRIVER_LOG("GAP CONNECTING: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT", type: %d\n", + addr.addr[5], addr.addr[4], addr.addr[3], addr.addr[2], addr.addr[1], addr.addr[0], addr.addr_type); + + ble_gap_conn_params_t conn_params = { + .min_conn_interval = BLE_MIN_CONN_INTERVAL, + .max_conn_interval = BLE_MAX_CONN_INTERVAL, + .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, + .slave_latency = BLE_SLAVE_LATENCY, + }; + + uint32_t err_code; + #if (BLE_API_VERSION == 2) + if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params)) != 0) { + #else + if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_DEFAULT)) != 0) { + #endif + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + } +} -// (void)sd_ble_gap_ppcp_get(&conn_params); +void ble_drv_connect(bleio_device_obj_t *device) { + SD_TEST_OR_ENABLE(); - // set connection parameters - memset(&conn_params, 0, sizeof(conn_params)); + mp_connect_address = &device->address; + ble_drv_adv_report_handler_set(NULL, ble_drv_connect_scan_callback); - conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL; - conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL; - conn_params.slave_latency = BLE_SLAVE_LATENCY; - conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT; + ble_drv_scan_start(100, 100); +} - uint32_t err_code; -#if (BLE_API_VERSION == 2) - if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params)) != 0) { -#else - if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_DEFAULT)) != 0) { -#endif - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not connect. status: 0x%02x"), (uint16_t)err_code)); - } +void ble_drv_disconnect(bleio_device_obj_t *device) { + sd_ble_gap_disconnect(device->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } -bool ble_drv_discover_services(mp_obj_t obj, uint16_t conn_handle, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb) { - BLE_DRIVER_LOG("Discover primary services. Conn handle: 0x" HEX2_FMT "\n", - conn_handle); +bool ble_drv_discover_services(bleio_device_obj_t *device, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb) { + BLE_DRIVER_LOG("Discover primary services. Conn handle: 0x" HEX2_FMT "\n", device->conn_handle); - mp_gattc_disc_service_observer = obj; + mp_gattc_disc_service_observer = device; disc_add_service_handler = cb; m_primary_service_found = false; uint32_t err_code; - err_code = sd_ble_gattc_primary_services_discover(conn_handle, - start_handle, - NULL); + err_code = sd_ble_gattc_primary_services_discover(device->conn_handle, start_handle, NULL); if (err_code != 0) { return false; } // busy loop until last service has been iterated while (disc_add_service_handler != NULL) { - ; +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif } - if (m_primary_service_found) { - return true; - } else { - return false; - } + return m_primary_service_found; } -bool ble_drv_discover_characteristic(mp_obj_t obj, - uint16_t conn_handle, - uint16_t start_handle, - uint16_t end_handle, - ble_drv_disc_add_char_callback_t cb) { - BLE_DRIVER_LOG("Discover characteristicts. Conn handle: 0x" HEX2_FMT "\n", - conn_handle); +bool ble_drv_discover_characteristic(bleio_device_obj_t *device, bleio_service_obj_t *service, uint16_t start_handle, ble_drv_disc_add_char_callback_t cb) { + BLE_DRIVER_LOG("Discover characteristicts. Conn handle: 0x" HEX2_FMT "\n", device->conn_handle); - mp_gattc_disc_char_observer = obj; + mp_gattc_disc_char_observer = service; disc_add_char_handler = cb; ble_gattc_handle_range_t handle_range; handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; + handle_range.end_handle = service->end_handle; m_characteristic_found = false; - uint32_t err_code; - err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + uint32_t err_code = sd_ble_gattc_characteristics_discover(device->conn_handle, &handle_range); if (err_code != 0) { return false; } // busy loop until last service has been iterated while (disc_add_char_handler != NULL) { - ; +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif } - if (m_characteristic_found) { - return true; - } else { - return false; - } + return m_characteristic_found; } void ble_drv_discover_descriptors(void) { @@ -908,12 +854,8 @@ void ble_drv_discover_descriptors(void) { } static void ble_evt_handler(ble_evt_t * p_ble_evt) { -// S132 event ranges. -// Common 0x01 -> 0x0F -// GAP 0x10 -> 0x2F -// GATTC 0x30 -> 0x4F -// GATTS 0x50 -> 0x6F -// L2CAP 0x70 -> 0x8F + printf("%s - 0x%02X\r\n", __func__, p_ble_evt->header.evt_id); + switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: BLE_DRIVER_LOG("GAP CONNECT\n"); @@ -1104,7 +1046,7 @@ static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attr static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)] __attribute__ ((aligned (4))); #endif -void SWI2_EGU2_IRQHandler(void) { +void SD_EVT_IRQHandler(void) { uint32_t evt_id; uint32_t err_code; do { diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index 8c6bd6ce3..e5282db73 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -32,12 +32,12 @@ #include #include +#include "shared-module/bleio/AdvertisementData.h" #include "shared-module/bleio/Characteristic.h" +#include "shared-module/bleio/Device.h" #include "shared-module/bleio/Scanner.h" #include "shared-module/bleio/Service.h" -#include "modubluepy.h" - typedef struct { uint8_t addr[6]; uint8_t addr_type; @@ -75,12 +75,12 @@ typedef struct { uint16_t value_handle; } ble_drv_char_data_t; -typedef void (*ble_drv_gap_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_gatts_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_gattc_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_adv_evt_callback_t)(bleio_scanner_obj_t *self, ble_drv_adv_data_t *data); -typedef void (*ble_drv_disc_add_service_callback_t)(mp_obj_t self, ble_drv_service_data_t * p_service_data); -typedef void (*ble_drv_disc_add_char_callback_t)(mp_obj_t self, ble_drv_char_data_t * p_desc_data); +typedef void (*ble_drv_gap_evt_callback_t)(bleio_device_obj_t *device, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_gatts_evt_callback_t)(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_gattc_evt_callback_t)(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_adv_evt_callback_t)(bleio_scanner_obj_t *scanner, ble_drv_adv_data_t *data); +typedef void (*ble_drv_disc_add_service_callback_t)(bleio_device_obj_t *device, ble_drv_service_data_t * p_service_data); +typedef void (*ble_drv_disc_add_char_callback_t)(bleio_service_obj_t *service, ble_drv_char_data_t * p_desc_data); typedef void (*ble_drv_gattc_char_data_callback_t)(bleio_characteristic_obj_t *self, uint16_t length, uint8_t * p_data); uint32_t ble_drv_stack_enable(void); @@ -97,15 +97,15 @@ void ble_drv_service_add(bleio_service_obj_t *service); bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic); -bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params); +bool ble_drv_advertise_data(bleio_advertisement_data_t *p_adv_params); void ble_drv_advertise_stop(void); -void ble_drv_gap_event_handler_set(mp_obj_t obs, ble_drv_gap_evt_callback_t evt_handler); +void ble_drv_gap_event_handler_set(bleio_device_obj_t *device, ble_drv_gap_evt_callback_t evt_handler); -void ble_drv_gatts_event_handler_set(mp_obj_t obj, ble_drv_gatts_evt_callback_t evt_handler); +void ble_drv_gatts_event_handler_set(bleio_device_obj_t *device, ble_drv_gatts_evt_callback_t evt_handler); -void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler); +void ble_drv_gattc_event_handler_set(bleio_device_obj_t *device, ble_drv_gattc_evt_callback_t evt_handler); void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); @@ -125,15 +125,13 @@ void ble_drv_scan_stop(void); void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_callback_t evt_handler); -void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type); +void ble_drv_connect(bleio_device_obj_t *device); + +void ble_drv_disconnect(bleio_device_obj_t *device); -bool ble_drv_discover_services(mp_obj_t obj, uint16_t conn_handle, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb); +bool ble_drv_discover_services(bleio_device_obj_t *device, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb); -bool ble_drv_discover_characteristic(mp_obj_t obj, - uint16_t conn_handle, - uint16_t start_handle, - uint16_t end_handle, - ble_drv_disc_add_char_callback_t cb); +bool ble_drv_discover_characteristic(bleio_device_obj_t *device, bleio_service_obj_t *service, uint16_t start_handle, ble_drv_disc_add_char_callback_t cb); void ble_drv_discover_descriptors(void); diff --git a/ports/nrf/drivers/bluetooth/ble_uart.h b/ports/nrf/drivers/bluetooth/ble_uart.h index e67176a26..336624cd3 100644 --- a/ports/nrf/drivers/bluetooth/ble_uart.h +++ b/ports/nrf/drivers/bluetooth/ble_uart.h @@ -29,7 +29,6 @@ #if BLUETOOTH_SD -#include "modubluepy.h" #include "ble_drv.h" void ble_uart_init0(void); diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c deleted file mode 100644 index f8266a82d..000000000 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/obj.h" - -#if MICROPY_PY_UBLUEPY - -extern const mp_obj_type_t ubluepy_peripheral_type; -extern const mp_obj_type_t ubluepy_service_type; - -STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluepy) }, -#if MICROPY_PY_UBLUEPY_PERIPHERAL - { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&ubluepy_peripheral_type) }, -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(mp_module_ubluepy_globals, mp_module_ubluepy_globals_table); - -const mp_obj_module_t mp_module_ubluepy = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_ubluepy_globals, -}; - -#endif // MICROPY_PY_UBLUEPY diff --git a/ports/nrf/modules/ubluepy/modubluepy.h b/ports/nrf/modules/ubluepy/modubluepy.h deleted file mode 100644 index e301f0476..000000000 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef UBLUEPY_H__ -#define UBLUEPY_H__ - -/* Examples: - -Advertisment: - -from ubluepy import Peripheral -p = Peripheral() -p.advertise(device_name="MicroPython") - -DB setup: - -from ubluepy import Service, Characteristic, UUID, Peripheral, constants -from pyb import LED - -def event_handler(id, handle, data): - print("BLE event:", id, "handle:", handle) - print(data) - - if id == constants.EVT_GAP_CONNECTED: - # connected - LED(2).on() - elif id == constants.EVT_GAP_DISCONNECTED: - # disconnect - LED(2).off() - elif id == 80: - print("id 80, data:", data) - -# u0 = UUID("0x180D") # HRM service -# u1 = UUID("0x2A37") # HRM measurement - -u0 = UUID("6e400001-b5a3-f393-e0a9-e50e24dcca9e") -u1 = UUID("6e400002-b5a3-f393-e0a9-e50e24dcca9e") -u2 = UUID("6e400003-b5a3-f393-e0a9-e50e24dcca9e") -s = Service(u0) -c0 = Characteristic(u1, props = Characteristic.PROP_WRITE | Characteristic.PROP_WRITE_WO_RESP) -c1 = Characteristic(u2, props = Characteristic.PROP_NOTIFY, attrs = Characteristic.ATTR_CCCD) -s.addCharacteristic(c0) -s.addCharacteristic(c1) -p = Peripheral() -p.addService(s) -p.setConnectionHandler(event_handler) -p.advertise(device_name="micr", services=[s]) - -*/ - -#include "common-hal/bleio/UUID.h" -#include "py/obj.h" - -extern const mp_obj_type_t ubluepy_peripheral_type; - -typedef enum { - UBLUEPY_ADDR_TYPE_PUBLIC = 0, - UBLUEPY_ADDR_TYPE_RANDOM_STATIC = 1, - UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = 2, - UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = 3, -} ubluepy_addr_type_t; - -typedef enum { - UBLUEPY_ROLE_PERIPHERAL, - UBLUEPY_ROLE_CENTRAL -} ubluepy_role_type_t; - -typedef struct _ubluepy_peripheral_obj_t { - mp_obj_base_t base; - ubluepy_role_type_t role; - volatile uint16_t conn_handle; - mp_obj_t delegate; - mp_obj_t notif_handler; - mp_obj_t conn_handler; - mp_obj_t service_list; -} ubluepy_peripheral_obj_t; - -typedef struct _ubluepy_advertise_data_t { - uint8_t * p_device_name; - uint8_t device_name_len; - mp_obj_t * p_services; - uint8_t num_of_services; - uint8_t * p_data; - uint8_t data_len; - bool connectable; -} ubluepy_advertise_data_t; - -typedef enum _ubluepy_prop_t { - UBLUEPY_PROP_BROADCAST = 0x01, - UBLUEPY_PROP_READ = 0x02, - UBLUEPY_PROP_WRITE_WO_RESP = 0x04, - UBLUEPY_PROP_WRITE = 0x08, - UBLUEPY_PROP_NOTIFY = 0x10, - UBLUEPY_PROP_INDICATE = 0x20, - UBLUEPY_PROP_AUTH_SIGNED_WR = 0x40, -} ubluepy_prop_t; - -typedef enum _ubluepy_attr_t { - UBLUEPY_ATTR_CCCD = 0x01, - UBLUEPY_ATTR_SCCD = 0x02, -} ubluepy_attr_t; - -#endif // UBLUEPY_H__ diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c deleted file mode 100644 index 3b1a0d279..000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Glenn Ruben Bakke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include "py/obj.h" -#include "py/runtime.h" -#include "py/objstr.h" -#include "py/objlist.h" - -#if MICROPY_PY_UBLUEPY - -#include "ble_drv.h" -#include "common-hal/bleio/UUID.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -STATIC void ubluepy_peripheral_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_peripheral_obj_t * self = (ubluepy_peripheral_obj_t *)o; - (void)self; - mp_printf(print, "Peripheral(conn_handle: " HEX2_FMT ")", - self->conn_handle); -} - -STATIC void gap_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (event_id == 16) { // connect event - self->conn_handle = conn_handle; - } else if (event_id == 17) { // disconnect event - self->conn_handle = 0xFFFF; // invalid connection handle - } - - if (self->conn_handler != mp_const_none) { - mp_obj_t args[3]; - mp_uint_t num_of_args = 3; - args[0] = MP_OBJ_NEW_SMALL_INT(event_id); - args[1] = MP_OBJ_NEW_SMALL_INT(conn_handle); - if (data != NULL) { - args[2] = mp_obj_new_bytearray_by_ref(length, data); - } else { - args[2] = mp_const_none; - } - - // for now hard-code all events to conn_handler - mp_call_function_n_kw(self->conn_handler, num_of_args, 0, args); - } - - (void)self; -} - -STATIC void gatts_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (self->conn_handler != mp_const_none) { - mp_obj_t args[3]; - mp_uint_t num_of_args = 3; - args[0] = MP_OBJ_NEW_SMALL_INT(event_id); - args[1] = MP_OBJ_NEW_SMALL_INT(attr_handle); - if (data != NULL) { - args[2] = mp_obj_new_bytearray_by_ref(length, data); - } else { - args[2] = mp_const_none; - } - - // for now hard-code all events to conn_handler - mp_call_function_n_kw(self->conn_handler, num_of_args, 0, args); - } - -} - -#if MICROPY_PY_UBLUEPY_CENTRAL - -static volatile bool m_disc_evt_received; - -STATIC void gattc_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - (void)self; - m_disc_evt_received = true; -} -#endif - -STATIC mp_obj_t ubluepy_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { - ARG_NEW_DEVICE_ADDR, - ARG_NEW_ADDR_TYPE - }; - - static const mp_arg_t allowed_args[] = { - { ARG_NEW_DEVICE_ADDR, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { ARG_NEW_ADDR_TYPE, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - ubluepy_peripheral_obj_t *s = m_new_obj(ubluepy_peripheral_obj_t); - s->base.type = type; - - s->delegate = mp_const_none; - s->conn_handler = mp_const_none; - s->notif_handler = mp_const_none; - s->conn_handle = 0xFFFF; - - s->service_list = mp_obj_new_list(0, NULL); - - return MP_OBJ_FROM_PTR(s); -} - -/// \method withDelegate(DefaultDelegate) -/// Set delegate instance for handling Bluetooth LE events. -/// -STATIC mp_obj_t peripheral_with_delegate(mp_obj_t self_in, mp_obj_t delegate) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - self->delegate = delegate; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_with_delegate_obj, peripheral_with_delegate); - -/// \method setNotificationHandler(func) -/// Set handler for Bluetooth LE notification events. -/// -STATIC mp_obj_t peripheral_set_notif_handler(mp_obj_t self_in, mp_obj_t func) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - self->notif_handler = func; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_set_notif_handler_obj, peripheral_set_notif_handler); - -/// \method setConnectionHandler(func) -/// Set handler for Bluetooth LE connection events. -/// -STATIC mp_obj_t peripheral_set_conn_handler(mp_obj_t self_in, mp_obj_t func) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - self->conn_handler = func; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_set_conn_handler_obj, peripheral_set_conn_handler); - -#if MICROPY_PY_UBLUEPY_PERIPHERAL - -/// \method advertise(device_name, [service=[service1, service2, ...]], [data=bytearray], [connectable=True]) -/// Start advertising. Connectable advertisement type by default. -/// -STATIC mp_obj_t peripheral_advertise(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_device_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_services, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - self->role = UBLUEPY_ROLE_PERIPHERAL; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_obj_t device_name_obj = args[0].u_obj; - mp_obj_t service_obj = args[1].u_obj; - mp_obj_t data_obj = args[2].u_obj; - mp_obj_t connectable_obj = args[3].u_obj; - - ubluepy_advertise_data_t adv_data; - memset(&adv_data, 0, sizeof(ubluepy_advertise_data_t)); - - if (device_name_obj != mp_const_none && MP_OBJ_IS_STR(device_name_obj)) { - GET_STR_DATA_LEN(device_name_obj, str_data, str_len); - - adv_data.p_device_name = (uint8_t *)str_data; - adv_data.device_name_len = str_len; - } - - if (service_obj != mp_const_none) { - mp_obj_t * services = NULL; - mp_uint_t num_services; - mp_obj_get_array(service_obj, &num_services, &services); - - if (num_services > 0) { - adv_data.p_services = services; - adv_data.num_of_services = num_services; - } - } - - if (data_obj != mp_const_none) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); - - if (bufinfo.len > 0) { - adv_data.p_data = bufinfo.buf; - adv_data.data_len = bufinfo.len; - } - } - - adv_data.connectable = true; - if (connectable_obj != mp_const_none && !(mp_obj_is_true(connectable_obj))) { - adv_data.connectable = false; - } else { - ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(self), gap_event_handler); - ble_drv_gatts_event_handler_set(MP_OBJ_FROM_PTR(self), gatts_event_handler); - } - - (void)ble_drv_advertise_data(&adv_data); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_peripheral_advertise_obj, 0, peripheral_advertise); - -/// \method advertise_stop() -/// Stop advertisement if any onging advertisement. -/// -STATIC mp_obj_t peripheral_advertise_stop(mp_obj_t self_in) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - (void)self; - - ble_drv_advertise_stop(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_advertise_stop_obj, peripheral_advertise_stop); - -#endif // MICROPY_PY_UBLUEPY_PERIPHERAL - -/// \method disconnect() -/// disconnect connection. -/// -STATIC mp_obj_t peripheral_disconnect(mp_obj_t self_in) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - (void)self; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_disconnect_obj, peripheral_disconnect); - -/// \method addService(Service) -/// Add service to the Peripheral. -/// -STATIC mp_obj_t peripheral_add_service(mp_obj_t self_in, mp_obj_t service) { - ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); - bleio_service_obj_t * p_service = MP_OBJ_TO_PTR(service); - - p_service->periph = self_in; - - mp_obj_list_append(self->service_list, service); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_add_service_obj, peripheral_add_service); - -/// \method getServices() -/// Return list with all service registered in the Peripheral. -/// -STATIC mp_obj_t peripheral_get_services(mp_obj_t self_in) { - ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); - - return self->service_list; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_get_services_obj, peripheral_get_services); - -#if MICROPY_PY_UBLUEPY_CENTRAL - -void static disc_add_service(mp_obj_t self, ble_drv_service_data_t * p_service_data) { - bleio_service_obj_t * p_service = m_new_obj(bleio_service_obj_t); - p_service->base.type = &bleio_service_type; - - bleio_uuid_obj_t * p_uuid = m_new_obj(bleio_uuid_obj_t); - p_uuid->base.type = &bleio_uuid_type; - - p_service->uuid = p_uuid; - - p_uuid->type = p_service_data->uuid_type; - p_uuid->value[0] = p_service_data->uuid & 0xFF; - p_uuid->value[1] = p_service_data->uuid >> 8; - - p_service->handle = p_service_data->start_handle; - p_service->start_handle = p_service_data->start_handle; - p_service->end_handle = p_service_data->end_handle; - - p_service->char_list = mp_obj_new_list(0, NULL); - - peripheral_add_service(self, MP_OBJ_FROM_PTR(p_service)); -} - -void static disc_add_char(mp_obj_t service_in, ble_drv_char_data_t * p_desc_data) { - bleio_service_obj_t * p_service = MP_OBJ_TO_PTR(service_in); - bleio_characteristic_obj_t * p_char = m_new_obj(bleio_characteristic_obj_t); - p_char->base.type = &bleio_characteristic_type; - - bleio_uuid_obj_t * p_uuid = m_new_obj(bleio_uuid_obj_t); - p_uuid->base.type = &bleio_uuid_type; - - p_char->uuid = p_uuid; - - p_uuid->type = p_desc_data->uuid_type; - p_uuid->value[0] = p_desc_data->uuid & 0xFF; - p_uuid->value[1] = p_desc_data->uuid >> 8; - - // add characteristic specific data from discovery - p_char->props.broadcast = p_desc_data->props.broadcast; - p_char->props.indicate = p_desc_data->props.indicate; - p_char->props.notify = p_desc_data->props.notify; - p_char->props.read = p_desc_data->props.read; - p_char->props.write = p_desc_data->props.write; - p_char->props.write_wo_resp = p_desc_data->props.write_wo_resp; - p_char->handle = p_desc_data->value_handle; - - // equivalent to ubluepy_service.c - service_add_characteristic() - // except the registration of the characteristic towards the bluetooth stack - p_char->service_handle = p_service->handle; - p_char->service = p_service; - - mp_obj_list_append(p_service->char_list, MP_OBJ_FROM_PTR(p_char)); -} - -/// \method connect(device_address [, addr_type=ADDR_TYPE_PUBLIC]) -/// Connect to device peripheral with the given device address. -/// addr_type can be either ADDR_TYPE_PUBLIC (default) or -/// ADDR_TYPE_RANDOM_STATIC. -/// -STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_obj_t dev_addr = pos_args[1]; - - self->role = UBLUEPY_ROLE_CENTRAL; - - static const mp_arg_t allowed_args[] = { - { MP_QSTR_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UBLUEPY_ADDR_TYPE_PUBLIC } }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - uint8_t addr_type = args[0].u_int; - - ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(self), gap_event_handler); - - if (MP_OBJ_IS_STR(dev_addr)) { - GET_STR_DATA_LEN(dev_addr, str_data, str_len); - if (str_len == 17) { // Example "11:22:33:aa:bb:cc" - - uint8_t * p_addr = m_new(uint8_t, 6); - - p_addr[0] = unichar_xdigit_value(str_data[16]); - p_addr[0] += unichar_xdigit_value(str_data[15]) << 4; - p_addr[1] = unichar_xdigit_value(str_data[13]); - p_addr[1] += unichar_xdigit_value(str_data[12]) << 4; - p_addr[2] = unichar_xdigit_value(str_data[10]); - p_addr[2] += unichar_xdigit_value(str_data[9]) << 4; - p_addr[3] = unichar_xdigit_value(str_data[7]); - p_addr[3] += unichar_xdigit_value(str_data[6]) << 4; - p_addr[4] = unichar_xdigit_value(str_data[4]); - p_addr[4] += unichar_xdigit_value(str_data[3]) << 4; - p_addr[5] = unichar_xdigit_value(str_data[1]); - p_addr[5] += unichar_xdigit_value(str_data[0]) << 4; - - ble_drv_connect(p_addr, addr_type); - - m_del(uint8_t, p_addr, 6); - } - } - - // block until connected - while (self->conn_handle == 0xFFFF) { - ; - } - - ble_drv_gattc_event_handler_set(MP_OBJ_FROM_PTR(self), gattc_event_handler); - - bool service_disc_retval = ble_drv_discover_services(self, self->conn_handle, 0x0001, disc_add_service); - - // continue discovery of primary services ... - while (service_disc_retval) { - // locate the last added service - mp_obj_t * services = NULL; - mp_uint_t num_services; - mp_obj_get_array(self->service_list, &num_services, &services); - - bleio_service_obj_t * p_service = (bleio_service_obj_t *)services[num_services - 1]; - - service_disc_retval = ble_drv_discover_services(self, - self->conn_handle, - p_service->end_handle + 1, - disc_add_service); - } - - // For each service perform a characteristic discovery - mp_obj_t * services = NULL; - mp_uint_t num_services; - mp_obj_get_array(self->service_list, &num_services, &services); - - for (uint16_t s = 0; s < num_services; s++) { - bleio_service_obj_t * p_service = (bleio_service_obj_t *)services[s]; - bool char_disc_retval = ble_drv_discover_characteristic(p_service, - self->conn_handle, - p_service->start_handle, - p_service->end_handle, - disc_add_char); - // continue discovery of characteristics ... - while (char_disc_retval) { - mp_obj_t * characteristics = NULL; - mp_uint_t num_chars; - mp_obj_get_array(p_service->char_list, &num_chars, &characteristics); - - bleio_characteristic_obj_t * p_char = (bleio_characteristic_obj_t *)characteristics[num_chars - 1]; - uint16_t next_handle = p_char->handle + 1; - if ((next_handle) < p_service->end_handle) { - char_disc_retval = ble_drv_discover_characteristic(p_service, - self->conn_handle, - next_handle, - p_service->end_handle, - disc_add_char); - } else { - break; - } - } - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_peripheral_connect_obj, 2, peripheral_connect); - -#endif - -STATIC const mp_rom_map_elem_t ubluepy_peripheral_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_withDelegate), MP_ROM_PTR(&ubluepy_peripheral_with_delegate_obj) }, - { MP_ROM_QSTR(MP_QSTR_setNotificationHandler), MP_ROM_PTR(&ubluepy_peripheral_set_notif_handler_obj) }, - { MP_ROM_QSTR(MP_QSTR_setConnectionHandler), MP_ROM_PTR(&ubluepy_peripheral_set_conn_handler_obj) }, - { MP_ROM_QSTR(MP_QSTR_getServices), MP_ROM_PTR(&ubluepy_peripheral_get_services_obj) }, -#if MICROPY_PY_UBLUEPY_CENTRAL - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ubluepy_peripheral_connect_obj) }, -#if 0 - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&ubluepy_peripheral_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_getServiceByUUID), MP_ROM_PTR(&ubluepy_peripheral_get_service_by_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_peripheral_get_chars_obj) }, - { MP_ROM_QSTR(MP_QSTR_getDescriptors), MP_ROM_PTR(&ubluepy_peripheral_get_descs_obj) }, - { MP_ROM_QSTR(MP_QSTR_waitForNotifications), MP_ROM_PTR(&ubluepy_peripheral_wait_for_notif_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_write_char_obj) }, - { MP_ROM_QSTR(MP_QSTR_readCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_read_char_obj) }, -#endif // 0 -#endif // MICROPY_PY_UBLUEPY_CENTRAL -#if MICROPY_PY_UBLUEPY_PERIPHERAL - { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) }, - { MP_ROM_QSTR(MP_QSTR_advertise_stop), MP_ROM_PTR(&ubluepy_peripheral_advertise_stop_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&ubluepy_peripheral_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_addService), MP_ROM_PTR(&ubluepy_peripheral_add_service_obj) }, -#if 0 - { MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_add_char_obj) }, - { MP_ROM_QSTR(MP_QSTR_addDescriptor), MP_ROM_PTR(&ubluepy_peripheral_add_desc_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_write_char_obj) }, - { MP_ROM_QSTR(MP_QSTR_readCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_read_char_obj) }, -#endif -#endif -#if MICROPY_PY_UBLUEPY_BROADCASTER - { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) }, -#endif -#if MICROPY_PY_UBLUEPY_OBSERVER - // Nothing yet. -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_peripheral_locals_dict, ubluepy_peripheral_locals_dict_table); - -const mp_obj_type_t ubluepy_peripheral_type = { - { &mp_type_type }, - .name = MP_QSTR_Peripheral, - .print = ubluepy_peripheral_print, - .make_new = ubluepy_peripheral_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_peripheral_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index b710808b9..62a041ae9 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -129,21 +129,15 @@ #define CIRCUITPY_GAMEPAD_TICKS 0x1f #if BLUETOOTH_SD -#define MICROPY_PY_BLEIO (1) -#define MICROPY_PY_BLE_NUS (0) -#define MICROPY_PY_UBLUEPY (1) -#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) -#define MICROPY_PY_UBLUEPY_CENTRAL (1) -#define BLUETOOTH_WEBBLUETOOTH_REPL (0) -#endif - -#ifndef MICROPY_PY_BLEIO -#define MICROPY_PY_BLEIO (0) + #define MICROPY_PY_BLEIO (1) + #define MICROPY_PY_BLE_NUS (0) + #define BLUETOOTH_WEBBLUETOOTH_REPL (0) +#else + #ifndef MICROPY_PY_BLEIO + #define MICROPY_PY_BLEIO (0) + #endif #endif -#ifndef MICROPY_PY_UBLUEPY -#define MICROPY_PY_UBLUEPY (0) -#endif // type definitions for the specific machine @@ -184,16 +178,8 @@ extern const struct _mp_obj_module_t neopixel_write_module; extern const struct _mp_obj_module_t usb_hid_module; extern const struct _mp_obj_module_t bleio_module; -extern const struct _mp_obj_module_t mp_module_ubluepy; - -#if MICROPY_PY_UBLUEPY -#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, -#else -#define UBLUEPY_MODULE -#endif - #if MICROPY_PY_BLEIO -#define BLEIO_MODULE { MP_ROM_QSTR(MP_QSTR_bleio), MP_ROM_PTR(&bleio_module) }, +#define BLEIO_MODULE { MP_ROM_QSTR(MP_QSTR_bleio), MP_ROM_PTR(&bleio_module) }, #else #define BLEIO_MODULE #endif @@ -221,8 +207,7 @@ extern const struct _mp_obj_module_t mp_module_ubluepy; { MP_OBJ_NEW_QSTR (MP_QSTR_gamepad ), (mp_obj_t)&gamepad_module }, \ { MP_OBJ_NEW_QSTR (MP_QSTR_time ), (mp_obj_t)&time_module }, \ USBHID_MODULE \ - BLEIO_MODULE \ - UBLUEPY_MODULE \ + BLEIO_MODULE // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ diff --git a/shared-bindings/bleio/Device.c b/shared-bindings/bleio/Device.c new file mode 100644 index 000000000..15ebd51ed --- /dev/null +++ b/shared-bindings/bleio/Device.c @@ -0,0 +1,348 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "ble_drv.h" +#include "py/objarray.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Adapter.h" +#include "shared-bindings/bleio/AddressType.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Device.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" +#include "shared-module/bleio/AdvertisementData.h" +#include "shared-module/bleio/Device.h" + +//| .. currentmodule:: bleio +//| +//| :class:`Device` -- BLE device +//| ========================================================= +//| +//| Provides access a to BLE device, either in a Peripheral or Central role. +//| When a device is created without any parameter passed to the constructor, +//| it will be set to the Peripheral role. If a address is passed, the device +//| will be a Central. For a Peripheral you can set the `name`, add services +//| via `add_service` and then start and stop advertising via `start_advertising` +//| and `stop_advertising`. For the Central, you can `bleio.Device.connect` and `bleio.Device.disconnect` +//| to the device, once a connection is established, the device's services can +//| be accessed using `services`. +//| +//| Usage:: +//| +//| import bleio +//| +//| # Peripheral +//| periph = bleio.Device() +//| +//| serv = bleio.Service(bleio.UUID(0x180f)) +//| p.add_service(serv) +//| +//| chara = bleio.Characteristic(bleio.UUID(0x2919)) +//| chara.read = True +//| chara.notify = True +//| serv.add_characteristic(chara) +//| +//| periph.start_advertising() +//| +//| # Central +//| scanner = bleio.Scanner() +//| entries = scanner.scan(2500) +//| +//| my_entry = None +//| for entry in entries: +//| if entry.name is not None and entry.name == 'MyDevice': +//| my_entry = entry +//| break +//| +//| central = bleio.Device(my_entry.address) +//| central.connect() +//| + +//| .. class:: Device(address=None) +//| +//| Create a new Device object. If the `address` parameter is not `None`, +//| the role is set to Central, otherwise it's set to Peripheral. +//| +//| :param bleio.Address address: The address of the device to connect to +//| + +//| .. attribute:: name +//| +//| For the Peripheral role, this property can be used to read and write the device's name. +//| For the Central role, this property will equal the name of the remote device, if one was +//| advertised by the device. In the Central role this property is read-only. +//| + +//| .. attribute:: services +//| +//| A `list` of `bleio.Service` that are offered by this device. (read-only) +//| For a Peripheral device, this list will contain services added using `add_service`, +//| for a Central, this list will be empty until a connection is established, at which point +//| it will be filled with the remote device's services. +//| + +//| .. method:: add_service(service) +//| +//| Appends the :py:data:`service` to the list of this devices's services. +//| This method can only be called for Peripheral devices. +//| +//| :param bleio.Service service: the service to append +//| + +//| .. method:: connect() +//| +//| Attempts a connection to the remote device. If the connection is successful, +//| the device's services are available via `services`. +//| This method can only be called for Central devices. +//| + +//| .. method:: disconnect() +//| +//| Disconnects from the remote device. +//| This method can only be called for Central devices. +//| + +//| .. method:: start_advertising(connectable=True) +//| +//| Starts advertising the device. The device's name and +//| services are put into the advertisement packets. +//| If :py:data:`connectable` is `True` then other devices are allowed to conncet to this device. +//| This method can only be called for Peripheral devices. +//| + +//| .. method:: stop_advertising() +//| +//| Disconnects from the remote device. +//| This method can only be called for Peripheral devices. +//| +static const char default_name[] = "CIRCUITPY"; + +STATIC void bleio_device_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_printf(print, "Device(role: %s)", self->is_peripheral ? "Peripheral" : "Central"); +} + +STATIC mp_obj_t bleio_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, 1, true); + bleio_device_obj_t *self = m_new_obj(bleio_device_obj_t); + self->base.type = &bleio_device_type; + self->service_list = mp_obj_new_list(0, NULL); + self->notif_handler = mp_const_none; + self->conn_handler = mp_const_none; + self->conn_handle = 0xFFFF; + self->is_peripheral = true; + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + + //TODO: Add ScanEntry + enum { ARG_address }; + static const mp_arg_t allowed_args[] = { + { ARG_address, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t address_obj = args[ARG_address].u_obj; + + if (address_obj != mp_const_none) { + bleio_address_obj_t *address = MP_OBJ_TO_PTR(address_obj); + + self->is_peripheral = false; + self->address.type = address->type; + memcpy(self->address.value, address->value, BLEIO_ADDRESS_BYTES); + } else { + self->name = mp_obj_new_str(default_name, strlen(default_name), false); + common_hal_bleio_adapter_get_address(&self->address); + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t bleio_device_add_service(mp_obj_t self_in, mp_obj_t service_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_in); + + if (!self->is_peripheral) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Can't add services in Central mode")); + } + + service->device = self_in; + + mp_obj_list_append(self->service_list, service); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_device_add_service_obj, bleio_device_add_service); + +STATIC mp_obj_t bleio_device_connect(mp_obj_t self_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->is_peripheral) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Can't connect in Peripheral mode")); + } + + common_hal_bleio_device_connect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_connect_obj, bleio_device_connect); + +STATIC mp_obj_t bleio_device_disconnect(mp_obj_t self_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_device_disconnect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_disconnect_obj, bleio_device_disconnect); + +STATIC mp_obj_t bleio_device_get_name(mp_obj_t self_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return self->name; +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_get_name_obj, bleio_device_get_name); + +static mp_obj_t bleio_device_set_name(mp_obj_t self_in, mp_obj_t value) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!self->is_peripheral) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Can't change the name in Central mode")); + } + + self->name = value; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_device_set_name_obj, bleio_device_set_name); + +const mp_obj_property_t bleio_device_name_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_device_get_name_obj, + (mp_obj_t)&bleio_device_set_name_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC mp_obj_t bleio_device_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + if (!self->is_peripheral) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Can't advertise in Central mode")); + } + + enum { ARG_connectable }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // TODO: data + bleio_advertisement_data_t adv_data = { + .device_name = self->name, + .services = mp_obj_new_list(0, NULL), + .data = mp_obj_new_bytearray(0, NULL), + .connectable = args[ARG_connectable].u_bool + }; + + mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list); + for (size_t i = 0; i < service_list->len; ++i) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + if (!service->is_secondary) { + mp_obj_list_append(adv_data.services, service_list->items[i]); + } + } + + common_hal_bleio_device_start_advertising(self, &adv_data); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_device_start_advertising_obj, 0, bleio_device_start_advertising); + +STATIC mp_obj_t bleio_device_stop_advertising(mp_obj_t self_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->is_peripheral) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Can't advertise in Central mode")); + } + + common_hal_bleio_device_stop_advertising(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_stop_advertising_obj, bleio_device_stop_advertising); + +STATIC mp_obj_t bleio_device_get_services(mp_obj_t self_in) { + bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return self->service_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_get_services_obj, bleio_device_get_services); + +const mp_obj_property_t bleio_device_services_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_device_get_services_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_device_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_add_service), MP_ROM_PTR(&bleio_device_add_service_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_device_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_device_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_device_start_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_device_stop_advertising_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_device_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_device_services_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_device_locals_dict, bleio_device_locals_dict_table); + +const mp_obj_type_t bleio_device_type = { + { &mp_type_type }, + .name = MP_QSTR_Device, + .print = bleio_device_print, + .make_new = bleio_device_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_device_locals_dict +}; diff --git a/shared-bindings/bleio/Device.h b/shared-bindings/bleio/Device.h new file mode 100644 index 000000000..d099e5c43 --- /dev/null +++ b/shared-bindings/bleio/Device.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H + +#include "shared-module/bleio/AdvertisementData.h" +#include "shared-module/bleio/Device.h" + +extern const mp_obj_type_t bleio_device_type; + +extern void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bleio_advertisement_data_t *adv_data); +extern void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device); +extern void common_hal_bleio_device_connect(bleio_device_obj_t *device); +extern void common_hal_bleio_device_disconnect(bleio_device_obj_t *device); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H diff --git a/shared-bindings/bleio/ScanEntry.c b/shared-bindings/bleio/ScanEntry.c index e38a08909..2eed24cd8 100644 --- a/shared-bindings/bleio/ScanEntry.c +++ b/shared-bindings/bleio/ScanEntry.c @@ -32,9 +32,10 @@ #include "py/objstr.h" #include "py/objtuple.h" #include "shared-bindings/bleio/Address.h" -#include "shared-module/bleio/AdvertisementData.h" -#include "shared-bindings/bleio/UUID.h" #include "shared-bindings/bleio/ScanEntry.h" +#include "shared-bindings/bleio/UUID.h" +#include "shared-module/bleio/AdvertisementData.h" +#include "shared-module/bleio/ScanEntry.h" //| .. currentmodule:: bleio //| diff --git a/shared-bindings/bleio/ScanEntry.h b/shared-bindings/bleio/ScanEntry.h index 4a201124e..2b44ba3f4 100644 --- a/shared-bindings/bleio/ScanEntry.h +++ b/shared-bindings/bleio/ScanEntry.h @@ -28,16 +28,7 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H -#include "shared-module/bleio/Address.h" -#include "py/objtype.h" - -typedef struct { - mp_obj_base_t base; - bleio_address_obj_t address; - bool connectable; - int8_t rssi; - mp_obj_t data; -} bleio_scanentry_obj_t; +#include "py/obj.h" extern const mp_obj_type_t bleio_scanentry_type; diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index 6451991e9..5b61a2966 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -73,7 +73,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_check_num(n_args, n_kw, 1, 1, true); bleio_service_obj_t *self = m_new_obj(bleio_service_obj_t); self->base.type = &bleio_service_type; - self->periph = mp_const_none; + self->device = mp_const_none; self->char_list = mp_obj_new_list(0, NULL); mp_map_t kw_args; @@ -81,7 +81,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, enum { ARG_uuid, ARG_secondary }; static const mp_arg_t allowed_args[] = { - { ARG_uuid, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { ARG_uuid, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; @@ -92,7 +92,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t uuid = args[ARG_uuid].u_obj; - if (uuid == MP_OBJ_NULL) { + if (uuid == mp_const_none) { return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 9f5a8f8f2..98099422c 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -31,6 +31,7 @@ #include "shared-bindings/bleio/AdvertisementData.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/Device.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" #include "shared-bindings/bleio/Service.h" @@ -57,6 +58,7 @@ //| Adapter //| Characteristic //| Descriptor +//| Device //| ScanEntry //| Scanner //| Service @@ -76,6 +78,7 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_AdvertisementData), MP_ROM_PTR(&bleio_advertisementdata_type) }, { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_Device), MP_ROM_PTR(&bleio_device_type) }, { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, diff --git a/shared-module/bleio/AdvertisementData.h b/shared-module/bleio/AdvertisementData.h index 2a9addf57..738d53b23 100644 --- a/shared-module/bleio/AdvertisementData.h +++ b/shared-module/bleio/AdvertisementData.h @@ -27,6 +27,8 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H +#include "py/obj.h" + // Taken from https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile enum { AdFlags = 0x01, @@ -73,4 +75,11 @@ enum { AdManufacturerSpecificData = 0xFF, }; +typedef struct { + mp_obj_t device_name; + mp_obj_t services; + mp_obj_t data; + bool connectable; +} bleio_advertisement_data_t; + #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADVERTISEMENTDATA_H diff --git a/shared-module/bleio/Device.h b/shared-module/bleio/Device.h new file mode 100644 index 000000000..afbd8f063 --- /dev/null +++ b/shared-module/bleio/Device.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_DEVICE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_DEVICE_H + +#include + +#include "shared-module/bleio/Address.h" + +typedef struct { + mp_obj_base_t base; + bool is_peripheral; + mp_obj_t name; + bleio_address_obj_t address; + uint16_t conn_handle; + mp_obj_t service_list; + mp_obj_t notif_handler; + mp_obj_t conn_handler; +} bleio_device_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_DEVICE_H diff --git a/shared-module/bleio/ScanEntry.h b/shared-module/bleio/ScanEntry.h new file mode 100644 index 000000000..2f01669e2 --- /dev/null +++ b/shared-module/bleio/ScanEntry.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Artur Pacholec + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H + +#include "shared-module/bleio/Address.h" + +typedef struct { + mp_obj_base_t base; + bleio_address_obj_t address; + bool connectable; + int8_t rssi; + mp_obj_t data; +} bleio_scanentry_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H diff --git a/shared-module/bleio/Service.h b/shared-module/bleio/Service.h index bd359a41d..1e3f09119 100644 --- a/shared-module/bleio/Service.h +++ b/shared-module/bleio/Service.h @@ -27,7 +27,6 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H -#include "modubluepy.h" #include "common-hal/bleio/UUID.h" typedef struct { @@ -35,7 +34,7 @@ typedef struct { uint16_t handle; bool is_secondary; bleio_uuid_obj_t *uuid; - mp_obj_t periph; + mp_obj_t device; mp_obj_t char_list; uint16_t start_handle; uint16_t end_handle; -- cgit v1.2.3 From 17f13ecc2cf10975bf5ff0631ce4326b9ffbbcf5 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Sun, 22 Jul 2018 16:06:19 +0200 Subject: nrf: Cleanup of the ble driver Moved the functions to classes that they belong to. --- ports/nrf/common-hal/bleio/Adapter.c | 117 ++- ports/nrf/common-hal/bleio/Characteristic.c | 159 +++- ports/nrf/common-hal/bleio/Device.c | 535 +++++++++++++- ports/nrf/common-hal/bleio/Scanner.c | 72 +- ports/nrf/common-hal/bleio/Service.c | 85 ++- ports/nrf/common-hal/bleio/UUID.c | 48 +- ports/nrf/drivers/bluetooth/ble_drv.c | 1038 ++------------------------- ports/nrf/drivers/bluetooth/ble_drv.h | 68 +- ports/nrf/drivers/bluetooth/ble_uart.h | 4 +- shared-bindings/bleio/Characteristic.c | 2 + shared-bindings/bleio/Characteristic.h | 1 + shared-bindings/bleio/Device.c | 24 +- shared-bindings/bleio/Device.h | 2 +- shared-bindings/bleio/Scanner.h | 1 + shared-bindings/bleio/Service.c | 2 +- shared-module/bleio/Characteristic.h | 2 +- shared-module/bleio/Device.h | 2 +- shared-module/bleio/Service.h | 3 +- 18 files changed, 1024 insertions(+), 1141 deletions(-) (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Adapter.c b/ports/nrf/common-hal/bleio/Adapter.c index bee9bd395..dd2fd00dd 100644 --- a/ports/nrf/common-hal/bleio/Adapter.c +++ b/ports/nrf/common-hal/bleio/Adapter.c @@ -28,32 +28,133 @@ #include #include +#include "ble.h" #include "ble_drv.h" -#include "nrfx.h" -#include "nrf_error.h" +#include "nrfx_power.h" +#include "nrf_nvic.h" #include "nrf_sdm.h" #include "py/nlr.h" -#include "shared-module/bleio/Address.h" +#include "shared-bindings/bleio/Adapter.h" + +STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AssertionError, + "Soft device assert, id: 0x%08lX, pc: 0x%08lX", id, pc)); +} + +STATIC uint32_t ble_stack_enable(void) { + nrf_clock_lf_cfg_t clock_config = { + .source = NRF_CLOCK_LF_SRC_XTAL, +#if (BLE_API_VERSION == 4) + .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM +#else + .xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM +#endif + }; + +#if (BLUETOOTH_SD == 140) + // The SD takes over the POWER IRQ and will fail if the IRQ is already in use + nrfx_power_uninit(); +#endif + + uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler); + if (err_code != NRF_SUCCESS) + return err_code; + + err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); + if (err_code != NRF_SUCCESS) + return err_code; + + uint32_t app_ram_start; +#if (BLE_API_VERSION == 2) + ble_enable_params_t ble_enable_params = { + .gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, + .gap_enable_params.central_conn_count = 1, + .gap_enable_params.periph_conn_count = 1, + }; + + app_ram_start = 0x200039c0; + err_code = sd_ble_enable(&ble_enable_params, &app_ram_start); +#else + app_ram_start = 0x20004000; + + ble_cfg_t ble_conf; + ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; + ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = BLE_GAP_CONN_COUNT_DEFAULT; + ble_conf.conn_cfg.params.gap_conn_cfg.event_length = BLE_GAP_EVENT_LENGTH_DEFAULT; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + memset(&ble_conf, 0, sizeof(ble_conf)); + ble_conf.gap_cfg.role_count_cfg.periph_role_count = 1; + ble_conf.gap_cfg.role_count_cfg.central_role_count = 1; + err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + memset(&ble_conf, 0, sizeof(ble_conf)); + ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; + ble_conf.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = MAX_TX_IN_PROGRESS; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + err_code = sd_ble_enable(&app_ram_start); +#endif + + return err_code; +} void common_hal_bleio_adapter_set_enabled(bool enabled) { - uint32_t err_code; + const bool is_enabled = common_hal_bleio_adapter_get_enabled(); + // Don't enable or disable twice + if ((is_enabled && enabled) || (!is_enabled && !enabled)) { + return; + } + + uint32_t err_code; if (enabled) { - err_code = ble_drv_stack_enable(); + err_code = ble_stack_enable(); } else { err_code = sd_softdevice_disable(); } if (err_code != NRF_SUCCESS) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Failed to change softdevice status, error: 0x%08lX", err_code)); + "Failed to change softdevice state, error: 0x%08lX", err_code)); } } bool common_hal_bleio_adapter_get_enabled(void) { - return ble_drv_stack_enabled(); + uint8_t is_enabled; + + const uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to get softdevice state, error: 0x%08lX", err_code)); + } + + return is_enabled; } void common_hal_bleio_adapter_get_address(bleio_address_obj_t *address) { - ble_drv_address_get(address); + ble_gap_addr_t local_address; + uint32_t err_code; + + common_hal_bleio_adapter_set_enabled(true); + +#if (BLE_API_VERSION == 2) + err_code = sd_ble_gap_address_get(&local_address); +#else + err_code = sd_ble_gap_addr_get(&local_address); +#endif + + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to get local address, error: 0x%08lX", err_code)); + } + + address->type = local_address.addr_type; + memcpy(address->value, local_address.addr, BLEIO_ADDRESS_BYTES); } diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 35b4f5e24..040cacc3f 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -24,26 +24,173 @@ * THE SOFTWARE. */ +#include +#include + #include "ble_drv.h" +#include "ble_gatts.h" +#include "nrf_soc.h" +#include "py/nlr.h" #include "shared-module/bleio/Characteristic.h" -#include "shared-module/bleio/Device.h" + +static volatile bleio_characteristic_obj_t *m_read_characteristic; +static volatile uint8_t m_tx_in_progress; +static nrf_mutex_t *m_write_mutex; +//static volatile bool m_write_done; + +STATIC void gatts_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + bleio_device_obj_t *device = characteristic->service->device; + const uint16_t conn_handle = device->conn_handle; + + ble_gatts_value_t gatts_value = { + .p_value = bufinfo->buf, + .len = bufinfo->len, + }; + + const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, characteristic->handle, &gatts_value); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to write gatts value, status: 0x%08lX", err_code)); + } +} + +STATIC void gatts_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + bleio_device_obj_t *device = characteristic->service->device; + uint16_t hvx_len = bufinfo->len; + + ble_gatts_hvx_params_t hvx_params = { + .handle = characteristic->handle, + .type = BLE_GATT_HVX_NOTIFICATION, + .p_len = &hvx_len, + .p_data = bufinfo->buf, + }; + + while (m_tx_in_progress > MAX_TX_IN_PROGRESS) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif + } + + const uint32_t err_code = sd_ble_gatts_hvx(device->conn_handle, &hvx_params); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to notify attribute value, status: 0x%08lX", err_code)); + } + + m_tx_in_progress += 1; +} + +STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) { + bleio_service_obj_t *service = characteristic->service; + bleio_device_obj_t *device = service->device; + + m_read_characteristic = characteristic; + + const uint32_t err_code = sd_ble_gattc_read(device->conn_handle, characteristic->handle, 0); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to read attribute value, status: 0x%08lX", err_code)); + } + + while (m_read_characteristic != NULL) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif + } +} + +STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { + bleio_device_obj_t *device = characteristic->service->device; + uint16_t conn_handle = device->conn_handle; + uint32_t err_code; + + ble_gattc_write_params_t write_params; + write_params.write_op = BLE_GATT_OP_WRITE_REQ; + + if (characteristic->props.write_wo_resp) { + write_params.write_op = BLE_GATT_OP_WRITE_CMD; + } + + write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL; + write_params.handle = characteristic->handle; + write_params.offset = 0; + write_params.len = bufinfo->len; + write_params.p_value = bufinfo->buf; + + if (write_params.write_op == BLE_GATT_OP_WRITE_CMD) { + err_code = sd_mutex_acquire(m_write_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to acquire mutex, status: 0x%08lX", err_code)); + } + } + + err_code = sd_ble_gattc_write(conn_handle, &write_params); + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to write attribute value, status: 0x%08lX", err_code)); + } + + while (sd_mutex_acquire(m_write_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif + } + + err_code = sd_mutex_release(m_write_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to release mutex, status: 0x%08lX", err_code)); + } +} + +STATIC void on_ble_evt(ble_evt_t *ble_evt, void *param) { + switch (ble_evt->header.evt_id) { +#if (BLE_API_VERSION == 4) + case BLE_GATTS_EVT_HVN_TX_COMPLETE: + m_tx_in_progress -= ble_evt->evt.gatts_evt.params.hvn_tx_complete.count; + break; +#else + case BLE_EVT_TX_COMPLETE: + m_tx_in_progress -= ble_evt->evt.common_evt.params.tx_complete.count; + break; +#endif + + case BLE_GATTC_EVT_READ_RSP: + { + ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; + m_read_characteristic->value_data = mp_obj_new_bytearray(response->len, response->data); + m_read_characteristic = NULL; + break; + } + + case BLE_GATTC_EVT_WRITE_RSP: + sd_mutex_release(m_write_mutex); +// m_write_done = true; + break; + } +} + +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self) { + ble_drv_add_event_handler(on_ble_evt, NULL); +} void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self) { - ble_drv_attr_c_read(self); + gattc_read(self); } void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - const bleio_device_obj_t *device = MP_OBJ_TO_PTR(self->service->device); + const bleio_device_obj_t *device = self->service->device; if (device->is_peripheral) { // TODO: Add indications if (self->props.notify) { - ble_drv_attr_s_notify(self, bufinfo); + gatts_notify(self, bufinfo); } else { - ble_drv_attr_s_write(self, bufinfo); + gatts_write(self, bufinfo); } } else { - ble_drv_attr_c_write(self, bufinfo); + gattc_write(self, bufinfo); } } diff --git a/ports/nrf/common-hal/bleio/Device.c b/ports/nrf/common-hal/bleio/Device.c index 9e7b382dd..195b6cd32 100644 --- a/ports/nrf/common-hal/bleio/Device.c +++ b/ports/nrf/common-hal/bleio/Device.c @@ -24,49 +24,528 @@ * THE SOFTWARE. */ +#include #include +#include "ble.h" #include "ble_drv.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_types.h" +#include "ble_hci.h" +#include "nrf_soc.h" +#include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Device.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -STATIC void gap_event_handler(bleio_device_obj_t *device, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) { - if (event_id == BLE_GAP_EVT_CONNECTED) { - device->conn_handle = conn_handle; - } else if (event_id == BLE_GAP_EVT_DISCONNECTED) { - device->conn_handle = BLE_CONN_HANDLE_INVALID; +#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) +#define BLE_SLAVE_LATENCY 0 +#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) + +#define BLE_ADV_LENGTH_FIELD_SIZE 1 +#define BLE_ADV_AD_TYPE_FIELD_SIZE 1 +#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 + +#ifndef BLE_GAP_ADV_MAX_SIZE +#define BLE_GAP_ADV_MAX_SIZE 31 +#endif + +static bleio_service_obj_t *m_char_discovery_service; +static volatile bool m_discovery_successful; +static nrf_mutex_t *m_discovery_mutex; + +#if (BLUETOOTH_SD == 140) +static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; + +static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; + +static ble_data_t m_scan_buffer = { + .p_data = m_scan_buffer_data, + .len = BLE_GAP_SCAN_BUFFER_MIN +}; +#endif + +STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connectable, mp_buffer_info_t *raw_data) { + common_hal_bleio_adapter_set_enabled(true); + + uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; + uint8_t byte_pos = 0; + uint32_t err_code; + +#define ADD_FIELD(field, len) \ + do { \ + if (byte_pos + (len) > BLE_GAP_ADV_MAX_SIZE) { \ + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, \ + "Can not fit data into the advertisment packet")); \ + } \ + adv_data[byte_pos] = (field); \ + byte_pos += (len); \ + } while (0) + + GET_STR_DATA_LEN(device->name, name_data, name_len); + if (name_len > 0) { + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + err_code = sd_ble_gap_device_name_set(&sec_mode, name_data, name_len); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + // TODO: Shorten if too long + + ADD_FIELD(BLE_ADV_AD_TYPE_FIELD_SIZE + name_len, BLE_ADV_LENGTH_FIELD_SIZE); + ADD_FIELD(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, BLE_ADV_AD_TYPE_FIELD_SIZE); + + memcpy(&adv_data[byte_pos], name_data, name_len); + byte_pos += name_len; + } + + // set flags, default to disc mode + if (raw_data->len == 0) { + ADD_FIELD(BLE_ADV_AD_TYPE_FIELD_SIZE + BLE_AD_TYPE_FLAGS_DATA_SIZE, BLE_ADV_LENGTH_FIELD_SIZE); + ADD_FIELD(BLE_GAP_AD_TYPE_FLAGS, BLE_AD_TYPE_FLAGS_DATA_SIZE); + ADD_FIELD(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE, BLE_AD_TYPE_FLAGS_DATA_SIZE); + } else { + if (byte_pos + raw_data->len > BLE_GAP_ADV_MAX_SIZE) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not fit data into the advertisment packet")); + } + + memcpy(&adv_data[byte_pos], raw_data->buf, raw_data->len); + byte_pos += raw_data->len; + } + + const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(device->service_list); + if (service_list->len > 0) { + bool has_128bit_services = false; + bool has_16bit_services = false; + + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + + if (service->is_secondary) { + continue; + } + + if (service->uuid->type == UUID_TYPE_16BIT) { + has_16bit_services = true; + } + + if (service->uuid->type == UUID_TYPE_128BIT) { + has_128bit_services = true; + } + } + + if (has_16bit_services) { + const uint8_t size_byte_pos = byte_pos; + uint8_t uuid_total_size = 0; + + // skip length byte for now, apply total length post calculation + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + + ADD_FIELD(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, BLE_ADV_AD_TYPE_FIELD_SIZE); + + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + uint8_t encoded_size = 0; + + if ((service->uuid->type != UUID_TYPE_16BIT) || service->is_secondary) { + continue; + } + + ble_uuid_t uuid; + uuid.type = BLE_UUID_TYPE_BLE; + uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); + + err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + uuid_total_size += encoded_size; + byte_pos += encoded_size; + } + + adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); + } + + if (has_128bit_services) { + const uint8_t size_byte_pos = byte_pos; + uint8_t uuid_total_size = 0; + + // skip length byte for now, apply total length post calculation + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + + ADD_FIELD(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, BLE_ADV_AD_TYPE_FIELD_SIZE); + + for (size_t i = 0; i < service_list->len; ++i) { + const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); + uint8_t encoded_size = 0; + + if ((service->uuid->type != UUID_TYPE_128BIT) || service->is_secondary) { + continue; + } + + ble_uuid_t uuid; + uuid.type = service->uuid->uuid_vs_idx; + uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); + + err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + uuid_total_size += encoded_size; + byte_pos += encoded_size; + } + + adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); + } + } + +#if (BLUETOOTH_SD == 132) + err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0); + if (err_code != NRF_SUCCESS) { + return err_code; + } +#endif + + static ble_gap_adv_params_t m_adv_params = { + .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), +#if (BLUETOOTH_SD == 140) + .properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED, + .duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED, + .filter_policy = BLE_GAP_ADV_FP_ANY, + .primary_phy = BLE_GAP_PHY_1MBPS, +#else + .type = BLE_GAP_ADV_TYPE_ADV_IND, + .fp = BLE_GAP_ADV_FP_ANY, +#endif + }; + + if (!connectable) { +#if (BLUETOOTH_SD == 140) + m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; +#else + m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; +#endif } + + common_hal_bleio_device_stop_advertising(device); + +#if (BLUETOOTH_SD == 140) + const ble_gap_adv_data_t ble_gap_adv_data = { + .adv_data.p_data = adv_data, + .adv_data.len = byte_pos, + }; + + err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &ble_gap_adv_data, &m_adv_params); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_CONN_CFG_TAG_CUSTOM); +#elif (BLUETOOTH_SD == 132 && BLE_API_VERSION == 4) + err_code = sd_ble_gap_adv_start(&m_adv_params, BLE_CONN_CFG_TAG_CUSTOM); +#else + err_code = sd_ble_gap_adv_start(&m_adv_params); +#endif + + return err_code; } -STATIC void gatts_event_handler(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { +STATIC bool discover_services(bleio_device_obj_t *device, uint16_t start_handle) { + m_discovery_successful = false; + + uint32_t err_code = sd_ble_gattc_primary_services_discover(device->conn_handle, start_handle, NULL); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to discover serivices, status: 0x%08lX", err_code)); + } + + err_code = sd_mutex_acquire(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to acquire mutex, status: 0x%08lX", err_code)); + } + + while (sd_mutex_acquire(m_discovery_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif + } + + err_code = sd_mutex_release(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to release mutex, status: 0x%08lX", err_code)); + } + return m_discovery_successful; } -void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bleio_advertisement_data_t *adv_data) { - if (adv_data->connectable) { - ble_drv_gap_event_handler_set(device, gap_event_handler); - ble_drv_gatts_event_handler_set(device, gatts_event_handler); +STATIC bool discover_characteristics(bleio_device_obj_t *device, bleio_service_obj_t *service, uint16_t start_handle) { + m_char_discovery_service = service; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = service->end_handle; + + m_discovery_successful = false; + + uint32_t err_code = sd_ble_gattc_characteristics_discover(device->conn_handle, &handle_range); + if (err_code != 0) { + return false; + } + + err_code = sd_mutex_acquire(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to acquire mutex, status: 0x%08lX", err_code)); } - ble_drv_advertise_data(adv_data); + while (sd_mutex_acquire(m_discovery_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP +#endif + } + + err_code = sd_mutex_release(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to release mutex, status: 0x%08lX", err_code)); + } + + return m_discovery_successful; +} + +STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_device_obj_t *device) { + for (size_t i = 0; i < response->count; ++i) { + const ble_gattc_service_t *gattc_service = &response->services[i]; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + service->device = device; + service->char_list = mp_obj_new_list(0, NULL); + service->start_handle = gattc_service->handle_range.start_handle; + service->end_handle = gattc_service->handle_range.end_handle; + service->handle = gattc_service->handle_range.start_handle; + + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + uuid->type = (gattc_service->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT; + uuid->value[0] = gattc_service->uuid.uuid & 0xFF; + uuid->value[1] = gattc_service->uuid.uuid >> 8; + service->uuid = uuid; + + mp_obj_list_append(device->service_list, service); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + + const uint32_t err_code = sd_mutex_release(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to release mutex, status: 0x%08lX", err_code)); + } +} + +STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_device_obj_t *device) { + for (size_t i = 0; i < response->count; ++i) { + const ble_gattc_char_t *gattc_char = &response->chars[i]; + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + uuid->type = (gattc_char->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT; + uuid->value[0] = gattc_char->uuid.uuid & 0xFF; + uuid->value[1] = gattc_char->uuid.uuid >> 8; + characteristic->uuid = uuid; + + characteristic->props.broadcast = gattc_char->char_props.broadcast; + characteristic->props.indicate = gattc_char->char_props.indicate; + characteristic->props.notify = gattc_char->char_props.notify; + characteristic->props.read = gattc_char->char_props.read; + characteristic->props.write = gattc_char->char_props.write; + characteristic->props.write_wo_resp = gattc_char->char_props.write_wo_resp; + characteristic->handle = gattc_char->handle_value; + + characteristic->service_handle = m_char_discovery_service->handle; + characteristic->service = m_char_discovery_service; + + mp_obj_list_append(m_char_discovery_service->char_list, MP_OBJ_FROM_PTR(characteristic)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + + const uint32_t err_code = sd_mutex_release(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to release mutex, status: 0x%08lX", err_code)); + } +} + +STATIC void on_adv_report(ble_gap_evt_adv_report_t *report, bleio_device_obj_t *device) { + uint32_t err_code; + + if (memcmp(report->peer_addr.addr, device->address.value, BLEIO_ADDRESS_BYTES) != 0) { +#if (BLUETOOTH_SD == 140) + err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to continue scanning, status: 0x%0xlX", err_code)); + } +#endif + return; + } + + ble_gap_scan_params_t scan_params = { + .active = 1, + .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), + .window = MSEC_TO_UNITS(100, UNIT_0_625_MS), + }; + + ble_gap_addr_t addr; + memset(&addr, 0, sizeof(addr)); + + addr.addr_type = report->peer_addr.addr_type; + memcpy(addr.addr, report->peer_addr.addr, BLEIO_ADDRESS_BYTES); + + ble_gap_conn_params_t conn_params = { + .min_conn_interval = BLE_MIN_CONN_INTERVAL, + .max_conn_interval = BLE_MAX_CONN_INTERVAL, + .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, + .slave_latency = BLE_SLAVE_LATENCY, + }; + +#if (BLE_API_VERSION == 2) + err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params); +#else + err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM); +#endif + + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to connect, status: 0x%08lX", err_code)); + } +} + +STATIC void on_ble_evt(ble_evt_t *ble_evt, void *device_in) { + bleio_device_obj_t *device = (bleio_device_obj_t*)device_in; + + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + { + ble_gap_conn_params_t conn_params; + device->conn_handle = ble_evt->evt.gap_evt.conn_handle; + + sd_ble_gap_ppcp_get(&conn_params); + sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params); + break; + } + + case BLE_GAP_EVT_DISCONNECTED: + device->conn_handle = BLE_CONN_HANDLE_INVALID; + break; + + case BLE_GAP_EVT_ADV_REPORT: + on_adv_report(&ble_evt->evt.gap_evt.params.adv_report, device); + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); + break; + + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + sd_ble_gatts_sys_attr_set(ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0); + break; + +#if (BLE_API_VERSION == 4) + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + sd_ble_gatts_exchange_mtu_reply(device->conn_handle, BLE_GATT_ATT_MTU_DEFAULT); + break; +#endif + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + sd_ble_gap_sec_params_reply(device->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: + { + ble_gap_evt_conn_param_update_request_t *request = &ble_evt->evt.gap_evt.params.conn_param_update_request; + sd_ble_gap_conn_param_update(device->conn_handle, &request->conn_params); + break; + } + } +} + +void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bool connectable, mp_buffer_info_t *raw_data) { + if (connectable) { + ble_drv_add_event_handler(on_ble_evt, device); + } + + const uint32_t err_code = set_advertisement_data(device, connectable, raw_data); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to start advertisment, status: 0x%08lX", err_code)); + } } void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device) { - (void)device; + uint32_t err_code; + +#if (BLUETOOTH_SD == 140) + if (m_adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) + return; - ble_drv_advertise_stop(); + err_code = sd_ble_gap_adv_stop(m_adv_handle); +#else + err_code = sd_ble_gap_adv_stop(); +#endif + + if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to stop advertisment, status: 0x%08lX", err_code)); + } } void common_hal_bleio_device_connect(bleio_device_obj_t *device) { - ble_drv_gap_event_handler_set(device, gap_event_handler); + ble_drv_add_event_handler(on_ble_evt, device); - ble_drv_connect(device); + ble_gap_scan_params_t scan_params = { + .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), + .window = MSEC_TO_UNITS(100, UNIT_0_625_MS), +#if (BLUETOOTH_SD == 140) + .scan_phys = BLE_GAP_PHY_1MBPS, +#endif + }; + + common_hal_bleio_adapter_set_enabled(true); + + uint32_t err_code; +#if (BLUETOOTH_SD == 140) + err_code = sd_ble_gap_scan_start(&scan_params, &m_scan_buffer); +#else + err_code = sd_ble_gap_scan_start(&scan_params); +#endif + + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to start scanning, status: 0x%0xlX", err_code)); + } while (device->conn_handle == BLE_CONN_HANDLE_INVALID) { #ifdef MICROPY_VM_HOOK_LOOP @@ -76,13 +555,23 @@ void common_hal_bleio_device_connect(bleio_device_obj_t *device) { // TODO: read name + if (m_discovery_mutex == NULL) { + m_discovery_mutex = m_new_ll(nrf_mutex_t, 1); + + err_code = sd_mutex_new(m_discovery_mutex); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to create mutex, status: 0x%0xlX", err_code)); + } + } + // find services - bool found_service = ble_drv_discover_services(device, BLE_GATT_HANDLE_START); + bool found_service = discover_services(device, BLE_GATT_HANDLE_START); while (found_service) { const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(device->service_list); const bleio_service_obj_t *service = service_list->items[service_list->len - 1]; - found_service = ble_drv_discover_services(device, service->end_handle + 1); + found_service = discover_services(device, service->end_handle + 1); } // find characteristics in each service @@ -90,7 +579,7 @@ void common_hal_bleio_device_connect(bleio_device_obj_t *device) { for (size_t i = 0; i < service_list->len; ++i) { bleio_service_obj_t *service = service_list->items[i]; - bool found_char = ble_drv_discover_characteristic(device, service, service->start_handle); + bool found_char = discover_characteristics(device, service, service->start_handle); while (found_char) { const mp_obj_list_t *char_list = MP_OBJ_TO_PTR(service->char_list); const bleio_characteristic_obj_t *characteristic = char_list->items[char_list->len - 1]; @@ -100,11 +589,11 @@ void common_hal_bleio_device_connect(bleio_device_obj_t *device) { break; } - found_char = ble_drv_discover_characteristic(device, service, next_handle); + found_char = discover_characteristics(device, service, next_handle); } } } void common_hal_bleio_device_disconnect(bleio_device_obj_t *device) { - ble_drv_disconnect(device); + sd_ble_gap_disconnect(device->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } diff --git a/ports/nrf/common-hal/bleio/Scanner.c b/ports/nrf/common-hal/bleio/Scanner.c index 150c417a3..17af49621 100644 --- a/ports/nrf/common-hal/bleio/Scanner.c +++ b/ports/nrf/common-hal/bleio/Scanner.c @@ -28,25 +28,83 @@ #include #include "ble_drv.h" +#include "ble_gap.h" #include "py/mphal.h" +#include "py/nlr.h" +#include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" #include "shared-module/bleio/ScanEntry.h" -STATIC void adv_event_handler(bleio_scanner_obj_t *self, bleio_scanentry_obj_t *entry) { +#if (BLUETOOTH_SD == 140) +static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; + +static ble_data_t m_scan_buffer = { + m_scan_buffer_data, + BLE_GAP_SCAN_BUFFER_MIN +}; +#endif + +STATIC void on_ble_evt(ble_evt_t *ble_evt, void *scanner_in) { + bleio_scanner_obj_t *scanner = (bleio_scanner_obj_t*)scanner_in; + ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report; + + if (ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) { + return; + } + // TODO: Don't add new entry for each item, group by address and update + bleio_scanentry_obj_t *entry = m_new_obj(bleio_scanentry_obj_t); + entry->base.type = &bleio_scanentry_type; + entry->rssi = report->rssi; - mp_obj_list_append(self->adv_reports, entry); + entry->address.type = report->peer_addr.addr_type; + memcpy(entry->address.value, report->peer_addr.addr, BLEIO_ADDRESS_BYTES); - ble_drv_scan_continue(); +#if (BLUETOOTH_SD == 140) + entry->data = mp_obj_new_bytearray(report->data.len, report->data.p_data); +#else + entry->data = mp_obj_new_bytearray(report->dlen, report->data); +#endif + + mp_obj_list_append(scanner->adv_reports, entry); + +#if (BLUETOOTH_SD == 140) + const uint32_t err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to continue scanning, status: 0x%0xlX", err_code)); + } +#endif } void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_int_t timeout) { - ble_drv_adv_report_handler_set(self, adv_event_handler); + ble_drv_add_event_handler(on_ble_evt, self); + + ble_gap_scan_params_t scan_params = { + .interval = MSEC_TO_UNITS(self->interval, UNIT_0_625_MS), + .window = MSEC_TO_UNITS(self->window, UNIT_0_625_MS), +#if (BLUETOOTH_SD == 140) + .scan_phys = BLE_GAP_PHY_1MBPS, +#endif + }; + + common_hal_bleio_adapter_set_enabled(true); - ble_drv_scan_start(self->interval, self->window); + uint32_t err_code; +#if (BLUETOOTH_SD == 140) + err_code = sd_ble_gap_scan_start(&scan_params, &m_scan_buffer); +#else + err_code = sd_ble_gap_scan_start(&scan_params); +#endif - mp_hal_delay_ms(timeout); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to start scanning, status: 0x%0xlX", err_code)); + } - ble_drv_scan_stop(); + if (timeout > 0) { + mp_hal_delay_ms(timeout); + sd_ble_gap_scan_stop(); + } } diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index b6e0595b1..9e376b333 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -25,14 +25,91 @@ */ #include "ble_drv.h" -#include "shared-module/bleio/Service.h" +#include "ble.h" +#include "py/nlr.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/Adapter.h" void common_hal_bleio_service_construct(bleio_service_obj_t *self) { - ble_drv_service_add(self); + ble_uuid_t uuid = { + .type = BLE_UUID_TYPE_BLE, + .uuid = self->uuid->value[0] | (self->uuid->value[1] << 8) + }; + + if (self->uuid->type == UUID_TYPE_128BIT) { + uuid.type = self->uuid->uuid_vs_idx; + } + + uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; + if (self->is_secondary) { + service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; + } + + common_hal_bleio_adapter_set_enabled(true); + + const uint32_t err_code = sd_ble_gatts_service_add(service_type, &uuid, &self->handle); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to add service, status: 0x%08lX", err_code)); + } } void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic) { - if (ble_drv_characteristic_add(characteristic)) { - characteristic->service = self; + ble_gatts_char_md_t char_md = { + .char_props.broadcast = characteristic->props.broadcast, + .char_props.read = characteristic->props.read, + .char_props.write_wo_resp = characteristic->props.write_wo_resp, + .char_props.write = characteristic->props.write, + .char_props.notify = characteristic->props.notify, + .char_props.indicate = characteristic->props.indicate, + }; + + ble_gatts_attr_md_t cccd_md = { + .vloc = BLE_GATTS_VLOC_STACK, + }; + + if (char_md.char_props.notify || char_md.char_props.indicate) { + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); + + char_md.p_cccd_md = &cccd_md; } + + ble_uuid_t uuid = { + .type = BLE_UUID_TYPE_BLE, + .uuid = characteristic->uuid->value[0] | (characteristic->uuid->value[1] << 8), + }; + + if (characteristic->uuid->type == UUID_TYPE_128BIT) + uuid.type = characteristic->uuid->uuid_vs_idx; + + ble_gatts_attr_md_t attr_md = { + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = 1, + }; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + + ble_gatts_attr_t attr_char_value = { + .p_uuid = &uuid, + .p_attr_md = &attr_md, + .init_len = sizeof(uint8_t), + .max_len = (BLE_GATT_ATT_MTU_DEFAULT - 3), + }; + + ble_gatts_char_handles_t handles; + + uint32_t err_code; + err_code = sd_ble_gatts_characteristic_add(characteristic->service_handle, &char_md, &attr_char_value, &handles); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to add characteristic, status: 0x%08lX", err_code)); + } + + characteristic->user_desc_handle = handles.user_desc_handle; + characteristic->cccd_handle = handles.cccd_handle; + characteristic->sccd_handle = handles.sccd_handle; + characteristic->handle = handles.value_handle; + characteristic->service = self; } diff --git a/ports/nrf/common-hal/bleio/UUID.c b/ports/nrf/common-hal/bleio/UUID.c index e655589a6..4d4c8c9fb 100644 --- a/ports/nrf/common-hal/bleio/UUID.c +++ b/ports/nrf/common-hal/bleio/UUID.c @@ -25,10 +25,13 @@ * THE SOFTWARE. */ +#include "ble.h" #include "ble_drv.h" #include "common-hal/bleio/UUID.h" +#include "nrf_error.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/UUID.h" #define UUID_STR_16BIT_LEN 6 @@ -59,37 +62,44 @@ void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, const mp_obj_t *uui } else if (str_len == UUID_STR_128BIT_LEN) { self->type = UUID_TYPE_128BIT; - uint8_t buffer[16]; - buffer[0] = xdigit_8b_value(str_data[35], str_data[34]); - buffer[1] = xdigit_8b_value(str_data[33], str_data[32]); - buffer[2] = xdigit_8b_value(str_data[31], str_data[30]); - buffer[3] = xdigit_8b_value(str_data[29], str_data[28]); - buffer[4] = xdigit_8b_value(str_data[27], str_data[26]); - buffer[5] = xdigit_8b_value(str_data[25], str_data[24]); + ble_uuid128_t vs_uuid; + vs_uuid.uuid128[0] = xdigit_8b_value(str_data[35], str_data[34]); + vs_uuid.uuid128[1] = xdigit_8b_value(str_data[33], str_data[32]); + vs_uuid.uuid128[2] = xdigit_8b_value(str_data[31], str_data[30]); + vs_uuid.uuid128[3] = xdigit_8b_value(str_data[29], str_data[28]); + vs_uuid.uuid128[4] = xdigit_8b_value(str_data[27], str_data[26]); + vs_uuid.uuid128[5] = xdigit_8b_value(str_data[25], str_data[24]); // 23 '-' - buffer[6] = xdigit_8b_value(str_data[22], str_data[21]); - buffer[7] = xdigit_8b_value(str_data[20], str_data[19]); + vs_uuid.uuid128[6] = xdigit_8b_value(str_data[22], str_data[21]); + vs_uuid.uuid128[7] = xdigit_8b_value(str_data[20], str_data[19]); // 18 '-' - buffer[8] = xdigit_8b_value(str_data[17], str_data[16]); - buffer[9] = xdigit_8b_value(str_data[15], str_data[14]); + vs_uuid.uuid128[8] = xdigit_8b_value(str_data[17], str_data[16]); + vs_uuid.uuid128[9] = xdigit_8b_value(str_data[15], str_data[14]); // 13 '-' - buffer[10] = xdigit_8b_value(str_data[12], str_data[11]); - buffer[11] = xdigit_8b_value(str_data[10], str_data[9]); + vs_uuid.uuid128[10] = xdigit_8b_value(str_data[12], str_data[11]); + vs_uuid.uuid128[11] = xdigit_8b_value(str_data[10], str_data[9]); // 8 '-' self->value[0] = xdigit_8b_value(str_data[7], str_data[6]); self->value[1] = xdigit_8b_value(str_data[5], str_data[4]); - buffer[14] = xdigit_8b_value(str_data[3], str_data[2]); - buffer[15] = xdigit_8b_value(str_data[1], str_data[0]); + vs_uuid.uuid128[14] = xdigit_8b_value(str_data[3], str_data[2]); + vs_uuid.uuid128[15] = xdigit_8b_value(str_data[1], str_data[0]); + + common_hal_bleio_adapter_set_enabled(true); + + const uint32_t err_code = sd_ble_uuid_vs_add(&vs_uuid, &self->uuid_vs_idx); + if (err_code != NRF_SUCCESS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Failed to add Vendor Specific UUID, status: 0x%08lX", err_code)); + } - ble_drv_uuid_add_vs(buffer, &self->uuid_vs_idx); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Invalid UUID string length")); + "Invalid UUID string length")); } return; @@ -113,10 +123,10 @@ void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, const mp_obj_t *uui void common_hal_bleio_uuid_print(bleio_uuid_obj_t *self, const mp_print_t *print) { if (self->type == UUID_TYPE_16BIT) { mp_printf(print, "UUID(uuid: 0x" HEX2_FMT HEX2_FMT ")", - self->value[1], self->value[0]); + self->value[1], self->value[0]); } else { mp_printf(print, "UUID(uuid: 0x" HEX2_FMT HEX2_FMT ", VS idx: " HEX2_FMT ")", - self->value[1], self->value[0], self->uuid_vs_idx); + self->value[1], self->value[0], self->uuid_vs_idx); } } diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c index 6d32ff6f9..0b6daf711 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ b/ports/nrf/drivers/bluetooth/ble_drv.c @@ -25,1027 +25,73 @@ * THE SOFTWARE. */ -#if BLUETOOTH_SD - -#include -#include #include +#include -#if (BLUETOOTH_SD == 132) -#define NRF52 // Needed for SD132 v2 -#endif - -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/Device.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "supervisor/shared/translate.h" +#include "ble.h" #include "ble_drv.h" #include "nrf_nvic.h" #include "nrf_sdm.h" -#include "nrfx_power.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/UUID.h" - -#define BLE_DRIVER_LOG printf - -#define BLE_ADV_LENGTH_FIELD_SIZE 1 -#define BLE_ADV_AD_TYPE_FIELD_SIZE 1 -#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 - -#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) -#define UNIT_0_625_MS (625) -#define UNIT_10_MS (10000) - -#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) -#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) -#define BLE_SLAVE_LATENCY 0 -#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) - -#ifndef BLE_GAP_ADV_MAX_SIZE -#define BLE_GAP_ADV_MAX_SIZE 31 -#endif - -#define SD_TEST_OR_ENABLE() \ -if (ble_drv_stack_enabled() == 0) { \ - (void)ble_drv_stack_enable(); \ -} - -static ble_drv_adv_evt_callback_t adv_event_handler; -static ble_drv_gatts_evt_callback_t gatts_event_handler; -static ble_drv_gap_evt_callback_t gap_event_handler; - -static bleio_characteristic_obj_t *mp_gattc_char_data_observer; -static bleio_device_obj_t *mp_gattc_disc_service_observer; -static bleio_service_obj_t *mp_gattc_disc_char_observer; -static bleio_address_obj_t *mp_connect_address; -static bleio_device_obj_t *mp_gatts_observer; -static bleio_scanner_obj_t *mp_adv_observer; -static bleio_device_obj_t *mp_gap_observer; - -static volatile bool m_primary_service_found; -static volatile bool m_characteristic_found; -static volatile bool m_tx_in_progress; -static volatile bool m_write_done; +#include "py/misc.h" nrf_nvic_state_t nrf_nvic_state = { 0 }; -#if (BLUETOOTH_SD == 140) -static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; -static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; - -static ble_data_t m_scan_buffer = -{ - m_scan_buffer_data, - BLE_GAP_SCAN_BUFFER_MIN -}; -#endif - -void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { - BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!"); -} - -uint32_t ble_drv_stack_enable(void) { - nrf_clock_lf_cfg_t clock_config = { - .source = NRF_CLOCK_LF_SRC_XTAL, - .rc_ctiv = 0, - .rc_temp_ctiv = 0, -#if (BLE_API_VERSION == 4) - .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM -#else - .xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM -#endif - }; - -#if (BLUETOOTH_SD == 140) - // The SD takes over the POWER IRQ and will fail if the IRQ is already in use - nrfx_power_uninit(); -#endif - - uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler); - if (err_code != NRF_SUCCESS) - BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code); - - err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); - if (err_code != NRF_SUCCESS) - BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code); - - // Enable BLE stack. - uint32_t app_ram_start; -#if (BLE_API_VERSION == 2) - ble_enable_params_t ble_enable_params; - memset(&ble_enable_params, 0x00, sizeof(ble_enable_params)); - ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT; - ble_enable_params.gatts_enable_params.service_changed = 0; - ble_enable_params.gap_enable_params.periph_conn_count = 1; - ble_enable_params.gap_enable_params.central_conn_count = 1; - - app_ram_start = 0x200039c0; - err_code = sd_ble_enable(&ble_enable_params, &app_ram_start); // 8K SD headroom from linker script. -#else - app_ram_start = 0x20004000; - err_code = sd_ble_enable(&app_ram_start); -#endif - - if (err_code != NRF_SUCCESS) { - BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start); - BLE_DRIVER_LOG("BLE enable status: " UINT_FMT "\n", (uint16_t)err_code); - } - - return err_code; -} - -uint8_t ble_drv_stack_enabled(void) { - uint8_t is_enabled; - uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); - - if (err_code != NRF_SUCCESS) { - BLE_DRIVER_LOG("Is enabled status: " UINT_FMT "\n", (uint16_t)err_code); - } - - return is_enabled; -} - -void ble_drv_address_get(bleio_address_obj_t *address) { - SD_TEST_OR_ENABLE(); - - ble_gap_addr_t local_ble_addr; -#if (BLE_API_VERSION == 2) - uint32_t err_code = sd_ble_gap_address_get(&local_ble_addr); -#else - uint32_t err_code = sd_ble_gap_addr_get(&local_ble_addr); -#endif - - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not query for the device address."))); - } - - BLE_DRIVER_LOG("ble address, type: " HEX2_FMT ", " \ - "address: " HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT ":" \ - HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT "\n", \ - local_ble_addr.addr_type, \ - local_ble_addr.addr[5], local_ble_addr.addr[4], local_ble_addr.addr[3], \ - local_ble_addr.addr[2], local_ble_addr.addr[1], local_ble_addr.addr[0]); - - address->type = local_ble_addr.addr_type; - memcpy(address->value, local_ble_addr.addr, BLEIO_ADDRESS_BYTES); -} - -bool ble_drv_uuid_add_vs(uint8_t *uuid, uint8_t *idx) { - SD_TEST_OR_ENABLE(); - - if (sd_ble_uuid_vs_add((ble_uuid128_t const *)uuid, idx) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Vendor Specific 128-bit UUID."))); - } - - return true; -} - -void ble_drv_service_add(bleio_service_obj_t *service) { - SD_TEST_OR_ENABLE(); - - ble_uuid_t uuid = { - .type = BLE_UUID_TYPE_BLE, - .uuid = service->uuid->value[0] | (service->uuid->value[1] << 8) - }; - - if (service->uuid->type == UUID_TYPE_128BIT) { - uuid.type = service->uuid->uuid_vs_idx; - } - - uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; - if (service->is_secondary) { - service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; - } - - if (sd_ble_gatts_service_add(service_type, &uuid, &service->handle) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Service."))); - } -} - -bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic) { - ble_gatts_char_md_t char_md; - ble_gatts_attr_md_t cccd_md; - ble_gatts_attr_t attr_char_value; - ble_uuid_t uuid; - ble_gatts_attr_md_t attr_md; - - memset(&char_md, 0, sizeof(char_md)); - - char_md.char_props.broadcast = characteristic->props.broadcast; - char_md.char_props.read = characteristic->props.read; - char_md.char_props.write_wo_resp = characteristic->props.write_wo_resp; - char_md.char_props.write = characteristic->props.write; - char_md.char_props.notify = characteristic->props.notify; - char_md.char_props.indicate = characteristic->props.indicate; - - char_md.p_char_user_desc = NULL; - char_md.p_char_pf = NULL; - char_md.p_user_desc_md = NULL; - char_md.p_sccd_md = NULL; - - if (characteristic->props.notify || characteristic->props.notify) { - memset(&cccd_md, 0, sizeof(cccd_md)); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); - cccd_md.vloc = BLE_GATTS_VLOC_STACK; - char_md.p_cccd_md = &cccd_md; - } else { - char_md.p_cccd_md = NULL; - } - - uuid.type = BLE_UUID_TYPE_BLE; - if (characteristic->uuid->type == UUID_TYPE_128BIT) - uuid.type = characteristic->uuid->uuid_vs_idx; - - uuid.uuid = characteristic->uuid->value[0]; - uuid.uuid += characteristic->uuid->value[1] << 8; - - memset(&attr_md, 0, sizeof(attr_md)); - - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); - - attr_md.vloc = BLE_GATTS_VLOC_STACK; - attr_md.rd_auth = 0; - attr_md.wr_auth = 0; - attr_md.vlen = 1; - - memset(&attr_char_value, 0, sizeof(attr_char_value)); - - attr_char_value.p_uuid = &uuid; - attr_char_value.p_attr_md = &attr_md; - attr_char_value.init_len = sizeof(uint8_t); - attr_char_value.init_offs = 0; -#if (BLE_API_VERSION == 2) - attr_char_value.max_len = (GATT_MTU_SIZE_DEFAULT - 3); -#else - attr_char_value.max_len = (BLE_GATT_ATT_MTU_DEFAULT - 3); -#endif - - ble_gatts_char_handles_t handles; - - uint32_t err_code = sd_ble_gatts_characteristic_add(characteristic->service_handle, - &char_md, - &attr_char_value, - &handles); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not add Characteristic. status: 0x%08lX"), err_code)); - } - - // apply handles to object instance - characteristic->handle = handles.value_handle; - characteristic->user_desc_handle = handles.user_desc_handle; - characteristic->cccd_handle = handles.cccd_handle; - characteristic->sccd_handle = handles.sccd_handle; - - return true; -} - -// TODO: Replace with just bleio_device_obj_t + data -bool ble_drv_advertise_data(bleio_advertisement_data_t *adv_params) { - SD_TEST_OR_ENABLE(); - - uint8_t byte_pos = 0; - uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; - - GET_STR_DATA_LEN(adv_params->device_name, name_data, name_len); - - if (name_len > 0) { - ble_gap_conn_sec_mode_t sec_mode; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); - - if (sd_ble_gap_device_name_set(&sec_mode, - name_data, - name_len) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not apply device name in the stack."))); - } - - adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + name_len); - byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; - - // TODO: Shorten if too long - adv_data[byte_pos] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; - byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; - - memcpy(&adv_data[byte_pos], name_data, name_len); - - byte_pos += name_len; - } - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(adv_params->data, &bufinfo, MP_BUFFER_WRITE); - - // set flags, default to disc mode - if (bufinfo.len == 0) { - adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + BLE_AD_TYPE_FLAGS_DATA_SIZE); - byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; - - adv_data[byte_pos] = BLE_GAP_AD_TYPE_FLAGS; - byte_pos += BLE_AD_TYPE_FLAGS_DATA_SIZE; - - adv_data[byte_pos] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; - byte_pos += 1; - } - - const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(adv_params->services); - if (service_list->len > 0) { - bool type_16bit_present = false; - bool type_128bit_present = false; - - for (size_t i = 0; i < service_list->len; ++i) { - const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); - - if (service->uuid->type == UUID_TYPE_16BIT) { - type_16bit_present = true; - } - - if (service->uuid->type == UUID_TYPE_128BIT) { - type_128bit_present = true; - } - } - - if (type_16bit_present) { - uint8_t size_byte_pos = byte_pos; - - // skip length byte for now, apply total length post calculation - byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; +__attribute__((aligned(4))) +static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)]; - adv_data[byte_pos] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE; - byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; +typedef struct event_handler { + struct event_handler *next; + void *param; + ble_drv_evt_handler_t func; +} event_handler_t; - uint8_t uuid_total_size = 0; - uint8_t encoded_size = 0; +static event_handler_t *m_event_handlers; - for (size_t i = 0; i < service_list->len; ++i) { - const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); - - if (service->uuid->type != UUID_TYPE_16BIT) { - continue; - } - - ble_uuid_t uuid; - uuid.type = BLE_UUID_TYPE_BLE; - uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); - - // calculate total size of uuids - if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not encode UUID, to check length."))); - } - - // do encoding into the adv buffer - if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can encode UUID into the advertisement packet."))); - } - - uuid_total_size += encoded_size; // size of entry - byte_pos += encoded_size; // relative to adv data packet - } - - adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); - } - - if (type_128bit_present) { - uint8_t size_byte_pos = byte_pos; - - // skip length byte for now, apply total length post calculation - byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; - - adv_data[byte_pos] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE; - byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; - - uint8_t uuid_total_size = 0; - uint8_t encoded_size = 0; - - for (size_t i = 0; i < service_list->len; ++i) { - const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); - - if (service->uuid->type != UUID_TYPE_128BIT) { - continue; - } - - ble_uuid_t uuid; - uuid.type = service->uuid->uuid_vs_idx; - uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8); - - // calculate total size of uuids - if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not encode UUID, to check length."))); - } - - // do encoding into the adv buffer - if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can encode UUID into the advertisement packet."))); - } - - uuid_total_size += encoded_size; // size of entry - byte_pos += encoded_size; // relative to adv data packet - } +void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param) { + event_handler_t *handler = m_new_ll(event_handler_t, 1); + handler->next = NULL; + handler->param = param; + handler->func = func; - adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); - } - } - - if (bufinfo.len > 0) { - if (byte_pos + bufinfo.len > BLE_GAP_ADV_MAX_SIZE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not fit data into the advertisement packet."))); - } - - memcpy(adv_data, bufinfo.buf, bufinfo.len); - byte_pos += bufinfo.len; - } - - uint32_t err_code; -#if (BLUETOOTH_SD == 132) - if ((err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not apply advertisement data. status: 0x%02x"), (uint16_t)err_code)); - } -#endif - - static ble_gap_adv_params_t m_adv_params; - - // initialize advertising params - memset(&m_adv_params, 0, sizeof(m_adv_params)); - if (adv_params->connectable) { -#if (BLUETOOTH_SD == 140) - m_adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; -#else - m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; -#endif - } else { -#if (BLUETOOTH_SD == 140) - m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; -#else - m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; -#endif - } - - m_adv_params.p_peer_addr = NULL; // undirected advertisement - m_adv_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); // approx 8 ms -#if (BLUETOOTH_SD == 140) - m_adv_params.duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED; - m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; - m_adv_params.primary_phy = BLE_GAP_PHY_1MBPS; -#else - m_adv_params.fp = BLE_GAP_ADV_FP_ANY; - m_adv_params.timeout = 0; // infinite advertisement -#endif - - ble_drv_advertise_stop(); - -#if (BLUETOOTH_SD == 140) - const ble_gap_adv_data_t ble_gap_adv_data = { - .adv_data = { - .p_data = adv_data, - .len = byte_pos - } - }; - - if ((err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &ble_gap_adv_data, &m_adv_params)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not apply advertisement data. status: 0x%02x"), (uint16_t)err_code)); - } - err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_CONN_CFG_TAG_DEFAULT); -#elif (BLUETOOTH_SD == 132 && BLE_API_VERSION == 4) - err_code = sd_ble_gap_adv_start(&m_adv_params, BLE_CONN_CFG_TAG_DEFAULT); -#else - err_code = sd_ble_gap_adv_start(&m_adv_params); -#endif - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not start advertisement. status: 0x%02x"), (uint16_t)err_code)); - } - - return true; -} - -void ble_drv_advertise_stop(void) { - uint32_t err_code; - -#if (BLUETOOTH_SD == 140) - if (m_adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) + if (m_event_handlers == NULL) { + m_event_handlers = handler; return; - - err_code = sd_ble_gap_adv_stop(m_adv_handle); -#else - err_code = sd_ble_gap_adv_stop(); -#endif - - if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not stop advertisement. status: 0x%02x"), (uint16_t)err_code)); - } -} - -void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { - ble_gatts_value_t gatts_value; - memset(&gatts_value, 0, sizeof(gatts_value)); - - gatts_value.len = len; - gatts_value.offset = 0; - gatts_value.p_value = p_data; - - uint32_t err_code = sd_ble_gatts_value_get(conn_handle, - handle, - &gatts_value); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not read attribute value. status: 0x%02x"), (uint16_t)err_code)); } -} - -void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); - uint16_t conn_handle = device->conn_handle; - ble_gatts_value_t gatts_value; - - memset(&gatts_value, 0, sizeof(gatts_value)); - - gatts_value.len = bufinfo->len; - gatts_value.offset = 0; - gatts_value.p_value = bufinfo->buf; - - uint32_t err_code = sd_ble_gatts_value_set(conn_handle, characteristic->handle, &gatts_value); - - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not write attribute value. status: 0x%02x"), (uint16_t)err_code)); - } -} - -void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); - uint16_t conn_handle = device->conn_handle; - ble_gatts_hvx_params_t hvx_params; - uint16_t hvx_len = bufinfo->len; - - memset(&hvx_params, 0, sizeof(hvx_params)); - - hvx_params.handle = characteristic->handle; - hvx_params.type = BLE_GATT_HVX_NOTIFICATION; - hvx_params.offset = 0; - hvx_params.p_len = &hvx_len; - hvx_params.p_data = bufinfo->buf; - - while (m_tx_in_progress) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif - } - - m_tx_in_progress = true; - uint32_t err_code; - if ((err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not notify attribute value. status: 0x%02x"), (uint16_t)err_code)); - } -} - -void ble_drv_gap_event_handler_set(bleio_device_obj_t *device, ble_drv_gap_evt_callback_t evt_handler) { - mp_gap_observer = device; - gap_event_handler = evt_handler; -} - -void ble_drv_gatts_event_handler_set(bleio_device_obj_t *device, ble_drv_gatts_evt_callback_t evt_handler) { - mp_gatts_observer = device; - gatts_event_handler = evt_handler; -} - -void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *device, ble_drv_adv_evt_callback_t evt_handler) { - mp_adv_observer = device; - adv_event_handler = evt_handler; -} - -void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic) { - bleio_service_obj_t *service = characteristic->service; - bleio_device_obj_t *device = MP_OBJ_TO_PTR(service->device); - - mp_gattc_char_data_observer = characteristic; - - const uint32_t err_code = sd_ble_gattc_read(device->conn_handle, characteristic->handle, 0); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not read attribute value. status: 0x%02x"), (uint16_t)err_code)); - } - - while (mp_gattc_char_data_observer != NULL) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif - } -} - -void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - bleio_device_obj_t *device = MP_OBJ_TO_PTR(characteristic->service->device); - uint16_t conn_handle = device->conn_handle; - - ble_gattc_write_params_t write_params; - write_params.write_op = BLE_GATT_OP_WRITE_REQ; - - if (characteristic->props.write_wo_resp) { - write_params.write_op = BLE_GATT_OP_WRITE_CMD; - } - - write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL; - write_params.handle = characteristic->handle; - write_params.offset = 0; - write_params.len = bufinfo->len; - write_params.p_value = bufinfo->buf; - - m_write_done = (write_params.write_op == BLE_GATT_OP_WRITE_CMD); - - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not write attribute value. status: 0x%02x"), (uint16_t)err_code)); - } - - while (m_write_done != true) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif - } -} - -void ble_drv_scan_start(uint16_t interval, uint16_t window) { - SD_TEST_OR_ENABLE(); - - ble_gap_scan_params_t scan_params; - memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); - - scan_params.active = 1; - scan_params.interval = MSEC_TO_UNITS(interval, UNIT_0_625_MS); - scan_params.window = MSEC_TO_UNITS(window, UNIT_0_625_MS); -#if (BLUETOOTH_SD == 140) - scan_params.scan_phys = BLE_GAP_PHY_1MBPS; -#endif - scan_params.timeout = 0; // Infinite - - uint32_t err_code; -#if (BLUETOOTH_SD == 140) - if ((err_code = sd_ble_gap_scan_start(&scan_params, &m_scan_buffer)) != 0) { -#else - if ((err_code = sd_ble_gap_scan_start(&scan_params)) != 0) { -#endif - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - translate("Can not start scanning. status: 0x%02x"), (uint16_t)err_code)); - } -} - -void ble_drv_scan_continue(void) { - SD_TEST_OR_ENABLE(); - -#if (BLUETOOTH_SD == 140) - uint32_t err_code; - if ((err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not continue scanning. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -#endif -} - -void ble_drv_scan_stop(void) { - sd_ble_gap_scan_stop(); -} - -STATIC void ble_drv_connect_scan_callback(bleio_scanner_obj_t *scanner, bleio_scanentry_obj_t *entry) { - if (memcmp(entry->address.value, mp_connect_address->value, BLEIO_ADDRESS_BYTES) == 0) { - ble_drv_adv_report_handler_set(NULL, NULL); - - ble_gap_scan_params_t scan_params; - memset(&scan_params, 0, sizeof(scan_params)); - - scan_params.active = 1; - scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); - scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); - scan_params.timeout = 0; - - ble_gap_addr_t addr; - memset(&addr, 0, sizeof(addr)); - - addr.addr_type = entry->address.type; - memcpy(addr.addr, entry->address.value, BLEIO_ADDRESS_BYTES); - - BLE_DRIVER_LOG("GAP CONNECTING: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT", type: %d\n", - addr.addr[5], addr.addr[4], addr.addr[3], addr.addr[2], addr.addr[1], addr.addr[0], addr.addr_type); - - ble_gap_conn_params_t conn_params = { - .min_conn_interval = BLE_MIN_CONN_INTERVAL, - .max_conn_interval = BLE_MAX_CONN_INTERVAL, - .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, - .slave_latency = BLE_SLAVE_LATENCY, - }; - - uint32_t err_code; - #if (BLE_API_VERSION == 2) - if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params)) != 0) { - #else - if ((err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_DEFAULT)) != 0) { - #endif - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code)); + event_handler_t *it = m_event_handlers; + while (it->next != NULL) { + if ((it->func == func) && (it->param == param)) { + m_free(handler); + return; } - } -} - -void ble_drv_connect(bleio_device_obj_t *device) { - SD_TEST_OR_ENABLE(); - - mp_connect_address = &device->address; - ble_drv_adv_report_handler_set(NULL, ble_drv_connect_scan_callback); - - ble_drv_scan_start(100, 100); -} - -void ble_drv_disconnect(bleio_device_obj_t *device) { - sd_ble_gap_disconnect(device->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); -} - -bool ble_drv_discover_services(bleio_device_obj_t *device, uint16_t start_handle) { - mp_gattc_disc_service_observer = device; - - m_primary_service_found = false; - - uint32_t err_code = sd_ble_gattc_primary_services_discover(device->conn_handle, start_handle, NULL); - if (err_code != NRF_SUCCESS) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Failed to discover serivices. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - while (mp_gattc_disc_service_observer != NULL) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + it = it->next; } - return m_primary_service_found; + it->next = handler; } -bool ble_drv_discover_characteristic(bleio_device_obj_t *device, bleio_service_obj_t *service, uint16_t start_handle) { - BLE_DRIVER_LOG("Discover characteristicts. Conn handle: 0x" HEX2_FMT "\n", device->conn_handle); - - mp_gattc_disc_char_observer = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_characteristic_found = false; - - uint32_t err_code = sd_ble_gattc_characteristics_discover(device->conn_handle, &handle_range); - if (err_code != 0) { - return false; - } - - while (mp_gattc_disc_char_observer != NULL) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif - } - - return m_characteristic_found; -} - -void ble_drv_discover_descriptors(void) { - -} - -STATIC void on_adv_report(ble_gap_evt_adv_report_t *report) { - bleio_scanentry_obj_t *entry = m_new_obj(bleio_scanentry_obj_t); - entry->base.type = &bleio_scanentry_type; - - entry->rssi = report->rssi; - - entry->address.type = report->peer_addr.addr_type; - memcpy(entry->address.value, report->peer_addr.addr, BLEIO_ADDRESS_BYTES); - -#if (BLUETOOTH_SD == 140) - entry->data = mp_obj_new_bytearray(report->data.len, report->data.p_data); -#else - entry->data = mp_obj_new_bytearray(report->dlen, report->data); -#endif - - if (adv_event_handler != NULL) { - adv_event_handler(mp_adv_observer, entry); - } -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response) { - BLE_DRIVER_LOG(">>> service count: %d\n", response->count); - - for (size_t i = 0; i < response->count; ++i) { - const ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - service->char_list = mp_obj_new_list(0, NULL); - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - service->device = mp_gattc_disc_service_observer; - - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - uuid->type = (gattc_service->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT; - uuid->value[0] = gattc_service->uuid.uuid & 0xFF; - uuid->value[1] = gattc_service->uuid.uuid >> 8; - service->uuid = uuid; - - mp_obj_list_append(mp_gattc_disc_service_observer->service_list, service); - } - - if (response->count > 0) { - m_primary_service_found = true; - } - - // mark end of service discovery - mp_gattc_disc_service_observer = NULL; -} - -STATIC void on_characteristic_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response) { - BLE_DRIVER_LOG(">>> characteristic count: %d\n", response->count); - - for (size_t i = 0; i < response->count; ++i) { - const ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - uuid->type = (gattc_char->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT; - uuid->value[0] = gattc_char->uuid.uuid & 0xFF; - uuid->value[1] = gattc_char->uuid.uuid >> 8; - characteristic->uuid = uuid; - - characteristic->props.broadcast = gattc_char->char_props.broadcast; - characteristic->props.indicate = gattc_char->char_props.indicate; - characteristic->props.notify = gattc_char->char_props.notify; - characteristic->props.read = gattc_char->char_props.read; - characteristic->props.write = gattc_char->char_props.write; - characteristic->props.write_wo_resp = gattc_char->char_props.write_wo_resp; - characteristic->handle = gattc_char->handle_value; - - characteristic->service_handle = mp_gattc_disc_char_observer->handle; - characteristic->service = mp_gattc_disc_char_observer; - - mp_obj_list_append(mp_gattc_disc_char_observer->char_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_characteristic_found = true; +void SD_EVT_IRQHandler(void) { + uint32_t evt_id; + while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) { +// sd_evt_handler(evt_id); } - // mark end of characteristic discovery - mp_gattc_disc_char_observer = NULL; -} - -STATIC void on_read_rsp(ble_gattc_evt_read_rsp_t *response) { - mp_gattc_char_data_observer->value_data = mp_obj_new_bytearray(response->len, response->data); - - mp_gattc_char_data_observer = NULL; -} - -STATIC void ble_evt_handler(ble_evt_t *p_ble_evt) { - printf("%s - 0x%02X\r\n", __func__, p_ble_evt->header.evt_id); - - switch (p_ble_evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: - BLE_DRIVER_LOG("GAP CONNECT\n"); - gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); - - ble_gap_conn_params_t conn_params; - (void)sd_ble_gap_ppcp_get(&conn_params); - (void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, &conn_params); - break; - - case BLE_GAP_EVT_DISCONNECTED: - BLE_DRIVER_LOG("GAP DISCONNECT\n"); - gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); - break; - - case BLE_GATTS_EVT_HVC: - gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gatts_evt.params.hvc.handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); - break; - - case BLE_GATTS_EVT_WRITE: - BLE_DRIVER_LOG("GATTS write\n"); - - uint16_t handle = p_ble_evt->evt.gatts_evt.params.write.handle; - uint16_t data_len = p_ble_evt->evt.gatts_evt.params.write.len; - uint8_t * p_data = &p_ble_evt->evt.gatts_evt.params.write.data[0]; - - gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, handle, data_len, p_data); - break; - - case BLE_GAP_EVT_CONN_PARAM_UPDATE: - BLE_DRIVER_LOG("GAP CONN PARAM UPDATE\n"); - break; - - case BLE_GATTS_EVT_SYS_ATTR_MISSING: - // No system attributes have been stored. - (void)sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0); - break; - -#if (BLE_API_VERSION == 4) - case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: - BLE_DRIVER_LOG("GATTS EVT EXCHANGE MTU REQUEST\n"); - (void)sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 23); // MAX MTU size - break; -#endif - -#if (BLE_API_VERSION == 4) - case BLE_GATTS_EVT_HVN_TX_COMPLETE: -#else - case BLE_EVT_TX_COMPLETE: -#endif - BLE_DRIVER_LOG("BLE EVT TX COMPLETE\n"); - m_tx_in_progress = false; - break; - - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - BLE_DRIVER_LOG("BLE EVT SEC PARAMS REQUEST\n"); - // pairing not supported - (void)sd_ble_gap_sec_params_reply(p_ble_evt->evt.gatts_evt.conn_handle, - BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, - NULL, NULL); - break; - - case BLE_GAP_EVT_ADV_REPORT: - on_adv_report(&p_ble_evt->evt.gap_evt.params.adv_report); - break; - - case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: - BLE_DRIVER_LOG("BLE EVT CONN PARAM UPDATE REQUEST\n"); - - (void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, - &p_ble_evt->evt.gap_evt.params.conn_param_update_request.conn_params); - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_characteristic_discovery_rsp(&p_ble_evt->evt.gattc_evt.params.char_disc_rsp); - break; - - case BLE_GATTC_EVT_READ_RSP: - on_read_rsp(&p_ble_evt->evt.gattc_evt.params.read_rsp); - break; - - case BLE_GATTC_EVT_WRITE_RSP: - BLE_DRIVER_LOG("BLE EVT WRITE RESPONSE\n"); - m_write_done = true; - break; + while (1) { + uint16_t evt_len = sizeof(m_ble_evt_buf); + const uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len); + if (err_code != NRF_SUCCESS) { + if (err_code == NRF_ERROR_DATA_SIZE) { + printf("NRF_ERROR_DATA_SIZE\n"); + } - case BLE_GATTC_EVT_HVX: - BLE_DRIVER_LOG("BLE EVT HVX RESPONSE\n"); break; + } - default: - BLE_DRIVER_LOG(">>> unhandled evt: 0x" HEX2_FMT "\n", p_ble_evt->header.evt_id); - break; + event_handler_t *it = m_event_handlers; + while (it != NULL) { + it->func((ble_evt_t *)m_ble_evt_buf, it->param); + it = it->next; + } } } - -#if (BLE_API_VERSION == 2) -static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attribute__ ((aligned (4))); -#else -static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)] __attribute__ ((aligned (4))); -#endif - -void SD_EVT_IRQHandler(void) { - uint32_t evt_id; - uint32_t err_code; - do { - err_code = sd_evt_get(&evt_id); - // TODO: handle non ble events - } while (err_code != NRF_ERROR_NOT_FOUND && err_code != NRF_SUCCESS); - - uint16_t evt_len = sizeof(m_ble_evt_buf); - do { - err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len); - ble_evt_handler((ble_evt_t *)m_ble_evt_buf); - } while (err_code != NRF_ERROR_NOT_FOUND && err_code != NRF_SUCCESS); -} - -#endif // BLUETOOTH_SD diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h index 3b065c7a9..426354a19 100644 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ b/ports/nrf/drivers/bluetooth/ble_drv.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,65 +28,26 @@ #ifndef BLUETOOTH_LE_DRIVER_H__ #define BLUETOOTH_LE_DRIVER_H__ -#if BLUETOOTH_SD +#include "ble.h" -#include "shared-bindings/bleio/Device.h" -#include "shared-bindings/bleio/Scanner.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-module/bleio/ScanEntry.h" +#if (BLUETOOTH_SD == 132) && (BLE_API_VERSION == 2) +#define NRF52 +#endif -typedef void (*ble_drv_gap_evt_callback_t)(bleio_device_obj_t *device, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_gatts_evt_callback_t)(bleio_device_obj_t *device, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); -typedef void (*ble_drv_adv_evt_callback_t)(bleio_scanner_obj_t *scanner, bleio_scanentry_obj_t *entry); +#define MAX_TX_IN_PROGRESS 10 -uint32_t ble_drv_stack_enable(void); +#ifndef BLE_GATT_ATT_MTU_DEFAULT + #define BLE_GATT_ATT_MTU_DEFAULT GATT_MTU_SIZE_DEFAULT +#endif -uint8_t ble_drv_stack_enabled(void); +#define BLE_CONN_CFG_TAG_CUSTOM 1 -void ble_drv_address_get(bleio_address_obj_t *address); +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) +#define UNIT_0_625_MS (625) +#define UNIT_10_MS (10000) -bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx); +typedef void (*ble_drv_evt_handler_t)(ble_evt_t*, void*); -void ble_drv_service_add(bleio_service_obj_t *service); - -bool ble_drv_characteristic_add(bleio_characteristic_obj_t *characteristic); - -bool ble_drv_advertise_data(bleio_advertisement_data_t *p_adv_params); - -void ble_drv_advertise_stop(void); - -void ble_drv_gap_event_handler_set(bleio_device_obj_t *device, ble_drv_gap_evt_callback_t evt_handler); - -void ble_drv_gatts_event_handler_set(bleio_device_obj_t *device, ble_drv_gatts_evt_callback_t evt_handler); - -void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); - -void ble_drv_attr_c_read(bleio_characteristic_obj_t *characteristic); - -void ble_drv_attr_s_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); - -void ble_drv_attr_s_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); - -void ble_drv_attr_c_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo); - -void ble_drv_scan_start(uint16_t interval, uint16_t window); - -void ble_drv_scan_continue(void); - -void ble_drv_scan_stop(void); - -void ble_drv_adv_report_handler_set(bleio_scanner_obj_t *self, ble_drv_adv_evt_callback_t evt_handler); - -void ble_drv_connect(bleio_device_obj_t *device); - -void ble_drv_disconnect(bleio_device_obj_t *device); - -bool ble_drv_discover_services(bleio_device_obj_t *device, uint16_t start_handle); - -bool ble_drv_discover_characteristic(bleio_device_obj_t *device, bleio_service_obj_t *service, uint16_t start_handle); - -void ble_drv_discover_descriptors(void); - -#endif // BLUETOOTH_SD +void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param); #endif // BLUETOOTH_LE_DRIVER_H__ diff --git a/ports/nrf/drivers/bluetooth/ble_uart.h b/ports/nrf/drivers/bluetooth/ble_uart.h index 336624cd3..b57a75229 100644 --- a/ports/nrf/drivers/bluetooth/ble_uart.h +++ b/ports/nrf/drivers/bluetooth/ble_uart.h @@ -27,7 +27,7 @@ #ifndef BLUETOOTH_LE_UART_H__ #define BLUETOOTH_LE_UART_H__ -#if BLUETOOTH_SD +#include #include "ble_drv.h" @@ -36,6 +36,4 @@ void ble_uart_advertise(void); bool ble_uart_connected(void); bool ble_uart_enabled(void); -#endif // BLUETOOTH_SD - #endif // BLUETOOTH_LE_UART_H__ diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index 905babecb..3563d3895 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -125,6 +125,8 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t "Invalid UUID parameter")); } + common_hal_bleio_characteristic_construct(self); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h index dd67170d9..0e99e97cc 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -31,6 +31,7 @@ extern const mp_obj_type_t bleio_characteristic_type; +extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); diff --git a/shared-bindings/bleio/Device.c b/shared-bindings/bleio/Device.c index 386261683..8c7cef95f 100644 --- a/shared-bindings/bleio/Device.c +++ b/shared-bindings/bleio/Device.c @@ -199,7 +199,7 @@ STATIC mp_obj_t bleio_device_add_service(mp_obj_t self_in, mp_obj_t service_in) "Can't add services in Central mode")); } - service->device = self_in; + service->device = self; mp_obj_list_append(self->service_list, service); @@ -266,31 +266,21 @@ STATIC mp_obj_t bleio_device_start_advertising(mp_uint_t n_args, const mp_obj_t "Can't advertise in Central mode")); } - enum { ARG_connectable }; + enum { ARG_connectable, ARG_data }; static const mp_arg_t allowed_args[] = { { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - // TODO: data - bleio_advertisement_data_t adv_data = { - .device_name = self->name, - .services = mp_obj_new_list(0, NULL), - .data = mp_obj_new_bytearray(0, NULL), - .connectable = args[ARG_connectable].u_bool - }; - - mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list); - for (size_t i = 0; i < service_list->len; ++i) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]); - if (!service->is_secondary) { - mp_obj_list_append(adv_data.services, service_list->items[i]); - } + mp_buffer_info_t bufinfo = { 0 }; + if (args[ARG_data].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); } - common_hal_bleio_device_start_advertising(self, &adv_data); + common_hal_bleio_device_start_advertising(self, args[ARG_connectable].u_bool, &bufinfo); return mp_const_none; } diff --git a/shared-bindings/bleio/Device.h b/shared-bindings/bleio/Device.h index d099e5c43..f989736dd 100644 --- a/shared-bindings/bleio/Device.h +++ b/shared-bindings/bleio/Device.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t bleio_device_type; -extern void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bleio_advertisement_data_t *adv_data); +extern void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bool connectable, mp_buffer_info_t *raw_data); extern void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device); extern void common_hal_bleio_device_connect(bleio_device_obj_t *device); extern void common_hal_bleio_device_disconnect(bleio_device_obj_t *device); diff --git a/shared-bindings/bleio/Scanner.h b/shared-bindings/bleio/Scanner.h index 03db5cd8b..9bd071747 100644 --- a/shared-bindings/bleio/Scanner.h +++ b/shared-bindings/bleio/Scanner.h @@ -34,5 +34,6 @@ extern const mp_obj_type_t bleio_scanner_type; extern void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_int_t timeout); +extern void common_hal_bleio_scanner_stop(bleio_scanner_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index 338269a5f..a2f9b9899 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -74,7 +74,7 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_check_num(n_args, n_kw, 1, 1, true); bleio_service_obj_t *self = m_new_obj(bleio_service_obj_t); self->base.type = &bleio_service_type; - self->device = mp_const_none; + self->device = NULL; self->char_list = mp_obj_new_list(0, NULL); mp_map_t kw_args; diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index 2347c9c30..13f75b2c9 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -33,7 +33,7 @@ typedef struct { mp_obj_base_t base; bleio_service_obj_t *service; - uint16_t service_handle; + uint16_t service_handle; // TODO: Is this needed? bleio_uuid_obj_t *uuid; mp_obj_t value_data; uint16_t handle; diff --git a/shared-module/bleio/Device.h b/shared-module/bleio/Device.h index afbd8f063..8d9ece5ef 100644 --- a/shared-module/bleio/Device.h +++ b/shared-module/bleio/Device.h @@ -36,7 +36,7 @@ typedef struct { bool is_peripheral; mp_obj_t name; bleio_address_obj_t address; - uint16_t conn_handle; + volatile uint16_t conn_handle; mp_obj_t service_list; mp_obj_t notif_handler; mp_obj_t conn_handler; diff --git a/shared-module/bleio/Service.h b/shared-module/bleio/Service.h index 1e3f09119..ff506d3f3 100644 --- a/shared-module/bleio/Service.h +++ b/shared-module/bleio/Service.h @@ -28,13 +28,14 @@ #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SERVICE_H #include "common-hal/bleio/UUID.h" +#include "shared-module/bleio/Device.h" typedef struct { mp_obj_base_t base; uint16_t handle; bool is_secondary; bleio_uuid_obj_t *uuid; - mp_obj_t device; + bleio_device_obj_t *device; mp_obj_t char_list; uint16_t start_handle; uint16_t end_handle; -- cgit v1.2.3 From b5e5805bb408ca3bb5975d8fad21070dbf4d51e9 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Mon, 23 Jul 2018 23:52:09 +0200 Subject: bleio: Remove redundant struct field --- ports/nrf/common-hal/bleio/Device.c | 2 -- ports/nrf/common-hal/bleio/Service.c | 3 +-- shared-bindings/bleio/Service.c | 4 ++-- shared-module/bleio/Characteristic.h | 1 - 4 files changed, 3 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Device.c b/ports/nrf/common-hal/bleio/Device.c index 8e52b2fbc..fd772c04d 100644 --- a/ports/nrf/common-hal/bleio/Device.c +++ b/ports/nrf/common-hal/bleio/Device.c @@ -376,8 +376,6 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio characteristic->props.write = gattc_char->char_props.write; characteristic->props.write_wo_resp = gattc_char->char_props.write_wo_resp; characteristic->handle = gattc_char->handle_value; - - characteristic->service_handle = m_char_discovery_service->handle; characteristic->service = m_char_discovery_service; mp_obj_list_append(m_char_discovery_service->char_list, MP_OBJ_FROM_PTR(characteristic)); diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index 9e376b333..93588d156 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -101,7 +101,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, blei ble_gatts_char_handles_t handles; uint32_t err_code; - err_code = sd_ble_gatts_characteristic_add(characteristic->service_handle, &char_md, &attr_char_value, &handles); + err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &attr_char_value, &handles); if (err_code != NRF_SUCCESS) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Failed to add characteristic, status: 0x%08lX", err_code)); @@ -111,5 +111,4 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, blei characteristic->cccd_handle = handles.cccd_handle; characteristic->sccd_handle = handles.sccd_handle; characteristic->handle = handles.value_handle; - characteristic->service = self; } diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index 3a4aa4737..94d245d7f 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -113,12 +113,12 @@ STATIC mp_obj_t bleio_service_add_characteristic(mp_obj_t self_in, mp_obj_t char bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(characteristic_in); - characteristic->service_handle = self->handle; - // TODO: If service is 128b then update Chara UUID to be 128b too common_hal_bleio_service_add_characteristic(self, characteristic); + characteristic->service = self; + mp_obj_list_append(self->char_list, characteristic); return mp_const_none; diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index 13f75b2c9..94c43f81e 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -33,7 +33,6 @@ typedef struct { mp_obj_base_t base; bleio_service_obj_t *service; - uint16_t service_handle; // TODO: Is this needed? bleio_uuid_obj_t *uuid; mp_obj_t value_data; uint16_t handle; -- cgit v1.2.3