You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by na...@apache.org on 2020/09/17 08:34:24 UTC

[mynewt-nimble] 02/02: apps/mesh_badge: Port app to Mynewt

This is an automated email from the ASF dual-hosted git repository.

naraj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 240e72f5afd06e37c60c7687f787f748f5c0b5cc
Author: MichaƂ Narajowski <mi...@codecoup.pl>
AuthorDate: Wed Nov 28 10:32:35 2018 +0100

    apps/mesh_badge: Port app to Mynewt
---
 apps/mesh_badge/CMakeLists.txt            |   5 -
 apps/mesh_badge/{README.rst => README.md} |  30 +--
 apps/mesh_badge/pkg.yml                   |  39 +++
 apps/mesh_badge/prj.conf                  |  66 -----
 apps/mesh_badge/sample.yaml               |   8 -
 apps/mesh_badge/src/board.h               |   4 +
 apps/mesh_badge/src/gatt_svr.c            | 226 ++++++++++++++++
 apps/mesh_badge/src/main.c                | 426 ++++++++++++++++++++----------
 apps/mesh_badge/src/mesh.c                | 153 ++++++++---
 apps/mesh_badge/src/mesh.h                |   8 +-
 apps/mesh_badge/src/mesh_badge.h          |  28 ++
 apps/mesh_badge/src/reel_board.c          | 349 +++++++++++++++++++-----
 apps/mesh_badge/syscfg.yml                |  57 ++++
 13 files changed, 1055 insertions(+), 344 deletions(-)

diff --git a/apps/mesh_badge/CMakeLists.txt b/apps/mesh_badge/CMakeLists.txt
deleted file mode 100644
index c5861dd..0000000
--- a/apps/mesh_badge/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-cmake_minimum_required(VERSION 3.8.2)
-include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
-project(NONE)
-
-target_sources(app PRIVATE src/main.c src/mesh.c src/${BOARD}.c)
diff --git a/apps/mesh_badge/README.rst b/apps/mesh_badge/README.md
similarity index 62%
rename from apps/mesh_badge/README.rst
rename to apps/mesh_badge/README.md
index f695896..8d2b3fa 100644
--- a/apps/mesh_badge/README.rst
+++ b/apps/mesh_badge/README.md
@@ -1,9 +1,7 @@
-.. _mesh_badge:
+### Mesh Badge
 
-Mesh Badge
-##########
 
-Overview
+##### Overview
 ********
 
 This sample app for the reel board showcases Bluetooth Mesh
@@ -14,27 +12,27 @@ Android and iOS) to access the service that the app exposes. The service
 can also be accessed with any Bluetooth LE GATT client from your PC,
 however these instructions focus on the necessary steps for phones.
 
-Steps to set up
+##### Steps to set up
 ***************
 
-#. On your phone, use the nRF Connect app to Scan for devices and look
+* On your phone, use the nRF Connect app to Scan for devices and look
    for "reel board"
-#. Connect to the device. You'll see a single service - select it
-#. Request to write to the characteristic by pressing on the upward pointing
+* Connect to the device. You'll see a single service - select it
+* Request to write to the characteristic by pressing on the upward pointing
    arrow symbol
-#. Select "Text" to enter text instead of hex
-#. Enter your name (or any other arbitrary text). Multiple words
+* Select "Text" to enter text instead of hex
+* Enter your name (or any other arbitrary text). Multiple words
    separated by spaces are possible. The font used on the reel display
    allows three rows of up to 12 characters
    wide text. You can force line breaks with a comma.
-#. Press "Send" - this will trigger pairing since this is a protected
+* Press "Send" - this will trigger pairing since this is a protected
    characteristic. The passkey for the pairing will be shown on the board's
    display. Enter the passkey in your phone.
-#. Once pairing is complete the board will show the text you sent. If
+* Once pairing is complete the board will show the text you sent. If
    you're not happy with it you can try writing something else.
-#. When you're happy with the text, disconnect from the board (exit the app or
+* When you're happy with the text, disconnect from the board (exit the app or
    go back to the device scan page)
-#. Once disconnected the board switches over to Bluetooth Mesh mode, and you
+* Once disconnected the board switches over to Bluetooth Mesh mode, and you
    can't connect to it anymore over GATT.
 
 If you configure multiple boards like this they can communicate with
@@ -45,6 +43,6 @@ the network and cause the other boards to display "<name> says hi!".
 To reset a board to its initial state (disable mesh, erase the stored
 text, and make it connectable over GATT):
 
-#. Keep the user button pressed when powering on (or press the reset button
+* Keep the user button pressed when powering on (or press the reset button
    when powered)
-#. Wait until "Reseting Device" is shown
+* Wait until "Reseting Device" is shown
diff --git a/apps/mesh_badge/pkg.yml b/apps/mesh_badge/pkg.yml
new file mode 100644
index 0000000..0718236
--- /dev/null
+++ b/apps/mesh_badge/pkg.yml
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+pkg.name: apps/mesh_badge
+pkg.type: app
+pkg.description: Sample app for the reel board that showcases Bluetooth Mesh
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - "@apache-mynewt-core/hw/drivers/display/cfb"
+    - "@apache-mynewt-core/hw/drivers/display/ssd1673"
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/sys/console/full"
+    - "@apache-mynewt-core/sys/log/full"
+    - "@apache-mynewt-core/sys/log/modlog"
+    - "@apache-mynewt-core/sys/stats/full"
+    - "@apache-mynewt-core/sys/shell"
+    - nimble/controller
+    - nimble/host
+    - nimble/host/services/gap
+    - nimble/host/services/gatt
+    - nimble/host/store/config
+    - nimble/transport/ram
diff --git a/apps/mesh_badge/prj.conf b/apps/mesh_badge/prj.conf
deleted file mode 100644
index 206ba5a..0000000
--- a/apps/mesh_badge/prj.conf
+++ /dev/null
@@ -1,66 +0,0 @@
-CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
-CONFIG_BT_RX_STACK_SIZE=4096
-
-CONFIG_BT_DEVICE_NAME_DYNAMIC=y
-CONFIG_BT_DEVICE_NAME_GATT_WRITABLE=y
-CONFIG_BT_SMP=y
-CONFIG_BT_PERIPHERAL=y
-CONFIG_BT_PRIVACY=y
-CONFIG_BT_DEVICE_NAME="reel board"
-CONFIG_BT_DEVICE_NAME_MAX=32
-
-CONFIG_BT_DEBUG_LOG=y
-CONFIG_BT_MESH_DEBUG=y
-#CONFIG_BT_DEBUG_HCI_CORE=y
-#CONFIG_BT_MESH_DEBUG_ADV=y
-
-CONFIG_BT_OBSERVER=y
-CONFIG_BT_BROADCASTER=y
-CONFIG_BT_RX_BUF_COUNT=30
-CONFIG_BT_L2CAP_RX_MTU=69
-CONFIG_BT_L2CAP_TX_MTU=69
-CONFIG_BT_L2CAP_TX_BUF_COUNT=8
-
-CONFIG_BT_MESH=y
-CONFIG_BT_MESH_RELAY=y
-#CONFIG_BT_MESH_GATT_PROXY=y
-CONFIG_BT_MESH_PB_ADV=n
-CONFIG_BT_MESH_PB_GATT=n
-CONFIG_BT_MESH_ADV_BUF_COUNT=30
-CONFIG_BT_MESH_LABEL_COUNT=0
-CONFIG_BT_MESH_CFG_CLI=y
-CONFIG_BT_MESH_TX_SEG_MAX=6
-CONFIG_BT_MESH_TX_SEG_MSG_COUNT=3
-CONFIG_BT_MESH_RX_SEG_MSG_COUNT=3
-CONFIG_BT_MESH_CRPL=128
-CONFIG_BT_MESH_RPL_STORE_TIMEOUT=120
-
-CONFIG_PRINTK=y
-CONFIG_SERIAL=y
-CONFIG_CONSOLE=y
-CONFIG_STDOUT_CONSOLE=y
-
-CONFIG_I2C=y
-CONFIG_GPIO=y
-CONFIG_SENSOR=y
-
-CONFIG_APDS9960=y
-
-CONFIG_HDC1008=y
-
-CONFIG_SPI=y
-CONFIG_SPI_ASYNC=y
-
-CONFIG_HEAP_MEM_POOL_SIZE=16384
-CONFIG_DISPLAY=y
-CONFIG_SSD1673=y
-
-CONFIG_CHARACTER_FRAMEBUFFER=y
-
-CONFIG_BT_SETTINGS=y
-CONFIG_FLASH=y
-CONFIG_FLASH_PAGE_LAYOUT=y
-CONFIG_FLASH_MAP=y
-CONFIG_FCB=y
-CONFIG_SETTINGS=y
-CONFIG_SETTINGS_FCB=y
diff --git a/apps/mesh_badge/sample.yaml b/apps/mesh_badge/sample.yaml
deleted file mode 100644
index 6a50f81..0000000
--- a/apps/mesh_badge/sample.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-sample:
-  description: reel board mesh badge sample
-  name: mesh badge
-tests:
-  test:
-    platform_whitelist: reel_board
-    tags: samples sensor
-    harness: sensor
diff --git a/apps/mesh_badge/src/board.h b/apps/mesh_badge/src/board.h
index 7842cd4..f1f3c37 100644
--- a/apps/mesh_badge/src/board.h
+++ b/apps/mesh_badge/src/board.h
@@ -5,7 +5,11 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#include "mesh/mesh.h"
+
 void board_refresh_display(void);
 void board_show_text(const char *text, bool center, s32_t duration);
 void board_blink_leds(void);
+void board_add_hello(u16_t addr, const char *name);
+void board_add_heartbeat(u16_t addr, u8_t hops);
 int board_init(void);
diff --git a/apps/mesh_badge/src/gatt_svr.c b/apps/mesh_badge/src/gatt_svr.c
new file mode 100644
index 0000000..85dca09
--- /dev/null
+++ b/apps/mesh_badge/src/gatt_svr.c
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "services/gap/ble_svc_gap.h"
+#include "bsp/bsp.h"
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+
+#include "mesh.h"
+#include "board.h"
+#include "mesh_badge.h"
+
+static const ble_uuid16_t gatt_cud_uuid = BLE_UUID16_INIT(0x2901);
+static const ble_uuid16_t gatt_cpf_uuid = BLE_UUID16_INIT(0x2904);
+
+/** @brief GATT Characteristic Presentation Format Attribute Value. */
+struct bt_gatt_cpf {
+    /** Format of the value of the characteristic */
+    u8_t format;
+    /** Exponent field to determine how the value of this characteristic is further formatted */
+    s8_t exponent;
+    /** Unit of the characteristic */
+    u16_t unit;
+    /** Name space of the description */
+    u8_t name_space;
+    /** Description of the characteristic as defined in a higher layer profile */
+    u16_t description;
+} __packed;
+
+#define CPF_FORMAT_UTF8 0x19
+
+static const struct bt_gatt_cpf name_cpf = {
+        .format = CPF_FORMAT_UTF8,
+};
+
+static const ble_uuid128_t name_uuid = BLE_UUID128_INIT(
+        0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
+        0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
+
+static const ble_uuid128_t name_enc_uuid = BLE_UUID128_INIT(
+        0xf1, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
+        0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
+
+static int
+gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
+                    struct ble_gatt_access_ctxt *ctxt,
+                    void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = &name_uuid.u,
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid = &name_enc_uuid.u,
+            .access_cb = gatt_svr_chr_access,
+            .flags = BLE_GATT_CHR_F_READ |
+                    BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                    .uuid = &gatt_cud_uuid.u,
+                    .access_cb = gatt_svr_chr_access,
+                    .att_flags = BLE_ATT_F_READ,
+                }, {
+                    .uuid = &gatt_cpf_uuid.u,
+                    .access_cb = gatt_svr_chr_access,
+                    .att_flags = BLE_ATT_F_READ,
+                }, {
+                    0, /* No more descriptors in this characteristic. */
+                } }
+        }, {
+            0, /* No more characteristics in this service. */
+        } },
+    },
+
+    {
+        0, /* No more services. */
+    },
+};
+
+static int read_name(struct os_mbuf *om)
+{
+    const char *value = bt_get_name();
+    int rc;
+
+    rc = os_mbuf_append(om, value, (uint16_t) strlen(value));
+    return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+}
+
+static int write_name(struct os_mbuf *om)
+{
+    char name[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
+    uint16_t len;
+    uint16_t om_len;
+    int rc;
+
+    om_len = OS_MBUF_PKTLEN(om);
+    if (om_len >= sizeof(name)) {
+        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+    }
+
+    rc = ble_hs_mbuf_to_flat(om, name, sizeof(name) - 1, &len);
+    if (rc != 0) {
+        return BLE_ATT_ERR_UNLIKELY;
+    }
+
+    name[len] = '\0';
+
+    rc = bt_set_name(name);
+    if (rc) {
+        return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    board_refresh_display();
+
+    return 0;
+}
+
+static int
+gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
+                    struct ble_gatt_access_ctxt *ctxt,
+                    void *arg)
+{
+    const ble_uuid_t *uuid;
+    int rc;
+
+    uuid = ctxt->chr->uuid;
+
+    if (ble_uuid_cmp(uuid, &name_enc_uuid.u) == 0) {
+        switch (ctxt->op) {
+        case BLE_GATT_ACCESS_OP_READ_CHR:
+            rc = read_name(ctxt->om);
+            return rc;
+
+        case BLE_GATT_ACCESS_OP_WRITE_CHR:
+            rc = write_name(ctxt->om);
+            return rc;
+
+        default:
+            assert(0);
+            return BLE_ATT_ERR_UNLIKELY;
+        }
+    } else if (ble_uuid_cmp(uuid, &gatt_cud_uuid.u) == 0) {
+        rc = os_mbuf_append(ctxt->om, "Badge Name",
+                            (uint16_t) strlen("Badge Name"));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    } else if (ble_uuid_cmp(uuid, &gatt_cpf_uuid.u) == 0) {
+        rc = os_mbuf_append(ctxt->om, &name_cpf,
+                            (uint16_t) sizeof(name_cpf));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    /* Unknown characteristic; the nimble stack should not have called this
+     * function.
+     */
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+void
+gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
+{
+    char buf[BLE_UUID_STR_LEN];
+
+    switch (ctxt->op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
+                    ctxt->svc.handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        MODLOG_DFLT(DEBUG, "registering characteristic %s with "
+                           "def_handle=%d val_handle=%d\n",
+                    ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
+                    ctxt->chr.def_handle,
+                    ctxt->chr.val_handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
+                    ctxt->dsc.handle);
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+}
+
+int
+gatt_svr_init(void)
+{
+    int rc;
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
diff --git a/apps/mesh_badge/src/main.c b/apps/mesh_badge/src/main.c
index 23fe414..d856d81 100644
--- a/apps/mesh_badge/src/main.c
+++ b/apps/mesh_badge/src/main.c
@@ -4,140 +4,155 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-#include <zephyr.h>
-#include <misc/printk.h>
-
-#include <string.h>
-
-#include <settings/settings.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/gatt.h>
+#include "console/console.h"
+#include "host/ble_gap.h"
+#include "mesh/glue.h"
+#include "services/gap/ble_svc_gap.h"
+#include "base64/base64.h"
 
+#include "mesh_badge.h"
 #include "mesh.h"
 #include "board.h"
 
-static const struct bt_data ad[] = {
-	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
-};
+static char badge_name[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
 
-static size_t first_name_len(const char *name)
-{
-	size_t len;
-
-	for (len = 0; *name; name++, len++) {
-		switch (*name) {
-		case ' ':
-		case ',':
-		case '\n':
-			return len;
-		}
-	}
+#define MESH_BADGE_NAME_ENCODE_SIZE      \
+    BASE64_ENCODE_SIZE(sizeof(badge_name))
 
-	return len;
-}
+static bool reset_mesh;
 
-static ssize_t read_name(struct bt_conn *conn, const struct bt_gatt_attr *attr,
-			 void *buf, u16_t len, u16_t offset)
+void print_addr(const void *addr)
 {
-	const char *value = bt_get_name();
+	const uint8_t *u8p;
 
-	return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
-				 strlen(value));
+	u8p = addr;
+	MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
+		    u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
 }
 
-static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr,
-			  const void *buf, u16_t len, u16_t offset,
-			  u8_t flags)
+static void
+print_conn_desc(struct ble_gap_conn_desc *desc)
 {
-	char name[CONFIG_BT_DEVICE_NAME_MAX];
-	int err;
+	MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
+		    desc->conn_handle, desc->our_ota_addr.type);
+	print_addr(desc->our_ota_addr.val);
+	MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
+		    desc->our_id_addr.type);
+	print_addr(desc->our_id_addr.val);
+	MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
+		    desc->peer_ota_addr.type);
+	print_addr(desc->peer_ota_addr.val);
+	MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
+		    desc->peer_id_addr.type);
+	print_addr(desc->peer_id_addr.val);
+	MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
+			  "encrypted=%d authenticated=%d bonded=%d\n",
+		    desc->conn_itvl, desc->conn_latency,
+		    desc->supervision_timeout,
+		    desc->sec_state.encrypted,
+		    desc->sec_state.authenticated,
+		    desc->sec_state.bonded);
+}
 
