summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-12-28 22:55:29 -0500
committerDan Halbert <halbert@halwitz.org>2018-12-28 23:34:23 -0500
commit4d1f0ec07be5e9cacaf0072a0f987871b8505ec4 (patch)
tree2cb328eb77d8c9732ecd24580b33869fa8a3c505 /ports
parent4167bf5b241eec4e5a04c36d7f7c66d43a8bb921 (diff)
Add Broadcaster. Reset correctly on reload.
Diffstat (limited to 'ports')
-rwxr-xr-xports/nrf/Makefile1
-rw-r--r--ports/nrf/bluetooth/ble_drv.c7
-rw-r--r--ports/nrf/bluetooth/ble_drv.h3
-rw-r--r--ports/nrf/common-hal/bleio/Adapter.c20
-rw-r--r--ports/nrf/common-hal/bleio/Broadcaster.c113
-rw-r--r--ports/nrf/common-hal/bleio/Broadcaster.h47
-rw-r--r--ports/nrf/common-hal/bleio/LocalPeripheral.c329
-rw-r--r--ports/nrf/common-hal/bleio/LocalPeripheral.h64
-rw-r--r--ports/nrf/common-hal/bleio/__init__.c7
-rw-r--r--ports/nrf/common-hal/bleio/__init__.h42
-rw-r--r--ports/nrf/supervisor/port.c3
11 files changed, 618 insertions, 18 deletions
diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index c427cdd26..58db910c1 100755
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -172,6 +172,7 @@ ifneq ($(SD), )
SRC_COMMON_HAL += \
bleio/__init__.c \
bleio/Adapter.c \
+ bleio/Broadcaster.c \
bleio/Characteristic.c \
bleio/Descriptor.c \
bleio/LocalPeripheral.c \
diff --git a/ports/nrf/bluetooth/ble_drv.c b/ports/nrf/bluetooth/ble_drv.c
index 0b6daf711..41d51cfb4 100644
--- a/ports/nrf/bluetooth/ble_drv.c
+++ b/ports/nrf/bluetooth/ble_drv.c
@@ -45,7 +45,12 @@ typedef struct event_handler {
ble_drv_evt_handler_t func;
} event_handler_t;
-static event_handler_t *m_event_handlers;
+static event_handler_t *m_event_handlers = NULL;
+
+void ble_drv_reset() {
+ // Linked-list members will be gc'd.
+ m_event_handlers = NULL;
+}
void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param) {
event_handler_t *handler = m_new_ll(event_handler_t, 1);
diff --git a/ports/nrf/bluetooth/ble_drv.h b/ports/nrf/bluetooth/ble_drv.h
index 0443b41b8..696aff1da 100644
--- a/ports/nrf/bluetooth/ble_drv.h
+++ b/ports/nrf/bluetooth/ble_drv.h
@@ -43,11 +43,14 @@
#define BLE_CONN_CFG_TAG_CUSTOM 1
#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))
+// 0.625 msecs (625 usecs)
+#define ADV_INTERVAL_UNIT_FLOAT_SECS (0.000625)
#define UNIT_0_625_MS (625)
#define UNIT_10_MS (10000)
typedef void (*ble_drv_evt_handler_t)(ble_evt_t*, void*);
+void ble_drv_reset();
void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param);
#endif // MICROPY_INCLUDED_NRF_BLUETOOTH_BLE_DRV_H
diff --git a/ports/nrf/common-hal/bleio/Adapter.c b/ports/nrf/common-hal/bleio/Adapter.c
index 318502e95..cd116711e 100644
--- a/ports/nrf/common-hal/bleio/Adapter.c
+++ b/ports/nrf/common-hal/bleio/Adapter.c
@@ -44,17 +44,11 @@ STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) {
STATIC uint32_t ble_stack_enable(void) {
nrf_clock_lf_cfg_t clock_config = {
.source = NRF_CLOCK_LF_SRC_XTAL,
-#if (BLE_API_VERSION == 4)
.accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM
-#else
- .xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM
-#endif
};
-#if (BLUETOOTH_SD == 140)
// The SD takes over the POWER IRQ and will fail if the IRQ is already in use
nrfx_power_uninit();
-#endif
uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler);
if (err_code != NRF_SUCCESS)
@@ -64,17 +58,10 @@ STATIC uint32_t ble_stack_enable(void) {
if (err_code != NRF_SUCCESS)
return err_code;
- uint32_t app_ram_start;
-#if (BLE_API_VERSION == 2)
- ble_enable_params_t ble_enable_params = {
- .gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT,
- .gap_enable_params.central_conn_count = 1,
- .gap_enable_params.periph_conn_count = 1,
- };
+ // Start with no event handlers, etc.
+ ble_drv_reset();
- app_ram_start = 0x200039c0;
- err_code = sd_ble_enable(&ble_enable_params, &app_ram_start);
-#else
+ uint32_t app_ram_start;
app_ram_start = 0x20004000;
ble_cfg_t ble_conf;
@@ -100,7 +87,6 @@ STATIC uint32_t ble_stack_enable(void) {
return err_code;
err_code = sd_ble_enable(&app_ram_start);
-#endif
return err_code;
}
diff --git a/ports/nrf/common-hal/bleio/Broadcaster.c b/ports/nrf/common-hal/bleio/Broadcaster.c
new file mode 100644
index 000000000..508ede1d6
--- /dev/null
+++ b/ports/nrf/common-hal/bleio/Broadcaster.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ *
+ * 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 <string.h>
+
+#include "ble.h"
+#include "ble_drv.h"
+#include "ble_hci.h"
+#include "nrf_soc.h"
+#include "py/runtime.h"
+
+#include "common-hal/bleio/Broadcaster.h"
+#include "shared-bindings/bleio/Adapter.h"
+#include "shared-bindings/bleio/Broadcaster.h"
+
+static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
+
+STATIC void check_data_fit(size_t pos, size_t data_len) {
+ if (pos + data_len >= BLE_GAP_ADV_SET_DATA_SIZE_MAX) {
+ mp_raise_ValueError(translate("Data too large for advertisement packet"));
+ }
+}
+
+void common_hal_bleio_broadcaster_construct(bleio_broadcaster_obj_t *self, mp_float_t interval) {
+ common_hal_bleio_adapter_set_enabled(true); // TODO -- Do this somewhere else maybe bleio __init__
+ const mp_float_t min = BLE_GAP_ADV_INTERVAL_MIN * ADV_INTERVAL_UNIT_FLOAT_SECS;
+ const mp_float_t max = BLE_GAP_ADV_INTERVAL_MAX * ADV_INTERVAL_UNIT_FLOAT_SECS;
+
+ if (interval < min || interval > max) {
+ // Would like to print range using the constants above, but vargs would convert to double.
+ mp_raise_ValueError(translate("interval not in range 0.0020 to 10.24"));
+ }
+ self->interval = interval;
+}
+
+
+void common_hal_bleio_broadcaster_start_advertising(bleio_broadcaster_obj_t *self, mp_buffer_info_t *data) {
+ size_t adv_data_pos = 0;
+ uint32_t err_code;
+
+ // Build up advertising packet.
+ check_data_fit(adv_data_pos, 1 + 1 + 1);
+ self->adv_data[adv_data_pos++] = 2;
+ self->adv_data[adv_data_pos++] = BLE_GAP_AD_TYPE_FLAGS;
+ self->adv_data[adv_data_pos++] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
+
+ // Data is always send as manufacturer-specific data
+ check_data_fit(adv_data_pos, 1 + 1 + data->len);
+ self->adv_data[adv_data_pos++] = 1 + data->len;
+ self->adv_data[adv_data_pos++] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
+ memcpy(&(self->adv_data[adv_data_pos]), data->buf, data->len);
+ adv_data_pos += data->len;
+
+ ble_gap_adv_params_t m_adv_params = {
+ .interval = (uint32_t) (self->interval / ADV_INTERVAL_UNIT_FLOAT_SECS),
+ .properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED,
+ .duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED,
+ .filter_policy = BLE_GAP_ADV_FP_ANY,
+ .primary_phy = BLE_GAP_PHY_1MBPS,
+ };
+
+ common_hal_bleio_broadcaster_stop_advertising(self);
+
+ const ble_gap_adv_data_t ble_gap_adv_data = {
+ .adv_data.p_data = self->adv_data,
+ .adv_data.len = adv_data_pos,
+ };
+
+ err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &ble_gap_adv_data, &m_adv_params);
+ if (err_code == NRF_SUCCESS) {
+ err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_CONN_CFG_TAG_CUSTOM);
+ }
+
+ if (err_code != NRF_SUCCESS) {
+ mp_raise_OSError_msg_varg(translate("Failed to start advertising, err 0x%04x"), err_code);
+ }
+}
+
+void common_hal_bleio_broadcaster_stop_advertising(bleio_broadcaster_obj_t *self) {
+
+ if (m_adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) {
+ return;
+ }
+
+ const uint32_t err_code = sd_ble_gap_adv_stop(m_adv_handle);
+
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) {
+ mp_raise_OSError_msg_varg(translate("Failed to stop advertising, err 0x%04x"), err_code);
+ }
+}
diff --git a/ports/nrf/common-hal/bleio/Broadcaster.h b/ports/nrf/common-hal/bleio/Broadcaster.h
new file mode 100644
index 000000000..72f93a443
--- /dev/null
+++ b/ports/nrf/common-hal/bleio/Broadcaster.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H
+#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H
+
+#include "ble.h"
+
+#include "shared-module/bleio/__init__.h"
+#include "shared-module/bleio/Address.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ // In seconds.
+ mp_float_t interval;
+ // The advertising data buffer is held by us, not by the SD, so we must
+ // maintain it and not change it. If we need to change its contents during advertising,
+ // there are tricks to get the SD to notice (see DevZone - TBS).
+ uint8_t adv_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
+
+} bleio_broadcaster_obj_t;
+
+#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H
diff --git a/ports/nrf/common-hal/bleio/LocalPeripheral.c b/ports/nrf/common-hal/bleio/LocalPeripheral.c
new file mode 100644
index 000000000..2a502c8dd
--- /dev/null
+++ b/ports/nrf/common-hal/bleio/LocalPeripheral.c
@@ -0,0 +1,329 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "ble.h"
+#include "ble_drv.h"
+#include "ble_hci.h"
+#include "nrf_soc.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/bleio/Adapter.h"
+#include "shared-bindings/bleio/Characteristic.h"
+#include "shared-bindings/bleio/LocalPeripheral.h"
+#include "shared-bindings/bleio/Service.h"
+#include "shared-bindings/bleio/UUID.h"
+
+#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS)
+#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS)
+#define BLE_SLAVE_LATENCY 0
+#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
+
+#define BLE_ADV_LENGTH_FIELD_SIZE 1
+#define BLE_ADV_AD_TYPE_FIELD_SIZE 1
+#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1
+
+static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
+
+STATIC void check_data_fit(size_t pos, size_t data_len) {
+ if (pos + data_len >= BLE_GAP_ADV_SET_DATA_SIZE_MAX) {
+ mp_raise_ValueError(translate("Data too large for advertisement packet"));
+ }
+}
+
+STATIC uint32_t add_services_to_advertisement(bleio_local_peripheral_obj_t *self, size_t* adv_data_pos_p, size_t uuid_len) {
+ uint32_t uuids_total_size = 0;
+ const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
+ uint32_t err_code = NRF_SUCCESS;
+
+ check_data_fit(*adv_data_pos_p, 1 + 1);
+
+ // Remember where length byte is; fill in later when we know the size.
+ const size_t length_pos = *adv_data_pos_p;
+ (*adv_data_pos_p)++;
+
+ self->adv_data[(*adv_data_pos_p)++] = (uuid_len == 16)
+ ? BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE
+ : BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE;
+
+ for (size_t i = 0; i < service_list->len; ++i) {
+ const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]);
+ uint8_t encoded_size = 0;
+
+ // Skip services of the wrong length and secondary services.
+ if (common_hal_bleio_uuid_get_size(service->uuid) != uuid_len || service->is_secondary) {
+ continue;
+ }
+
+ ble_uuid_t uuid;
+ bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid);
+
+ err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &(self->adv_data[*adv_data_pos_p]));
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ check_data_fit(*adv_data_pos_p, encoded_size);
+ uuids_total_size += encoded_size;
+ (*adv_data_pos_p) += encoded_size;
+ }
+
+ self->adv_data[length_pos] = 1 + uuids_total_size; // 1 for the field type.
+ return err_code;
+}
+
+
+
+STATIC uint32_t set_advertisement_data(bleio_local_peripheral_obj_t *self, bool connectable, mp_buffer_info_t *raw_data) {
+ common_hal_bleio_adapter_set_enabled(true);
+
+ size_t adv_data_pos = 0;
+ uint32_t err_code;
+
+ GET_STR_DATA_LEN(self->name, name_data, name_len);
+ if (name_len > 0) {
+ ble_gap_conn_sec_mode_t sec_mode;
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
+
+ // We'll add the name after everything else, shortening it if necessary.
+ err_code = sd_ble_gap_device_name_set(&sec_mode, name_data, name_len);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+ }
+
+ if (raw_data->len != 0) {
+ // User-supplied advertising packet.
+ check_data_fit(adv_data_pos, raw_data->len);
+ memcpy(&(self->adv_data[adv_data_pos]), raw_data->buf, raw_data->len);
+ adv_data_pos += raw_data->len;
+ } else {
+ // Build up advertising packet.
+ check_data_fit(adv_data_pos, 1 + 1 + 1);
+ self->adv_data[adv_data_pos++] = 2;
+ self->adv_data[adv_data_pos++] = BLE_GAP_AD_TYPE_FLAGS;
+ self->adv_data[adv_data_pos++] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
+
+ // The 16-bit ids and 128-bit ids are grouped together by length, so find it whether we have
+ // 16 and/or 128-bit service UUIDs.
+
+ const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
+ if (service_list->len > 0) {
+ bool has_128bit_services = false;
+ bool has_16bit_services = false;
+
+ for (size_t i = 0; i < service_list->len; ++i) {
+ const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]);
+
+ if (service->is_secondary) {
+ continue;
+ }
+
+ switch (common_hal_bleio_uuid_get_size(service->uuid)) {
+ case 16:
+ has_16bit_services = true;
+ break;
+ case 128:
+ has_128bit_services = true;
+ break;
+ }
+ }
+
+ // Add 16-bit service UUID's in a group, then 128-bit service UUID's.
+
+ if (has_16bit_services) {
+ err_code = add_services_to_advertisement(self, &adv_data_pos, 16);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+ }
+
+ if (has_128bit_services) {
+ err_code = add_services_to_advertisement(self, &adv_data_pos, 128);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+ }
+ }
+
+ // Always include TX power.
+ check_data_fit(adv_data_pos, 1 + 1 + 1);
+ self->adv_data[adv_data_pos++] = 1 + 1;
+ self->adv_data[adv_data_pos++] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
+ self->adv_data[adv_data_pos++] = 0; // TODO - allow power level to be set later.
+
+ // We need room for at least a one-character name.
+ check_data_fit(adv_data_pos, 1 + 1 + 1);
+
+ // How big a name can we fit?
+ size_t bytes_left = BLE_GAP_ADV_SET_DATA_SIZE_MAX - adv_data_pos - 1 - 1;
+ size_t partial_name_len = MIN(bytes_left, name_len);
+ self->adv_data[adv_data_pos++] = 1 + partial_name_len;
+ self->adv_data[adv_data_pos++] = (partial_name_len == name_len)
+ ? BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME
+ : BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
+ memcpy(&(self->adv_data[adv_data_pos]), name_data, partial_name_len);
+ adv_data_pos += partial_name_len;
+ } // end of advertising packet construction
+
+ static ble_gap_adv_params_t m_adv_params = {
+ .interval = MSEC_TO_UNITS(1000, UNIT_0_625_MS),
+ .properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED,
+ .duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED,
+ .filter_policy = BLE_GAP_ADV_FP_ANY,
+ .primary_phy = BLE_GAP_PHY_1MBPS,
+ };
+
+ if (!connectable) {
+ m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
+ }
+
+ common_hal_bleio_local_peripheral_stop_advertising(self);
+
+ const ble_gap_adv_data_t ble_gap_adv_data = {
+ .adv_data.p_data = self->adv_data,
+ .adv_data.len = adv_data_pos,
+ };
+
+ err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &ble_gap_adv_data, &m_adv_params);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_CONN_CFG_TAG_CUSTOM);
+
+ return err_code;
+}
+
+STATIC void on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
+ bleio_local_peripheral_obj_t *self = (bleio_local_peripheral_obj_t*)self_in;
+
+ switch (ble_evt->header.evt_id) {
+ case BLE_GAP_EVT_CONNECTED: {
+ // Central has connected.
+ ble_gap_conn_params_t conn_params;
+ self->conn_handle = ble_evt->evt.gap_evt.conn_handle;
+ sd_ble_gap_ppcp_get(&conn_params);
+ sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params);
+ break;
+ }
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ // Central has disconnected.
+ self->conn_handle = BLE_CONN_HANDLE_INVALID;
+ break;
+
+ case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
+ ble_gap_phys_t const phys = {
+ .rx_phys = BLE_GAP_PHY_AUTO,
+ .tx_phys = BLE_GAP_PHY_AUTO,
+ };
+ sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys);
+ break;
+ }
+
+ case BLE_GAP_EVT_ADV_SET_TERMINATED:
+ // Someday may handle timeouts or limit reached.
+ break;
+
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
+ break;
+
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: {
+ ble_gap_evt_conn_param_update_request_t *request = &ble_evt->evt.gap_evt.params.conn_param_update_request;
+ sd_ble_gap_conn_param_update(self->conn_handle, &request->conn_params);
+ break;
+ }
+
+ case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: {
+ sd_ble_gatts_exchange_mtu_reply(self->conn_handle, BLE_GATT_ATT_MTU_DEFAULT);
+ break;
+ }
+
+ }
+}
+
+
+void common_hal_bleio_local_peripheral_construct(bleio_local_peripheral_obj_t *self) {
+ common_hal_bleio_adapter_set_enabled(true); // TODO -- Do this somewhere else maybe bleio __init__
+
+ self->gatt_role = GATT_ROLE_NONE;
+ self->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ // Add all the services.
+
+ mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
+ for (size_t service_idx = 0; service_idx < service_list->len; ++service_idx) {
+ bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[service_idx]);
+
+ ble_uuid_t uuid;
+ bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid);
+
+ uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY;
+ if (service->is_secondary) {
+ service_type = BLE_GATTS_SRVC_TYPE_SECONDARY;
+ }
+
+ const uint32_t err_code = sd_ble_gatts_service_add(service_type, &uuid, &service->handle);
+ if (err_code != NRF_SUCCESS) {
+ mp_raise_OSError_msg_varg(translate("Failed to add service, err 0x%04x"), err_code);
+ }
+
+ // Once the service has been registered, its characteristics can be added.
+ common_hal_bleio_service_add_all_characteristics(service);
+ }
+}
+
+
+bool common_hal_bleio_local_peripheral_get_connected(bleio_local_peripheral_obj_t *self) {
+ return self->conn_handle != BLE_CONN_HANDLE_INVALID;
+}
+
+void common_hal_bleio_local_peripheral_start_advertising(bleio_local_peripheral_obj_t *self, bool connectable, mp_buffer_info_t *raw_data) {
+ if (connectable) {
+ ble_drv_add_event_handler(on_ble_evt, self);
+ }
+
+ const uint32_t err_code = set_advertisement_data(self, connectable, raw_data);
+ if (err_code != NRF_SUCCESS) {
+ mp_raise_OSError_msg_varg(translate("Failed to start advertising, err 0x%04x"), err_code);
+ }
+}
+
+void common_hal_bleio_local_peripheral_stop_advertising(bleio_local_peripheral_obj_t *self) {
+
+ if (m_adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET)
+ return;
+
+ const uint32_t err_code = sd_ble_gap_adv_stop(m_adv_handle);
+
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) {
+ mp_raise_OSError_msg_varg(translate("Failed to stop advertising, err 0x%04x"), err_code);
+ }
+}
diff --git a/ports/nrf/common-hal/bleio/LocalPeripheral.h b/ports/nrf/common-hal/bleio/LocalPeripheral.h
new file mode 100644
index 000000000..8d84867ae
--- /dev/null
+++ b/ports/nrf/common-hal/bleio/LocalPeripheral.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_LOCALPERIPHERAL_H
+#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_LOCALPERIPHERAL_H
+
+#include <stdbool.h>
+
+#include "ble.h"
+
+#include "shared-module/bleio/__init__.h"
+#include "shared-module/bleio/Address.h"
+
+// typedef struct {
+// mp_obj_base_t base;
+// bool is_peripheral;
+// mp_obj_t name;
+// bleio_address_obj_t address;
+// volatile uint16_t conn_handle;
+// mp_obj_t service_list;
+// mp_obj_t notif_handler;
+// mp_obj_t conn_handler;
+// } bleio_device_obj_t;
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_obj_t name;
+ gatt_role_t gatt_role;
+ volatile uint16_t conn_handle;
+ mp_obj_t service_list;
+ mp_obj_t notif_handler;
+ mp_obj_t conn_handler;
+ // The advertising data buffer is held by us, not by the SD, so we must
+ // maintain it and not change it. If we need to change its contents during advertising,
+ // there are tricks to get the SD to notice (see DevZone - TBS).
+ uint8_t adv_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
+
+} bleio_local_peripheral_obj_t;
+
+#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_LOCALPERIPHERAL_H
diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c
index f795e889b..5a8a7ff16 100644
--- a/ports/nrf/common-hal/bleio/__init__.c
+++ b/ports/nrf/common-hal/bleio/__init__.c
@@ -30,6 +30,13 @@
#include "shared-bindings/bleio/LocalPeripheral.h"
#include "common-hal/bleio/__init__.h"
+// Turn off BLE on a reset or reload.
+void bleio_reset() {
+ if (common_hal_bleio_adapter_get_enabled()) {
+ common_hal_bleio_adapter_set_enabled(false);
+ }
+}
+
// The singleton bleio.Adapter object, bound to bleio.adapter
// It currently only has properties and no state
const super_adapter_obj_t common_hal_bleio_adapter_obj = {
diff --git a/ports/nrf/common-hal/bleio/__init__.h b/ports/nrf/common-hal/bleio/__init__.h
new file mode 100644
index 000000000..9e044f37c
--- /dev/null
+++ b/ports/nrf/common-hal/bleio/__init__.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_INIT_H
+#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_INIT_H
+
+#include "shared-bindings/bleio/__init__.h"
+#include "shared-bindings/bleio/Adapter.h"
+
+#include "shared-module/bleio/__init__.h"
+
+// We assume variable length data.
+// 20 bytes max (23 - 3).
+#define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3)
+
+gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device);
+uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device);
+
+#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_INIT_H
diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c
index ece5bae29..cf0434793 100644
--- a/ports/nrf/supervisor/port.c
+++ b/ports/nrf/supervisor/port.c
@@ -38,6 +38,7 @@
#include "shared-module/gamepad/__init__.h"
#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/bleio/__init__.h"
#include "common-hal/busio/I2C.h"
#include "common-hal/busio/SPI.h"
#include "common-hal/pulseio/PWMOut.h"
@@ -86,6 +87,8 @@ void reset_port(void) {
pulseout_reset();
timers_reset();
+ bleio_reset();
+
reset_all_pins();
}