diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c new file mode 100644 index 0000000000000..f6c3de873b401 --- /dev/null +++ b/extmod/modbluetooth.c @@ -0,0 +1,387 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * 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/objstr.h" +#include "py/runtime.h" +#include "extmod/modbluetooth.h" + +#if MICROPY_PY_BLUETOOTH + +STATIC const mp_obj_type_t bluetooth_type; +STATIC const mp_obj_type_t service_type; +STATIC const mp_obj_type_t characteristic_type; + +typedef struct _mp_obj_bluetooth_t { + mp_obj_base_t base; +} mp_obj_bluetooth_t; + + +// instantiated Bluetooth object +STATIC const mp_obj_bluetooth_t bluetooth_obj = { + { &bluetooth_type }, +}; + +// Easier (hopefully tail-called) error handling. +STATIC mp_obj_t bluetooth_handle_errno(int errno_) { + if (errno_ != 0) { + mp_raise_OSError(errno_); + } + return mp_const_none; +} + +// Parse string UUIDs, which are probably 128-bit UUIDs. +void mp_bt_parse_uuid_str(mp_obj_t obj, uint8_t *uuid) { + GET_STR_DATA_LEN(obj, str_data, str_len); + int uuid_i = 32; + for (int i = 0; i < str_len; i++) { + char c = str_data[i]; + if (c == '-') { + continue; + } + if (c >= '0' && c <= '9') { + c = c - '0'; + } else if (c >= 'a' && c <= 'f') { + c = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + c = c - 'A' + 10; + } else { + mp_raise_ValueError("unknown char in UUID"); + } + uuid_i--; + if (uuid_i < 0) { + mp_raise_ValueError("UUID too long"); + } + if (uuid_i % 2 == 0) { + // lower nibble + uuid[uuid_i/2] |= c; + } else { + // upper nibble + uuid[uuid_i/2] = c << 4; + } + } + if (uuid_i > 0) { + mp_raise_ValueError("UUID too short"); + } +} + +// Format string UUID. Example output: +// '6e400001-b5a3-f393-e0a9-e50e24dcca9e' +mp_obj_t mp_bt_format_uuid_str(uint8_t *uuid) { + char str[36]; + char *s = str; + for (int i = 15; i >= 0; i--) { + char nibble = uuid[i] >> 4; + if (nibble >= 10) { + nibble += 'a' - 10; + } else { + nibble += '0'; + } + *(s++) = nibble; + + nibble = uuid[i] & 0xf; + if (nibble >= 10) { + nibble += 'a' - 10; + } else { + nibble += '0'; + } + *(s++) = nibble; + + if (i == 12 || i == 10 || i == 8 || i == 6) { + *(s++) = '-'; + } + } + return mp_obj_new_str(str, MP_ARRAY_SIZE(str)); +} + +STATIC mp_obj_t bluetooth_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + return MP_OBJ_FROM_PTR(&bluetooth_obj); +} + +STATIC mp_obj_t bluetooth_active(size_t n_args, const mp_obj_t *args) { + if (n_args == 2) { // boolean enable/disable argument supplied + if (mp_obj_is_true(args[1])) { + int errno_ = mp_bt_enable(); + if (errno_ != 0) { + mp_raise_OSError(errno_); + } + } else { + mp_bt_disable(); + } + } + return mp_obj_new_bool(mp_bt_is_enabled()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_active_obj, 1, 2, bluetooth_active); + +STATIC mp_obj_t bluetooth_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_interval, ARG_name, ARG_connectable }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_interval, MP_ARG_INT, {.u_int = 100} }, + { MP_QSTR_name, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_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); + + mp_int_t interval = args[ARG_interval].u_int; + if (interval == 0) { + mp_bt_advertise_stop(); + return mp_const_none; + } + interval = interval * 8 / 5; // convert from 1ms to 0.625ms units + if (interval < 0x20 || interval > 0x4000) { + mp_raise_ValueError("interval out of range"); + } + + mp_bt_adv_type_t adv_type = MP_BT_ADV_TYPE_ADV_IND; // connectable=True + if (!mp_obj_is_true(args[ARG_connectable].u_obj)) { + adv_type = MP_BT_ADV_TYPE_ADV_NONCONN_IND; // connectable=False + } + + size_t name_len; + const char *name = NULL; + if (args[ARG_name].u_obj != mp_const_none) { + name = mp_obj_str_get_data(args[ARG_name].u_obj, &name_len); + } + + uint8_t adv_data[31]; + size_t adv_data_len = 0; + + if (name != NULL) { + adv_data[adv_data_len++] = 2; // 1 byte type + 1 byte flags data + adv_data[adv_data_len++] = MP_BLE_GAP_AD_TYPE_FLAG; + adv_data[adv_data_len++] = MP_BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; + + if (name_len + 3 > sizeof(adv_data) - adv_data_len) { + mp_raise_ValueError("advertisement packet overflow"); + } + adv_data[adv_data_len++] = name_len + 1; + adv_data[adv_data_len++] = MP_BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; + for (size_t i=0; i 0x4000) { + mp_raise_ValueError("interval out of range"); + } + + mp_bt_adv_type_t adv_type = MP_BT_ADV_TYPE_ADV_IND; // connectable=True + if (!mp_obj_is_true(args[ARG_connectable].u_obj)) { + adv_type = MP_BT_ADV_TYPE_ADV_NONCONN_IND; // connectable=False + } + + size_t adv_data_len; + const uint8_t *adv_data = NULL; + if (args[ARG_adv_data].u_obj != mp_const_none) { + adv_data = (const uint8_t*)mp_obj_str_get_data(args[ARG_adv_data].u_obj, &adv_data_len); + } + + size_t sr_data_len; + const uint8_t *sr_data = NULL; + if (args[ARG_sr_data].u_obj != mp_const_none) { + sr_data = (const uint8_t*)mp_obj_str_get_data(args[ARG_sr_data].u_obj, &sr_data_len); + } + + int errno_ = mp_bt_advertise_start(adv_type, interval, adv_data_len ? adv_data : NULL, adv_data_len, sr_data_len ? sr_data : NULL, sr_data_len); + return bluetooth_handle_errno(errno_); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_advertise_raw_obj, 1, bluetooth_advertise_raw); + +STATIC mp_obj_t bluetooth_add_service(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_uuid, ARG_characteristics }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_characteristics, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + 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); + + mp_obj_list_t *characteristics = args[ARG_characteristics].u_obj; + if (characteristics == NULL || !mp_obj_is_type(args[ARG_characteristics].u_obj, &mp_type_list)) { + mp_raise_ValueError("characteristics must be a list"); + } + for (int i = 0; i < characteristics->len; i++) { + mp_obj_t characteristic = characteristics->items[i]; + if (characteristic == NULL || !mp_obj_is_type(characteristic, &characteristic_type)) { + mp_raise_ValueError("not a Characteristic"); + } + if (((mp_bt_characteristic_t*)characteristic)->service != NULL) { + mp_raise_ValueError("Characteristic already added to Service"); + } + } + + mp_bt_service_t *service = m_new_obj(mp_bt_service_t); + service->base.type = &service_type; + mp_bt_parse_uuid(args[ARG_uuid].u_obj, &service->uuid); + int errno_ = mp_bt_add_service(service, characteristics->len, (mp_bt_characteristic_t**)characteristics->items); + bluetooth_handle_errno(errno_); + return service; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_add_service_obj, 1, bluetooth_add_service); + +STATIC mp_obj_t service_uuid(mp_obj_t self_in) { + mp_bt_service_t *service = self_in; + return mp_bt_format_uuid(&service->uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(service_uuid_obj, service_uuid); + +STATIC const mp_rom_map_elem_t service_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&service_uuid_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(service_locals_dict, service_locals_dict_table); + +STATIC const mp_obj_type_t service_type = { + { &mp_type_type }, + .name = MP_QSTR_Service, + .locals_dict = (void*)&service_locals_dict, +}; + +STATIC mp_obj_t characteristic_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_uuid, ARG_flags }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_flags, MP_ARG_INT | MP_ARG_REQUIRED }, + }; + 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); + + if ((uint8_t)(args[ARG_flags].u_int) != args[ARG_flags].u_int) { + // Flags don't fit in 8 bits. + mp_raise_ValueError("invalid flags"); + } + + mp_bt_characteristic_t *characteristic = m_new_obj(mp_bt_characteristic_t); + characteristic->base.type = &characteristic_type; + mp_bt_parse_uuid(args[0].u_obj, &characteristic->uuid); + characteristic->flags = (uint8_t)(args[ARG_flags].u_int); + return characteristic; +} + +STATIC mp_obj_t characteristic_service(mp_obj_t self_in) { + mp_bt_characteristic_t *characteristic = self_in; + if (characteristic->service == NULL) { + return mp_const_none; + } + return characteristic->service; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(characteristic_service_obj, characteristic_service); + +STATIC mp_obj_t characteristic_uuid(mp_obj_t self_in) { + mp_bt_characteristic_t *characteristic = self_in; + return mp_bt_format_uuid(&characteristic->uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(characteristic_uuid_obj, characteristic_uuid); + +STATIC mp_obj_t characteristic_write(mp_obj_t self_in, mp_obj_t value_in) { + mp_bt_characteristic_t *characteristic = self_in; + GET_STR_DATA_LEN(value_in, str_data, str_len); + int errno_ = mp_bt_characteristic_value_set(characteristic->value_handle, str_data, str_len); + return bluetooth_handle_errno(errno_); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(characteristic_write_obj, characteristic_write); + +STATIC mp_obj_t characteristic_read(mp_obj_t self_in) { + mp_bt_characteristic_t *characteristic = self_in; + uint8_t data[MP_BT_MAX_ATTR_SIZE]; + size_t value_len = MP_BT_MAX_ATTR_SIZE; + int errno_ = mp_bt_characteristic_value_get(characteristic->value_handle, data, &value_len); + if (errno_ != 0) { + mp_raise_OSError(errno_); + } + return mp_obj_new_bytes(data, value_len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(characteristic_read_obj, characteristic_read); + +STATIC const mp_rom_map_elem_t characteristic_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_service), MP_ROM_PTR(&characteristic_service_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&characteristic_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&characteristic_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&characteristic_read_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(characteristic_locals_dict, characteristic_locals_dict_table); + +STATIC const mp_obj_type_t characteristic_type = { + { &mp_type_type }, + .name = MP_QSTR_Characteristic, + .make_new = characteristic_make_new, + .locals_dict = (void*)&characteristic_locals_dict, +}; + +STATIC const mp_rom_map_elem_t bluetooth_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&bluetooth_advertise_obj) }, + { MP_ROM_QSTR(MP_QSTR_advertise_raw), MP_ROM_PTR(&bluetooth_advertise_raw_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_service), MP_ROM_PTR(&bluetooth_add_service_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(bluetooth_locals_dict, bluetooth_locals_dict_table); + +STATIC const mp_obj_type_t bluetooth_type = { + { &mp_type_type }, + .name = MP_QSTR_Bluetooth, + .make_new = bluetooth_make_new, + .locals_dict = (void*)&bluetooth_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth) }, + { MP_ROM_QSTR(MP_QSTR_Bluetooth), MP_ROM_PTR(&bluetooth_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&service_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLE_FLAG_READ) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE), MP_ROM_INT(MP_BLE_FLAG_WRITE) }, + { MP_ROM_QSTR(MP_QSTR_FLAG_NOTIFY), MP_ROM_INT(MP_BLE_FLAG_NOTIFY) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table); + +const mp_obj_module_t mp_module_bluetooth = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_bluetooth_globals, +}; + +#endif //MICROPY_PY_BLUETOOTH diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h new file mode 100644 index 0000000000000..c665260e267fb --- /dev/null +++ b/extmod/modbluetooth.h @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * 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. + */ + +#pragma once + +#if MICROPY_PY_BLUETOOTH + +#include +#include "bluetooth/bluetooth.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + mp_bt_uuid_t uuid; + mp_bt_service_handle_t handle; +} mp_bt_service_t; + +// A characteristic. +// Object fits in 4 words (1 GC object), with 1 byte unused at the end. +typedef struct { + mp_obj_base_t base; + mp_bt_uuid_t uuid; + mp_bt_service_t *service; + mp_bt_characteristic_handle_t value_handle; + uint8_t flags; +} mp_bt_characteristic_t; + +// Enables the Bluetooth stack. Returns errno on failure. +int mp_bt_enable(void); + +// Disables the Bluetooth stack. Is a no-op when not enabled. +void mp_bt_disable(void); + +// Returns true when the Bluetooth stack is enabled. +bool mp_bt_is_enabled(void); + +// Start advertisement. Will re-start advertisement when already enabled. +// Returns errno on failure. +int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len); + +// Stop advertisement. No-op when already stopped. +void mp_bt_advertise_stop(void); + +// Add a service with the given list of characteristics. +int mp_bt_add_service(mp_bt_service_t *service, size_t num_characteristics, mp_bt_characteristic_t **characteristics); + +// Set the given characteristic to the given value. +int mp_bt_characteristic_value_set(mp_bt_characteristic_handle_t handle, const void *value, size_t value_len); + +// Read the characteristic value. The size of the buffer must be given in +// value_len, which will be updated with the actual value. +int mp_bt_characteristic_value_get(mp_bt_characteristic_handle_t handle, void *value, size_t *value_len); + +// Parse an UUID object from the caller and stores the result in the uuid +// parameter. Must accept both strings and integers for 128-bit and 16-bit +// UUIDs. +void mp_bt_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid); + +// Format an UUID object to be returned from a .uuid() call. May result in +// a small int or a string. +mp_obj_t mp_bt_format_uuid(mp_bt_uuid_t *uuid); + +// Parse a string UUID object into the 16-byte buffer. The string must be +// the correct size, otherwise this function will throw an error. +void mp_bt_parse_uuid_str(mp_obj_t obj, uint8_t *uuid); + +// Format a 128-bit UUID from the 16-byte buffer as a string. +mp_obj_t mp_bt_format_uuid_str(uint8_t *uuid); + +// Data types of advertisement packet. +#define MP_BLE_GAP_AD_TYPE_FLAG (0x01) +#define MP_BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME (0x09) + +// Flags element of advertisement packet. +#define MP_BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) // discoverable for everyone +#define MP_BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) // BLE only - no classic BT supported +#define MP_BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE (MP_BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | MP_BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) + +#define MP_BLE_FLAG_READ (1 << 1) +#define MP_BLE_FLAG_WRITE (1 << 3) +#define MP_BLE_FLAG_NOTIFY (1 << 4) + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ea90c9f3f5a9d..c896298e45bea 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -7,6 +7,7 @@ MICROPY_PY_USSL = 0 MICROPY_SSL_AXTLS = 0 MICROPY_FATFS = 1 MICROPY_PY_BTREE = 1 +MICROPY_PY_BLUETOOTH = 1 #FROZEN_DIR = scripts FROZEN_MPY_DIR = modules @@ -111,6 +112,26 @@ INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include INC_ESPCOMP += -I$(ESPCOMP)/pthread/include INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/api/include/api +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/bta/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/bta/dm/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/bta/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/bta/sys/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/btc/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/btc/profile/esp/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/btc/profile/esp/blufi/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/btc/profile/std/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/common/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/device/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/hci/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/osi/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/btm/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/gap/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/gatt/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/l2cap/include +INC_ESPCOMP += -I$(ESPCOMP)/bt/bluedroid/stack/smp/include # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ @@ -181,6 +202,7 @@ SRC_C = \ machine_uart.c \ modmachine.c \ modnetwork.c \ + bluetooth/bluetooth.c \ network_lan.c \ network_ppp.c \ modsocket.c \ @@ -665,6 +687,146 @@ ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ port/os_xtensa.o \ ) +ESPIDF_BT_O = $(addprefix $(ESPCOMP)/bt/,\ + bt.o \ + bluedroid/api/esp_a2dp_api.o \ + bluedroid/api/esp_avrc_api.o \ + bluedroid/api/esp_blufi_api.o \ + bluedroid/api/esp_bt_device.o \ + bluedroid/api/esp_bt_main.o \ + bluedroid/api/esp_gap_ble_api.o \ + bluedroid/api/esp_gap_bt_api.o \ + bluedroid/api/esp_gattc_api.o \ + bluedroid/api/esp_gatt_common_api.o \ + bluedroid/api/esp_gatts_api.o \ + bluedroid/api/esp_hf_client_api.o \ + bluedroid/api/esp_spp_api.o \ + bluedroid/bta/dm/bta_dm_act.o \ + bluedroid/bta/dm/bta_dm_api.o \ + bluedroid/bta/dm/bta_dm_cfg.o \ + bluedroid/bta/dm/bta_dm_ci.o \ + bluedroid/bta/dm/bta_dm_co.o \ + bluedroid/bta/dm/bta_dm_main.o \ + bluedroid/bta/dm/bta_dm_pm.o \ + bluedroid/bta/dm/bta_dm_sco.o \ + bluedroid/bta/gatt/bta_gattc_act.o \ + bluedroid/bta/gatt/bta_gattc_api.o \ + bluedroid/bta/gatt/bta_gattc_cache.o \ + bluedroid/bta/gatt/bta_gattc_ci.o \ + bluedroid/bta/gatt/bta_gattc_co.o \ + bluedroid/bta/gatt/bta_gattc_main.o \ + bluedroid/bta/gatt/bta_gatt_common.o \ + bluedroid/bta/gatt/bta_gattc_utils.o \ + bluedroid/bta/gatt/bta_gatts_act.o \ + bluedroid/bta/gatt/bta_gatts_api.o \ + bluedroid/bta/gatt/bta_gatts_co.o \ + bluedroid/bta/gatt/bta_gatts_main.o \ + bluedroid/bta/gatt/bta_gatts_utils.o \ + bluedroid/bta/sys/bta_sys_conn.o \ + bluedroid/bta/sys/bta_sys_main.o \ + bluedroid/bta/sys/utl.o \ + bluedroid/btc/core/btc_alarm.o \ + bluedroid/btc/core/btc_ble_storage.o \ + bluedroid/btc/core/btc_config.o \ + bluedroid/btc/core/btc_dev.o \ + bluedroid/btc/core/btc_dm.o \ + bluedroid/btc/core/btc_main.o \ + bluedroid/btc/core/btc_manage.o \ + bluedroid/btc/core/btc_profile_queue.o \ + bluedroid/btc/core/btc_sec.o \ + bluedroid/btc/core/btc_sm.o \ + bluedroid/btc/core/btc_storage.o \ + bluedroid/btc/core/btc_task.o \ + bluedroid/btc/core/btc_util.o \ + bluedroid/btc/profile/esp/blufi/blufi_prf.o \ + bluedroid/btc/profile/esp/blufi/blufi_protocol.o \ + bluedroid/btc/profile/std/gap/btc_gap_ble.o \ + bluedroid/btc/profile/std/gap/btc_gap_bt.o \ + bluedroid/btc/profile/std/gatt/btc_gattc.o \ + bluedroid/btc/profile/std/gatt/btc_gatt_common.o \ + bluedroid/btc/profile/std/gatt/btc_gatts.o \ + bluedroid/btc/profile/std/gatt/btc_gatt_util.o \ + bluedroid/device/bdaddr.o \ + bluedroid/device/controller.o \ + bluedroid/device/interop.o \ + bluedroid/hci/hci_audio.o \ + bluedroid/hci/hci_hal_h4.o \ + bluedroid/hci/hci_layer.o \ + bluedroid/hci/hci_packet_factory.o \ + bluedroid/hci/hci_packet_parser.o \ + bluedroid/hci/packet_fragmenter.o \ + bluedroid/main/bte_init.o \ + bluedroid/main/bte_main.o \ + bluedroid/osi/alarm.o \ + bluedroid/osi/allocator.o \ + bluedroid/osi/buffer.o \ + bluedroid/osi/config.o \ + bluedroid/osi/fixed_queue.o \ + bluedroid/osi/future.o \ + bluedroid/osi/hash_functions.o \ + bluedroid/osi/hash_map.o \ + bluedroid/osi/list.o \ + bluedroid/osi/mutex.o \ + bluedroid/osi/osi.o \ + bluedroid/osi/semaphore.o \ + bluedroid/stack/btm/btm_acl.o \ + bluedroid/stack/btm/btm_ble_addr.o \ + bluedroid/stack/btm/btm_ble_adv_filter.o \ + bluedroid/stack/btm/btm_ble_batchscan.o \ + bluedroid/stack/btm/btm_ble_bgconn.o \ + bluedroid/stack/btm/btm_ble.o \ + bluedroid/stack/btm/btm_ble_cont_energy.o \ + bluedroid/stack/btm/btm_ble_gap.o \ + bluedroid/stack/btm/btm_ble_multi_adv.o \ + bluedroid/stack/btm/btm_ble_privacy.o \ + bluedroid/stack/btm/btm_dev.o \ + bluedroid/stack/btm/btm_devctl.o \ + bluedroid/stack/btm/btm_inq.o \ + bluedroid/stack/btm/btm_main.o \ + bluedroid/stack/btm/btm_pm.o \ + bluedroid/stack/btm/btm_sco.o \ + bluedroid/stack/btm/btm_sec.o \ + bluedroid/stack/btu/btu_hcif.o \ + bluedroid/stack/btu/btu_init.o \ + bluedroid/stack/btu/btu_task.o \ + bluedroid/stack/gap/gap_api.o \ + bluedroid/stack/gap/gap_ble.o \ + bluedroid/stack/gap/gap_conn.o \ + bluedroid/stack/gap/gap_utils.o \ + bluedroid/stack/gatt/att_protocol.o \ + bluedroid/stack/gatt/gatt_api.o \ + bluedroid/stack/gatt/gatt_attr.o \ + bluedroid/stack/gatt/gatt_auth.o \ + bluedroid/stack/gatt/gatt_cl.o \ + bluedroid/stack/gatt/gatt_db.o \ + bluedroid/stack/gatt/gatt_main.o \ + bluedroid/stack/gatt/gatt_sr.o \ + bluedroid/stack/gatt/gatt_utils.o \ + bluedroid/stack/hcic/hciblecmds.o \ + bluedroid/stack/hcic/hcicmds.o \ + bluedroid/stack/l2cap/l2cap_client.o \ + bluedroid/stack/l2cap/l2c_api.o \ + bluedroid/stack/l2cap/l2c_ble.o \ + bluedroid/stack/l2cap/l2c_csm.o \ + bluedroid/stack/l2cap/l2c_fcr.o \ + bluedroid/stack/l2cap/l2c_link.o \ + bluedroid/stack/l2cap/l2c_main.o \ + bluedroid/stack/l2cap/l2c_ucd.o \ + bluedroid/stack/l2cap/l2c_utils.o \ + bluedroid/stack/smp/aes.o \ + bluedroid/stack/smp/p_256_curvepara.o \ + bluedroid/stack/smp/p_256_ecc_pp.o \ + bluedroid/stack/smp/p_256_multprecision.o \ + bluedroid/stack/smp/smp_act.o \ + bluedroid/stack/smp/smp_api.o \ + bluedroid/stack/smp/smp_br_main.o \ + bluedroid/stack/smp/smp_cmac.o \ + bluedroid/stack/smp/smp_keys.o \ + bluedroid/stack/smp/smp_l2c.o \ + bluedroid/stack/smp/smp_main.o \ + bluedroid/stack/smp/smp_utils.o \ + ) + OBJ_ESPIDF = OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) @@ -693,6 +855,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_BT_O)) $(OBJ_ESPIDF): $(SDKCONFIG_H) @@ -723,6 +886,7 @@ LIB_ESPIDF += ulp LIB_ESPIDF += lwip LIB_ESPIDF += mbedtls LIB_ESPIDF += wpa_supplicant +LIB_ESPIDF += bt BUILD_ESPIDF_LIB = $(BUILD)/esp-idf @@ -763,6 +927,7 @@ $(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) $(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) +$(eval $(call gen_espidf_lib_rule,bt,$(ESPIDF_BT_O))) LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) @@ -832,6 +997,7 @@ APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ APP_LD_ARGS += $(LIBC_LIBM) APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a +APP_LD_ARGS += $(ESPCOMP)/bt/lib/libbtdm_app.a APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 APP_LD_ARGS += $(OBJ) APP_LD_ARGS += $(LIB) diff --git a/ports/esp32/bluetooth/bluetooth.c b/ports/esp32/bluetooth/bluetooth.c new file mode 100644 index 0000000000000..3ab9b0b16a7aa --- /dev/null +++ b/ports/esp32/bluetooth/bluetooth.c @@ -0,0 +1,387 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * 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. + */ + +#if MICROPY_PY_BLUETOOTH + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_gatts_api.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "extmod/modbluetooth.h" + +// Semaphore to serialze asynchronous calls. +STATIC SemaphoreHandle_t mp_bt_call_complete; +STATIC esp_bt_status_t mp_bt_call_status; +STATIC union { + // Ugly hack to return values from an event handler back to a caller. + esp_gatt_if_t gatts_if; + uint16_t service_handle; + uint16_t attr_handle; +} mp_bt_call_result; + +STATIC mp_bt_adv_type_t bluetooth_adv_type; +STATIC uint16_t bluetooth_adv_interval; +STATIC uint16_t bluetooth_app_id = 0; // provide unique number for each application profile + +STATIC void mp_bt_gap_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); +STATIC void mp_bt_gatts_callback(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + +// Convert an esp_err_t into an errno number. +STATIC int mp_bt_esp_errno(esp_err_t err) { + if (err != 0) { + return MP_EPERM; + } + return 0; +} + +// Convert the result of an asynchronous call to an errno value. +STATIC int mp_bt_status_errno(void) { + if (mp_bt_call_status != ESP_BT_STATUS_SUCCESS) { + return MP_EPERM; + } + return 0; +} + +// Initialize at early boot. +void mp_bt_init(void) { + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + mp_bt_call_complete = xSemaphoreCreateBinary(); +} + +int mp_bt_enable(void) { + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + esp_err_t err = esp_bt_controller_init(&bt_cfg); + if (err != 0) { + return mp_bt_esp_errno(err); + } + err = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (err != 0) { + return mp_bt_esp_errno(err); + } + err = esp_bluedroid_init(); + if (err != 0) { + return mp_bt_esp_errno(err); + } + err = esp_bluedroid_enable(); + if (err != 0) { + return mp_bt_esp_errno(err); + } + err = esp_ble_gap_register_callback(mp_bt_gap_callback); + if (err != 0) { + return mp_bt_esp_errno(err); + } + err = esp_ble_gatts_register_callback(mp_bt_gatts_callback); + if (err != 0) { + return mp_bt_esp_errno(err); + } + return 0; +} + +void mp_bt_disable(void) { + esp_bluedroid_disable(); + esp_bluedroid_deinit(); + esp_bt_controller_disable(); + esp_bt_controller_deinit(); +} + +bool mp_bt_is_enabled(void) { + return esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_ENABLED; +} + +STATIC esp_err_t mp_bt_advertise_start_internal(void) { + esp_ble_adv_params_t ble_adv_params = {0, + .adv_int_min = bluetooth_adv_interval, + .adv_int_max = bluetooth_adv_interval, + .adv_type = bluetooth_adv_type, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + }; + return esp_ble_gap_start_advertising(&ble_adv_params); +} + +int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { + if (adv_data != NULL) { + esp_err_t err = esp_ble_gap_config_adv_data_raw((uint8_t*)adv_data, adv_data_len); + if (err != 0) { + return mp_bt_esp_errno(err); + } + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + } + + if (sr_data != NULL) { + esp_err_t err = esp_ble_gap_config_scan_rsp_data_raw((uint8_t*)sr_data, sr_data_len); + if (err != 0) { + return mp_bt_esp_errno(err); + } + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + } + + bluetooth_adv_type = type; + bluetooth_adv_interval = interval; + esp_err_t err = mp_bt_advertise_start_internal(); + if (err != 0) { + return mp_bt_esp_errno(err); + } + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + return mp_bt_status_errno(); +} + +void mp_bt_advertise_stop(void) { + esp_err_t err = esp_ble_gap_stop_advertising(); + if (err != 0) { + return; + } + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); +} + +int mp_bt_add_service(mp_bt_service_t *service, size_t num_characteristics, mp_bt_characteristic_t **characteristics) { + // In ESP-IDF, a service is more than just a service, it's an + // "application profile". One application profile contains exactly one + // service. For details, see: + // https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md + + // Register an application profile. + esp_err_t err = esp_ble_gatts_app_register(bluetooth_app_id); + if (err != 0) { + return mp_bt_esp_errno(err); + } + bluetooth_app_id++; + // Wait for ESP_GATTS_REG_EVT + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + if (mp_bt_call_status != 0) { + return mp_bt_status_errno(); + } + esp_gatt_if_t gatts_if = mp_bt_call_result.gatts_if; + + // Calculate the number of required handles. + // This formula is a guess. I can't seem to find any documentation for + // the required number of handles. + uint16_t num_handle = 1 + num_characteristics * 2; + + // Create the service. + esp_gatt_srvc_id_t bluetooth_service_id; + bluetooth_service_id.is_primary = true; + bluetooth_service_id.id.inst_id = 0; + bluetooth_service_id.id.uuid = service->uuid; + err = esp_ble_gatts_create_service(gatts_if, &bluetooth_service_id, num_handle); + if (err != 0) { + return mp_bt_esp_errno(err); + } + // Wait for ESP_GATTS_CREATE_EVT + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + if (mp_bt_call_status != 0) { + return mp_bt_status_errno(); + } + service->handle = mp_bt_call_result.service_handle; + + // Start the service. + err = esp_ble_gatts_start_service(service->handle); + if (err != 0) { + return mp_bt_esp_errno(err); + } + // Wait for ESP_GATTS_START_EVT + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + if (mp_bt_call_status != 0) { + return mp_bt_status_errno(); + } + + // Add each characteristic. + for (size_t i = 0; i < num_characteristics; i++) { + mp_bt_characteristic_t *characteristic = characteristics[i]; + + esp_gatt_perm_t perm = 0; + perm |= (characteristic->flags & MP_BLE_FLAG_READ) ? ESP_GATT_PERM_READ : 0; + perm |= (characteristic->flags & MP_BLE_FLAG_WRITE) ? ESP_GATT_PERM_WRITE : 0; + + esp_gatt_char_prop_t property = 0; + property |= (characteristic->flags & MP_BLE_FLAG_READ) ? ESP_GATT_CHAR_PROP_BIT_READ : 0; + property |= (characteristic->flags & MP_BLE_FLAG_WRITE) ? ESP_GATT_CHAR_PROP_BIT_WRITE : 0; + property |= (characteristic->flags & MP_BLE_FLAG_NOTIFY) ? ESP_GATT_CHAR_PROP_BIT_NOTIFY : 0; + + esp_attr_value_t char_val = {0}; + char_val.attr_max_len = MP_BT_MAX_ATTR_SIZE; + char_val.attr_len = 0; + char_val.attr_value = NULL; + + esp_attr_control_t control = {0}; + control.auto_rsp = ESP_GATT_AUTO_RSP; + + esp_err_t err = esp_ble_gatts_add_char(service->handle, &characteristic->uuid, perm, property, &char_val, &control); + if (err != 0) { + return mp_bt_esp_errno(err); + } + // Wait for ESP_GATTS_ADD_CHAR_EVT + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + if (mp_bt_call_status != 0) { + return mp_bt_status_errno(); + } + + // Now that the characteristic has been added successfully to the + // service, update the characteristic's service. + // Note that the caller has already ensured that + // characteristic->service is NULL. + characteristic->service = service; + characteristic->value_handle = mp_bt_call_result.attr_handle; + } + + return 0; +} + +int mp_bt_characteristic_value_set(mp_bt_characteristic_handle_t handle, const void *value, size_t value_len) { + esp_err_t err = esp_ble_gatts_set_attr_value(handle, value_len, value); + if (err != 0) { + return mp_bt_esp_errno(err); + } + // Wait for ESP_GATTS_SET_ATTR_VAL_EVT + xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); + return mp_bt_status_errno(); +} + +int mp_bt_characteristic_value_get(mp_bt_characteristic_handle_t handle, void *value, size_t *value_len) { + uint16_t bt_len; + const uint8_t *bt_ptr; + esp_err_t err = esp_ble_gatts_get_attr_value(handle, &bt_len, &bt_ptr); + if (err != 0) { + return mp_bt_esp_errno(err); + } + if (*value_len > bt_len) { + // Copy up to *value_len bytes. + *value_len = bt_len; + } + memcpy(value, bt_ptr, *value_len); + return 0; +} + +// Parse a UUID object from the caller. +void mp_bt_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { + if (MP_OBJ_IS_SMALL_INT(obj) && MP_OBJ_SMALL_INT_VALUE(obj) == (uint32_t)(uint16_t)MP_OBJ_SMALL_INT_VALUE(obj)) { + // Integer fits inside 16 bits, assume it's a standard UUID. + uuid->len = ESP_UUID_LEN_16; + uuid->uuid.uuid16 = MP_OBJ_SMALL_INT_VALUE(obj); + } else if (mp_obj_is_str(obj)) { + // Guessing this is a 128-bit (proprietary) UUID. + uuid->len = ESP_UUID_LEN_128; + mp_bt_parse_uuid_str(obj, &uuid->uuid.uuid128[0]); + } else { + mp_raise_ValueError("cannot parse UUID"); + } +} + +// Format a UUID object to be returned from a .uuid() call. +mp_obj_t mp_bt_format_uuid(mp_bt_uuid_t *uuid) { + switch (uuid->len) { + case ESP_UUID_LEN_16: + return MP_OBJ_NEW_SMALL_INT(uuid->uuid.uuid16); + case ESP_UUID_LEN_128: + return mp_bt_format_uuid_str(uuid->uuid.uuid128); + default: + return mp_const_none; + } +} + +// Event callbacks. Most API calls generate an event here to report the +// result. +STATIC void mp_bt_gap_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + switch (event) { + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + mp_bt_call_status = param->adv_start_cmpl.status; + // May return an error (queue full) when called from + // mp_bt_gatts_callback, but that's OK. + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: + break; + default: + ESP_LOGI("bluetooth", "GAP: unknown event: %d", event); + break; + } +} + +STATIC void mp_bt_gatts_callback(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_CONNECT_EVT: + break; + case ESP_GATTS_DISCONNECT_EVT: + // restart advertisement + mp_bt_advertise_start_internal(); + break; + case ESP_GATTS_REG_EVT: + // Application profile created. + mp_bt_call_status = param->reg.status; + mp_bt_call_result.gatts_if = gatts_if; + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GATTS_CREATE_EVT: + // Service created. + mp_bt_call_status = param->create.status; + mp_bt_call_result.service_handle = param->create.service_handle; + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GATTS_START_EVT: + // Service started. + mp_bt_call_status = param->start.status; + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GATTS_ADD_CHAR_EVT: + // Characteristic added. + mp_bt_call_status = param->add_char.status; + mp_bt_call_result.attr_handle = param->add_char.attr_handle; + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GATTS_SET_ATTR_VAL_EVT: + // Characteristic value set by application. + mp_bt_call_status = param->set_attr_val.status; + xSemaphoreGive(mp_bt_call_complete); + break; + case ESP_GATTS_READ_EVT: + // Characteristic value read by connected device. + break; + case ESP_GATTS_WRITE_EVT: + // Characteristic value written by connected device. + break; + default: + ESP_LOGI("bluetooth", "GATTS: unknown event: %d", event); + break; + } +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/drivers/bluetooth/ble_uart.h b/ports/esp32/bluetooth/bluetooth.h similarity index 73% rename from ports/nrf/drivers/bluetooth/ble_uart.h rename to ports/esp32/bluetooth/bluetooth.h index e67176a26feb6..fb787ca228f81 100644 --- a/ports/nrf/drivers/bluetooth/ble_uart.h +++ b/ports/esp32/bluetooth/bluetooth.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,19 +24,21 @@ * THE SOFTWARE. */ -#ifndef BLUETOOTH_LE_UART_H__ -#define BLUETOOTH_LE_UART_H__ +#pragma once -#if BLUETOOTH_SD +#include "esp_gap_ble_api.h" -#include "modubluepy.h" -#include "ble_drv.h" +typedef esp_ble_adv_type_t mp_bt_adv_type_t; -void ble_uart_init0(void); -void ble_uart_advertise(void); -bool ble_uart_connected(void); -bool ble_uart_enabled(void); +#define MP_BT_ADV_TYPE_ADV_IND ADV_TYPE_IND +#define MP_BT_ADV_TYPE_ADV_NONCONN_IND ADV_TYPE_NONCONN_IND -#endif // BLUETOOTH_SD +#define MP_BT_MAX_ATTR_SIZE (20) -#endif // BLUETOOTH_LE_UART_H__ +void mp_bt_init(void); + +typedef esp_bt_uuid_t mp_bt_uuid_t; + +typedef uint16_t mp_bt_service_handle_t; + +typedef uint16_t mp_bt_characteristic_handle_t; diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index 23fc8dead589f..4fdfe986f1b52 100644 --- a/ports/esp32/boards/sdkconfig +++ b/ports/esp32/boards/sdkconfig @@ -28,3 +28,9 @@ CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y CONFIG_PPP_SUPPORT=y CONFIG_PPP_PAP_SUPPORT=y CONFIG_PPP_CHAP_SUPPORT=y + +# Bluetooth +CONFIG_BT_ENABLED=y +CONFIG_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BT_ACL_CONNECTIONS=4 +CONFIG_GATTS_ENABLE=y diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 188fb5e70dd34..ec0cf193c6876 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -52,6 +52,7 @@ #include "modmachine.h" #include "modnetwork.h" #include "mpthreadport.h" +#include "bluetooth/bluetooth.h" // MicroPython runs as a task under FreeRTOS #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) @@ -151,6 +152,7 @@ void mp_task(void *pvParameter) { void app_main(void) { nvs_flash_init(); + mp_bt_init(); xTaskCreate(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, &mp_main_task_handle); } diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7b9b40025035a..23983f2303d00 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -177,6 +177,7 @@ extern const struct _mp_obj_module_t uos_module; extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_bluetooth; extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ @@ -187,6 +188,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_bluetooth), (mp_obj_t)&mp_module_bluetooth }, \ { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 6ca83f1e6e331..b43dc83dc4e6c 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -38,14 +38,17 @@ endif # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h -# include py core make definitions -include ../../py/py.mk - +ifneq ($(SD), ) +MICROPY_PY_BLUETOOTH ?= 1 +endif MICROPY_FATFS ?= 0 FATFS_DIR = lib/oofatfs MPY_CROSS = ../../mpy-cross/mpy-cross MPY_TOOL = ../../tools/mpy-tool.py +# include py core make definitions +include ../../py/py.mk + CROSS_COMPILE = arm-none-eabi- INC += -I. @@ -53,13 +56,10 @@ INC += -I../.. INC += -I$(BUILD) INC += -I./../../lib/cmsis/inc INC += -I./modules/machine -INC += -I./modules/ubluepy INC += -I./modules/music INC += -I./modules/random -INC += -I./modules/ble INC += -I./modules/board INC += -I../../lib/mp-readline -INC += -I./drivers/bluetooth INC += -I./drivers INC += -I../../lib/nrfx/ INC += -I../../lib/nrfx/drivers @@ -197,8 +197,7 @@ SRC_C += \ drivers/flash.c \ drivers/softpwm.c \ drivers/ticker.c \ - drivers/bluetooth/ble_drv.c \ - drivers/bluetooth/ble_uart.c \ + bluetooth/bluetooth.c \ DRIVERS_SRC_C += $(addprefix modules/,\ machine/modmachine.c \ @@ -216,19 +215,8 @@ DRIVERS_SRC_C += $(addprefix modules/,\ utime/modutime.c \ board/modboard.c \ board/led.c \ - ubluepy/modubluepy.c \ - ubluepy/ubluepy_peripheral.c \ - ubluepy/ubluepy_service.c \ - ubluepy/ubluepy_characteristic.c \ - ubluepy/ubluepy_uuid.c \ - ubluepy/ubluepy_delegate.c \ - ubluepy/ubluepy_constants.c \ - ubluepy/ubluepy_descriptor.c \ - ubluepy/ubluepy_scanner.c \ - ubluepy/ubluepy_scan_entry.c \ music/modmusic.c \ music/musictunes.c \ - ble/modble.c \ random/modrandom.c \ ) diff --git a/ports/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c new file mode 100644 index 0000000000000..fdba6ea7ab342 --- /dev/null +++ b/ports/nrf/bluetooth/bluetooth.c @@ -0,0 +1,445 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 - 2018 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem + * + * 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. + */ + +#if MICROPY_PY_BLUETOOTH + +#include +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/modbluetooth.h" +#include "drivers/flash.h" + +#include "nrf_sdm.h" +#include "ble.h" +#if !NRF51 +#include "nrf_nvic.h" +#endif + +#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(12, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS) +#define BLE_SLAVE_LATENCY 0 +#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) + +#if NRF51 + #define MAX_TX_IN_PROGRESS (6) +#else + #define MAX_TX_IN_PROGRESS (10) +#endif +#if !defined(GATT_MTU_SIZE_DEFAULT) && defined(BLE_GATT_ATT_MTU_DEFAULT) + #define GATT_MTU_SIZE_DEFAULT BLE_GATT_ATT_MTU_DEFAULT +#endif + +#if NRF51 +STATIC mp_bt_adv_type_t bluetooth_adv_type; +STATIC uint16_t bluetooth_adv_interval; +#else +#include "nrf_nvic.h" +nrf_nvic_state_t nrf_nvic_state = {0}; +static uint8_t bluetooth_adv_handle; +static uint8_t bluetooth_adv_data[31]; +static uint8_t bluetooth_sr_data[31]; +#endif + +#if NRF51 +void softdevice_assert_handler(uint32_t pc, uint16_t line_number, const uint8_t * p_file_name) { + printf("ERROR: SoftDevice assert!!!\n"); +} +#else +void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { + printf("ERROR: SoftDevice assert!!!\n"); +} +#endif + +#if !NRF51 +#if BLUETOOTH_LFCLK_RC +STATIC const nrf_clock_lf_cfg_t clock_config = { + .source = NRF_CLOCK_LF_SRC_RC, + .rc_ctiv = 16, + .rc_temp_ctiv = 2, + .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM +}; +#else +STATIC const nrf_clock_lf_cfg_t clock_config = { + .source = NRF_CLOCK_LF_SRC_XTAL, + .rc_ctiv = 0, + .rc_temp_ctiv = 0, + .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM +}; +#endif // BLUETOOTH_LFCLK_RC +#endif // !NRF51 + +STATIC const uint8_t ble_default_device_name[] = "MPY"; + +// Connection params for sd_ble_gap_ppcp_set. +STATIC const ble_gap_conn_params_t gap_conn_params = { + .min_conn_interval = BLE_MIN_CONN_INTERVAL, + .max_conn_interval = BLE_MAX_CONN_INTERVAL, + .slave_latency = BLE_SLAVE_LATENCY, + .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, +}; + +STATIC int mp_bt_errno(uint32_t err_code) { + switch (err_code) { + case 0: + return 0; // no error + case NRF_ERROR_INVALID_PARAM: + return MP_EINVAL; + case NRF_ERROR_NO_MEM: + return MP_ENOMEM; + case NRF_ERROR_INVALID_ADDR: + return MP_EFAULT; // bad address + case NRF_ERROR_NOT_FOUND: + return MP_ENOENT; + case NRF_ERROR_DATA_SIZE: + return MP_E2BIG; + case NRF_ERROR_FORBIDDEN: + return MP_EACCES; + default: + return MP_EPERM; // catch-all + } +} + +int mp_bt_enable(void) { + if (mp_bt_is_enabled()) { + return 0; + } + + // initialize our state +#if !NRF51 + bluetooth_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; +#endif + +#if NRF51 + #if BLUETOOTH_LFCLK_RC + uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION, + softdevice_assert_handler); + #else + uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, + softdevice_assert_handler); + #endif // BLUETOOTH_LFCLK_RC + +#else // NRF52xxx + uint32_t err_code = sd_softdevice_enable(&clock_config, + softdevice_assert_handler); +#endif + + if (err_code != 0) { // sd_softdevice_enable + return mp_bt_errno(err_code); + } + + sd_nvic_EnableIRQ(SD_EVT_IRQn); + +#if NRF51 + ble_enable_params_t ble_enable_params = {0}; + ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT; + ble_enable_params.gatts_enable_params.service_changed = 0; + err_code = sd_ble_enable(&ble_enable_params); +#else + uint32_t app_ram_start_cfg = 0x200039c0; + err_code = sd_ble_enable(&app_ram_start_cfg); // 8K SD headroom from linker script. +#endif + if (err_code != 0) { // sd_ble_enable + return mp_bt_errno(err_code); + } + + // set up security mode + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + if ((err_code = sd_ble_gap_device_name_set(&sec_mode, + ble_default_device_name, + sizeof(ble_default_device_name) - 1)) != 0) { + return mp_bt_errno(err_code); + } + + if ((err_code = sd_ble_gap_ppcp_set(&gap_conn_params)) != 0) { + return mp_bt_errno(err_code); + } + + return 0; // success +} + +void mp_bt_disable(void) { + sd_softdevice_disable(); +} + +bool mp_bt_is_enabled(void) { + uint8_t is_enabled; + sd_softdevice_is_enabled(&is_enabled); + return is_enabled != 0; +} + +#if NRF51 +STATIC uint32_t mp_bt_advertise_start_internal(void) { + ble_gap_adv_params_t adv_params; + adv_params.type = bluetooth_adv_type; + adv_params.p_peer_addr = NULL; + adv_params.fp = BLE_GAP_ADV_FP_ANY; // no filter policy + adv_params.interval = bluetooth_adv_interval; + return sd_ble_gap_adv_start(&adv_params); +} +#endif + +int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) { + uint32_t err_code = 0; + mp_bt_advertise_stop(); // restart if already started + +#if NRF51 + sd_ble_gap_adv_data_set(adv_data, adv_data_len, sr_data, sr_data_len); + bluetooth_adv_type = type; + bluetooth_adv_interval = interval; + err_code = mp_bt_advertise_start_internal(); + return mp_bt_errno(err_code); + +#elif NRF52 + if (adv_data_len) { + memcpy(bluetooth_adv_data, adv_data, adv_data_len); + } + if (sr_data_len) { + memcpy(bluetooth_sr_data, sr_data, sr_data_len); + } + + ble_gap_adv_data_t ble_adv_data = {0}; + ble_adv_data.adv_data.p_data = bluetooth_adv_data; + ble_adv_data.adv_data.len = adv_data_len; + ble_adv_data.scan_rsp_data.p_data = bluetooth_sr_data; + ble_adv_data.scan_rsp_data.len = sr_data_len; + + ble_gap_adv_params_t adv_params = {0}; + adv_params.properties.type = type; + adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; // no filter policy + adv_params.interval = interval; + adv_params.max_adv_evts = 0; // infinite advertisment + adv_params.primary_phy = BLE_GAP_PHY_AUTO; + adv_params.secondary_phy = BLE_GAP_PHY_AUTO; + adv_params.scan_req_notification = 0; // Do not raise scan request notifications when scanned. + + uint32_t err_code = sd_ble_gap_adv_set_configure(&bluetooth_adv_handle, &ble_adv_data, &adv_params); + if (err_code != 0) { + return mp_bt_errno(err_code); + } + + err_code = sd_ble_gap_adv_start(bluetooth_adv_handle, BLE_CONN_CFG_TAG_DEFAULT); +#else + (void)bluetooth_sr_data; + (void)bluetooth_adv_data; +#endif + return mp_bt_errno(err_code); +} + +void mp_bt_advertise_stop(void) { +#if NRF51 + sd_ble_gap_adv_stop(); +#else + sd_ble_gap_adv_stop(bluetooth_adv_handle); +#endif +} + +static void ble_evt_handler(ble_evt_t * p_ble_evt) { + switch (p_ble_evt->header.evt_id) { + case BLE_GAP_EVT_DISCONNECTED: +#if NRF51 + mp_bt_advertise_start_internal(); +#else + sd_ble_gap_adv_start(bluetooth_adv_handle, BLE_CONN_CFG_TAG_DEFAULT); +#endif + break; + +#if NRF52 + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, GATT_MTU_SIZE_DEFAULT); + break; +#endif + } +} + +int mp_bt_add_service(mp_bt_service_t *service, size_t num_characteristics, mp_bt_characteristic_t **characteristics) { + uint32_t err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service->uuid, &service->handle); + if (err_code != 0) { + return mp_bt_errno(err_code); + } + + // Add each characteristic. + for (size_t i = 0; i < num_characteristics; i++) { + mp_bt_characteristic_t *characteristic = characteristics[i]; + + // Create characteristic metadata. + ble_gatts_char_md_t char_md = {0}; + char_md.char_props.read = (characteristic->flags & MP_BLE_FLAG_READ) ? 1 : 0; + char_md.char_props.write = (characteristic->flags & MP_BLE_FLAG_WRITE) ? 1 : 0; + char_md.char_props.notify = (characteristic->flags & MP_BLE_FLAG_NOTIFY) ? 1 : 0; + + // Create attribute metadata. + ble_gatts_attr_md_t attr_md = {0}; + attr_md.vlen = 1; + attr_md.vloc = BLE_GATTS_VLOC_STACK; + attr_md.rd_auth = 0; + attr_md.wr_auth = 0; + if (characteristic->flags & MP_BLE_FLAG_READ) { + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + } + if (characteristic->flags & MP_BLE_FLAG_WRITE) { + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + } + + // Create characteristic value. + ble_gatts_attr_t attr_char_value = {0}; + attr_char_value.p_uuid = &characteristic->uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = 0; + attr_char_value.init_offs = 0; + attr_char_value.max_len = MP_BT_MAX_ATTR_SIZE; + attr_char_value.p_value = NULL; + + // Output handles. + ble_gatts_char_handles_t handles; + + // BLE_GATT_HANDLE_INVALID: add to previously added service. + uint32_t err_code = sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID, &char_md, &attr_char_value, &handles); + if (err_code != 0) { + return mp_bt_errno(err_code); + } + + // Now that the characteristic has been added successfully to the + // service, update the characteristic's service. + // Note that the caller has already ensured that + // characteristic->service is NULL. + characteristic->service = service; + characteristic->value_handle = handles.value_handle; + } + + return 0; +} + +int mp_bt_characteristic_value_set(mp_bt_characteristic_handle_t handle, const void *value, size_t value_len) { + ble_gatts_value_t data = {0}; + data.len = value_len; + data.offset = 0; + data.p_value = (void*)value; // value is only read so we can discard const + uint32_t err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID, handle, &data); + return mp_bt_errno(err_code); +} + +int mp_bt_characteristic_value_get(mp_bt_characteristic_handle_t handle, void *value, size_t *value_len) { + ble_gatts_value_t data = {0}; + data.len = *value_len; + data.offset = 0; + data.p_value = value; + uint32_t err_code = sd_ble_gatts_value_get(BLE_CONN_HANDLE_INVALID, handle, &data); + *value_len = data.len; + return mp_bt_errno(err_code); +} + +// Parse a UUID object from the caller. +void mp_bt_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { + if (MP_OBJ_IS_SMALL_INT(obj) && MP_OBJ_SMALL_INT_VALUE(obj) == (uint32_t)(uint16_t)MP_OBJ_SMALL_INT_VALUE(obj)) { + // Integer fits inside 16 bits. + uuid->type = BLE_UUID_TYPE_BLE; + uuid->uuid = MP_OBJ_SMALL_INT_VALUE(obj); + } else if (mp_obj_is_str(obj)) { + // Guessing this is a 128-bit (proprietary) UUID. + ble_uuid128_t buf; + mp_bt_parse_uuid_str(obj, &buf.uuid128[0]); + uint32_t err_code = sd_ble_uuid_vs_add(&buf, &uuid->type); + if (err_code != 0) { + mp_raise_OSError(mp_bt_errno(err_code)); + } + uuid->uuid = (uint16_t)(buf.uuid128[12]) | ((uint16_t)(buf.uuid128[13]) << 8); + } else { + mp_raise_ValueError("cannot parse UUID"); + } +} + +mp_obj_t mp_bt_format_uuid(mp_bt_uuid_t *uuid) { + uint8_t raw[16]; + uint8_t raw_len; + if (sd_ble_uuid_encode(uuid, &raw_len, raw) != 0) { + return mp_const_none; + } + switch (raw_len) { + case 2: + return MP_OBJ_NEW_SMALL_INT((int)(raw[0]) | ((int)(raw[1]) << 8)); + case 16: + return mp_bt_format_uuid_str(raw); + default: + return mp_const_none; + } +} + +static void sd_evt_handler(uint32_t evt_id) { + switch (evt_id) { +#if MICROPY_MBFS + case NRF_EVT_FLASH_OPERATION_SUCCESS: + flash_operation_finished(FLASH_STATE_SUCCESS); + break; + case NRF_EVT_FLASH_OPERATION_ERROR: + flash_operation_finished(FLASH_STATE_ERROR); + break; +#endif + default: + // unhandled event! + break; + } +} + +static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attribute__ ((aligned (4))); + +#ifdef NRF51 +void SWI2_IRQHandler(void) { +#else +void SWI2_EGU2_IRQHandler(void) { +#endif + + uint32_t evt_id; + while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) { + sd_evt_handler(evt_id); + } + + while (1) { + uint16_t evt_len = sizeof(m_ble_evt_buf); + uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len); + if (err_code != NRF_SUCCESS) { + // Possible error conditions: + // * NRF_ERROR_NOT_FOUND: no events left, break + // * NRF_ERROR_DATA_SIZE: retry with a bigger data buffer + // (currently not handled, TODO) + // * NRF_ERROR_INVALID_ADDR: pointer is not aligned, should + // not happen. + // In all cases, it's best to simply stop now. + break; + } + ble_evt_handler((ble_evt_t *)m_ble_evt_buf); + } +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/modules/ble/help_sd.h b/ports/nrf/bluetooth/bluetooth.h similarity index 59% rename from ports/nrf/modules/ble/help_sd.h rename to ports/nrf/bluetooth/bluetooth.h index 027bbdd513489..9ed705f5c2e6f 100644 --- a/ports/nrf/modules/ble/help_sd.h +++ b/ports/nrf/bluetooth/bluetooth.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,24 +24,33 @@ * THE SOFTWARE. */ -#ifndef HELP_SD_H__ -#define HELP_SD_H__ +#pragma once -#include "bluetooth_conf.h" +#if MICROPY_PY_BLUETOOTH -#if MICROPY_PY_BLE +#include -#define HELP_TEXT_SD \ -"If compiled with SD= the additional commands are\n" \ -"available:\n" \ -" ble.enable() -- enable bluetooth stack\n" \ -" ble.disable() -- disable bluetooth stack\n" \ -" ble.enabled() -- check whether bluetooth stack is enabled\n" \ -" ble.address() -- return device address as text string\n" \ -"\n" - -#else -#define HELP_TEXT_SD -#endif // MICROPY_PY_BLE +#include "ble_gap.h" +#include "ble_gatt.h" + +typedef uint8_t mp_bt_adv_type_t; +#if NRF51 +#define MP_BT_ADV_TYPE_ADV_IND BLE_GAP_ADV_TYPE_ADV_IND +#define MP_BT_ADV_TYPE_ADV_DIRECT_IND BLE_GAP_ADV_TYPE_ADV_DIRECT_IND +#define MP_BT_ADV_TYPE_ADV_SCAN_IND BLE_GAP_ADV_TYPE_ADV_SCAN_IND +#define MP_BT_ADV_TYPE_ADV_NONCONN_IND BLE_GAP_ADV_TYPE_ADV_NONCONN_IND +#else +#define MP_BT_ADV_TYPE_ADV_IND BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED +#define MP_BT_ADV_TYPE_ADV_NONCONN_IND BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED #endif + +#define MP_BT_MAX_ATTR_SIZE (20) + +typedef ble_uuid_t mp_bt_uuid_t; + +typedef uint16_t mp_bt_service_handle_t; + +typedef uint16_t mp_bt_characteristic_handle_t; + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/bluetooth_conf.h b/ports/nrf/bluetooth_conf.h deleted file mode 100644 index 58d47e2188686..0000000000000 --- a/ports/nrf/bluetooth_conf.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef BLUETOOTH_CONF_H__ -#define BLUETOOTH_CONF_H__ - -// SD specific configurations. - -#if (BLUETOOTH_SD == 110) - -#define MICROPY_PY_BLE (1) -#define MICROPY_PY_BLE_NUS (0) -#define BLUETOOTH_WEBBLUETOOTH_REPL (0) -#define MICROPY_PY_UBLUEPY (1) -#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) - -#elif (BLUETOOTH_SD == 132) - -#define MICROPY_PY_BLE (1) -#define MICROPY_PY_BLE_NUS (0) -#define BLUETOOTH_WEBBLUETOOTH_REPL (0) -#define MICROPY_PY_UBLUEPY (1) -#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) -#define MICROPY_PY_UBLUEPY_CENTRAL (1) - -#elif (BLUETOOTH_SD == 140) - -#define MICROPY_PY_BLE (1) -#define MICROPY_PY_BLE_NUS (0) -#define BLUETOOTH_WEBBLUETOOTH_REPL (0) -#define MICROPY_PY_UBLUEPY (1) -#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) -#define MICROPY_PY_UBLUEPY_CENTRAL (1) - -#else -#error "SD not supported" -#endif - -// Default defines. - -#ifndef MICROPY_PY_BLE -#define MICROPY_PY_BLE (0) -#endif - -#ifndef MICROPY_PY_BLE_NUS -#define MICROPY_PY_BLE_NUS (0) -#endif - -#endif diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c deleted file mode 100644 index ff3c885c153f5..0000000000000 --- a/ports/nrf/drivers/bluetooth/ble_drv.c +++ /dev/null @@ -1,1181 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 - 2018 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. - */ - -#if BLUETOOTH_SD - -#include -#include -#include - -#include "py/runtime.h" -#include "ble_drv.h" -#include "mpconfigport.h" -#include "nrf_sdm.h" -#include "ble_gap.h" -#include "ble.h" // sd_ble_uuid_encode -#include "drivers/flash.h" -#include "mphalport.h" - - -#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 -#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 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_SLAVE_LATENCY 0 -#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) - -#if (BLUETOOTH_SD == 110) - #define MAX_TX_IN_PROGRESS (6) -#else - #define MAX_TX_IN_PROGRESS (10) -#endif -#if !defined(GATT_MTU_SIZE_DEFAULT) && defined(BLE_GATT_ATT_MTU_DEFAULT) - #define GATT_MTU_SIZE_DEFAULT BLE_GATT_ATT_MTU_DEFAULT -#endif - -#define SD_TEST_OR_ENABLE() \ -if (ble_drv_stack_enabled() == 0) { \ - (void)ble_drv_stack_enable(); \ -} - -static volatile bool m_adv_in_progress; -static volatile uint8_t 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; - -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) -static volatile bool m_primary_service_found; -static volatile bool m_characteristic_found; -static volatile bool m_write_done; - -static volatile ble_drv_adv_evt_callback_t adv_event_handler; -static volatile ble_drv_gattc_evt_callback_t gattc_event_handler; -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 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; -#endif - -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) -#include "nrf_nvic.h" -#define BLE_GAP_ADV_MAX_SIZE 31 -#define BLE_DRV_CONN_CONFIG_TAG 1 - -static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; -static uint8_t m_scan_buffer[BLE_GAP_SCAN_BUFFER_MIN]; - -nrf_nvic_state_t nrf_nvic_state = {0}; -#endif - -#if (BLUETOOTH_SD == 110) -void softdevice_assert_handler(uint32_t pc, uint16_t line_number, const uint8_t * p_file_name) { - BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!"); -} -#else -void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { - BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!"); -} -#endif - -uint32_t ble_drv_stack_enable(void) { - m_adv_in_progress = false; - m_tx_in_progress = 0; - -#if (BLUETOOTH_SD == 110) - #if BLUETOOTH_LFCLK_RC - uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION, - softdevice_assert_handler); - #else - uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, - softdevice_assert_handler); - #endif // BLUETOOTH_LFCLK_RC -#endif // (BLUETOOTH_SD == 110) - -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - #if BLUETOOTH_LFCLK_RC - nrf_clock_lf_cfg_t clock_config = { - .source = NRF_CLOCK_LF_SRC_RC, - .rc_ctiv = 16, - .rc_temp_ctiv = 2, - .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM - }; - #else - nrf_clock_lf_cfg_t clock_config = { - .source = NRF_CLOCK_LF_SRC_XTAL, - .rc_ctiv = 0, - .rc_temp_ctiv = 0, - .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM - }; - #endif // BLUETOOTH_LFCLK_RC - - uint32_t err_code = sd_softdevice_enable(&clock_config, - softdevice_assert_handler); -#endif // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - - BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code); - - err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); - - BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code); - -#if (BLUETOOTH_SD == 110) - 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; -#else - ble_cfg_t ble_conf; - uint32_t app_ram_start_cfg = 0x200039c0; - ble_conf.conn_cfg.conn_cfg_tag = BLE_DRV_CONN_CONFIG_TAG; - ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = 2; - ble_conf.conn_cfg.params.gap_conn_cfg.event_length = 3; - err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start_cfg); - - BLE_DRIVER_LOG("BLE_CONN_CFG_GAP status: " UINT_FMT "\n", (uint16_t)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; - ble_conf.gap_cfg.role_count_cfg.central_sec_count = 0; - err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start_cfg); - - BLE_DRIVER_LOG("BLE_GAP_CFG_ROLE_COUNT status: " UINT_FMT "\n", (uint16_t)err_code); - - memset(&ble_conf, 0, sizeof(ble_conf)); - ble_conf.conn_cfg.conn_cfg_tag = BLE_DRV_CONN_CONFIG_TAG; - 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_cfg); - - BLE_DRIVER_LOG("BLE_CONN_CFG_GATTS status: " UINT_FMT "\n", (uint16_t)err_code); -#endif - -#if (BLUETOOTH_SD == 110) - err_code = sd_ble_enable(&ble_enable_params); -#else - uint32_t app_ram_start = 0x200039c0; - err_code = sd_ble_enable(&app_ram_start); // 8K SD headroom from linker script. - 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, - "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, - "Cannot set PPCP parameters.")); - } - - return err_code; -} - -void ble_drv_stack_disable(void) { - sd_softdevice_disable(); -} - -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); - - return is_enabled; -} - -void ble_drv_address_get(ble_drv_addr_t * p_addr) { - SD_TEST_OR_ENABLE(); - - ble_gap_addr_t local_ble_addr; -#if (BLUETOOTH_SD == 110) - 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, - "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]); - - p_addr->addr_type = local_ble_addr.addr_type; - memcpy(p_addr->addr, local_ble_addr.addr, 6); -} - -bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) { - SD_TEST_OR_ENABLE(); - - if (sd_ble_uuid_vs_add((ble_uuid128_t const *)p_uuid, idx) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not add Vendor Specific 128-bit UUID.")); - } - - return true; -} - -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 = 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, - "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, - "Can not add Service.")); - } - } - return true; -} - -bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { - 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 = (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.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) { - 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 = 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; - - 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; - attr_char_value.max_len = (GATT_MTU_SIZE_DEFAULT - 3); - - ble_gatts_char_handles_t handles; - - if (sd_ble_gatts_characteristic_add(p_char_obj->service_handle, - &char_md, - &attr_char_value, - &handles) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not add Characteristic.")); - } - - // 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; - - return true; -} - -bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { - SD_TEST_OR_ENABLE(); - - uint8_t byte_pos = 0; - - static 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; - - 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) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "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); - byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; - 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; - } - - // Add FLAGS only if manually controlled data has not been used. - if (p_adv_params->data_len == 0) { - // set flags, default to disc mode - 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) { - - bool type_16bit_present = false; - 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 == UBLUEPY_UUID_16_BIT) { - type_16bit_present = true; - } - - if (p_service->p_uuid->type == UBLUEPY_UUID_128_BIT) { - 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; - - adv_data[byte_pos] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE; - byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; - - uint8_t uuid_total_size = 0; - 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]; - - 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; - // 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, - "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, - "Can encode UUID into the advertisment 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); - } - - 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 (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]; - - 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; - - // 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, - "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, - "Can encode UUID into the advertisment 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) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not fit data into the advertisment packet.")); - } - - memcpy(adv_data, p_adv_params->p_data, p_adv_params->data_len); - byte_pos += p_adv_params->data_len; - } - - // scan response data not set - uint32_t err_code; -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - const ble_gap_adv_data_t m_adv_data = { - .adv_data.p_data = adv_data, - .adv_data.len = byte_pos, - .scan_rsp_data.p_data = NULL, - .scan_rsp_data.len = 0 - }; -#endif - - static ble_gap_adv_params_t m_adv_params; - memset(&m_adv_params, 0, sizeof(m_adv_params)); - - // initialize advertising params - if (p_adv_params->connectable) { -#if (BLUETOOTH_SD == 110) - m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; -#else - m_adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; -#endif - } else { -#if (BLUETOOTH_SD == 110) - m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; -#else - m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED; -#endif - } - -#if (BLUETOOTH_SD == 110) - m_adv_params.fp = BLE_GAP_ADV_FP_ANY; - m_adv_params.timeout = 0; // infinite advertisment -#else - m_adv_params.properties.anonymous = 0; - m_adv_params.properties.include_tx_power = 0; - m_adv_params.filter_policy = 0; - m_adv_params.max_adv_evts = 0; // infinite advertisment - m_adv_params.primary_phy = BLE_GAP_PHY_AUTO; - m_adv_params.secondary_phy = BLE_GAP_PHY_AUTO; - m_adv_params.scan_req_notification = 0; // Do not raise scan request notifications when scanned. -#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 == 110) - 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, - "Can not apply advertisment data. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -#else - if ((err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not apply advertisment data. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -#endif - BLE_DRIVER_LOG("Set Adv data size: " UINT_FMT "\n", byte_pos); - - ble_drv_advertise_stop(); - -#if (BLUETOOTH_SD == 110) - err_code = sd_ble_gap_adv_start(&m_adv_params); -#else - uint8_t conf_tag = BLE_DRV_CONN_CONFIG_TAG; // Could also be set to tag from sd_ble_cfg_set - err_code = sd_ble_gap_adv_start(m_adv_handle, conf_tag); -#endif - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not start advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - - m_adv_in_progress = true; - - return true; -} - -void ble_drv_advertise_stop(void) { - if (m_adv_in_progress == true) { - uint32_t err_code; - -#if (BLUETOOTH_SD == 110) - if ((err_code = sd_ble_gap_adv_stop()) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not stop advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -#else - if ((err_code = sd_ble_gap_adv_stop(m_adv_handle)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not stop advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -#endif - } - m_adv_in_progress = false; -} - -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, - "Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - -} - -void ble_drv_attr_s_write(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_set(conn_handle, handle, &gatts_value); - - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -} - -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; - ble_gatts_hvx_params_t hvx_params; - - memset(&hvx_params, 0, sizeof(hvx_params)); - - hvx_params.handle = handle; - hvx_params.type = BLE_GATT_HVX_NOTIFICATION; - hvx_params.offset = 0; - hvx_params.p_len = &hvx_len; - hvx_params.p_data = p_data; - - while (m_tx_in_progress > MAX_TX_IN_PROGRESS) { - ; - } - - BLE_DRIVER_LOG("Request TX, m_tx_in_progress: %u\n", m_tx_in_progress); - 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, - "Can not notify attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - m_tx_in_progress++; - BLE_DRIVER_LOG("Queued TX, m_tx_in_progress: %u\n", m_tx_in_progress); -} - -void ble_drv_gap_event_handler_set(mp_obj_t obj, ble_drv_gap_evt_callback_t evt_handler) { - mp_gap_observer = obj; - 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; - gatts_event_handler = evt_handler; -} - -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - -void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler) { - mp_gattc_observer = obj; - 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; - adv_event_handler = evt_handler; -} - - -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; - gattc_char_data_handle = cb; - - uint32_t err_code = sd_ble_gattc_read(conn_handle, - handle, - 0); - if (err_code != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - - while (gattc_char_data_handle != NULL) { - ; - } -} - -void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response) { - - ble_gattc_write_params_t write_params; - - if (w_response) { - write_params.write_op = BLE_GATT_OP_WRITE_REQ; - } else { - 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.offset = 0; - write_params.len = len; - write_params.p_value = p_data; - - m_write_done = !w_response; - - 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, - "Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } - - while (m_write_done != true) { - ; - } -} - -void ble_drv_scan_start(bool cont) { - SD_TEST_OR_ENABLE(); - - ble_gap_scan_params_t scan_params; - memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); - scan_params.extended = 0; - 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_data_t scan_buffer = { - .p_data = m_scan_buffer, - .len = BLE_GAP_SCAN_BUFFER_MIN - }; - - uint32_t err_code; - ble_gap_scan_params_t * p_scan_params = &scan_params; - if (cont) { - p_scan_params = NULL; - } - if ((err_code = sd_ble_gap_scan_start(p_scan_params, &scan_buffer)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not start scanning. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -} - -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(); - - ble_gap_scan_params_t scan_params; - memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); - scan_params.extended = 0; - 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_addr_t addr; - memset(&addr, 0, sizeof(addr)); - - addr.addr_type = addr_type; - memcpy(addr.addr, p_addr, 6); - - 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); - - ble_gap_conn_params_t conn_params; - - // set connection parameters - memset(&conn_params, 0, sizeof(conn_params)); - - 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; - - uint8_t conn_tag = BLE_DRV_CONN_CONFIG_TAG; - - uint32_t err_code; - if ((err_code = sd_ble_gap_connect(&addr, - &scan_params, - &conn_params, - conn_tag)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, - "Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code)); - } -} - -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); - - mp_gattc_disc_service_observer = obj; - 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); - if (err_code != 0) { - return false; - } - - // busy loop until last service has been iterated - while (disc_add_service_handler != NULL) { - ; - } - - if (m_primary_service_found) { - return true; - } else { - return false; - } -} - -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); - - mp_gattc_disc_char_observer = obj; - disc_add_char_handler = cb; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_characteristic_found = false; - - uint32_t err_code; - err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); - if (err_code != 0) { - return false; - } - - // busy loop until last service has been iterated - while (disc_add_char_handler != NULL) { - ; - } - - if (m_characteristic_found) { - return true; - } else { - return false; - } -} - -void ble_drv_discover_descriptors(void) { - -} - -#endif // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - -static void sd_evt_handler(uint32_t evt_id) { - switch (evt_id) { -#if MICROPY_MBFS - case NRF_EVT_FLASH_OPERATION_SUCCESS: - flash_operation_finished(FLASH_STATE_SUCCESS); - break; - case NRF_EVT_FLASH_OPERATION_ERROR: - flash_operation_finished(FLASH_STATE_ERROR); - break; -#endif - default: - // unhandled event! - break; - } -} - -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 - switch (p_ble_evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: - BLE_DRIVER_LOG("GAP CONNECT\n"); - m_adv_in_progress = false; - 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 (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - case BLE_GATTS_EVT_HVN_TX_COMPLETE: -#else - case BLE_EVT_TX_COMPLETE: -#endif - BLE_DRIVER_LOG("BLE EVT TX COMPLETE\n"); -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - BLE_DRIVER_LOG("HVN_TX_COMPLETE, count: %u\n", p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count); - m_tx_in_progress -= p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count; - BLE_DRIVER_LOG("TX_COMPLETE, m_tx_in_progress: %u\n", m_tx_in_progress); -#else - BLE_DRIVER_LOG("TX_COMPLETE, count: %u\n", p_ble_evt->evt.common_evt.params.tx_complete.count); - m_tx_in_progress -= p_ble_evt->evt.common_evt.params.tx_complete.count; - BLE_DRIVER_LOG("TX_COMPLETE, m_tx_in_progress: %u\n", m_tx_in_progress); -#endif - 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; - -#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - case BLE_GAP_EVT_ADV_REPORT: - BLE_DRIVER_LOG("BLE EVT ADV REPORT\n"); - ble_drv_adv_data_t adv_data = { - .p_peer_addr = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr, - .addr_type = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr_type, - .is_scan_resp = p_ble_evt->evt.gap_evt.params.adv_report.type.scan_response, - .rssi = p_ble_evt->evt.gap_evt.params.adv_report.rssi, - .data_len = p_ble_evt->evt.gap_evt.params.adv_report.data.len, - .p_data = p_ble_evt->evt.gap_evt.params.adv_report.data.p_data, -// .adv_type = - }; - // TODO: Fix unsafe callback to possible undefined callback... - adv_event_handler(mp_adv_observer, - p_ble_evt->header.evt_id, - &adv_data); - 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: - BLE_DRIVER_LOG("BLE EVT PRIMARY SERVICE DISCOVERY RESPONSE\n"); - BLE_DRIVER_LOG(">>> service count: %d\n", p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count); - - for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count; i++) { - ble_gattc_service_t * p_service = &p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i]; - - ble_drv_service_data_t service; - service.uuid_type = p_service->uuid.type; - service.uuid = p_service->uuid.uuid; - service.start_handle = p_service->handle_range.start_handle; - service.end_handle = p_service->handle_range.end_handle; - - disc_add_service_handler(mp_gattc_disc_service_observer, &service); - } - - if (p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count > 0) { - m_primary_service_found = true; - } - - // mark end of service discovery - disc_add_service_handler = NULL; - - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - BLE_DRIVER_LOG("BLE EVT CHAR DISCOVERY RESPONSE\n"); - BLE_DRIVER_LOG(">>> characteristic count: %d\n", p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count); - - for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count; i++) { - ble_gattc_char_t * p_char = &p_ble_evt->evt.gattc_evt.params.char_disc_rsp.chars[i]; - - ble_drv_char_data_t char_data; - char_data.uuid_type = p_char->uuid.type; - char_data.uuid = p_char->uuid.uuid; - 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 - - disc_add_char_handler(mp_gattc_disc_char_observer, &char_data); - } - - if (p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count > 0) { - m_characteristic_found = true; - } - - // mark end of characteristic discovery - disc_add_char_handler = NULL; - - break; - - case BLE_GATTC_EVT_READ_RSP: - BLE_DRIVER_LOG("BLE EVT READ RESPONSE, offset: 0x"HEX2_FMT", length: 0x"HEX2_FMT"\n", - p_ble_evt->evt.gattc_evt.params.read_rsp.offset, - p_ble_evt->evt.gattc_evt.params.read_rsp.len); - - gattc_char_data_handle(mp_gattc_char_data_observer, - p_ble_evt->evt.gattc_evt.params.read_rsp.len, - p_ble_evt->evt.gattc_evt.params.read_rsp.data); - - // mark end of read - gattc_char_data_handle = NULL; - - break; - - case BLE_GATTC_EVT_WRITE_RSP: - BLE_DRIVER_LOG("BLE EVT WRITE RESPONSE\n"); - m_write_done = true; - break; - - case BLE_GATTC_EVT_HVX: - BLE_DRIVER_LOG("BLE EVT HVX RESPONSE\n"); - break; - - 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 // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) - - default: - BLE_DRIVER_LOG(">>> unhandled evt: 0x" HEX2_FMT "\n", p_ble_evt->header.evt_id); - break; - } -} - -static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attribute__ ((aligned (4))); - -#ifdef NRF51 -void SWI2_IRQHandler(void) { -#else -void SWI2_EGU2_IRQHandler(void) { -#endif - - uint32_t evt_id; - while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) { - sd_evt_handler(evt_id); - } - - while (1) { - uint16_t evt_len = sizeof(m_ble_evt_buf); - uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len); - if (err_code != NRF_SUCCESS) { - // Possible error conditions: - // * NRF_ERROR_NOT_FOUND: no events left, break - // * NRF_ERROR_DATA_SIZE: retry with a bigger data buffer - // (currently not handled, TODO) - // * NRF_ERROR_INVALID_ADDR: pointer is not aligned, should - // not happen. - // In all cases, it's best to simply stop now. - if (err_code == NRF_ERROR_DATA_SIZE) { - BLE_DRIVER_LOG("NRF_ERROR_DATA_SIZE\n"); - } - break; - } - ble_evt_handler((ble_evt_t *)m_ble_evt_buf); - } -} - -#endif // BLUETOOTH_SD diff --git a/ports/nrf/drivers/bluetooth/ble_drv.h b/ports/nrf/drivers/bluetooth/ble_drv.h deleted file mode 100644 index ac68959375ce6..0000000000000 --- a/ports/nrf/drivers/bluetooth/ble_drv.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 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 BLUETOOTH_LE_DRIVER_H__ -#define BLUETOOTH_LE_DRIVER_H__ - -#if BLUETOOTH_SD - -#include -#include - -#include "modubluepy.h" - -typedef struct { - uint8_t addr[6]; - uint8_t addr_type; -} ble_drv_addr_t; - -typedef struct { - uint8_t * p_peer_addr; - uint8_t addr_type; - bool is_scan_resp; - int8_t rssi; - uint8_t data_len; - uint8_t * p_data; - uint8_t adv_type; -} ble_drv_adv_data_t; - -typedef struct { - uint16_t uuid; - uint8_t uuid_type; - uint16_t start_handle; - uint16_t end_handle; -} ble_drv_service_data_t; - -typedef struct { - uint16_t uuid; - uint8_t uuid_type; - uint8_t props; - uint16_t decl_handle; - 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)(mp_obj_t self, uint16_t event_id, 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); - -uint32_t ble_drv_stack_enable(void); - -void ble_drv_stack_disable(void); - -uint8_t ble_drv_stack_enabled(void); - -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); - -bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj); - -bool ble_drv_advertise_data(ubluepy_advertise_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_gatts_event_handler_set(mp_obj_t obj, 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_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_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); - -void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); - -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(bool cont); - -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_connect(uint8_t * p_addr, uint8_t addr_type); - -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_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); - -void ble_drv_discover_descriptors(void); - -#endif // BLUETOOTH_SD - -#endif // BLUETOOTH_LE_DRIVER_H__ diff --git a/ports/nrf/drivers/bluetooth/ble_uart.c b/ports/nrf/drivers/bluetooth/ble_uart.c deleted file mode 100644 index 4a23cd6d2cc2c..0000000000000 --- a/ports/nrf/drivers/bluetooth/ble_uart.c +++ /dev/null @@ -1,280 +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. - */ - -#if BLUETOOTH_SD - -#include -#include "ble_uart.h" -#include "ringbuffer.h" -#include "mphalport.h" -#include "lib/utils/interrupt_char.h" - -#if MICROPY_PY_BLE_NUS - -static ubluepy_uuid_obj_t uuid_obj_service = { - .base.type = &ubluepy_uuid_type, - .type = UBLUEPY_UUID_128_BIT, - .value = {0x01, 0x00} -}; - -static ubluepy_uuid_obj_t uuid_obj_char_tx = { - .base.type = &ubluepy_uuid_type, - .type = UBLUEPY_UUID_128_BIT, - .value = {0x03, 0x00} -}; - -static ubluepy_uuid_obj_t uuid_obj_char_rx = { - .base.type = &ubluepy_uuid_type, - .type = UBLUEPY_UUID_128_BIT, - .value = {0x02, 0x00} -}; - -static ubluepy_service_obj_t ble_uart_service = { - .base.type = &ubluepy_service_type, - .p_uuid = &uuid_obj_service, - .type = UBLUEPY_SERVICE_PRIMARY -}; - -static ubluepy_characteristic_obj_t ble_uart_char_rx = { - .base.type = &ubluepy_characteristic_type, - .p_uuid = &uuid_obj_char_rx, - .props = UBLUEPY_PROP_WRITE | UBLUEPY_PROP_WRITE_WO_RESP, - .attrs = 0, -}; - -static ubluepy_characteristic_obj_t ble_uart_char_tx = { - .base.type = &ubluepy_characteristic_type, - .p_uuid = &uuid_obj_char_tx, - .props = UBLUEPY_PROP_NOTIFY, - .attrs = UBLUEPY_ATTR_CCCD, -}; - -static ubluepy_peripheral_obj_t ble_uart_peripheral = { - .base.type = &ubluepy_peripheral_type, - .conn_handle = 0xFFFF, -}; - -static volatile bool m_cccd_enabled; -static volatile bool m_connected; - -ringBuffer_typedef(uint8_t, ringbuffer_t); - -static ringbuffer_t m_rx_ring_buffer; -static ringbuffer_t * mp_rx_ring_buffer = &m_rx_ring_buffer; -static uint8_t m_rx_ring_buffer_data[128]; - -static ubluepy_advertise_data_t m_adv_data_uart_service; - -#if BLUETOOTH_WEBBLUETOOTH_REPL -static ubluepy_advertise_data_t m_adv_data_eddystone_url; -#endif // BLUETOOTH_WEBBLUETOOTH_REPL - -int mp_hal_stdin_rx_chr(void) { - while (!ble_uart_enabled()) { - // wait for connection - } - while (isBufferEmpty(mp_rx_ring_buffer)) { - ; - } - - uint8_t byte; - bufferRead(mp_rx_ring_buffer, byte); - return (int)byte; -} - -void mp_hal_stdout_tx_strn(const char *str, size_t len) { - // Not connected: drop output - if (!ble_uart_enabled()) return; - - uint8_t *buf = (uint8_t *)str; - size_t send_len; - - while (len > 0) { - if (len >= 20) { - send_len = 20; // (GATT_MTU_SIZE_DEFAULT - 3) - } else { - send_len = len; - } - - ubluepy_characteristic_obj_t * p_char = &ble_uart_char_tx; - - ble_drv_attr_s_notify(p_char->p_service->p_periph->conn_handle, - p_char->handle, - send_len, - buf); - - len -= send_len; - buf += send_len; - } -} - -void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { - mp_hal_stdout_tx_strn(str, len); -} - -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; - m_connected = true; - } else if (event_id == 17) { // disconnect event - self->conn_handle = 0xFFFF; // invalid connection handle - m_connected = false; - m_cccd_enabled = false; - ble_uart_advertise(); - } -} - -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); - (void)self; - - if (event_id == 80) { // gatts write - if (ble_uart_char_tx.cccd_handle == attr_handle) { - m_cccd_enabled = true; - } else if (ble_uart_char_rx.handle == attr_handle) { - for (uint16_t i = 0; i < length; i++) { - #if MICROPY_KBD_EXCEPTION - if (data[i] == mp_interrupt_char) { - mp_keyboard_interrupt(); - m_rx_ring_buffer.start = 0; - m_rx_ring_buffer.end = 0; - } else - #endif - { - bufferWrite(mp_rx_ring_buffer, data[i]); - } - } - } - } -} - -void ble_uart_init0(void) { - uint8_t base_uuid[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}; - uint8_t uuid_vs_idx; - - (void)ble_drv_uuid_add_vs(base_uuid, &uuid_vs_idx); - - uuid_obj_service.uuid_vs_idx = uuid_vs_idx; - uuid_obj_char_tx.uuid_vs_idx = uuid_vs_idx; - uuid_obj_char_rx.uuid_vs_idx = uuid_vs_idx; - - (void)ble_drv_service_add(&ble_uart_service); - ble_uart_service.char_list = mp_obj_new_list(0, NULL); - - // add TX characteristic - ble_uart_char_tx.service_handle = ble_uart_service.handle; - bool retval = ble_drv_characteristic_add(&ble_uart_char_tx); - if (retval) { - ble_uart_char_tx.p_service = &ble_uart_service; - } - mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_tx)); - - // add RX characteristic - ble_uart_char_rx.service_handle = ble_uart_service.handle; - retval = ble_drv_characteristic_add(&ble_uart_char_rx); - if (retval) { - ble_uart_char_rx.p_service = &ble_uart_service; - } - mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_rx)); - - // setup the peripheral - ble_uart_peripheral.service_list = mp_obj_new_list(0, NULL); - mp_obj_list_append(ble_uart_peripheral.service_list, MP_OBJ_FROM_PTR(&ble_uart_service)); - ble_uart_service.p_periph = &ble_uart_peripheral; - - ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gap_event_handler); - ble_drv_gatts_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gatts_event_handler); - - ble_uart_peripheral.conn_handle = 0xFFFF; - - char device_name[] = "mpus"; - - mp_obj_t service_list = mp_obj_new_list(0, NULL); - mp_obj_list_append(service_list, MP_OBJ_FROM_PTR(&ble_uart_service)); - - mp_obj_t * services = NULL; - mp_uint_t num_services; - mp_obj_get_array(service_list, &num_services, &services); - - m_adv_data_uart_service.p_services = services; - m_adv_data_uart_service.num_of_services = num_services; - m_adv_data_uart_service.p_device_name = (uint8_t *)device_name; - m_adv_data_uart_service.device_name_len = strlen(device_name); - m_adv_data_uart_service.connectable = true; - m_adv_data_uart_service.p_data = NULL; - -#if BLUETOOTH_WEBBLUETOOTH_REPL - // for now point eddystone URL to https://goo.gl/F7fZ69 => https://aykevl.nl/apps/nus/ - static uint8_t eddystone_url_data[27] = {0x2, 0x1, 0x6, - 0x3, 0x3, 0xaa, 0xfe, - 19, 0x16, 0xaa, 0xfe, 0x10, 0xee, 0x3, 'g', 'o', 'o', '.', 'g', 'l', '/', 'F', '7', 'f', 'Z', '6', '9'}; - // eddystone url adv data - m_adv_data_eddystone_url.p_data = eddystone_url_data; - m_adv_data_eddystone_url.data_len = sizeof(eddystone_url_data); - m_adv_data_eddystone_url.connectable = false; -#endif - - m_cccd_enabled = false; - - // initialize ring buffer - m_rx_ring_buffer.size = sizeof(m_rx_ring_buffer_data) + 1; - m_rx_ring_buffer.start = 0; - m_rx_ring_buffer.end = 0; - m_rx_ring_buffer.elems = m_rx_ring_buffer_data; - - m_connected = false; - - ble_uart_advertise(); -} - -void ble_uart_advertise(void) { -#if BLUETOOTH_WEBBLUETOOTH_REPL - while (!m_connected) { - (void)ble_drv_advertise_data(&m_adv_data_uart_service); - mp_hal_delay_ms(500); - (void)ble_drv_advertise_data(&m_adv_data_eddystone_url); - mp_hal_delay_ms(500); - } - - ble_drv_advertise_stop(); -#else - (void)ble_drv_advertise_data(&m_adv_data_uart_service); -#endif // BLUETOOTH_WEBBLUETOOTH_REPL -} - -bool ble_uart_connected(void) { - return (m_connected); -} - -bool ble_uart_enabled(void) { - return (m_cccd_enabled); -} - -#endif // MICROPY_PY_BLE_NUS - -#endif // BLUETOOTH_SD diff --git a/ports/nrf/drivers/bluetooth/ringbuffer.h b/ports/nrf/drivers/bluetooth/ringbuffer.h deleted file mode 100644 index 3438b5c9b5bc1..0000000000000 --- a/ports/nrf/drivers/bluetooth/ringbuffer.h +++ /dev/null @@ -1,99 +0,0 @@ -/* The MIT License (MIT) - * - * Copyright (c) 2013 Philip Thrasher - * - * 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. - * Philip Thrasher's Crazy Awesome Ring Buffer Macros! - * - * Below you will find some naughty macros for easy owning and manipulating - * generic ring buffers. Yes, they are slightly evil in readability, but they - * are really fast, and they work great. - * - * Example usage: - * - * #include - * - * // So we can use this in any method, this gives us a typedef - * // named 'intBuffer'. - * ringBuffer_typedef(int, intBuffer); - * - * int main() { - * // Declare vars. - * intBuffer myBuffer; - * - * bufferInit(myBuffer,1024,int); - * - * // We must have the pointer. All of the macros deal with the pointer. - * // (except for init.) - * intBuffer* myBuffer_ptr; - * myBuffer_ptr = &myBuffer; - * - * // Write two values. - * bufferWrite(myBuffer_ptr,37); - * bufferWrite(myBuffer_ptr,72); - * - * // Read a value into a local variable. - * int first; - * bufferRead(myBuffer_ptr,first); - * assert(first == 37); // true - * - * int second; - * bufferRead(myBuffer_ptr,second); - * assert(second == 72); // true - * - * return 0; - * } - * - */ - -#ifndef _ringbuffer_h -#define _ringbuffer_h - -#define ringBuffer_typedef(T, NAME) \ - typedef struct { \ - int size; \ - volatile int start; \ - volatile int end; \ - T* elems; \ - } NAME - -#define bufferInit(BUF, S, T) \ - BUF.size = S+1; \ - BUF.start = 0; \ - BUF.end = 0; \ - BUF.elems = (T*)calloc(BUF.size, sizeof(T)) - - -#define bufferDestroy(BUF) free(BUF->elems) -#define nextStartIndex(BUF) ((BUF->start + 1) % BUF->size) -#define nextEndIndex(BUF) ((BUF->end + 1) % BUF->size) -#define isBufferEmpty(BUF) (BUF->end == BUF->start) -#define isBufferFull(BUF) (nextEndIndex(BUF) == BUF->start) - -#define bufferWrite(BUF, ELEM) \ - BUF->elems[BUF->end] = ELEM; \ - BUF->end = (BUF->end + 1) % BUF->size; \ - if (isBufferEmpty(BUF)) { \ - BUF->start = nextStartIndex(BUF); \ - } - -#define bufferRead(BUF, ELEM) \ - ELEM = BUF->elems[BUF->start]; \ - BUF->start = nextStartIndex(BUF); - -#endif diff --git a/ports/nrf/drivers/flash.c b/ports/nrf/drivers/flash.c index 5a7256a0c6227..a28d2f4f846ed 100644 --- a/ports/nrf/drivers/flash.c +++ b/ports/nrf/drivers/flash.c @@ -29,9 +29,11 @@ #if MICROPY_MBFS && BLUETOOTH_SD #include "drivers/flash.h" -#include "drivers/bluetooth/ble_drv.h" +#include "extmod/modbluetooth.h" #include "nrf_soc.h" +extern bool RF_STACK_ENABLED(void); + // Rotates bits in `value` left `shift` times. STATIC inline uint32_t rotate_left(uint32_t value, uint32_t shift) { return (value << shift) | (value >> (32 - shift)); @@ -48,7 +50,7 @@ void flash_operation_finished(flash_state_t result) { } STATIC bool operation_wait(uint32_t result) { - if (ble_drv_stack_enabled() != 1) { + if (!RF_STACK_ENABLED()) { // SoftDevice is not enabled, no event will be generated. return result == NRF_SUCCESS; } diff --git a/ports/nrf/examples/powerup.py b/ports/nrf/examples/powerup.py deleted file mode 100644 index 6f14309f39f34..0000000000000 --- a/ports/nrf/examples/powerup.py +++ /dev/null @@ -1,213 +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 - -# MicroPython controller for PowerUp 3.0 paper airplane -# https://www.poweruptoys.com/products/powerup-v3 -# -# Examples is written for nrf52832, pca10040 using s132 bluetooth stack. -# -# Joystick shield pin mapping: -# - analog stick x-direction - ADC0 - P0.02/"P2" -# - buttons P0.13 - P0.16 / "P13", "P14", "P15", "P16" -# -# Example usage: -# -# from powerup import PowerUp3 -# p = PowerUp3() - -import time -from machine import ADC -from machine import Pin -from ubluepy import Peripheral, Scanner, constants - -def bytes_to_str(bytes): - string = "" - for b in bytes: - string += chr(b) - return string - -def get_device_names(scan_entries): - dev_names = [] - for e in scan_entries: - scan = e.getScanData() - if scan: - for s in scan: - if s[0] == constants.ad_types.AD_TYPE_COMPLETE_LOCAL_NAME: - dev_names.append((e, bytes_to_str(s[2]))) - return dev_names - -def find_device_by_name(name): - s = Scanner() - scan_res = s.scan(500) - - device_names = get_device_names(scan_res) - for dev in device_names: - if name == dev[1]: - return dev[0] - -class PowerUp3: - def __init__(self): - self.x_adc = ADC(1) - - self.btn_speed_up = Pin("P13", mode=Pin.IN, pull=Pin.PULL_UP) - self.btn_speed_down = Pin("P15", mode=Pin.IN, pull=Pin.PULL_UP) - self.btn_speed_full = Pin("P14", mode=Pin.IN, pull=Pin.PULL_UP) - self.btn_speed_off = Pin("P16", mode=Pin.IN, pull=Pin.PULL_UP) - - self.x_mid = 0 - - self.calibrate() - self.connect() - self.loop() - - def read_stick_x(self): - return self.x_adc.value() - - def button_speed_up(self): - return not bool(self.btn_speed_up.value()) - - def button_speed_down(self): - return not bool(self.btn_speed_down.value()) - - def button_speed_full(self): - return not bool(self.btn_speed_full.value()) - - def button_speed_off(self): - return not bool(self.btn_speed_off.value()) - - def calibrate(self): - self.x_mid = self.read_stick_x() - - def __str__(self): - return "calibration x: %i, y: %i" % (self.x_mid) - - def map_chars(self): - s = self.p.getServices() - - service_batt = s[3] - service_control = s[4] - - self.char_batt_lvl = service_batt.getCharacteristics()[0] - self.char_control_speed = service_control.getCharacteristics()[0] - self.char_control_angle = service_control.getCharacteristics()[2] - - def battery_level(self): - return int(self.char_batt_lvl.read()[0]) - - def speed(self, new_speed=None): - if new_speed == None: - return int(self.char_control_speed.read()[0]) - else: - self.char_control_speed.write(bytearray([new_speed])) - - def angle(self, new_angle=None): - if new_angle == None: - return int(self.char_control_angle.read()[0]) - else: - self.char_control_angle.write(bytearray([new_angle])) - - def connect(self): - dev = None - - # connect to the airplane - while not dev: - dev = find_device_by_name("TailorToys PowerUp") - if dev: - self.p = Peripheral() - self.p.connect(dev.addr()) - - # locate interesting characteristics - self.map_chars() - - def rudder_center(self): - if self.old_angle != 0: - self.old_angle = 0 - self.angle(0) - - def rudder_left(self, angle): - steps = (angle // self.interval_size_left) - new_angle = 60 - steps - - if self.old_angle != new_angle: - self.angle(new_angle) - self.old_angle = new_angle - - def rudder_right(self, angle): - steps = (angle // self.interval_size_right) - new_angle = -steps - - if self.old_angle != new_angle: - self.angle(new_angle) - self.old_angle = new_angle - - def throttle(self, speed): - if (speed > 200): - speed = 200 - elif (speed < 0): - speed = 0 - - if self.old_speed != speed: - self.speed(speed) - self.old_speed = speed - - def loop(self): - adc_threshold = 10 - right_threshold = self.x_mid + adc_threshold - left_threshold = self.x_mid - adc_threshold - - self.interval_size_left = self.x_mid // 60 - self.interval_size_right = (255 - self.x_mid) // 60 - - self.old_angle = 0 - self.old_speed = 0 - - while True: - - time.sleep_ms(100) - - # read out new angle - new_angle = self.read_stick_x() - if (new_angle < 256): - if (new_angle > right_threshold): - self.rudder_right(new_angle - self.x_mid) - elif (new_angle < left_threshold): - self.rudder_left(new_angle) - else: - self.rudder_center() - - # read out new speed - new_speed = self.old_speed - - if self.button_speed_up(): - new_speed += 25 - elif self.button_speed_down(): - new_speed -= 25 - elif self.button_speed_full(): - new_speed = 200 - elif self.button_speed_off(): - new_speed = 0 - else: - pass - - self.throttle(new_speed) diff --git a/ports/nrf/examples/ubluepy_eddystone.py b/ports/nrf/examples/ubluepy_eddystone.py deleted file mode 100644 index c8abd5aea6ba0..0000000000000 --- a/ports/nrf/examples/ubluepy_eddystone.py +++ /dev/null @@ -1,58 +0,0 @@ -from ubluepy import Peripheral, constants - -BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE = const(0x02) -BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED = const(0x04) - -BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE = const(BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) - -EDDYSTONE_FRAME_TYPE_URL = const(0x10) -EDDYSTONE_URL_PREFIX_HTTP_WWW = const(0x00) # "http://www". -EDDYSTONE_URL_SUFFIX_DOT_COM = const(0x01) # ".com" - -def string_to_binarray(text): - b = bytearray([]) - for c in text: - b.append(ord(c)) - return b - -def gen_ad_type_content(ad_type, data): - b = bytearray(1) - b.append(ad_type) - b.extend(data) - b[0] = len(b) - 1 - return b - -def generate_eddystone_adv_packet(url): - # flags - disc_mode = bytearray([BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE]) - packet_flags = gen_ad_type_content(constants.ad_types.AD_TYPE_FLAGS, disc_mode) - - # 16-bit uuid - uuid = bytearray([0xAA, 0xFE]) - packet_uuid16 = gen_ad_type_content(constants.ad_types.AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, uuid) - - # eddystone data - rssi = 0xEE # -18 dB, approx signal strength at 0m. - eddystone_data = bytearray([]) - eddystone_data.append(EDDYSTONE_FRAME_TYPE_URL) - eddystone_data.append(rssi) - eddystone_data.append(EDDYSTONE_URL_PREFIX_HTTP_WWW) - eddystone_data.extend(string_to_binarray(url)) - eddystone_data.append(EDDYSTONE_URL_SUFFIX_DOT_COM) - - # service data - service_data = uuid + eddystone_data - packet_service_data = gen_ad_type_content(constants.ad_types.AD_TYPE_SERVICE_DATA, service_data) - - # generate advertisment packet - packet = bytearray([]) - packet.extend(packet_flags) - packet.extend(packet_uuid16) - packet.extend(packet_service_data) - - return packet - -def start(): - adv_packet = generate_eddystone_adv_packet("micropython") - p = Peripheral() - p.advertise(data=adv_packet, connectable=False) \ No newline at end of file diff --git a/ports/nrf/examples/ubluepy_scan.py b/ports/nrf/examples/ubluepy_scan.py deleted file mode 100644 index ab11661ccaa2e..0000000000000 --- a/ports/nrf/examples/ubluepy_scan.py +++ /dev/null @@ -1,38 +0,0 @@ -from ubluepy import Scanner, constants - -def bytes_to_str(bytes): - string = "" - for b in bytes: - string += chr(b) - return string - -def get_device_names(scan_entries): - dev_names = [] - for e in scan_entries: - scan = e.getScanData() - if scan: - for s in scan: - if s[0] == constants.ad_types.AD_TYPE_COMPLETE_LOCAL_NAME: - dev_names.append((e, bytes_to_str(s[2]))) - return dev_names - -def find_device_by_name(name): - s = Scanner() - scan_res = s.scan(100) - - device_names = get_device_names(scan_res) - for dev in device_names: - if name == dev[1]: - return dev[0] - -# >>> res = find_device_by_name("micr") -# >>> if res: -# ... print("address:", res.addr()) -# ... print("address type:", res.addr_type()) -# ... print("rssi:", res.rssi()) -# ... -# ... -# ... -# address: c2:73:61:89:24:45 -# address type: 1 -# rssi: -26 diff --git a/ports/nrf/examples/ubluepy_temp.py b/ports/nrf/examples/ubluepy_temp.py deleted file mode 100644 index 7df057bf4821b..0000000000000 --- a/ports/nrf/examples/ubluepy_temp.py +++ /dev/null @@ -1,92 +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 - -from board import LED -from machine import RTCounter, Temp -from ubluepy import Service, Characteristic, UUID, Peripheral, constants - -def event_handler(id, handle, data): - global rtc - global periph - global serv_env_sense - global notif_enabled - - if id == constants.EVT_GAP_CONNECTED: - # indicated 'connected' - LED(1).on() - - elif id == constants.EVT_GAP_DISCONNECTED: - # stop low power timer - rtc.stop() - # indicate 'disconnected' - LED(1).off() - # restart advertisment - periph.advertise(device_name="micr_temp", services=[serv_env_sense]) - - elif id == constants.EVT_GATTS_WRITE: - # write to this Characteristic is to CCCD - if int(data[0]) == 1: - notif_enabled = True - # start low power timer - rtc.start() - else: - notif_enabled = False - # stop low power timer - rtc.stop() - -def send_temp(timer_id): - global notif_enabled - global char_temp - - if notif_enabled: - # measure chip temperature - temp = Temp.read() - temp = temp * 100 - char_temp.write(bytearray([temp & 0xFF, temp >> 8])) - -# start off with LED(1) off -LED(1).off() - -# use RTC1 as RTC0 is used by bluetooth stack -# set up RTC callback every 5 second -rtc = RTCounter(1, period=50, mode=RTCounter.PERIODIC, callback=send_temp) - -notif_enabled = False - -uuid_env_sense = UUID("0x181A") # Environmental Sensing service -uuid_temp = UUID("0x2A6E") # Temperature characteristic - -serv_env_sense = Service(uuid_env_sense) - -temp_props = Characteristic.PROP_NOTIFY | Characteristic.PROP_READ -temp_attrs = Characteristic.ATTR_CCCD -char_temp = Characteristic(uuid_temp, props = temp_props, attrs = temp_attrs) - -serv_env_sense.addCharacteristic(char_temp) - -periph = Peripheral() -periph.addService(serv_env_sense) -periph.setConnectionHandler(event_handler) -periph.advertise(device_name="micr_temp", services=[serv_env_sense]) - diff --git a/ports/nrf/help.c b/ports/nrf/help.c index 5856ef6e372de..10d236d97e6b2 100644 --- a/ports/nrf/help.c +++ b/ports/nrf/help.c @@ -27,10 +27,6 @@ #include "py/builtin.h" -#if BLUETOOTH_SD -#include "help_sd.h" -#endif - const char nrf5_help_text[] = "Welcome to MicroPython!\n" "\n" @@ -41,9 +37,6 @@ const char nrf5_help_text[] = " board.LED(n) -- create an LED object for LED n (n=" HELP_TEXT_BOARD_LED ")\n" "\n" #endif -#if BLUETOOTH_SD -HELP_TEXT_SD -#endif "Control commands:\n" " CTRL-A -- on a blank line, enter raw REPL mode\n" " CTRL-B -- on a blank line, enter normal REPL mode\n" diff --git a/ports/nrf/modules/ble/modble.c b/ports/nrf/modules/ble/modble.c deleted file mode 100644 index 2b6dd6e2236cf..0000000000000 --- a/ports/nrf/modules/ble/modble.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 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 -#include "py/runtime.h" - -#if MICROPY_PY_BLE - -#include "led.h" -#include "mpconfigboard.h" -#include "ble_drv.h" - -/// \method enable() -/// Enable BLE softdevice. -mp_obj_t ble_obj_enable(void) { - printf("SoftDevice enabled\n"); - uint32_t err_code = ble_drv_stack_enable(); - if (err_code < 0) { - // TODO: raise exception. - } - return mp_const_none; -} - -/// \method disable() -/// Disable BLE softdevice. -mp_obj_t ble_obj_disable(void) { - ble_drv_stack_disable(); - return mp_const_none; -} - -/// \method enabled() -/// Get state of whether the softdevice is enabled or not. -mp_obj_t ble_obj_enabled(void) { - uint8_t is_enabled = ble_drv_stack_enabled(); - mp_int_t enabled = is_enabled; - return MP_OBJ_NEW_SMALL_INT(enabled); -} - -/// \method address() -/// Return device address as text string. -mp_obj_t ble_obj_address(void) { - ble_drv_addr_t local_addr; - ble_drv_address_get(&local_addr); - - vstr_t vstr; - vstr_init(&vstr, 17); - - vstr_printf(&vstr, ""HEX2_FMT":"HEX2_FMT":"HEX2_FMT":" \ - HEX2_FMT":"HEX2_FMT":"HEX2_FMT"", - local_addr.addr[5], local_addr.addr[4], local_addr.addr[3], - local_addr.addr[2], local_addr.addr[1], local_addr.addr[0]); - - mp_obj_t mac_str = mp_obj_new_str(vstr.buf, vstr.len); - - vstr_clear(&vstr); - - return mac_str; -} - -STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_enable_obj, ble_obj_enable); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_disable_obj, ble_obj_disable); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_enabled_obj, ble_obj_enabled); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_address_obj, ble_obj_address); - -STATIC const mp_rom_map_elem_t ble_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ble) }, - { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&ble_obj_enable_obj) }, - { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&ble_obj_disable_obj) }, - { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&ble_obj_enabled_obj) }, - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&ble_obj_address_obj) }, -}; - - -STATIC MP_DEFINE_CONST_DICT(ble_module_globals, ble_module_globals_table); - -const mp_obj_module_t ble_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&ble_module_globals, -}; - -#endif // MICROPY_PY_BLE diff --git a/ports/nrf/modules/machine/temp.c b/ports/nrf/modules/machine/temp.c index 361d988857890..c06c4dffcd22c 100644 --- a/ports/nrf/modules/machine/temp.c +++ b/ports/nrf/modules/machine/temp.c @@ -27,17 +27,15 @@ #include #include -#include "py/nlr.h" #include "py/runtime.h" #include "py/mphal.h" #include "temp.h" #include "nrf_temp.h" #if BLUETOOTH_SD -#include "py/nlr.h" -#include "ble_drv.h" +#include "extmod/modbluetooth.h" #include "nrf_soc.h" -#define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) +extern bool RF_STACK_ENABLED(void); #endif // BLUETOOTH_SD #if MICROPY_PY_MACHINE_TEMP @@ -80,7 +78,7 @@ STATIC mp_obj_t machine_temp_make_new(const mp_obj_type_t *type, size_t n_args, STATIC mp_obj_t machine_temp_read(mp_uint_t n_args, const mp_obj_t *args) { #if BLUETOOTH_SD - if (BLUETOOTH_STACK_ENABLED() == 1) { + if (RF_STACK_ENABLED() == 1) { int32_t temp; (void)sd_temp_get(&temp); return MP_OBJ_NEW_SMALL_INT(temp / 4); // resolution of 0.25 degree celsius diff --git a/ports/nrf/modules/random/modrandom.c b/ports/nrf/modules/random/modrandom.c index f67bffb27786a..9a10ce54db4fc 100644 --- a/ports/nrf/modules/random/modrandom.c +++ b/ports/nrf/modules/random/modrandom.c @@ -36,9 +36,9 @@ #include "modrandom.h" #if BLUETOOTH_SD +#include "extmod/modbluetooth.h" #include "nrf_soc.h" -#include "ble_drv.h" -#define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) +extern bool RF_STACK_ENABLED(void); #endif static inline uint32_t generate_hw_random(void) { @@ -65,7 +65,7 @@ static inline uint32_t generate_hw_random(void) { uint32_t machine_rng_generate_random_word(void) { #if BLUETOOTH_SD - if (BLUETOOTH_STACK_ENABLED() == 1) { + if (RF_STACK_ENABLED() == 1) { uint32_t retval = 0; uint32_t status; do { diff --git a/ports/nrf/modules/ubluepy/modubluepy.c b/ports/nrf/modules/ubluepy/modubluepy.c deleted file mode 100644 index b306c065b2906..0000000000000 --- a/ports/nrf/modules/ubluepy/modubluepy.c +++ /dev/null @@ -1,70 +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; -extern const mp_obj_type_t ubluepy_uuid_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; -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) }, -#if MICROPY_PY_UBLUEPY_PERIPHERAL - { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&ubluepy_peripheral_type) }, -#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) }, - { 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_UUID), MP_ROM_PTR(&ubluepy_uuid_type) }, - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&ubluepy_characteristic_type) }, - { MP_ROM_QSTR(MP_QSTR_constants), MP_ROM_PTR(&ubluepy_constants_type) }, -#if MICROPY_PY_UBLUEPY_DESCRIPTOR - { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&ubluepy_descriptor_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 fbd07b8b9be7f..0000000000000 --- a/ports/nrf/modules/ubluepy/modubluepy.h +++ /dev/null @@ -1,200 +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 board 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 "py/obj.h" - -extern const mp_obj_type_t ubluepy_uuid_type; -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; - -typedef enum { - UBLUEPY_UUID_16_BIT = 1, - UBLUEPY_UUID_128_BIT -} ubluepy_uuid_type_t; - -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, -#if 0 - UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = 2, - UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = 3, -#endif -} ubluepy_addr_type_t; - -typedef enum { - UBLUEPY_ROLE_PERIPHERAL, - UBLUEPY_ROLE_CENTRAL -} ubluepy_role_type_t; - -typedef struct _ubluepy_uuid_obj_t { - mp_obj_base_t base; - ubluepy_uuid_type_t type; - uint8_t value[2]; - uint8_t uuid_vs_idx; -} ubluepy_uuid_obj_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_service_obj_t { - mp_obj_base_t base; - uint16_t handle; - uint8_t type; - ubluepy_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_characteristic_obj_t { - mp_obj_base_t base; - uint16_t handle; - ubluepy_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_descriptor_obj_t { - mp_obj_base_t base; - uint16_t handle; - ubluepy_uuid_obj_t * p_uuid; -} ubluepy_descriptor_obj_t; - -typedef struct _ubluepy_delegate_obj_t { - mp_obj_base_t base; -} ubluepy_delegate_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 struct _ubluepy_scanner_obj_t { - mp_obj_base_t base; - 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, - 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_characteristic.c b/ports/nrf/modules/ubluepy/ubluepy_characteristic.c deleted file mode 100644 index 2ca7f2f42759a..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_characteristic.c +++ /dev/null @@ -1,221 +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" - -#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL - -#include "modubluepy.h" -#include "ble_drv.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, &ubluepy_uuid_type)) { - s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); - // (void)sd_characterstic_add(s); - } else { - mp_raise_ValueError("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_constants.c b/ports/nrf/modules/ubluepy/ubluepy_constants.c deleted file mode 100644 index 14e433e6ebff3..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_constants.c +++ /dev/null @@ -1,99 +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" - -#if MICROPY_PY_UBLUEPY - -#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_ADDR_TYPE_PUBLIC), MP_ROM_INT(UBLUEPY_ADDR_TYPE_PUBLIC) }, - { MP_ROM_QSTR(MP_QSTR_ADDR_TYPE_RANDOM_STATIC), MP_ROM_INT(UBLUEPY_ADDR_TYPE_RANDOM_STATIC) }, - - { 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); - -const mp_obj_type_t ubluepy_constants_type = { - { &mp_type_type }, - .name = MP_QSTR_constants, - .locals_dict = (mp_obj_dict_t*)&ubluepy_constants_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY diff --git a/ports/nrf/modules/ubluepy/ubluepy_delegate.c b/ports/nrf/modules/ubluepy/ubluepy_delegate.c deleted file mode 100644 index 07bb7f49286fd..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_delegate.c +++ /dev/null @@ -1,89 +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" - -#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL - -#include "modubluepy.h" - -STATIC void ubluepy_delegate_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_delegate_obj_t * self = (ubluepy_delegate_obj_t *)o; - (void)self; - mp_printf(print, "DefaultDelegate()"); -} - -STATIC mp_obj_t ubluepy_delegate_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - ubluepy_delegate_obj_t *s = m_new_obj(ubluepy_delegate_obj_t); - s->base.type = type; - - return MP_OBJ_FROM_PTR(s); -} - -/// \method handleConnection() -/// Handle connection events. -/// -STATIC mp_obj_t delegate_handle_conn(mp_obj_t self_in) { - ubluepy_delegate_obj_t *self = MP_OBJ_TO_PTR(self_in); - - (void)self; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_delegate_handle_conn_obj, delegate_handle_conn); - -/// \method handleNotification() -/// Handle notification events. -/// -STATIC mp_obj_t delegate_handle_notif(mp_obj_t self_in) { - ubluepy_delegate_obj_t *self = MP_OBJ_TO_PTR(self_in); - - (void)self; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_delegate_handle_notif_obj, delegate_handle_notif); - -STATIC const mp_rom_map_elem_t ubluepy_delegate_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_handleConnection), MP_ROM_PTR(&ubluepy_delegate_handle_conn_obj) }, - { MP_ROM_QSTR(MP_QSTR_handleNotification), MP_ROM_PTR(&ubluepy_delegate_handle_notif_obj) }, -#if 0 - { MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) }, -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_delegate_locals_dict, ubluepy_delegate_locals_dict_table); - -const mp_obj_type_t ubluepy_delegate_type = { - { &mp_type_type }, - .name = MP_QSTR_DefaultDelegate, - .print = ubluepy_delegate_print, - .make_new = ubluepy_delegate_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_delegate_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/ports/nrf/modules/ubluepy/ubluepy_descriptor.c b/ports/nrf/modules/ubluepy/ubluepy_descriptor.c deleted file mode 100644 index b15301954d07e..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_descriptor.c +++ /dev/null @@ -1,82 +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/objstr.h" -#include "py/misc.h" - -#if MICROPY_PY_UBLUEPY - -#include "modubluepy.h" -#include "ble_drv.h" - -STATIC void ubluepy_descriptor_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_descriptor_obj_t * self = (ubluepy_descriptor_obj_t *)o; - - mp_printf(print, "Descriptor(uuid: 0x" HEX2_FMT HEX2_FMT ")", - self->p_uuid->value[1], self->p_uuid->value[0]); -} - -STATIC mp_obj_t ubluepy_descriptor_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 }; - - static const mp_arg_t allowed_args[] = { - { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - }; - - // 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_descriptor_obj_t * s = m_new_obj(ubluepy_descriptor_obj_t); - s->base.type = type; - - mp_obj_t uuid_obj = args[ARG_NEW_UUID].u_obj; - - (void)uuid_obj; - - return MP_OBJ_FROM_PTR(s); -} - -STATIC const mp_rom_map_elem_t ubluepy_descriptor_locals_dict_table[] = { -#if 0 - { MP_ROM_QSTR(MP_QSTR_binVal), MP_ROM_PTR(&ubluepy_descriptor_bin_val_obj) }, -#endif -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_descriptor_locals_dict, ubluepy_descriptor_locals_dict_table); - -const mp_obj_type_t ubluepy_descriptor_type = { - { &mp_type_type }, - .name = MP_QSTR_Descriptor, - .print = ubluepy_descriptor_print, - .make_new = ubluepy_descriptor_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_descriptor_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY diff --git a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/ports/nrf/modules/ubluepy/ubluepy_peripheral.c deleted file mode 100644 index 3a45e56a07648..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_peripheral.c +++ /dev/null @@ -1,498 +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" - -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 advertisment 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 advertisment if any onging advertisment. -/// -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); - ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service); - - p_service->p_periph = self; - - 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) { - ubluepy_service_obj_t * p_service = m_new_obj(ubluepy_service_obj_t); - p_service->base.type = &ubluepy_service_type; - - ubluepy_uuid_obj_t * p_uuid = m_new_obj(ubluepy_uuid_obj_t); - p_uuid->base.type = &ubluepy_uuid_type; - - p_service->p_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) { - 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; - - ubluepy_uuid_obj_t * p_uuid = m_new_obj(ubluepy_uuid_obj_t); - p_uuid->base.type = &ubluepy_uuid_type; - - p_char->p_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->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; - - 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); - - ubluepy_service_obj_t * p_service = (ubluepy_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++) { - ubluepy_service_obj_t * p_service = (ubluepy_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); - - ubluepy_characteristic_obj_t * p_char = (ubluepy_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/modules/ubluepy/ubluepy_scan_entry.c b/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c deleted file mode 100644 index 773070b08907f..0000000000000 --- 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 deleted file mode 100644 index f5c9a6dca8083..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_scanner.c +++ /dev/null @@ -1,127 +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_CENTRAL - -#include "ble_drv.h" -#include "mphalport.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; - - vstr_t vstr; - vstr_init(&vstr, 17); - - 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); - - mp_obj_list_append(self->adv_reports, item); - - // Continue scanning - ble_drv_scan_start(true); -} - -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(false); - - // 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/ports/nrf/modules/ubluepy/ubluepy_service.c b/ports/nrf/modules/ubluepy/ubluepy_service.c deleted file mode 100644 index e5bf42a09fd30..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_service.c +++ /dev/null @@ -1,183 +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" - -#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL - -#include "modubluepy.h" -#include "ble_drv.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, &ubluepy_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 { - mp_raise_ValueError("Invalid Service type"); - } - - (void)ble_drv_service_add(s); - - } else { - mp_raise_ValueError("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); - ubluepy_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; - } - - 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); - ubluepy_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, &ubluepy_uuid_type))) { - mp_raise_ValueError("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++) { - ubluepy_characteristic_obj_t * p_char = (ubluepy_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]) == - (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/ports/nrf/modules/ubluepy/ubluepy_uuid.c b/ports/nrf/modules/ubluepy/ubluepy_uuid.c deleted file mode 100644 index cbcb1009682f7..0000000000000 --- a/ports/nrf/modules/ubluepy/ubluepy_uuid.c +++ /dev/null @@ -1,171 +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/objstr.h" -#include "py/misc.h" - -#if MICROPY_PY_UBLUEPY - -#include "modubluepy.h" -#include "ble_drv.h" - -STATIC void ubluepy_uuid_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { - ubluepy_uuid_obj_t * self = (ubluepy_uuid_obj_t *)o; - if (self->type == UBLUEPY_UUID_16_BIT) { - mp_printf(print, "UUID(uuid: 0x" HEX2_FMT HEX2_FMT ")", - 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); - } -} - -STATIC mp_obj_t ubluepy_uuid_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 }; - - static const mp_arg_t allowed_args[] = { - { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - }; - - // 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_uuid_obj_t *s = m_new_obj(ubluepy_uuid_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_int(uuid_obj)) { - s->type = UBLUEPY_UUID_16_BIT; - s->value[1] = (((uint16_t)mp_obj_get_int(uuid_obj)) >> 8) & 0xFF; - s->value[0] = ((uint8_t)mp_obj_get_int(uuid_obj)) & 0xFF; - } else if (mp_obj_is_str(uuid_obj)) { - GET_STR_DATA_LEN(uuid_obj, str_data, str_len); - if (str_len == 6) { // Assume hex digit prefixed with 0x - s->type = UBLUEPY_UUID_16_BIT; - s->value[0] = unichar_xdigit_value(str_data[5]); - s->value[0] += unichar_xdigit_value(str_data[4]) << 4; - s->value[1] = unichar_xdigit_value(str_data[3]); - s->value[1] += unichar_xdigit_value(str_data[2]) << 4; - } else if (str_len == 36) { - s->type = UBLUEPY_UUID_128_BIT; - uint8_t buffer[16]; - buffer[0] = unichar_xdigit_value(str_data[35]); - buffer[0] += unichar_xdigit_value(str_data[34]) << 4; - buffer[1] = unichar_xdigit_value(str_data[33]); - buffer[1] += unichar_xdigit_value(str_data[32]) << 4; - buffer[2] = unichar_xdigit_value(str_data[31]); - buffer[2] += unichar_xdigit_value(str_data[30]) << 4; - buffer[3] = unichar_xdigit_value(str_data[29]); - buffer[3] += unichar_xdigit_value(str_data[28]) << 4; - buffer[4] = unichar_xdigit_value(str_data[27]); - buffer[4] += unichar_xdigit_value(str_data[26]) << 4; - buffer[5] = unichar_xdigit_value(str_data[25]); - buffer[5] += unichar_xdigit_value(str_data[24]) << 4; - // 23 '-' - buffer[6] = unichar_xdigit_value(str_data[22]); - buffer[6] += unichar_xdigit_value(str_data[21]) << 4; - buffer[7] = unichar_xdigit_value(str_data[20]); - buffer[7] += unichar_xdigit_value(str_data[19]) << 4; - // 18 '-' - buffer[8] = unichar_xdigit_value(str_data[17]); - buffer[8] += unichar_xdigit_value(str_data[16]) << 4; - buffer[9] = unichar_xdigit_value(str_data[15]); - buffer[9] += unichar_xdigit_value(str_data[14]) << 4; - // 13 '-' - buffer[10] = unichar_xdigit_value(str_data[12]); - buffer[10] += unichar_xdigit_value(str_data[11]) << 4; - buffer[11] = unichar_xdigit_value(str_data[10]); - buffer[11] += unichar_xdigit_value(str_data[9]) << 4; - // 8 '-' - // 16-bit field - s->value[0] = unichar_xdigit_value(str_data[7]); - s->value[0] += unichar_xdigit_value(str_data[6]) << 4; - s->value[1] = unichar_xdigit_value(str_data[5]); - s->value[1] += unichar_xdigit_value(str_data[4]) << 4; - - buffer[14] = unichar_xdigit_value(str_data[3]); - buffer[14] += unichar_xdigit_value(str_data[2]) << 4; - buffer[15] = unichar_xdigit_value(str_data[1]); - buffer[15] += unichar_xdigit_value(str_data[0]) << 4; - - ble_drv_uuid_add_vs(buffer, &s->uuid_vs_idx); - } else { - mp_raise_ValueError("Invalid UUID string length"); - } - } else if (mp_obj_is_type(uuid_obj, &ubluepy_uuid_type)) { - // deep copy instance - ubluepy_uuid_obj_t * p_old = MP_OBJ_TO_PTR(uuid_obj); - s->type = p_old->type; - s->value[0] = p_old->value[0]; - s->value[1] = p_old->value[1]; - } else { - mp_raise_ValueError("Invalid UUID parameter"); - } - - return MP_OBJ_FROM_PTR(s); -} - -/// \method binVal() -/// Get binary value of the 16 or 128 bit UUID. Returned as bytearray type. -/// -STATIC mp_obj_t uuid_bin_val(mp_obj_t self_in) { - ubluepy_uuid_obj_t * self = MP_OBJ_TO_PTR(self_in); - - // TODO: Extend the uint16 byte value to 16 byte if 128-bit, - // also encapsulate it in a bytearray. For now, return - // the uint16_t field of the UUID. - return MP_OBJ_NEW_SMALL_INT(self->value[0] | self->value[1] << 8); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_uuid_bin_val_obj, uuid_bin_val); - -STATIC const mp_rom_map_elem_t ubluepy_uuid_locals_dict_table[] = { -#if 0 - { MP_ROM_QSTR(MP_QSTR_getCommonName), MP_ROM_PTR(&ubluepy_uuid_get_common_name_obj) }, -#endif - // Properties - { MP_ROM_QSTR(MP_QSTR_binVal), MP_ROM_PTR(&ubluepy_uuid_bin_val_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(ubluepy_uuid_locals_dict, ubluepy_uuid_locals_dict_table); - -const mp_obj_type_t ubluepy_uuid_type = { - { &mp_type_type }, - .name = MP_QSTR_UUID, - .print = ubluepy_uuid_print, - .make_new = ubluepy_uuid_make_new, - .locals_dict = (mp_obj_dict_t*)&ubluepy_uuid_locals_dict -}; - -#endif // MICROPY_PY_UBLUEPY diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 0e3cf7b39d6ee..0cbf2ea2e7e90 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -178,23 +178,13 @@ #define MICROPY_PY_RANDOM_HW_RNG (0) #endif +#ifndef RF_STACK_ENABLED +#define RF_STACK_ENABLED mp_bt_is_enabled +#endif #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) -// if sdk is in use, import configuration -#if BLUETOOTH_SD -#include "bluetooth_conf.h" -#endif - -#ifndef MICROPY_PY_UBLUEPY -#define MICROPY_PY_UBLUEPY (0) -#endif - -#ifndef MICROPY_PY_BLE_NUS -#define MICROPY_PY_BLE_NUS (0) -#endif - // type definitions for the specific machine #define BYTES_PER_WORD (4) @@ -216,14 +206,14 @@ extern const struct _mp_obj_module_t board_module; extern const struct _mp_obj_module_t machine_module; extern const struct _mp_obj_module_t mp_module_utime; extern const struct _mp_obj_module_t mp_module_uos; -extern const struct _mp_obj_module_t mp_module_ubluepy; extern const struct _mp_obj_module_t music_module; extern const struct _mp_obj_module_t random_module; +extern const struct _mp_obj_module_t mp_module_bluetooth; -#if MICROPY_PY_UBLUEPY -#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, +#if MICROPY_PY_BLUETOOTH +#define BLUETOOTH_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, #else -#define UBLUEPY_MODULE +#define BLUETOOTH_MODULE #endif #if MICROPY_PY_MUSIC @@ -245,14 +235,7 @@ extern const struct _mp_obj_module_t random_module; #define MICROPY_BOARD_BUILTINS #endif // BOARD_SPECIFIC_MODULES -#if BLUETOOTH_SD - -#if MICROPY_PY_BLE -extern const struct _mp_obj_module_t ble_module; -#define BLE_MODULE { MP_ROM_QSTR(MP_QSTR_ble), MP_ROM_PTR(&ble_module) }, -#else -#define BLE_MODULE -#endif +#if MICROPY_PY_BLUETOOTH #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ @@ -260,15 +243,13 @@ extern const struct _mp_obj_module_t ble_module; { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ - BLE_MODULE \ + BLUETOOTH_MODULE \ MUSIC_MODULE \ - UBLUEPY_MODULE \ RANDOM_MODULE \ MICROPY_BOARD_BUILTINS \ #else -extern const struct _mp_obj_module_t ble_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ @@ -294,7 +275,6 @@ extern const struct _mp_obj_module_t ble_module; #define MICROPY_PORT_CONSTANTS \ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ - BLE_MODULE \ #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/nrf/nrfx_glue.h b/ports/nrf/nrfx_glue.h index 0108e3242fd19..d809e428aad43 100644 --- a/ports/nrf/nrfx_glue.h +++ b/ports/nrf/nrfx_glue.h @@ -34,18 +34,17 @@ #if BLUETOOTH_SD +#include "extmod/modbluetooth.h" #if NRF51 #include "nrf_soc.h" #else #include "nrf_nvic.h" #endif -#include "ble_drv.h" - #if (BLUETOOTH_SD == 110) #define NRFX_IRQ_ENABLE(irq_number) \ do { \ - if (ble_drv_stack_enabled() == 1) \ + if (mp_bt_is_enabled()) \ { \ sd_nvic_EnableIRQ(irq_number); \ } else { \ @@ -59,7 +58,7 @@ #if (BLUETOOTH_SD == 110) #define NRFX_IRQ_DISABLE(irq_number) \ do { \ - if (ble_drv_stack_enabled() == 1) \ + if (mp_bt_is_enabled()) \ { \ sd_nvic_DisableIRQ(irq_number); \ } else { \ @@ -73,7 +72,7 @@ #if (BLUETOOTH_SD == 110) #define NRFX_IRQ_PRIORITY_SET(irq_number, priority) \ do { \ - if (ble_drv_stack_enabled() == 1) \ + if (mp_bt_is_enabled()) \ { \ sd_nvic_SetPriority(irq_number, priority); \ } else { \ @@ -87,7 +86,7 @@ #if (BLUETOOTH_SD == 110) #define NRFX_IRQ_PENDING_SET(irq_number) \ do { \ - if (ble_drv_stack_enabled() == 1) \ + if (mp_bt_is_enabled()) \ { \ sd_nvic_SetPendingIRQ(irq_number); \ } else { \ @@ -101,7 +100,7 @@ #if (BLUETOOTH_SD == 110) #define NRFX_IRQ_PENDING_CLEAR(irq_number) \ do { \ - if (ble_drv_stack_enabled() == 1) \ + if (mp_bt_is_enabled()) \ { \ sd_nvic_ClearPendingIRQ(irq_number); \ } else { \ diff --git a/py/py.mk b/py/py.mk index 0fbc9f14bbe3c..5c93c870afac7 100644 --- a/py/py.mk +++ b/py/py.mk @@ -147,6 +147,11 @@ CFLAGS_MOD += $(CFLAGS_USERMOD) LDFLAGS_MOD += $(LDFLAGS_USERMOD) endif +ifeq ($(MICROPY_PY_BLUETOOTH),1) +SRC_MOD += extmod/modbluetooth.c +CFLAGS_MOD += -DMICROPY_PY_BLUETOOTH=1 +endif + # py object files PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \