From 3b0bed08d979d47ba8e6b975f7ef4bf1b6c2b8c1 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 23 Jul 2018 21:41:54 +0200 Subject: [PATCH 1/8] all: Add bluetooth module for BLE. Rebased to master with the help of Mirko Vogt. --- extmod/modbluetooth.c | 150 +++++++++++++ extmod/modbluetooth.h | 55 +++++ ports/esp32/Makefile | 166 ++++++++++++++ ports/esp32/bluetooth/bluetooth.c | 205 +++++++++++++++++ ports/esp32/bluetooth/bluetooth.h | 36 +++ ports/esp32/boards/sdkconfig | 6 + ports/esp32/main.c | 2 + ports/esp32/mpconfigport.h | 2 + ports/nrf/Makefile | 23 +- ports/nrf/bluetooth/bluetooth.c | 316 +++++++++++++++++++++++++++ ports/nrf/bluetooth/bluetooth.h | 47 ++++ ports/nrf/drivers/flash.c | 4 +- ports/nrf/modules/machine/temp.c | 6 +- ports/nrf/modules/random/modrandom.c | 4 +- ports/nrf/mpconfigport.h | 24 +- ports/nrf/nrfx_glue.h | 13 +- py/py.mk | 5 + 17 files changed, 1011 insertions(+), 53 deletions(-) create mode 100644 extmod/modbluetooth.c create mode 100644 extmod/modbluetooth.h create mode 100644 ports/esp32/bluetooth/bluetooth.c create mode 100644 ports/esp32/bluetooth/bluetooth.h create mode 100644 ports/nrf/bluetooth/bluetooth.c create mode 100644 ports/nrf/bluetooth/bluetooth.h diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c new file mode 100644 index 000000000000..4c57ecc88791 --- /dev/null +++ b/extmod/modbluetooth.c @@ -0,0 +1,150 @@ +/* + * 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/runtime.h" +#include "extmod/modbluetooth.h" + +#if MICROPY_PY_BLUETOOTH + +STATIC const mp_obj_type_t bluetooth_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; +} + +STATIC mp_obj_t bluetooth_make_new() { + 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 +#include "bluetooth/bluetooth.h" + +// 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, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len); + +// Stop advertisement. No-op when already stopped. +void mp_bt_advertise_stop(void); + +// 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) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ea90c9f3f5a9..c896298e45be 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 000000000000..4eb303928355 --- /dev/null +++ b/ports/esp32/bluetooth/bluetooth.c @@ -0,0 +1,205 @@ +/* + * 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 "py/mperrno.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 mp_bt_adv_type_t bluetooth_adv_type; +STATIC uint16_t bluetooth_adv_interval; + +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() { + 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); + } + err = esp_ble_gatts_app_register(0); + 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, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len) { + if (adv_data != NULL) { + esp_err_t err = esp_ble_gap_config_adv_data_raw(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(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); +} + +// 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_REG_EVT: + break; + case ESP_GATTS_CONNECT_EVT: + break; + case ESP_GATTS_DISCONNECT_EVT: + // restart advertisement + mp_bt_advertise_start_internal(); + break; + default: + ESP_LOGI("bluetooth", "GATTS: unknown event: %d", event); + break; + } +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/esp32/bluetooth/bluetooth.h b/ports/esp32/bluetooth/bluetooth.h new file mode 100644 index 000000000000..4021b5d922b7 --- /dev/null +++ b/ports/esp32/bluetooth/bluetooth.h @@ -0,0 +1,36 @@ +/* + * 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 + +#include "esp_gap_ble_api.h" + +typedef esp_ble_adv_type_t mp_bt_adv_type_t; + +#define MP_BT_ADV_TYPE_ADV_IND ADV_TYPE_IND +#define MP_BT_ADV_TYPE_ADV_NONCONN_IND ADV_TYPE_NONCONN_IND + +void mp_bt_init(void); diff --git a/ports/esp32/boards/sdkconfig b/ports/esp32/boards/sdkconfig index 23fc8dead589..4fdfe986f1b5 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 188fb5e70dd3..ec0cf193c687 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 7b9b40025035..23983f2303d0 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 6ca83f1e6e33..1a51f6a63d91 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. @@ -197,8 +200,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 +218,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 000000000000..896b5f3d0de3 --- /dev/null +++ b/ports/nrf/bluetooth/bluetooth.c @@ -0,0 +1,316 @@ +/* + * 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) { + if (err_code == NRF_ERROR_INVALID_PARAM) { + return MP_EINVAL; + } else if (err_code != 0) { + return MP_EPERM; + } + return 0; +} + +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, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len) { + 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; + uint32_t 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); + return mp_bt_errno(err_code); +#endif +} + +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 + } +} + +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/bluetooth/bluetooth.h b/ports/nrf/bluetooth/bluetooth.h new file mode 100644 index 000000000000..9d5b23028990 --- /dev/null +++ b/ports/nrf/bluetooth/bluetooth.h @@ -0,0 +1,47 @@ +/* + * 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 "ble_gap.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 + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/drivers/flash.c b/ports/nrf/drivers/flash.c index 5a7256a0c622..4e032227bc7c 100644 --- a/ports/nrf/drivers/flash.c +++ b/ports/nrf/drivers/flash.c @@ -29,7 +29,7 @@ #if MICROPY_MBFS && BLUETOOTH_SD #include "drivers/flash.h" -#include "drivers/bluetooth/ble_drv.h" +#include "extmod/modbluetooth.h" #include "nrf_soc.h" // Rotates bits in `value` left `shift` times. @@ -48,7 +48,7 @@ void flash_operation_finished(flash_state_t result) { } STATIC bool operation_wait(uint32_t result) { - if (ble_drv_stack_enabled() != 1) { + if (!mp_bt_is_enabled()) { // SoftDevice is not enabled, no event will be generated. return result == NRF_SUCCESS; } diff --git a/ports/nrf/modules/machine/temp.c b/ports/nrf/modules/machine/temp.c index 361d98885789..7e2eaa5a574a 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()) +#define BLUETOOTH_STACK_ENABLED() (mp_bt_is_enabled()) #endif // BLUETOOTH_SD #if MICROPY_PY_MACHINE_TEMP diff --git a/ports/nrf/modules/random/modrandom.c b/ports/nrf/modules/random/modrandom.c index f67bffb27786..1a45862200db 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()) +#define BLUETOOTH_STACK_ENABLED() (mp_bt_is_enabled()) #endif static inline uint32_t generate_hw_random(void) { diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 0e3cf7b39d6e..66ec09d1cb9d 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -187,10 +187,6 @@ #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 @@ -216,16 +212,10 @@ 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 mp_module_bluetooth; extern const struct _mp_obj_module_t music_module; extern const struct _mp_obj_module_t random_module; -#if MICROPY_PY_UBLUEPY -#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, -#else -#define UBLUEPY_MODULE -#endif - #if MICROPY_PY_MUSIC #define MUSIC_MODULE { MP_ROM_QSTR(MP_QSTR_music), MP_ROM_PTR(&music_module) }, #else @@ -247,28 +237,19 @@ extern const struct _mp_obj_module_t random_module; #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 - #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) }, \ { 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 \ + { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, \ 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 0108e3242fd1..d809e428aad4 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 0fbc9f14bbe3..5c93c870afac 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 \ From 9f059ed0d2c374986ba929e55048d0c3adc831cb Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 1 Aug 2018 13:34:59 +0200 Subject: [PATCH 2/8] extmod/modbluetooth: Add Bluetooth.advertise_raw(). This is useful for more advanced use cases, like iBeacon/Eddystone. --- extmod/modbluetooth.c | 44 +++++++++++++++++++++++++++++++ extmod/modbluetooth.h | 2 +- ports/esp32/bluetooth/bluetooth.c | 6 ++--- ports/nrf/bluetooth/bluetooth.c | 2 +- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 4c57ecc88791..a04852c76db4 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -123,9 +123,53 @@ STATIC mp_obj_t bluetooth_advertise(size_t n_args, const mp_obj_t *pos_args, mp_ } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_advertise_obj, 1, bluetooth_advertise); +STATIC mp_obj_t bluetooth_advertise_raw(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_interval, ARG_adv_data, ARG_sr_data, ARG_connectable }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_interval, MP_ARG_INT, {.u_int = 100} }, + { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_sr_data, 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 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 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) }, }; STATIC MP_DEFINE_CONST_DICT(bluetooth_locals_dict, bluetooth_locals_dict_table); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index b8987d5595f0..f7fa7638293d 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -40,7 +40,7 @@ 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, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len); +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); diff --git a/ports/esp32/bluetooth/bluetooth.c b/ports/esp32/bluetooth/bluetooth.c index 4eb303928355..d9a7c598c4fe 100644 --- a/ports/esp32/bluetooth/bluetooth.c +++ b/ports/esp32/bluetooth/bluetooth.c @@ -124,9 +124,9 @@ STATIC esp_err_t mp_bt_advertise_start_internal(void) { return esp_ble_gap_start_advertising(&ble_adv_params); } -int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len) { +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(adv_data, adv_data_len); + 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); } @@ -134,7 +134,7 @@ int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, uint8_t *adv } if (sr_data != NULL) { - esp_err_t err = esp_ble_gap_config_scan_rsp_data_raw(sr_data, sr_data_len); + 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); } diff --git a/ports/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c index 896b5f3d0de3..ec2f5f079280 100644 --- a/ports/nrf/bluetooth/bluetooth.c +++ b/ports/nrf/bluetooth/bluetooth.c @@ -198,7 +198,7 @@ STATIC uint32_t mp_bt_advertise_start_internal(void) { } #endif -int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len) { +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) { mp_bt_advertise_stop(); // restart if already started #if NRF51 From a7eaba94ce99c2ceef7c0d74f2faefec902119f1 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 1 Mar 2019 11:08:55 +0100 Subject: [PATCH 3/8] extmod/modbluetooth: Add Bluetooth.add_service(). At the moment, only a service is created. Characteristics within a service cannot yet be added. --- extmod/modbluetooth.c | 25 +++++++++ extmod/modbluetooth.h | 14 +++++ ports/esp32/bluetooth/bluetooth.c | 86 ++++++++++++++++++++++++++++--- ports/esp32/bluetooth/bluetooth.h | 4 ++ ports/nrf/bluetooth/bluetooth.c | 16 ++++++ ports/nrf/bluetooth/bluetooth.h | 4 ++ 6 files changed, 143 insertions(+), 6 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index a04852c76db4..449dfcf8f964 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -31,6 +31,7 @@ #if MICROPY_PY_BLUETOOTH STATIC const mp_obj_type_t bluetooth_type; +STATIC const mp_obj_type_t service_type; typedef struct _mp_obj_bluetooth_t { mp_obj_base_t base; @@ -166,10 +167,33 @@ STATIC mp_obj_t bluetooth_advertise_raw(size_t n_args, const mp_obj_t *pos_args, } 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_interval, ARG_adv_data, ARG_sr_data, ARG_connectable }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_bt_service_t *service = m_new_obj(mp_bt_service_t); + service->base.type = &service_type; + bluetooth_parse_uuid(args[0].u_obj, &service->uuid); + int errno_ = mp_bt_add_service(service); + bluetooth_handle_errno(errno_); + return service; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_add_service_obj, 1, bluetooth_add_service); + +STATIC const mp_obj_type_t service_type = { + { &mp_type_type }, + .name = MP_QSTR_Service, +}; + 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); @@ -183,6 +207,7 @@ STATIC const mp_obj_type_t bluetooth_type = { 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) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index f7fa7638293d..c20691485e60 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -28,6 +28,13 @@ #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; // Enables the Bluetooth stack. Returns errno on failure. int mp_bt_enable(void); @@ -45,6 +52,13 @@ int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_ // Stop advertisement. No-op when already stopped. void mp_bt_advertise_stop(void); +int mp_bt_add_service(mp_bt_service_t *service); + +// 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 bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_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) diff --git a/ports/esp32/bluetooth/bluetooth.c b/ports/esp32/bluetooth/bluetooth.c index d9a7c598c4fe..0dbfcb89b3ec 100644 --- a/ports/esp32/bluetooth/bluetooth.c +++ b/ports/esp32/bluetooth/bluetooth.c @@ -34,14 +34,21 @@ #include "freertos/semphr.h" #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; +} 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); @@ -94,10 +101,6 @@ int mp_bt_enable(void) { if (err != 0) { return mp_bt_esp_errno(err); } - err = esp_ble_gatts_app_register(0); - if (err != 0) { - return mp_bt_esp_errno(err); - } return 0; } @@ -159,6 +162,62 @@ void mp_bt_advertise_stop(void) { xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); } +int mp_bt_add_service(mp_bt_service_t *service) { + // 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; + + // 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, 1); + 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); + return mp_bt_status_errno(); +} + +// Parse a UUID object from the caller. +void bluetooth_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 { + mp_raise_ValueError("cannot parse UUID"); + } +} + // 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) { @@ -188,14 +247,29 @@ STATIC void mp_bt_gap_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_para 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_REG_EVT: - break; 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; default: ESP_LOGI("bluetooth", "GATTS: unknown event: %d", event); break; diff --git a/ports/esp32/bluetooth/bluetooth.h b/ports/esp32/bluetooth/bluetooth.h index 4021b5d922b7..3383b2f0b318 100644 --- a/ports/esp32/bluetooth/bluetooth.h +++ b/ports/esp32/bluetooth/bluetooth.h @@ -34,3 +34,7 @@ typedef esp_ble_adv_type_t mp_bt_adv_type_t; #define MP_BT_ADV_TYPE_ADV_NONCONN_IND ADV_TYPE_NONCONN_IND void mp_bt_init(void); + +typedef esp_bt_uuid_t mp_bt_uuid_t; + +typedef uint16_t mp_bt_service_handle_t; diff --git a/ports/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c index ec2f5f079280..fcfb3c942045 100644 --- a/ports/nrf/bluetooth/bluetooth.c +++ b/ports/nrf/bluetooth/bluetooth.c @@ -267,6 +267,22 @@ static void ble_evt_handler(ble_evt_t * p_ble_evt) { } } +int mp_bt_add_service(mp_bt_service_t *service) { + uint32_t err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service->uuid, &service->handle); + return mp_bt_errno(err_code); +} + +// Parse a UUID object from the caller. +void bluetooth_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 { + mp_raise_ValueError("cannot parse UUID"); + } +} + static void sd_evt_handler(uint32_t evt_id) { switch (evt_id) { #if MICROPY_MBFS diff --git a/ports/nrf/bluetooth/bluetooth.h b/ports/nrf/bluetooth/bluetooth.h index 9d5b23028990..af1dcc309f1e 100644 --- a/ports/nrf/bluetooth/bluetooth.h +++ b/ports/nrf/bluetooth/bluetooth.h @@ -44,4 +44,8 @@ typedef uint8_t mp_bt_adv_type_t; #define MP_BT_ADV_TYPE_ADV_NONCONN_IND BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED #endif +typedef ble_uuid_t mp_bt_uuid_t; + +typedef uint16_t mp_bt_service_handle_t; + #endif // MICROPY_PY_BLUETOOTH From d194ac2ec5ce164cd239a112532541ab41ea0ffb Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 1 Mar 2019 14:31:15 +0100 Subject: [PATCH 4/8] extmod/modbluetooth: Add support for 128-bit UUIDs. 128-bit proprietary UUIDs can be passed using strings. Dashes and capitalization are ignored. --- extmod/modbluetooth.c | 36 +++++++++++++++++++++++++++++++ extmod/modbluetooth.h | 4 ++++ ports/esp32/bluetooth/bluetooth.c | 4 ++++ ports/nrf/bluetooth/bluetooth.c | 12 +++++++++++ 4 files changed, 56 insertions(+) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 449dfcf8f964..167441a1d0f8 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -25,6 +25,7 @@ */ #include "py/obj.h" +#include "py/objstr.h" #include "py/runtime.h" #include "extmod/modbluetooth.h" @@ -51,6 +52,41 @@ STATIC mp_obj_t bluetooth_handle_errno(int errno_) { return mp_const_none; } +// Parse string UUIDs, which are probably 128-bit UUIDs. +void bluetooth_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"); + } +} + STATIC mp_obj_t bluetooth_make_new() { return MP_OBJ_FROM_PTR(&bluetooth_obj); } diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index c20691485e60..7f2deb1ea26f 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -59,6 +59,10 @@ int mp_bt_add_service(mp_bt_service_t *service); // UUIDs. void bluetooth_parse_uuid(mp_obj_t obj, 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 bluetooth_parse_uuid_str(mp_obj_t obj, 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) diff --git a/ports/esp32/bluetooth/bluetooth.c b/ports/esp32/bluetooth/bluetooth.c index 0dbfcb89b3ec..3cdf45dbb6d9 100644 --- a/ports/esp32/bluetooth/bluetooth.c +++ b/ports/esp32/bluetooth/bluetooth.c @@ -213,6 +213,10 @@ void bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { // 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; + bluetooth_parse_uuid_str(obj, &uuid->uuid.uuid128[0]); } else { mp_raise_ValueError("cannot parse UUID"); } diff --git a/ports/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c index fcfb3c942045..3a1e130b0c46 100644 --- a/ports/nrf/bluetooth/bluetooth.c +++ b/ports/nrf/bluetooth/bluetooth.c @@ -111,6 +111,8 @@ STATIC const ble_gap_conn_params_t gap_conn_params = { STATIC int mp_bt_errno(uint32_t err_code) { if (err_code == NRF_ERROR_INVALID_PARAM) { return MP_EINVAL; + } else if (err_code == NRF_ERROR_NO_MEM) { + return MP_ENOMEM; } else if (err_code != 0) { return MP_EPERM; } @@ -278,6 +280,16 @@ void bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { // 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. + uuid->type = BLE_UUID_TYPE_BLE; + ble_uuid128_t buf; + bluetooth_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"); } From 62de90d6b7c3ec15f729eead0a80d99428ab25f2 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 3 Mar 2019 17:37:25 +0100 Subject: [PATCH 5/8] extmod/modbluetooth: Add support for characteristics. Add support for adding characteristics to services. They can be read and written on both the esp32 and the nrf. Events of any kind (notifications etc.) haven't been implemented yet. --- extmod/modbluetooth.c | 156 +++++++++++++++++++++++++++--- extmod/modbluetooth.h | 35 ++++++- ports/esp32/bluetooth/bluetooth.c | 114 +++++++++++++++++++++- ports/esp32/bluetooth/bluetooth.h | 4 + ports/nrf/bluetooth/bluetooth.c | 115 ++++++++++++++++++++-- ports/nrf/bluetooth/bluetooth.h | 5 + 6 files changed, 400 insertions(+), 29 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 167441a1d0f8..f6c3de873b40 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -33,6 +33,7 @@ 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; @@ -53,7 +54,7 @@ STATIC mp_obj_t bluetooth_handle_errno(int errno_) { } // Parse string UUIDs, which are probably 128-bit UUIDs. -void bluetooth_parse_uuid_str(mp_obj_t obj, uint8_t *uuid) { +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++) { @@ -87,7 +88,36 @@ void bluetooth_parse_uuid_str(mp_obj_t obj, uint8_t *uuid) { } } -STATIC mp_obj_t bluetooth_make_new() { +// 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); } @@ -204,32 +234,130 @@ STATIC mp_obj_t bluetooth_advertise_raw(size_t n_args, const mp_obj_t *pos_args, 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_interval, ARG_adv_data, ARG_sr_data, ARG_connectable }; + enum { ARG_uuid, ARG_characteristics }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_uuid, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none } }, + { 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; - bluetooth_parse_uuid(args[0].u_obj, &service->uuid); - int errno_ = mp_bt_add_service(service); + 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_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) }, + { 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); @@ -241,9 +369,13 @@ STATIC const mp_obj_type_t bluetooth_type = { }; 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___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); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 7f2deb1ea26f..d62112535ddd 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -36,6 +36,16 @@ typedef struct { 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); @@ -52,16 +62,31 @@ int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_ // Stop advertisement. No-op when already stopped. void mp_bt_advertise_stop(void); -int mp_bt_add_service(mp_bt_service_t *service); +// 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 bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid); +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 bluetooth_parse_uuid_str(mp_obj_t obj, uint8_t *uuid); +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) @@ -71,3 +96,7 @@ void bluetooth_parse_uuid_str(mp_obj_t obj, uint8_t *uuid); #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) diff --git a/ports/esp32/bluetooth/bluetooth.c b/ports/esp32/bluetooth/bluetooth.c index 3cdf45dbb6d9..3ab9b0b16a7a 100644 --- a/ports/esp32/bluetooth/bluetooth.c +++ b/ports/esp32/bluetooth/bluetooth.c @@ -32,6 +32,7 @@ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#include #include "py/mperrno.h" #include "py/runtime.h" @@ -44,6 +45,7 @@ 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; @@ -62,7 +64,7 @@ STATIC int mp_bt_esp_errno(esp_err_t err) { } // Convert the result of an asynchronous call to an errno value. -STATIC int mp_bt_status_errno() { +STATIC int mp_bt_status_errno(void) { if (mp_bt_call_status != ESP_BT_STATUS_SUCCESS) { return MP_EPERM; } @@ -162,7 +164,7 @@ void mp_bt_advertise_stop(void) { xSemaphoreTake(mp_bt_call_complete, portMAX_DELAY); } -int mp_bt_add_service(mp_bt_service_t *service) { +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: @@ -181,12 +183,17 @@ int mp_bt_add_service(mp_bt_service_t *service) { } 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, 1); + err = esp_ble_gatts_create_service(gatts_if, &bluetooth_service_id, num_handle); if (err != 0) { return mp_bt_esp_errno(err); } @@ -204,11 +211,79 @@ int mp_bt_add_service(mp_bt_service_t *service) { } // 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 bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { +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; @@ -216,12 +291,24 @@ void bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { } else if (mp_obj_is_str(obj)) { // Guessing this is a 128-bit (proprietary) UUID. uuid->len = ESP_UUID_LEN_128; - bluetooth_parse_uuid_str(obj, &uuid->uuid.uuid128[0]); + 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) { @@ -274,6 +361,23 @@ STATIC void mp_bt_gatts_callback(esp_gatts_cb_event_t event, esp_gatt_if_t gatts 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; diff --git a/ports/esp32/bluetooth/bluetooth.h b/ports/esp32/bluetooth/bluetooth.h index 3383b2f0b318..fb787ca228f8 100644 --- a/ports/esp32/bluetooth/bluetooth.h +++ b/ports/esp32/bluetooth/bluetooth.h @@ -33,8 +33,12 @@ typedef esp_ble_adv_type_t mp_bt_adv_type_t; #define MP_BT_ADV_TYPE_ADV_IND ADV_TYPE_IND #define MP_BT_ADV_TYPE_ADV_NONCONN_IND ADV_TYPE_NONCONN_IND +#define MP_BT_MAX_ATTR_SIZE (20) + 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/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c index 3a1e130b0c46..85bd55e5c032 100644 --- a/ports/nrf/bluetooth/bluetooth.c +++ b/ports/nrf/bluetooth/bluetooth.c @@ -109,14 +109,24 @@ STATIC const ble_gap_conn_params_t gap_conn_params = { }; STATIC int mp_bt_errno(uint32_t err_code) { - if (err_code == NRF_ERROR_INVALID_PARAM) { + switch (err_code) { + case 0: + return 0; // no error + case NRF_ERROR_INVALID_PARAM: return MP_EINVAL; - } else if (err_code == NRF_ERROR_NO_MEM) { + case NRF_ERROR_NO_MEM: return MP_ENOMEM; - } else if (err_code != 0) { - return MP_EPERM; + 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 } - return 0; } int mp_bt_enable(void) { @@ -269,22 +279,93 @@ static void ble_evt_handler(ble_evt_t * p_ble_evt) { } } -int mp_bt_add_service(mp_bt_service_t *service) { +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 bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *uuid) { +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. - uuid->type = BLE_UUID_TYPE_BLE; ble_uuid128_t buf; - bluetooth_parse_uuid_str(obj, &buf.uuid128[0]); + 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)); @@ -295,6 +376,22 @@ void bluetooth_parse_uuid(mp_obj_t obj, mp_bt_uuid_t *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 diff --git a/ports/nrf/bluetooth/bluetooth.h b/ports/nrf/bluetooth/bluetooth.h index af1dcc309f1e..9ed705f5c2e6 100644 --- a/ports/nrf/bluetooth/bluetooth.h +++ b/ports/nrf/bluetooth/bluetooth.h @@ -31,6 +31,7 @@ #include #include "ble_gap.h" +#include "ble_gatt.h" typedef uint8_t mp_bt_adv_type_t; @@ -44,8 +45,12 @@ typedef uint8_t mp_bt_adv_type_t; #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 From c7b7604414c4b25e6170c5ec5f32dddef1f127b6 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 19 Mar 2019 22:51:43 +0100 Subject: [PATCH 6/8] nrf/bluetooth: Deprecate nrf-port ubluepy module. Removing nrf-port Bluetooth LE drivers and micropython wrapper objects/modules. Also, deprecating the legacy examples using ubluepy. --- ports/nrf/Makefile | 5 +- ports/nrf/bluetooth_conf.h | 46 - ports/nrf/drivers/bluetooth/ble_drv.c | 1181 ----------------- ports/nrf/drivers/bluetooth/ble_drv.h | 129 -- ports/nrf/drivers/bluetooth/ble_uart.c | 280 ---- ports/nrf/drivers/bluetooth/ble_uart.h | 42 - ports/nrf/drivers/bluetooth/ringbuffer.h | 99 -- ports/nrf/drivers/flash.c | 4 +- ports/nrf/examples/powerup.py | 213 --- ports/nrf/examples/ubluepy_eddystone.py | 58 - ports/nrf/examples/ubluepy_scan.py | 38 - ports/nrf/examples/ubluepy_temp.py | 92 -- ports/nrf/help.c | 7 - ports/nrf/modules/ble/help_sd.h | 47 - ports/nrf/modules/ble/modble.c | 105 -- ports/nrf/modules/machine/temp.c | 4 +- ports/nrf/modules/random/modrandom.c | 4 +- ports/nrf/modules/ubluepy/modubluepy.c | 70 - ports/nrf/modules/ubluepy/modubluepy.h | 200 --- .../modules/ubluepy/ubluepy_characteristic.c | 221 --- ports/nrf/modules/ubluepy/ubluepy_constants.c | 99 -- ports/nrf/modules/ubluepy/ubluepy_delegate.c | 89 -- .../nrf/modules/ubluepy/ubluepy_descriptor.c | 82 -- .../nrf/modules/ubluepy/ubluepy_peripheral.c | 498 ------- .../nrf/modules/ubluepy/ubluepy_scan_entry.c | 146 -- ports/nrf/modules/ubluepy/ubluepy_scanner.c | 127 -- ports/nrf/modules/ubluepy/ubluepy_service.c | 183 --- ports/nrf/modules/ubluepy/ubluepy_uuid.c | 171 --- ports/nrf/mpconfigport.h | 24 +- 29 files changed, 20 insertions(+), 4244 deletions(-) delete mode 100644 ports/nrf/bluetooth_conf.h delete mode 100644 ports/nrf/drivers/bluetooth/ble_drv.c delete mode 100644 ports/nrf/drivers/bluetooth/ble_drv.h delete mode 100644 ports/nrf/drivers/bluetooth/ble_uart.c delete mode 100644 ports/nrf/drivers/bluetooth/ble_uart.h delete mode 100644 ports/nrf/drivers/bluetooth/ringbuffer.h delete mode 100644 ports/nrf/examples/powerup.py delete mode 100644 ports/nrf/examples/ubluepy_eddystone.py delete mode 100644 ports/nrf/examples/ubluepy_scan.py delete mode 100644 ports/nrf/examples/ubluepy_temp.py delete mode 100644 ports/nrf/modules/ble/help_sd.h delete mode 100644 ports/nrf/modules/ble/modble.c delete mode 100644 ports/nrf/modules/ubluepy/modubluepy.c delete mode 100644 ports/nrf/modules/ubluepy/modubluepy.h delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_characteristic.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_constants.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_delegate.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_descriptor.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_peripheral.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_scan_entry.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_scanner.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_service.c delete mode 100644 ports/nrf/modules/ubluepy/ubluepy_uuid.c diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 1a51f6a63d91..b43dc83dc4e6 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -39,7 +39,7 @@ endif QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h ifneq ($(SD), ) -MICROPY_PY_BLUETOOTH = 1 +MICROPY_PY_BLUETOOTH ?= 1 endif MICROPY_FATFS ?= 0 FATFS_DIR = lib/oofatfs @@ -56,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 diff --git a/ports/nrf/bluetooth_conf.h b/ports/nrf/bluetooth_conf.h deleted file mode 100644 index 58d47e218868..000000000000 --- 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 ff3c885c153f..000000000000 --- 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 ac68959375ce..000000000000 --- 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 4a23cd6d2cc2..000000000000 --- 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/ble_uart.h b/ports/nrf/drivers/bluetooth/ble_uart.h deleted file mode 100644 index e67176a26feb..000000000000 --- a/ports/nrf/drivers/bluetooth/ble_uart.h +++ /dev/null @@ -1,42 +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 BLUETOOTH_LE_UART_H__ -#define BLUETOOTH_LE_UART_H__ - -#if BLUETOOTH_SD - -#include "modubluepy.h" -#include "ble_drv.h" - -void ble_uart_init0(void); -void ble_uart_advertise(void); -bool ble_uart_connected(void); -bool ble_uart_enabled(void); - -#endif // BLUETOOTH_SD - -#endif // BLUETOOTH_LE_UART_H__ diff --git a/ports/nrf/drivers/bluetooth/ringbuffer.h b/ports/nrf/drivers/bluetooth/ringbuffer.h deleted file mode 100644 index 3438b5c9b5bc..000000000000 --- 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 4e032227bc7c..a28d2f4f846e 100644 --- a/ports/nrf/drivers/flash.c +++ b/ports/nrf/drivers/flash.c @@ -32,6 +32,8 @@ #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 (!mp_bt_is_enabled()) { + 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 6f14309f39f3..000000000000 --- 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 c8abd5aea6ba..000000000000 --- 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 ab11661ccaa2..000000000000 --- 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 7df057bf4821..000000000000 --- 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 5856ef6e372d..10d236d97e6b 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/help_sd.h b/ports/nrf/modules/ble/help_sd.h deleted file mode 100644 index 027bbdd51348..000000000000 --- a/ports/nrf/modules/ble/help_sd.h +++ /dev/null @@ -1,47 +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 HELP_SD_H__ -#define HELP_SD_H__ - -#include "bluetooth_conf.h" - -#if MICROPY_PY_BLE - -#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 - -#endif diff --git a/ports/nrf/modules/ble/modble.c b/ports/nrf/modules/ble/modble.c deleted file mode 100644 index 2b6dd6e2236c..000000000000 --- 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 7e2eaa5a574a..c06c4dffcd22 100644 --- a/ports/nrf/modules/machine/temp.c +++ b/ports/nrf/modules/machine/temp.c @@ -35,7 +35,7 @@ #if BLUETOOTH_SD #include "extmod/modbluetooth.h" #include "nrf_soc.h" -#define BLUETOOTH_STACK_ENABLED() (mp_bt_is_enabled()) +extern bool RF_STACK_ENABLED(void); #endif // BLUETOOTH_SD #if MICROPY_PY_MACHINE_TEMP @@ -78,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 1a45862200db..9a10ce54db4f 100644 --- a/ports/nrf/modules/random/modrandom.c +++ b/ports/nrf/modules/random/modrandom.c @@ -38,7 +38,7 @@ #if BLUETOOTH_SD #include "extmod/modbluetooth.h" #include "nrf_soc.h" -#define BLUETOOTH_STACK_ENABLED() (mp_bt_is_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 b306c065b290..000000000000 --- 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 fbd07b8b9be7..000000000000 --- 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 2ca7f2f42759..000000000000 --- 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 14e433e6ebff..000000000000 --- 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 07bb7f49286f..000000000000 --- 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 b15301954d07..000000000000 --- 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 3a45e56a0764..000000000000 --- 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 773070b08907..000000000000 --- 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 f5c9a6dca808..000000000000 --- 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 e5bf42a09fd3..000000000000 --- 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 cbcb1009682f..000000000000 --- 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 66ec09d1cb9d..0cbf2ea2e7e9 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -178,19 +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_BLE_NUS -#define MICROPY_PY_BLE_NUS (0) -#endif - // type definitions for the specific machine #define BYTES_PER_WORD (4) @@ -212,9 +206,15 @@ 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_bluetooth; 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_BLUETOOTH +#define BLUETOOTH_MODULE { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, +#else +#define BLUETOOTH_MODULE +#endif #if MICROPY_PY_MUSIC #define MUSIC_MODULE { MP_ROM_QSTR(MP_QSTR_music), MP_ROM_PTR(&music_module) }, @@ -235,7 +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_BLUETOOTH #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ @@ -243,7 +243,7 @@ extern const struct _mp_obj_module_t random_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) }, \ - { MP_ROM_QSTR(MP_QSTR_bluetooth), MP_ROM_PTR(&mp_module_bluetooth) }, \ + BLUETOOTH_MODULE \ MUSIC_MODULE \ RANDOM_MODULE \ MICROPY_BOARD_BUILTINS \ From 593091844dccb1371716c2dc24b5b66079ea74e7 Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 19 Mar 2019 22:55:56 +0100 Subject: [PATCH 7/8] extmod/bluetooth: Guard header to only be used if enabled. --- extmod/modbluetooth.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index d62112535ddd..c665260e267f 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -26,6 +26,8 @@ #pragma once +#if MICROPY_PY_BLUETOOTH + #include #include "bluetooth/bluetooth.h" #include "py/obj.h" @@ -100,3 +102,5 @@ mp_obj_t mp_bt_format_uuid_str(uint8_t *uuid); #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 From 1c7e0c9248fb9a08f0f8f8b97096d6c6c26847ea Mon Sep 17 00:00:00 2001 From: Glenn Ruben Bakke Date: Tue, 19 Mar 2019 22:59:56 +0100 Subject: [PATCH 8/8] nrf/bluetooth: Return err_code from mp_bt_advertise_start. --- ports/nrf/bluetooth/bluetooth.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/nrf/bluetooth/bluetooth.c b/ports/nrf/bluetooth/bluetooth.c index 85bd55e5c032..fdba6ea7ab34 100644 --- a/ports/nrf/bluetooth/bluetooth.c +++ b/ports/nrf/bluetooth/bluetooth.c @@ -211,13 +211,14 @@ STATIC uint32_t mp_bt_advertise_start_internal(void) { #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; - uint32_t err_code = mp_bt_advertise_start_internal(); + err_code = mp_bt_advertise_start_internal(); return mp_bt_errno(err_code); #elif NRF52 @@ -249,8 +250,11 @@ int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, const uint8_ } err_code = sd_ble_gap_adv_start(bluetooth_adv_handle, BLE_CONN_CFG_TAG_DEFAULT); - return mp_bt_errno(err_code); +#else + (void)bluetooth_sr_data; + (void)bluetooth_adv_data; #endif + return mp_bt_errno(err_code); } void mp_bt_advertise_stop(void) {