-	if (offset) {
-		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
-	}
+static int gap_event(struct ble_gap_event *event, void *arg);
 
-	if (len >= CONFIG_BT_DEVICE_NAME_MAX) {
-		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
+static void advertise(void)
+{
+	uint8_t own_addr_type;
+	struct ble_gap_adv_params adv_params;
+	struct ble_hs_adv_fields fields;
+	const char *name;
+	int rc;
+
+	/* Figure out address to use while advertising (no privacy for now) */
+	rc = ble_hs_id_infer_auto(0, &own_addr_type);
+	if (rc != 0) {
+		MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
+		return;
 	}
 
-	memcpy(name, buf, len);
-	name[len] = '\0';
-
-	err = bt_set_name(name);
-	if (err) {
-		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
+	/**
+	 *  Set the advertisement data included in our advertisements:
+	 *     o Flags (indicates advertisement type and other general info).
+	 *     o Advertising tx power.
+	 *     o Device name.
+	 *     o 16-bit service UUIDs (alert notifications).
+	 */
+
+	memset(&fields, 0, sizeof fields);
+
+	/* Advertise two flags:
+	 *     o Discoverability in forthcoming advertisement (general)
+	 *     o BLE-only (BR/EDR unsupported).
+	 */
+	fields.flags = BLE_HS_ADV_F_DISC_GEN |
+		       BLE_HS_ADV_F_BREDR_UNSUP;
+
+#if 0
+	/* Indicate that the TX power level field should be included; have the
+	 * stack fill this value automatically.  This is done by assiging the
+	 * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
+	 */
+	fields.tx_pwr_lvl_is_present = 1;
+	fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
+#endif
+
+	name = ble_svc_gap_device_name();
+	fields.name = (uint8_t *)name;
+	fields.name_len = (uint8_t) strlen(name);
+	fields.name_is_complete = 1;
+
+	rc = ble_gap_adv_set_fields(&fields);
+	if (rc != 0) {
+		MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
+		return;
 	}
 
-	mesh_set_name(name, first_name_len(name));
-	board_refresh_display();
-
-	return len;
+	/* Begin advertising. */
+	memset(&adv_params, 0, sizeof adv_params);
+	adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+	adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+	rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
+			       &adv_params, gap_event, NULL);
+	if (rc != 0) {
+		MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
+		return;
+	}
 }
 
-static struct bt_uuid_128 name_uuid = BT_UUID_INIT_128(
-	0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
-	0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
-
-static struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128(
-	0xf1, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
-	0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
-
-#define CPF_FORMAT_UTF8 0x19
-
-static const struct bt_gatt_cpf name_cpf = {
-	.format = CPF_FORMAT_UTF8,
-};
-
-/* Vendor Primary Service Declaration */
-static struct bt_gatt_attr name_attrs[] = {
-	/* Vendor Primary Service Declaration */
-	BT_GATT_PRIMARY_SERVICE(&name_uuid),
-	BT_GATT_CHARACTERISTIC(&name_enc_uuid.uuid,
-			       BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
-			       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT,
-			       read_name, write_name, NULL),
-	BT_GATT_CUD("Badge Name", BT_GATT_PERM_READ),
-	BT_GATT_CPF(&name_cpf),
-};
-
-static struct bt_gatt_service name_svc = BT_GATT_SERVICE(name_attrs);
-
-static void passkey_display(struct bt_conn *conn, unsigned int passkey)
+static void passkey_display(uint16_t conn_handle)
 {
 	char buf[20];
+	struct ble_sm_io pk;
+	int rc;
+
+	bt_rand(&pk.passkey, sizeof(pk.passkey));
+	/* Max value is 999999 */
+	pk.passkey %= 1000000;
+	pk.action = BLE_SM_IOACT_DISP;
 
-	snprintk(buf, sizeof(buf), "Passkey:\n%06u", passkey);
+	rc = ble_sm_inject_io(conn_handle, &pk);
+	assert(rc == 0);
+
+	snprintk(buf, sizeof(buf), "Passkey:\n%06lu", pk.passkey);
 
 	printk("%s\n", buf);
 	board_show_text(buf, false, K_FOREVER);
 }
 
-static void passkey_cancel(struct bt_conn *conn)
-{
-	printk("Cancel\n");
-}
-
-static void pairing_complete(struct bt_conn *conn, bool bonded)
+static void pairing_complete(uint16_t conn_handle, bool bonded)
 {
 	printk("Pairing Complete\n");
 	board_show_text("Pairing Complete", false, K_SECONDS(2));
 }
 
-static void pairing_failed(struct bt_conn *conn)
+static void pairing_failed(uint16_t conn_handle)
 {
 	printk("Pairing Failed\n");
 	board_show_text("Pairing Failed", false, K_SECONDS(2));
 }
 
-const struct bt_conn_auth_cb auth_cb = {
-	.passkey_display = passkey_display,
-	.cancel = passkey_cancel,
-	.pairing_complete = pairing_complete,
-	.pairing_failed = pairing_failed,
-};
-
-static void connected(struct bt_conn *conn, u8_t err)
+static void connected(uint16_t conn_handle, int err)
 {
 	printk("Connected (err 0x%02x)\n", err);
 
@@ -148,35 +163,129 @@ static void connected(struct bt_conn *conn, u8_t err)
 	}
 }
 
-static void disconnected(struct bt_conn *conn, u8_t reason)
+static void disconnected(uint16_t conn_handle, int reason)
 {
 	printk("Disconnected (reason 0x%02x)\n", reason);
 
-	if (strcmp(CONFIG_BT_DEVICE_NAME, bt_get_name()) &&
+	if (strcmp(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME), bt_get_name()) != 0 &&
 	    !mesh_is_initialized()) {
 		/* Mesh will take over advertising control */
-		bt_le_adv_stop();
+		ble_gap_adv_stop();
 		mesh_start();
 	} else {
 		board_show_text("Disconnected", false, K_SECONDS(2));
 	}
 }
 
-static struct bt_conn_cb conn_cb = {
-	.connected = connected,
-	.disconnected = disconnected,
-};
-
-static void bt_ready(int err)
+static int gap_event(struct ble_gap_event *event, void *arg)
 {
-	if (err) {
-		printk("Bluetooth init failed (err %d)\n", err);
-		return;
+	struct ble_gap_conn_desc desc;
+	int rc;
+
+	switch (event->type) {
+		case BLE_GAP_EVENT_CONNECT:
+			/* A new connection was established or a connection attempt failed. */
+			MODLOG_DFLT(INFO, "connection %s; status=%d ",
+				    event->connect.status == 0 ? "established" : "failed",
+				    event->connect.status);
+			if (event->connect.status == 0) {
+				rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+				assert(rc == 0);
+				print_conn_desc(&desc);
+				connected(event->connect.conn_handle,
+					  event->connect.status);
+			}
+			MODLOG_DFLT(INFO, "\n");
+
+			if (event->connect.status != 0) {
+				/* Connection failed; resume advertising. */
+				advertise();
+			}
+			return 0;
+
+		case BLE_GAP_EVENT_DISCONNECT:
+			MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
+			print_conn_desc(&event->disconnect.conn);
+			MODLOG_DFLT(INFO, "\n");
+
+			/* Connection terminated; resume advertising. */
+			advertise();
+
+			disconnected(event->disconnect.conn.conn_handle,
+				     event->disconnect.reason);
+			return 0;
+
+		case BLE_GAP_EVENT_CONN_UPDATE:
+			/* The central has updated the connection parameters. */
+			MODLOG_DFLT(INFO, "connection updated; status=%d ",
+				    event->conn_update.status);
+			rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+			assert(rc == 0);
+			print_conn_desc(&desc);
+			MODLOG_DFLT(INFO, "\n");
+			return 0;
+
+		case BLE_GAP_EVENT_ENC_CHANGE:
+			/* Encryption has been enabled or disabled for this connection. */
+			MODLOG_DFLT(INFO, "encryption change event; status=%d ",
+				    event->enc_change.status);
+			rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+			assert(rc == 0);
+			print_conn_desc(&desc);
+			MODLOG_DFLT(INFO, "\n");
+
+			if (desc.sec_state.bonded) {
+				pairing_complete(event->enc_change.conn_handle, true);
+			} else if(desc.sec_state.encrypted) {
+				pairing_complete(event->enc_change.conn_handle, false);
+			} else {
+				pairing_failed(event->enc_change.conn_handle);
+			}
+			return 0;
+
+		case BLE_GAP_EVENT_PASSKEY_ACTION:
+			MODLOG_DFLT(INFO, "passkey action event; conn_handle=%d action=%d numcmp=%d\n",
+				    event->passkey.conn_handle,
+				    event->passkey.params.action,
+				    event->passkey.params.numcmp);
+			passkey_display(event->passkey.conn_handle);
+			return 0;
+
+		case BLE_GAP_EVENT_REPEAT_PAIRING:
+			/* We already have a bond with the peer, but it is attempting to
+			 * establish a new secure link.  This app sacrifices security for
+			 * convenience: just throw away the old bond and accept the new link.
+			 */
+
+			/* Delete the old bond. */
+			rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+			assert(rc == 0);
+			ble_store_util_delete_peer(&desc.peer_id_addr);
+
+			/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
+			 * continue with the pairing operation.
+			 */
+			return BLE_GAP_REPEAT_PAIRING_RETRY;
+
 	}
 
+	return 0;
+}
+
+static void on_sync(void)
+{
+	int err;
+	ble_addr_t addr;
+
+	/* Use NRPA */
+	err = ble_hs_id_gen_rnd(1, &addr);
+	assert(err == 0);
+	err = ble_hs_id_set_rnd(addr.val);
+	assert(err == 0);
+
 	printk("Bluetooth initialized\n");
 
-	err = mesh_init();
+	err = mesh_init(addr.type);
 	if (err) {
 		printk("Initializing mesh failed (err %d)\n", err);
 		return;
@@ -184,29 +293,20 @@ static void bt_ready(int err)
 
 	printk("Mesh initialized\n");
 
-	bt_conn_cb_register(&conn_cb);
-	bt_conn_auth_cb_register(&auth_cb);
-
-	bt_gatt_service_register(&name_svc);
-
 	if (IS_ENABLED(CONFIG_SETTINGS)) {
 		settings_load();
 	}
 
+	if (reset_mesh) {
+		bt_mesh_reset();
+		reset_mesh = false;
+	}
+
 	if (!mesh_is_initialized()) {
-		/* Start advertising */
-		err = bt_le_adv_start(BT_LE_ADV_CONN_NAME,
-				      ad, ARRAY_SIZE(ad), NULL, 0);
-		if (err) {
-			printk("Advertising failed to start (err %d)\n", err);
-			return;
-		}
+		advertise();
 	} else {
-		const char *name = bt_get_name();
-
 		printk("Already provisioned\n");
-
-		mesh_set_name(name, first_name_len(name));
+		ble_svc_gap_device_name_set(bt_get_name());
 	}
 
 	board_refresh_display();
@@ -214,22 +314,80 @@ static void bt_ready(int err)
 	printk("Board started\n");
 }
 
-void main(void)
+void schedule_mesh_reset(void)
+{
+	reset_mesh = true;
+}
+
+static void on_reset(int reason)
+{
+	MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
+}
+
+const char *bt_get_name(void)
+{
+	char buf[MESH_BADGE_NAME_ENCODE_SIZE];
+	int rc, len;
+
+	rc = conf_get_stored_value("mesh_badge/badge_name",
+				   buf, sizeof(buf));
+	if (rc == OS_ENOENT) {
+		bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
+	} else {
+		assert(rc == 0);
+	}
+
+	memset(badge_name, '\0', sizeof(badge_name));
+	len = base64_decode(buf, badge_name);
+	if (len < 0) {
+		bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
+	}
+
+	return badge_name;
+}
+
+int bt_set_name(const char *name)
+{
+	char buf[MESH_BADGE_NAME_ENCODE_SIZE];
+	int rc;
+
+	memset(badge_name, '\0', sizeof(badge_name));
+	memcpy(badge_name, name, strlen(name));
+	base64_encode(badge_name, sizeof(badge_name), buf, 1);
+	rc = conf_save_one("mesh_badge/badge_name", buf);
+	assert(rc == 0);
+
+	return 0;
+}
+
+int main(void)
 {
 	int err;
 
+	/* Initialize OS */
+	sysinit();
+
 	err = board_init();
 	if (err) {
 		printk("board init failed (err %d)\n", err);
-		return;
+		assert(err == 0);
 	}
 
-	printk("Starting Board Demo\n");
-
-	/* Initialize the Bluetooth Subsystem */
-	err = bt_enable(bt_ready);
-	if (err) {
-		printk("Bluetooth init failed (err %d)\n", err);
-		return;
+	/* Initialize the NimBLE host configuration. */
+	ble_hs_cfg.reset_cb = on_reset;
+	ble_hs_cfg.sync_cb = on_sync;
+	ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
+	ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+	ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY;
+
+	err = gatt_svr_init();
+	assert(err == 0);
+
+	/*
+	 * As the last thing, process events from default event queue.
+	 */
+	while (1) {
+		os_eventq_run(os_eventq_dflt_get());
 	}
+	return 0;
 }
diff --git a/apps/mesh_badge/src/mesh.c b/apps/mesh_badge/src/mesh.c
index aa4b8a7..80a174c 100644
--- a/apps/mesh_badge/src/mesh.c
+++ b/apps/mesh_badge/src/mesh.c
@@ -4,29 +4,28 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-#include <zephyr.h>
-#include <string.h>
-#include <misc/printk.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/mesh.h>
-#include <bluetooth/hci.h>
+#include "console/console.h"
+#include "mesh/mesh.h"
 
+#include "mesh_badge.h"
 #include "mesh.h"
 #include "board.h"
 
-#define MOD_LF         0x0000
-#define OP_LF          0xbb
-#define OP_VENDOR_MSG  BT_MESH_MODEL_OP_3(OP_LF, BT_COMP_ID_LF)
+#define BT_COMP_ID_LF 0x05f1
 
-#define DEFAULT_TTL    7
-#define GROUP_ADDR     0xc123
-#define NET_IDX        0x000
-#define APP_IDX        0x000
-#define FLAGS          0
+#define MOD_LF            0x0000
+#define OP_HELLO          0xbb
+#define OP_HEARTBEAT      0xbc
+#define OP_VND_HELLO      BT_MESH_MODEL_OP_3(OP_HELLO, BT_COMP_ID_LF)
+#define OP_VND_HEARTBEAT  BT_MESH_MODEL_OP_3(OP_HEARTBEAT, BT_COMP_ID_LF)
 
-static struct k_work publish_work;
-static struct k_work mesh_start_work;
+#define DEFAULT_TTL       31
+#define GROUP_ADDR        0xc123
+#define NET_IDX           0x000
+#define APP_IDX           0x000
+#define FLAGS             0
+static struct ble_npl_callout hello_work;
+static struct ble_npl_callout mesh_start_work;
 
 static void heartbeat(u8_t hops, u16_t feat)
 {
@@ -67,7 +66,8 @@ static struct bt_mesh_health_srv health_srv = {
 	.cb = &health_srv_cb,
 };
 
-BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
+static struct os_mbuf *bt_mesh_pub_msg_health_pub;
+static struct bt_mesh_model_pub health_pub;
 
 static struct bt_mesh_model root_models[] = {
 	BT_MESH_MODEL_CFG_SRV(&cfg_srv),
@@ -75,22 +75,26 @@ static struct bt_mesh_model root_models[] = {
 	BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
 };
 
-static void vnd_message(struct bt_mesh_model *model,
+static void vnd_hello(struct bt_mesh_model *model,
 			struct bt_mesh_msg_ctx *ctx,
-			struct net_buf_simple *buf)
+			struct os_mbuf *buf)
 {
 	char str[32];
 	size_t len;
 
-	printk("Vendor message from 0x%04x\n", ctx->addr);
+	printk("Hello message from 0x%04x\n", ctx->addr);
 
 	if (ctx->addr == bt_mesh_model_elem(model)->addr) {
 		printk("Ignoring message from self\n");
 		return;
 	}
 
-	len = min(buf->len, 8);
-	memcpy(str, buf->data, len);
+	len = min(buf->om_len, 8);
+	memcpy(str, buf->om_data, len);
+	str[len] = '\0';
+
+	board_add_hello(ctx->addr, str);
+
 	strcpy(str + len, " says hi!");
 
 	board_show_text(str, false, K_SECONDS(3));
@@ -98,13 +102,46 @@ static void vnd_message(struct bt_mesh_model *model,
 	board_blink_leds();
 }
 
+static void vnd_heartbeat(struct bt_mesh_model *model,
+			  struct bt_mesh_msg_ctx *ctx,
+			  struct os_mbuf *buf)
+{
+	u8_t init_ttl, hops;
+
+	/* Ignore messages from self */
+	if (ctx->addr == bt_mesh_model_elem(model)->addr) {
+		return;
+	}
+
+	init_ttl = net_buf_simple_pull_u8(buf);
+	hops = init_ttl - ctx->recv_ttl + 1;
+
+	printk("Heartbeat from 0x%04x over %u hop%s\n", ctx->addr,
+	       hops, hops == 1 ? "" : "s");
+
+	board_add_heartbeat(ctx->addr, hops);
+}
+
 static const struct bt_mesh_model_op vnd_ops[] = {
-	{ OP_VENDOR_MSG, 1, vnd_message },
+	{ OP_VND_HELLO, 1, vnd_hello },
+	{ OP_VND_HEARTBEAT, 1, vnd_heartbeat },
 	BT_MESH_MODEL_OP_END,
 };
 
-/* Limit the payload to 11 bytes so that it doesn't get segmented */
-BT_MESH_MODEL_PUB_DEFINE(vnd_pub, NULL, 3 + 8);
+static int pub_update(struct bt_mesh_model *mod)
+{
+	struct os_mbuf *msg = mod->pub->msg;
+
+	printk("Preparing to send heartbeat\n");
+
+	bt_mesh_model_msg_init(msg, OP_VND_HEARTBEAT);
+	net_buf_simple_add_u8(msg, DEFAULT_TTL);
+
+	return 0;
+}
+
+static struct os_mbuf *bt_mesh_pub_msg_vnd_pub;
+static struct bt_mesh_model_pub vnd_pub;
 
 static struct bt_mesh_model vnd_models[] = {
 	BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL),
@@ -120,19 +157,49 @@ static const struct bt_mesh_comp comp = {
 	.elem_count = ARRAY_SIZE(elements),
 };
 
-static void publish_message(struct k_work *work)
+static size_t first_name_len(const char *name)
 {
-	if (bt_mesh_model_publish(&vnd_models[0]) == 0) {
+	size_t len;
+
+	for (len = 0; *name; name++, len++) {
+		switch (*name) {
+		case ' ':
+		case ',':
+		case '\n':
+			return len;
+		}
+	}
+
+	return len;
+}
+
+static void send_hello(struct ble_npl_event *work)
+{
+	struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 8 + 4);
+	struct bt_mesh_msg_ctx ctx = {
+		.net_idx = NET_IDX,
+		.app_idx = APP_IDX,
+		.addr = GROUP_ADDR,
+		.send_ttl = DEFAULT_TTL,
+	};
+	const char *name = bt_get_name();
+
+	bt_mesh_model_msg_init(msg, OP_VND_HELLO);
+	net_buf_simple_add_mem(msg, name, first_name_len(name));
+
+	if (bt_mesh_model_send(&vnd_models[0], &ctx, msg, NULL, NULL) == 0) {
 		board_show_text("Saying \"hi!\" to everyone", false,
 				K_SECONDS(2));
 	} else {
 		board_show_text("Sending Failed!", false, K_SECONDS(2));
 	}
+
+	os_mbuf_free_chain(msg);
 }
 
-void mesh_publish(void)
+void mesh_send_hello(void)
 {
-	k_work_submit(&publish_work);
+	k_work_submit(&hello_work);
 }
 
 static int provision_and_configure(void)
@@ -150,6 +217,7 @@ static int provision_and_configure(void)
 		.addr = GROUP_ADDR,
 		.app_idx = APP_IDX,
 		.ttl = DEFAULT_TTL,
+		.period = BT_MESH_PUB_PERIOD_SEC(10),
 	};
 	u8_t dev_key[16];
 	u16_t addr;
@@ -201,7 +269,7 @@ static int provision_and_configure(void)
 	return addr;
 }
 
-static void start_mesh(struct k_work *work)
+static void start_mesh(struct ble_npl_event *work)
 {
 	int err;
 
@@ -223,27 +291,32 @@ void mesh_start(void)
 	k_work_submit(&mesh_start_work);
 }
 
-void mesh_set_name(const char *name, size_t len)
+bool mesh_is_initialized(void)
 {
-	bt_mesh_model_msg_init(vnd_pub.msg, OP_VENDOR_MSG);
-	len = min(len, net_buf_simple_tailroom(vnd_pub.msg));
-	net_buf_simple_add_mem(vnd_pub.msg, name, len);
+	return bt_mesh_is_provisioned();
 }
 
-bool mesh_is_initialized(void)
+u16_t mesh_get_addr(void)
 {
-	return elements[0].addr != BT_MESH_ADDR_UNASSIGNED;
+	return elements[0].addr;
 }
 
-int mesh_init(void)
+int mesh_init(u8_t addr_type)
 {
 	static const u8_t dev_uuid[16] = { 0xc0, 0xff, 0xee };
 	static const struct bt_mesh_prov prov = {
 		.uuid = dev_uuid,
 	};
 
-	k_work_init(&publish_work, publish_message);
+	bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(0);
+	health_pub.msg = bt_mesh_pub_msg_health_pub;
+
+	bt_mesh_pub_msg_vnd_pub = NET_BUF_SIMPLE(3 + 1);
+	vnd_pub.msg = bt_mesh_pub_msg_vnd_pub;
+	vnd_pub.update = pub_update;
+
+	k_work_init(&hello_work, send_hello);
 	k_work_init(&mesh_start_work, start_mesh);
 
-	return bt_mesh_init(&prov, &comp);
+	return bt_mesh_init(addr_type, &prov, &comp);
 }
diff --git a/apps/mesh_badge/src/mesh.h b/apps/mesh_badge/src/mesh.h
index 951771b..2c94de0 100644
--- a/apps/mesh_badge/src/mesh.h
+++ b/apps/mesh_badge/src/mesh.h
@@ -4,9 +4,11 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-void mesh_publish(void);
-void mesh_set_name(const char *name, size_t len);
+#include "mesh/mesh.h"
 
+void mesh_send_hello(void);
+
+u16_t mesh_get_addr(void);
 bool mesh_is_initialized(void);
 void mesh_start(void);
-int mesh_init(void);
+int mesh_init(u8_t addr_type);
diff --git a/apps/mesh_badge/src/mesh_badge.h b/apps/mesh_badge/src/mesh_badge.h
new file mode 100644
index 0000000..a156f1c
--- /dev/null
+++ b/apps/mesh_badge/src/mesh_badge.h
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+struct ble_gatt_register_ctxt;
+
+void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
+int gatt_svr_init(void);
+
+void schedule_mesh_reset(void);
+const char *bt_get_name(void);
+int bt_set_name(const char *);
+
diff --git a/apps/mesh_badge/src/reel_board.c b/apps/mesh_badge/src/reel_board.c
index ca5809f..b144a83 100644
--- a/apps/mesh_badge/src/reel_board.c
+++ b/apps/mesh_badge/src/reel_board.c
@@ -5,19 +5,38 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-#include <zephyr.h>
-#include <device.h>
-#include <gpio.h>
-#include <display/cfb.h>
-#include <misc/printk.h>
-#include <flash.h>
+#include "os/mynewt.h"
+#include "bsp/bsp.h"
+#include "console/console.h"
+#include "hal/hal_flash.h"
+#include "hal/hal_gpio.h"
+#include "mesh/glue.h"
+#include "services/gap/ble_svc_gap.h"
+
+#include "mesh_badge.h"
+#include "display/cfb.h"
+#include "mesh.h"
+#include "board.h"
 
-#include <string.h>
+#define printk console_printf
 
-#include <bluetooth/bluetooth.h>
+enum font_size {
+	FONT_BIG = 0,
+	FONT_MEDIUM = 1,
+	FONT_SMALL = 2,
+};
 
-#include "mesh.h"
-#include "board.h"
+struct font_info {
+	u8_t columns;
+} fonts[] = {
+	[FONT_BIG] =    { .columns = 12 },
+	[FONT_MEDIUM] = { .columns = 16 },
+	[FONT_SMALL] =  { .columns = 25 },
+};
+
+#define LONG_PRESS_TIMEOUT K_SECONDS(1)
+
+#define STAT_COUNT 128
 
 #define EDGE (GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE)
 
@@ -27,43 +46,43 @@
 #define PULL_UP 0
 #endif
 
-#define LINE_MAX 12
-
-static struct device *epd_dev;
+static struct os_dev *epd_dev;
 static bool pressed;
-static struct device *gpio;
+static bool stats_view;
 static struct k_delayed_work epd_work;
+static struct k_delayed_work long_press_work;
 
 static struct {
-	struct device *dev;
-	const char *name;
-	u32_t pin;
+    int pin;
 } leds[] = {
-	{ .name = LED0_GPIO_CONTROLLER, .pin = LED0_GPIO_PIN, },
-	{ .name = LED1_GPIO_CONTROLLER, .pin = LED1_GPIO_PIN, },
-	{ .name = LED2_GPIO_CONTROLLER, .pin = LED2_GPIO_PIN, },
-	{ .name = LED3_GPIO_CONTROLLER, .pin = LED3_GPIO_PIN, },
+	{ .pin = LED_1, },
+	{ .pin = RGB_LED_RED, },
+	{ .pin = RGB_LED_GRN, },
+	{ .pin = RGB_LED_BLU, },
 };
 
 struct k_delayed_work led_timer;
 
-static size_t print_line(int row, const char *text, size_t len, bool center)
+static size_t print_line(enum font_size font_size, int row, const char *text,
+			 size_t len, bool center)
 {
 	u8_t font_height, font_width;
-	u8_t line[LINE_MAX + 1];
+	char line[fonts[FONT_SMALL].columns + 1];
 	int pad;
 
-	len = min(len, LINE_MAX);
+	cfb_framebuffer_set_font(epd_dev, font_size);
+
+	len = min(len, fonts[font_size].columns);
 	memcpy(line, text, len);
 	line[len] = '\0';
 
 	if (center) {
-		pad = (LINE_MAX - len) / 2;
+		pad = (fonts[font_size].columns - len) / 2;
 	} else {
 		pad = 0;
 	}
 
-	cfb_get_font_size(epd_dev, 0, &font_width, &font_height);
+	cfb_get_font_size(epd_dev, font_size, &font_width, &font_height);
 
 	if (cfb_print(epd_dev, line, font_width * pad, font_height * row)) {
 		printk("Failed to print a string\n");
@@ -72,12 +91,12 @@ static size_t print_line(int row, const char *text, size_t len, bool center)
 	return len;
 }
 
-static size_t get_len(const char *text)
+static size_t get_len(enum font_size font, const char *text)
 {
 	const char *space = NULL;
 	size_t i;
 
-	for (i = 0; i <= LINE_MAX; i++) {
+	for (i = 0; i <= fonts[font].columns; i++) {
 		switch (text[i]) {
 		case '\n':
 		case '\0':
@@ -97,7 +116,7 @@ static size_t get_len(const char *text)
 		return space - text;
 	}
 
-	return LINE_MAX;
+	return fonts[font].columns;
 }
 
 void board_blink_leds(void)
@@ -109,7 +128,6 @@ void board_show_text(const char *text, bool center, s32_t duration)
 {
 	int i;
 
-	cfb_framebuffer_set_font(epd_dev, 0);
 	cfb_framebuffer_clear(epd_dev, false);
 
 	for (i = 0; i < 3; i++) {
@@ -119,12 +137,12 @@ void board_show_text(const char *text, bool center, s32_t duration)
 			text++;
 		}
 
-		len = get_len(text);
+		len = get_len(FONT_BIG, text);
 		if (!len) {
 			break;
 		}
 
-		text += print_line(i, text, len, center);
+		text += print_line(FONT_BIG, i, text, len, center);
 		if (!*text) {
 			break;
 		}
@@ -137,11 +155,191 @@ void board_show_text(const char *text, bool center, s32_t duration)
 	}
 }
 
-static void epd_update(struct k_work *work)
+static struct stat {
+	u16_t addr;
+	char name[9];
+	u8_t min_hops;
+	u8_t max_hops;
+	u16_t hello_count;
+	u16_t heartbeat_count;
+} stats[STAT_COUNT] = {
+	[0 ... (STAT_COUNT - 1)] = {
+		.min_hops = BT_MESH_TTL_MAX,
+		.max_hops = 0,
+	},
+};
+
+static u32_t stat_count;
+
+#define NO_UPDATE -1
+
+static int add_hello(u16_t addr, const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(stats); i++) {
+		struct stat *stat = &stats[i];
+
+		if (!stat->addr) {
+			stat->addr = addr;
+			strncpy(stat->name, name, sizeof(stat->name) - 1);
+			stat->hello_count = 1;
+			stat_count++;
+			return i;
+		}
+
+		if (stat->addr == addr) {
+			/* Update name, incase it has changed */
+			strncpy(stat->name, name, sizeof(stat->name) - 1);
+
+			if (stat->hello_count < 0xffff) {
+				stat->hello_count++;
+				return i;
+			}
+
+			return NO_UPDATE;
+		}
+	}
+
+	return NO_UPDATE;
+}
+
+static int add_heartbeat(u16_t addr, u8_t hops)
 {
-	char buf[CONFIG_BT_DEVICE_NAME_MAX];
 	int i;
 
+	for (i = 0; i < ARRAY_SIZE(stats); i++) {
+		struct stat *stat = &stats[i];
+
+		if (!stat->addr) {
+			stat->addr = addr;
+			stat->heartbeat_count = 1;
+			stat->min_hops = hops;
+			stat->max_hops = hops;
+			stat_count++;
+			return i;
+		}
+
+		if (stat->addr == addr) {
+			if (hops < stat->min_hops) {
+				stat->min_hops = hops;
+			} else if (hops > stat->max_hops) {
+				stat->max_hops = hops;
+			}
+
+			if (stat->heartbeat_count < 0xffff) {
+				stat->heartbeat_count++;
+				return i;
+			}
+
+			return NO_UPDATE;
+		}
+	}
+
+	return NO_UPDATE;
+}
+
+void board_add_hello(u16_t addr, const char *name)
+{
+	u32_t sort_i;
+
+	sort_i = add_hello(addr, name);
+	if (sort_i != NO_UPDATE) {
+	}
+}
+
+void board_add_heartbeat(u16_t addr, u8_t hops)
+{
+	u32_t sort_i;
+
+	sort_i = add_heartbeat(addr, hops);
+	if (sort_i != NO_UPDATE) {
+	}
+}
+
+static void show_statistics(void)
+{
+	int top[4] = { -1, -1, -1, -1 };
+	int len, i, line = 0;
+	struct stat *stat;
+	char str[32];
+
+	cfb_framebuffer_clear(epd_dev, false);
+
+	len = snprintk(str, sizeof(str),
+		       "Own Address: 0x%04x", mesh_get_addr());
+	print_line(FONT_SMALL, line++, str, len, false);
+
+	len = snprintk(str, sizeof(str),
+		       "Node Count:  %lu", stat_count + 1);
+	print_line(FONT_SMALL, line++, str, len, false);
+
+	/* Find the top sender */
+	for (i = 0; i < ARRAY_SIZE(stats); i++) {
+		int j;
+
+		stat = &stats[i];
+		if (!stat->addr) {
+			break;
+		}
+
+		if (!stat->hello_count) {
+			continue;
+		}
+
+		for (j = 0; j < ARRAY_SIZE(top); j++) {
+			if (top[j] < 0) {
+				top[j] = i;
+				break;
+			}
+
+			if (stat->hello_count <= stats[top[j]].hello_count) {
+				continue;
+			}
+
+			/* Move other elements down the list */
+			if (j < ARRAY_SIZE(top) - 1) {
+				memmove(&top[j + 1], &top[j],
+					((ARRAY_SIZE(top) - j - 1) *
+					 sizeof(top[j])));
+			}
+
+			top[j] = i;
+			break;
+		}
+	}
+
+	if (stat_count >= 0) {
+		len = snprintk(str, sizeof(str), "Most messages from:");
+		print_line(FONT_SMALL, line++, str, len, false);
+
+		for (i = 0; i < ARRAY_SIZE(top); i++) {
+			if (top[i] < 0) {
+				break;
+			}
+
+			stat = &stats[top[i]];
+
+			len = snprintk(str, sizeof(str), "%-3u 0x%04x %s",
+				       stat->hello_count, stat->addr,
+				       stat->name);
+			print_line(FONT_SMALL, line++, str, len, false);
+		}
+	}
+
+	cfb_framebuffer_finalize(epd_dev);
+}
+
+static void epd_update(struct ble_npl_event *work)
+{
+	char buf[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
+	int i;
+
+	if (stats_view) {
+		show_statistics();
+		return;
+	}
+
 	strncpy(buf, bt_get_name(), sizeof(buf));
 
 	/* Convert commas to newlines */
@@ -154,18 +352,27 @@ static void epd_update(struct k_work *work)
 	board_show_text(buf, true, K_FOREVER);
 }
 
+static void long_press(struct ble_npl_event *work)
+{
+	/* Treat as release so actual release doesn't send messages */
+	pressed = false;
+	stats_view = !stats_view;
+	board_refresh_display();
+}
+
 static bool button_is_pressed(void)
 {
 	u32_t val;
 
-	gpio_pin_read(gpio, SW0_GPIO_PIN, &val);
+	val = (uint32_t) hal_gpio_read(BUTTON_1);
 
 	return !val;
 }
 
-static void button_interrupt(struct device *dev, struct gpio_callback *cb,
-			     u32_t pins)
+static void button_interrupt(struct os_event *ev)
 {
+	int pin_pos = (int ) ev->ev_arg;
+
 	if (button_is_pressed() == pressed) {
 		return;
 	}
@@ -173,48 +380,55 @@ static void button_interrupt(struct device *dev, struct gpio_callback *cb,
 	pressed = !pressed;
 	printk("Button %s\n", pressed ? "pressed" : "released");
 
-	/* We only care about button release for now */
 	if (pressed) {
+		k_delayed_work_submit(&long_press_work, LONG_PRESS_TIMEOUT);
 		return;
 	}
 
+	k_delayed_work_cancel(&long_press_work);
+
 	if (!mesh_is_initialized()) {
 		return;
 	}
 
-	if (pins & BIT(SW0_GPIO_PIN)) {
-		mesh_publish();
+	/* Short press does currently nothing in statistics view */
+	if (stats_view) {
+		return;
 	}
-}
-
-static int configure_button(void)
-{
-	static struct gpio_callback button_cb;
 
-	gpio = device_get_binding(GPIO_KEYS_BUTTON_0_GPIO_CONTROLLER);
-	if (!gpio) {
-		return -ENODEV;
+	if (pin_pos == BUTTON_1) {
+		mesh_send_hello();
 	}
+}
 
-	gpio_pin_configure(gpio, SW0_GPIO_PIN,
-			   (GPIO_DIR_IN | GPIO_INT |  PULL_UP | EDGE));
+static struct os_event button_event;
 
-	gpio_init_callback(&button_cb, button_interrupt, BIT(SW0_GPIO_PIN));
-	gpio_add_callback(gpio, &button_cb);
+static void
+gpio_irq_handler(void *arg)
+{
+	button_event.ev_arg = arg;
+	os_eventq_put(os_eventq_dflt_get(), &button_event);
+}
+
+static int configure_button(void)
+{
+	button_event.ev_cb = button_interrupt;
 
-	gpio_pin_enable_callback(gpio, SW0_GPIO_PIN);
+	hal_gpio_irq_init(BUTTON_1, gpio_irq_handler, (void *) BUTTON_1,
+			  HAL_GPIO_TRIG_BOTH, HAL_GPIO_PULL_UP);
+	hal_gpio_irq_enable(BUTTON_1);
 
 	return 0;
 }
 
-static void led_timeout(struct k_work *work)
+static void led_timeout(struct ble_npl_event *work)
 {
 	static int led_cntr;
 	int i;
 
 	/* Disable all LEDs */
 	for (i = 0; i < ARRAY_SIZE(leds); i++) {
-		gpio_pin_write(leds[i].dev, leds[i].pin, 1);
+		hal_gpio_write(leds[i].pin, 1);
 	}
 
 	/* Stop after 5 iterations */
@@ -225,7 +439,7 @@ static void led_timeout(struct k_work *work)
 
 	/* Select and enable current LED */
 	i = led_cntr++ % ARRAY_SIZE(leds);
-	gpio_pin_write(leds[i].dev, leds[i].pin, 0);
+	hal_gpio_write(leds[i].pin, 0);
 
 	k_delayed_work_submit(&led_timer, K_MSEC(100));
 }
@@ -235,15 +449,7 @@ static int configure_leds(void)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(leds); i++) {
-		leds[i].dev = device_get_binding(leds[i].name);
-		if (!leds[i].dev) {
-			printk("Failed to get %s device\n", leds[i].name);
-			return -ENODEV;
-		}
-
-		gpio_pin_configure(leds[i].dev, leds[i].pin, GPIO_DIR_OUT);
-		gpio_pin_write(leds[i].dev, leds[i].pin, 1);
-
+		hal_gpio_init_out(leds[i].pin, 1);
 	}
 
 	k_delayed_work_init(&led_timer, led_timeout);
@@ -252,12 +458,10 @@ static int configure_leds(void)
 
 static int erase_storage(void)
 {
-	struct device *dev;
-
-	dev = device_get_binding(FLASH_DEV_NAME);
-
-	return flash_erase(dev, FLASH_AREA_STORAGE_OFFSET,
-			   FLASH_AREA_STORAGE_SIZE);
+	bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
+	ble_store_clear();
+	schedule_mesh_reset();
+	return 0;
 }
 
 void board_refresh_display(void)
@@ -267,7 +471,7 @@ void board_refresh_display(void)
 
 int board_init(void)
 {
-	epd_dev = device_get_binding(CONFIG_SSD1673_DEV_NAME);
+	epd_dev = os_dev_lookup(MYNEWT_VAL(SSD1673_OS_DEV_NAME));
 	if (epd_dev == NULL) {
 		printk("SSD1673 device not found\n");
 		return -ENODEV;
@@ -291,6 +495,7 @@ int board_init(void)
 	}
 
 	k_delayed_work_init(&epd_work, epd_update);
+	k_delayed_work_init(&long_press_work, long_press);
 
 	pressed = button_is_pressed();
 	if (pressed) {
diff --git a/apps/mesh_badge/syscfg.yml b/apps/mesh_badge/syscfg.yml
new file mode 100644
index 0000000..adac845
--- /dev/null
+++ b/apps/mesh_badge/syscfg.yml
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Package: apps/mesh_badge
+
+syscfg.vals:
+    # Enable the shell task.
+    SHELL_TASK: 1
+
+    # Set log level to info (disable debug logging).
+    LOG_LEVEL: 1
+
+    # Default task settings
+    OS_MAIN_STACK_SIZE: 768
+
+    # Newtmgr is not supported in this app, so disable newtmgr-over-shell.
+    SHELL_NEWTMGR: 0
+
+    REEL_BOARD_ENABLE_ACTIVE_MODE: 1
+    SPI_0_MASTER: 1
+
+    BLE_MESH: 1
+    MSYS_1_BLOCK_COUNT: 48
+
+    BLE_SVC_GAP_DEVICE_NAME: '"reel board"'
+
+    BLE_SM_SC: 1
+    BLE_SM_BONDING: 1
+    BLE_MESH_RELAY: 1
+    BLE_MESH_GATT_PROXY: 0
+    BLE_MESH_PB_ADV: 0
+    BLE_MESH_PB_GATT: 0
+    BLE_MESH_ADV_BUF_COUNT: 30
+    BLE_MESH_LABEL_COUNT: 0
+    BLE_MESH_CFG_CLI: 1
+    BLE_MESH_TX_SEG_MAX: 6
+    BLE_MESH_TX_SEG_MSG_COUNT: 3
+    BLE_MESH_RX_SEG_MSG_COUNT: 3
+    BLE_MESH_CRPL: 128
+    BLE_MESH_RPL_STORE_TIMEOUT: 120
+    BLE_MESH_SETTINGS: 1
+    CONFIG_NFFS: 1