You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ad...@apache.org on 2016/08/10 00:08:03 UTC

[5/6] incubator-mynewt-site git commit: bleprph update.

bleprph update.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/commit/43a2bbac
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/tree/43a2bbac
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/diff/43a2bbac

Branch: refs/heads/develop
Commit: 43a2bbacc0f18860b1e2d8bacabad2320439c006
Parents: 01cda7b
Author: Christopher Collins <cc...@apache.org>
Authored: Fri Aug 5 14:44:18 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Aug 5 16:01:50 2016 -0700

----------------------------------------------------------------------
 docs/os/tutorials/bleprph/bleprph-adv.md        | 114 +++++-----
 docs/os/tutorials/bleprph/bleprph-chr-access.md | 212 ++++++++-----------
 docs/os/tutorials/bleprph/bleprph-conn.md       | 156 --------------
 docs/os/tutorials/bleprph/bleprph-gap-event.md  | 161 ++++++++++++++
 docs/os/tutorials/bleprph/bleprph-intro.md      |   5 +-
 docs/os/tutorials/bleprph/bleprph-svc-reg.md    | 128 ++++++-----
 mkdocs.yml                                      |   2 +-
 7 files changed, 376 insertions(+), 402 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-adv.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-adv.md b/docs/os/tutorials/bleprph/bleprph-adv.md
index ac4f3bd..44a39ac 100644
--- a/docs/os/tutorials/bleprph/bleprph-adv.md
+++ b/docs/os/tutorials/bleprph/bleprph-adv.md
@@ -39,14 +39,43 @@ Let's take a look at *bleprph*'s advertisement code (*main.c*):
 static void
 bleprph_advertise(void)
 {
+    struct ble_gap_adv_params adv_params;
     struct ble_hs_adv_fields fields;
+    const char *name;
     int rc;
 
-    /* Set the advertisement data included in our advertisements. */
+    /**
+     *  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);
-    fields.name = (uint8_t *)bleprph_device_name;
-    fields.name_len = strlen(bleprph_device_name);
+
+    /* Indicate that the flags field should be included; specify a value of 0
+     * to instruct the stack to fill the value in for us.
+     */
+    fields.flags_is_present = 1;
+    fields.flags = 0;
+
+    /* Indicate that the TX power level field should be included; have the
+     * stack fill this one automatically as well.  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;
+
+    name = ble_svc_gap_device_name();
+    fields.name = (uint8_t *)name;
+    fields.name_len = strlen(name);
     fields.name_is_complete = 1;
+
+    fields.uuids16 = (uint16_t[]){ GATT_SVR_SVC_ALERT_UUID };
+    fields.num_uuids16 = 1;
+    fields.uuids16_is_complete = 1;
+
     rc = ble_gap_adv_set_fields(&fields);
     if (rc != 0) {
         BLEPRPH_LOG(ERROR, "error setting advertisement data; rc=%d\n", rc);
@@ -54,8 +83,11 @@ bleprph_advertise(void)
     }
 
     /* Begin advertising. */
-    rc = ble_gap_adv_start(BLE_GAP_DISC_MODE_GEN, BLE_GAP_CONN_MODE_UND,
-                           NULL, 0, NULL, bleprph_on_connect, NULL);
+    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(BLE_ADDR_TYPE_PUBLIC, 0, NULL, BLE_HS_FOREVER,
+                           &adv_params, bleprph_gap_event, NULL);
     if (rc != 0) {
         BLEPRPH_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
         return;
@@ -70,18 +102,9 @@ Now let's examine this code in detail.
 #### Setting advertisement data
 
 
-A NimBLE peripheral specifies what information to include in its advertisements with the following function:
-
-<br>
+A NimBLE peripheral specifies what information to include in its advertisements with the [ble_gap_adv_set_fields()](../../../network/ble/ble_hs/ble_gap/functions/ble_gap_adv_set_fields.md) function.
 
-```c
-int
-ble_gap_adv_set_fields(struct ble_hs_adv_fields *adv_fields)
-```
-
-<br>
-
-The *adv_fields* argument specifies the fields and their contents to include in
+The *fields* argument specifies the fields and their contents to include in
 subsequent advertisements.  The Bluetooth [Core Specification
 Supplement](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735)
 defines a set of standard fields that can be included in an advertisement; the
@@ -96,44 +119,30 @@ function makes a copy of all the advertisement data before it returns.
 *bleprph* doesn't take full advantange of this; it stores its device name in a
 static array.
 
-The code sets three members of the *struct ble_hs_adv_fields* instance:
-
-* name
-* name\_len
-* name\_is\_complete
-
-The first two fields are used to communicate the device's name and are quite
-straight-forward.  The third field requires some explanation.  Bluetooth
-specifies two name-related advertisement fields: *Shortened Local Name* and
-*Complete Local Name*.  Setting the `name_is_complete` variable to 1 or 0 tells
-NimBLE which of these two fields to include in advertisements.  Some other
-advertisement fields also correspond to multiple variables in the field struct,
-so it is a good idea to review the *ble\_hs\_adv\_fields* reference to
-make sure you get the details right in your app.
+The code sets several members of the *struct ble_hs_adv_fields* instance.  Most
+of them are quite straight-forward.  However, the *name\_is\_complete* field
+requires some explanation.  Bluetooth specifies two name-related advertisement
+fields: *Shortened Local Name* and *Complete Local Name*.  Setting the
+`name_is_complete` variable to 1 or 0 tells NimBLE which of these two fields to
+include in advertisements.  Some other advertisement fields also correspond to
+multiple variables in the field struct, so it is a good idea to review the
+*ble\_hs\_adv\_fields* reference to make sure you get the details right in your
+app.
 
 <br>
 
 #### Begin advertising
 
 
-An app starts advertising with the following function:
-
-<br>
-
-```c
-int
-ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode,
-                  uint8_t *peer_addr, uint8_t peer_addr_type,
-                  struct hci_adv_params *adv_params,
-                  ble_gap_conn_fn *cb, void *cb_arg)
-```
-
-This function allows a lot of flexibility, and it might seem daunting at first
-glance.  *bleprph* specifies a simple set of arguments that is appropriate for
-most peripherals.  When getting started on a typical peripheral, we recommend
-you use the same arguments as *bleprph*, with the exception of the last two
-(*cb* and *cb_arg*).  These last two arguments will be specific to your app, so
-let's talk about them.
+An app starts advertising with
+[ble_gap_adv_start()](../../../network/ble/ble_hs/ble_gap/functions/ble_gap_adv_start.md)
+function.  This function allows a lot of flexibility, and it might seem
+daunting at first glance.  *bleprph* specifies a simple set of arguments that
+is appropriate for most peripherals.  When getting started on a typical
+peripheral, we recommend you use the same arguments as *bleprph*, with the
+exception of the last two (*cb* and *cb_arg*; *bleprph_gap_event* and *NULL* in
+this case).  These last two arguments will be specific to your app, so let's
+talk about them.
 
 *cb* is a callback function.  It gets executed when a central connects to your
 peripheral after receiving an advertisement.  The *cb_arg* argument gets passed
@@ -141,10 +150,15 @@ to the *cb* callback.  If your callback doesn't need the *cb_arg* parameter,
 you can do what *bleprph* does and pass *NULL*.  Once a connection is
 established, the *cb* callback becomes permanently associated with the
 connection.  All subsequent events related to the connection are communicated
-to your app via calls to this callback function.  Connection callbacks are an
+to your app via calls to this callback function.  GAP event callbacks are an
 important part of building a BLE app, and we examine *bleprph*'s connection
 callback in detail in the next section of this tutorial.
 
 <br>
 
-**One final note:** Your peripheral automatically stops advertising when a central connects to it.  You can immediately resume advertising if you want to allow another central to connect, but you will need to do so explicitly by calling `ble_gap_adv_start()` again.  Also, be aware NimBLE's default configuration only allows a single connection at a time.  NimBLE supports multiple concurrent connections, but you must configure it to do so first.
+**One final note:** Your peripheral automatically stops advertising when a
+central connects to it.  You can immediately resume advertising if you want to
+allow another central to connect, but you will need to do so explicitly by
+calling `ble_gap_adv_start()` again.  Also, be aware NimBLE's default
+configuration only allows a single connection at a time.  NimBLE supports
+multiple concurrent connections, but you must configure it to do so first.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-chr-access.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-chr-access.md b/docs/os/tutorials/bleprph/bleprph-chr-access.md
index 3865e12..3e6c3a5 100644
--- a/docs/os/tutorials/bleprph/bleprph-chr-access.md
+++ b/docs/os/tutorials/bleprph/bleprph-chr-access.md
@@ -12,7 +12,7 @@ Each characteristic definition in an attribute table contains an *access_cb*
 field.  The *access_cb* field is an application callback that gets executed
 whenever a peer device attempts to read or write the characteristic.
 
-Earlier in this tutorial, we looked at how *bleprph* implements the GAP
+Earlier in this tutorial, we looked at how *bleprph* implements the ANS
 service.  Let's take another look at how *bleprph* specifies the first few
 characteristics in this service.
 
@@ -21,80 +21,68 @@ characteristics in this service.
 ```c
 static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
     {
-        /*** Service: GAP. */
-        .type               = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128            = BLE_UUID16(BLE_GAP_SVC_UUID16),
-        .characteristics    = (struct ble_gatt_chr_def[]) { {
-            /*** Characteristic: Device Name. */
-            .uuid128            = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME),
-            .access_cb          = gatt_svr_chr_access_gap,
-            .flags              = BLE_GATT_CHR_F_READ,
+        /*** Alert Notification Service. */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(GATT_SVR_SVC_ALERT_UUID),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_READ,
         }, {
-            /*** Characteristic: Appearance. */
-            .uuid128            = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE),
-            .access_cb          = gatt_svr_chr_access_gap,
-            .flags              = BLE_GATT_CHR_F_READ,
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_NEW_ALERT),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_NOTIFY,
         }, {
     // [...]
 ```
 
-As you can see, *bleprph* uses the same *access_cb* function for all the GAP
+As you can see, *bleprph* uses the same *access_cb* function for all the ANS
 service characteristics, but the developer could have implemented separate
-functions for each characteristic if they preferred.  Here is the *access_cb*
-function that the GAP service characteristics use:
+functions for each characteristic if they preferred.  Here is part of the
+*access_cb* function that the ANS service characteristics use:
 
 <br>
 
 ```c
+
 static int
-gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                        union ble_gatt_access_ctxt *ctxt, void *arg)
+gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
+                          struct ble_gatt_access_ctxt *ctxt,
+                          void *arg)
 {
     uint16_t uuid16;
+    int rc;
 
-    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+    uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128);
     assert(uuid16 != 0);
 
     switch (uuid16) {
-    case BLE_GAP_CHR_UUID16_DEVICE_NAME:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)bleprph_device_name;
-        ctxt->chr_access.len = strlen(bleprph_device_name);
-        break;
-
-    case BLE_GAP_CHR_UUID16_APPEARANCE:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bleprph_appearance;
-        ctxt->chr_access.len = sizeof bleprph_appearance;
-        break;
-
-    case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bleprph_privacy_flag;
-        ctxt->chr_access.len = sizeof bleprph_privacy_flag;
-        break;
-
-    case BLE_GAP_CHR_UUID16_RECONNECT_ADDR:
-        assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-        if (ctxt->chr_access.len != sizeof bleprph_reconnect_addr) {
-            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
-        }
-        memcpy(bleprph_reconnect_addr, ctxt->chr_access.data,
-               sizeof bleprph_reconnect_addr);
-        break;
-
-    case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bleprph_pref_conn_params;
-        ctxt->chr_access.len = sizeof bleprph_pref_conn_params;
-        break;
+    case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID:
+        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_cat,
+                            sizeof gatt_svr_new_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+
+    case GATT_SVR_CHR_UNR_ALERT_STAT_UUID:
+        if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            if (OS_MBUF_PKTLEN(ctxt->om) != sizeof gatt_svr_unr_alert_stat) {
+                return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+            }
+
+            rc = ble_hs_mbuf_to_flat(ctxt->om, &gatt_svr_unr_alert_stat,
+                                     sizeof gatt_svr_unr_alert_stat, NULL);
+            if (rc != 0) {
+                return BLE_ATT_ERR_UNLIKELY;
+            }
+
+            return 0;
+
+    /* [...] */
 
     default:
         assert(0);
-        break;
+        return BLE_ATT_ERR_UNLIKELY;
     }
-
-    return 0;
 }
 ```
 
@@ -104,44 +92,38 @@ After you've taken a moment to examine the structure of this function, let's exp
 
 #### Function signature
 
-<br>
-
 ```c
 static int
-gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                        union ble_gatt_access_ctxt *ctxt, void *arg)
+gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
+                          struct ble_gatt_access_ctxt *ctxt,
+                          void *arg)
 ```
 
 A characteristic access function always takes this same set of parameters and
 always returns an int.  The parameters to this function type are documented
 below.
 
-<br>
-
 | **Parameter** | **Purpose** | **Notes** |
 | ------------- | ----------- | --------- |
 | conn_handle   | Indicates which connection the characteristic access was sent over. | Use this value to determine which peer is accessing the characteristic. |
 | attr_handle   | The low-level ATT handle of the characteristic value attribute. | Can be used to determine which characteristic is being accessed if you don't want to perform a UUID lookup. |
 | op            | Indicates whether this is a read or write operation | Valid values are:<br>*BLE_GATT_ACCESS_OP_READ_CHR*<br>*BLE_GATT_ACCESS_OP_WRITE_CHR* |
-| ctxt          | Contains the characteristic value pointer that the application needs to access. | For characteristic accesses, use the *ctxt->chr_access* member; for descriptor accesses, use the *ctxt->dsc_access* member. |
+| ctxt          | Contains the characteristic value mbuf that the application needs to access. | For characteristic accesses, use the *ctxt->chr* member; for descriptor accesses, use the *ctxt->dsc* member. |
 
 The return value of the access function tells the NimBLE stack how to respond
 to the peer performing the operation.  A value of 0 indicates success.  For
-failures, the function returns the specific ATT error code that the NimBLE
-stack should respond with.  The ATT error codes are defined in
-[net/nimble/host/include/host/ble_att.h](https://github.com/apache/incubator-mynewt-core/blob/master/net/nimble/host/include/host/ble_att.h).
+failures, the function returns the specific [ATT error code](../../../network/ble/ble_hs/ble_hs_return_codes/#return-codes-att) that the NimBLE
+stack should respond with.  *Note:* The return code is a formal code, **not** a NimBLE value!
 
 <br>
 
 #### Determine characteristic being accessed
 
-<br>
-
 ```c
 {
     uint16_t uuid16;
 
-    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+    uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128);
     assert(uuid16 != 0);
 
     switch (uuid16) {
@@ -155,94 +137,76 @@ accomplish this task:
 * Map characteristics to ATT handles during service registration; use the *attr_handle* parameter as a key into this table during characteristic access.
 * Implement a dedicated function for each characteristic; each function inherently knows which characteristic it corresponds to.
 
-All the GAP service characteristics have 16-bit UUIDs, so this function uses
+All the ANS service characteristics have 16-bit UUIDs, so this function uses
 the *ble_uuid_128_to_16()* function to convert the 128-bit UUID to its
 corresponding 16-bit UUID.  This conversion function returns the corresponding
 16-bit UUID on success, or 0 on failure.  Success is asserted here to ensure
 the NimBLE stack is doing its job properly; the stack should only call this
 function for accesses to characteristics that it is registered with, and all
-GAP service characteristics have valid 16-bit UUIDs.
+ANS service characteristics have valid 16-bit UUIDs.
 
 <br>
 
 #### Read access
 
-<br>
-
 ```c
-    case BLE_GAP_CHR_UUID16_DEVICE_NAME:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)bleprph_device_name;
-        ctxt->chr_access.len = strlen(bleprph_device_name);
-        break;
+    case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID:
+        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_cat,
+                            sizeof gatt_svr_new_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 ```
 
-This code excerpt handles read accesses to the device name characteristic.  The
-*assert()* here is another case of making sure the NimBLE stack is doing its
-job; this characteristic was registered as read-only, so the stack should have
-prevented write accesses.
+This code excerpt handles read accesses to the Supported New Alert Category
+characteristic.  The *assert()* here is another case of making sure the NimBLE
+stack is doing its job; this characteristic was registered as read-only, so the
+stack should have prevented write accesses.
 
-To fulfill a characteristic read request, the application needs to assign the
-*ctxt->chr_access.data* field to point to the attribute data to respond with,
-and fill the *ctxt->chr_access.len* field with the length of the attribute data.
-*bleprph* stores the device name in read-only memory as follows:
+To fulfill a characteristic read request, the application needs fill a buffer (*om*) with the characteristic value.  The NimBLE host will then include the contents of this buffer in its read response.  NimBLE uses [mbufs](../../../os/core_os/mbuf/mbuf) to exchange data between itself and the application.  To fill an mbuf with data that is available in a contiguous chunk of memory, the *os_mbuf_append()* function suffices.  The source of the data, *gatt_svr_new_alert_cat*, is is stored in read-only memory as follows:
 
 <br>
 
 ```c
-const char *bleprph_device_name = "nimble-bleprph";
+static const uint8_t gatt_svr_new_alert_cat = 0x01; /* Simple alert. */
 ```
 
-The cast to pointer-to-void is a necessary annoyance to remove the *const*
-qualifier from the device name variable.  You will need to "cast away const"
-whenever you respond to read requests with read-only data.
-
 It is not shown in the above snippet, but this function ultimately returns 0.
 By returning 0, *bleprph* indicates that the characteristic data in
-*ctxt->chr_access* is valid and that NimBLE should include it in its response
+*ctxt->om* is valid and that NimBLE should include it in its response
 to the peer.
 
 <br>
 
-**A word of warning:** The attribute data that *ctxt->chr_access.data* points to
-must remain valid after the access function returns, as the NimBLE stack needs
-to use it to form a GATT read response.  In other words, you must not
-allocate the characteristic value data on the stack of the access function.
-Two characteristic accesses never occur at the same time, so it is OK to use
-the same memory for repeated accesses.
-
-<br>
-
 #### Write access
 
-<br>
-
 ```c
-    case BLE_GAP_CHR_UUID16_RECONNECT_ADDR:
-        assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-        if (ctxt->chr_access.len != sizeof bleprph_reconnect_addr) {
-            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
-        }
-        memcpy(bleprph_reconnect_addr, ctxt->chr_access.data,
-               sizeof bleprph_reconnect_addr);
-        break;
+static uint16_t gatt_svr_unr_alert_stat;
 ```
 
-This code excerpt handles writes to the reconnect address characteristic.  This
-characteristic was registered as write-only, so the *assert()* here is just a
-safety precaution to ensure the NimBLE stack is doing its job.
+```c
+    case GATT_SVR_CHR_UNR_ALERT_STAT_UUID:
+        if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            if (OS_MBUF_PKTLEN(ctxt->om) != sizeof gatt_svr_unr_alert_stat) {
+                return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+            }
+
+            rc = ble_hs_mbuf_to_flat(ctxt->om, &gatt_svr_unr_alert_stat,
+                                     sizeof gatt_svr_unr_alert_stat, NULL);
+            if (rc != 0) {
+                return BLE_ATT_ERR_UNLIKELY;
+            }
+
+            return 0;
+        } else /* [...] */
+```
 
-For writes, the roles of the *ctxt->chr_access.data* and *ctxt->chr_access.len*
-fields are the reverse of the read case.  The NimBLE stack uses these fields to
-indicate the data written by the peer.
+This code excerpt handles writes to the New Alert characteristic.  For writes,
+the role of the *ctxt->om* field is the reverse of the read case.  The NimBLE
+stack uses these fields to indicate the data written by the peer.
 
 Many characteristics have strict length requirements for write operations.
-This characteristic has such a restriction; if the written data is not a 48-bit
-BR address, the application tells NimBLE to respond with an invalid attribute
-value length error.
-
-For writes, the *ctxt->chr_access.data* pointer is only valid for the duration
-of the access function.  If the application needs to save the written data, it
-should store it elsewhere before the function returns.  In this case, *bleprph*
-stores the specified address in a global variable called
-*bleprph_reconnect_addr*.
+This characteristic has such a restriction; if the written data is not a 2-byte
+value, the application tells NimBLE to respond with an invalid attribute value
+length error.
+
+*bleprph* copies the data out of the supplied mbuf and writes it to a contiguous chunk of storage (the *gatt_svr_unr_alert_stat* variable).  This is accomplished with the [ble_hs_mbuf_to_flat()](../../../network/ble/ble_hs/other/functions/ble_hs_mbuf_to_flat) function.  If the application did not have a suitable destination for the data handy, it could have inherited the mbuf from the context object.  This is done by saving a copy of the mbuf pointer, and assigning *NULL* to *ctxt->om*.  By assigning *NULL* to the mbuf pointer, your application prevents the stack from freeing the mbuf while it is still being used.  Be aware, however, that it is the application's responsibility to free inherited mbufs.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-conn.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-conn.md b/docs/os/tutorials/bleprph/bleprph-conn.md
deleted file mode 100644
index ffbf7a1..0000000
--- a/docs/os/tutorials/bleprph/bleprph-conn.md
+++ /dev/null
@@ -1,156 +0,0 @@
-## BLE Peripheral Project
-
-### Connection callbacks
-
-<br>
-
-#### Overview
-
-
-Every BLE connection has a *connection callback* associated with it.  A
-connection callback is a bit of application code which NimBLE uses to inform
-you of connection-related events.  For example, if a connection is terminated,
-NimBLE lets you know about it with a call to that connection's callback.
-
-In the [advertising section](bleprph-adv/) of this tutorial, we saw how the
-application specifies a connection callback when it begins advertising.  NimBLE
-uses this callback to notify the application that a central has connected to
-your peripheral after receiving an advertisement.  Let's revisit how *bleprph* specifies its connection callback when advertising:
-
-<br>
-
-```c
-    /* Begin advertising. */
-    rc = ble_gap_adv_start(BLE_GAP_DISC_MODE_GEN, BLE_GAP_CONN_MODE_UND,
-                           NULL, 0, NULL, bleprph_on_connect, NULL);
-    if (rc != 0) {
-        BLEPRPH_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
-        return;
-    }
-```
-
-<br>
-
-#### bleprph_on_connect()
-
-
-The `bleprph_on_connect()` function is *bleprph*'s connection callback; NimBLE
-calls this function when the advertising operation leads to connection
-establishment.  Upon connecting, this callback becomes permanently associated
-with the connection; all subsequent events related to this connection are
-communicated through this callback.
-
-Now let's look at the function that *bleprph* uses for all its connection
-callbacks: `bleprph_on_connect()`.
-
-
-```c
-static int
-bleprph_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
-                   void *arg)
-{
-    switch (event) {
-    case BLE_GAP_EVENT_CONN:
-        BLEPRPH_LOG(INFO, "connection %s; status=%d ",
-                    status == 0 ? "up" : "down", status);
-        bleprph_print_conn_desc(ctxt->desc);
-        BLEPRPH_LOG(INFO, "\n");
-
-        if (status != 0) {
-            /* Connection terminated; resume advertising. */
-            bleprph_advertise();
-        }
-        break;
-    }
-
-    return 0;
-}
-```
-
-<br>
-
-Connection callbacks are used to communicate a variety of events related to a
-connection.  An application determines the type of event that occurred by
-inspecting the value of the *event* parameter.  The full list of event codes
-can be found in [net/nimble/host/include/host/ble_gatt.h](https://github.com/apache/incubator-mynewt-core/blob/master/net/nimble/host/include/host/ble_gatt.h).
-*bleprph* only concerns itself with a single event type: *BLE_GAP_EVENT_CONN*.
-This event indicates that a new connection has been established, or an existing
-connection has been terminated; the *status* parameter clarifies which.  As you
-can see, *bleprph* uses the *status* parameter to determine if it should resume
-advertising.
-
-The *ctxt* parameter contains additional information about the connection
-event.  *bleprph* does nothing more than log some fields of this struct, but
-some apps will likely want to perform further actions, e.g., perform service
-discovery on the connected device.  The *struct ble_gap_conn_ctxt* type is
-defined as follows:
-
-```c
-struct ble_gap_conn_ctxt {
-    struct ble_gap_conn_desc *desc;
-
-    union {
-        struct {
-            struct ble_gap_upd_params *self_params;
-            struct ble_gap_upd_params *peer_params;
-        } update;
-
-        struct ble_gap_sec_params *sec_params;
-    };
-};
-```
-
-<br>
-
-As shown, a connection context object consists of two parts:
-
-* *desc:* The connection descriptor; indicates properties of the connection.
-* *anonymous union:* The contents are event-specific; check the *event* code to determine which member field (if any) is relevant.
-
-For events of type *BLE_GAP_EVENT_CONN*, the anonymous union is not used at all, so the only information carried by the context struct is the connection descriptor.  The *struct ble_gap_conn_desc* type is defined as follows:
-
-```c
-struct ble_gap_conn_desc {
-    uint8_t peer_addr[6];
-    uint16_t conn_handle;
-    uint16_t conn_itvl;
-    uint16_t conn_latency;
-    uint16_t supervision_timeout;
-    uint8_t peer_addr_type;
-};
-```
-
-<br>
-
-We will examine these fields in a slightly different order from how they appear
-in the struct definition.
-
-<br>
-
-| *Field* | *Purpose* | *Notes* |
-| ------- | --------- | ------- |
-| peer\_addr | The 48-bit address of the peer device. | |
-| peer\_addr\_type | Whether the peer is using a public or random address. | The address type list is documented in [net/nimble/include/nimble/hci_common.h](https://github.com/apache/incubator-mynewt-core/blob/master/net/nimble/include/nimble/hci_common.h). |
-| conn\_handle | The 16-bit handle associated with this connection. | This number is how your app and the NimBLE stack refer to this connection. |
-| conn\_itvl,<br>conn\_latency,<br>supervision\_timeout | Low-level properties of the connection. | |
-
-<br>
-
-#### Guarantees
-
-It is important to know what your application code is allowed to do from within
-a connection callback.
-
-**No restrictions on NimBLE operations**
-
-Your app is free to make calls into the NimBLE stack from within a connection
-callback.  *bleprph* takes advantage of this freedom when it resumes
-advertising upon connection termination.  All other NimBLE operations are also
-allowed (service discovery, pairing initiation, etc).
-
-**All context data is transient**
-
-Pointers in the context object point to data living on the stack.  Your
-callback is free to read (or write, if appropriate) through these pointers, but
-you should not store these pointers for later use.  If your application needs
-to retain some data from a context object, it needs to make a copy.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-gap-event.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-gap-event.md b/docs/os/tutorials/bleprph/bleprph-gap-event.md
new file mode 100644
index 0000000..cedf219
--- /dev/null
+++ b/docs/os/tutorials/bleprph/bleprph-gap-event.md
@@ -0,0 +1,161 @@
+## BLE Peripheral Project
+
+### GAP Event callbacks
+
+<br>
+
+#### Overview
+
+
+Every BLE connection has a *GAP event callback* associated with it.  A
+GAP event callback is a bit of application code which NimBLE uses to inform
+you of connection-related events.  For example, if a connection is terminated,
+NimBLE lets you know about it with a call to that connection's callback.
+
+In the [advertising section](bleprph-adv/) of this tutorial, we saw how the
+application specifies a GAP event callback when it begins advertising.  NimBLE
+uses this callback to notify the application that a central has connected to
+your peripheral after receiving an advertisement.  Let's revisit how *bleprph* specifies its connection callback when advertising:
+
+<br>
+
+```c
+    /* 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(BLE_ADDR_TYPE_PUBLIC, 0, NULL, BLE_HS_FOREVER,
+                           &adv_params, bleprph_gap_event, NULL);
+    if (rc != 0) {
+        BLEPRPH_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
+        return;
+    }
+```
+
+<br>
+
+#### bleprph_gap_event()
+
+
+The `bleprph_gap_event()` function is *bleprph*'s GAP event callback; NimBLE
+calls this function when the advertising operation leads to connection
+establishment.  Upon connection establishment, this callback becomes
+permanently associated with the connection; all subsequent events related to
+this connection are communicated through this callback.
+
+Now let's look at the function that *bleprph* uses for all its connection
+callbacks: `bleprph_gap_event()`.
+
+
+```c
+/**
+ * The nimble host executes this callback when a GAP event occurs.  The
+ * application associates a GAP event callback with each connection that forms.
+ * bleprph uses the same callback for all connections.
+ *
+ * @param event                 The type of event being signalled.
+ * @param ctxt                  Various information pertaining to the event.
+ * @param arg                   Application-specified argument; unuesd by
+ *                                  bleprph.
+ *
+ * @return                      0 if the application successfully handled the
+ *                                  event; nonzero on failure.  The semantics
+ *                                  of the return code is specific to the
+ *                                  particular GAP event being signalled.
+ */
+static int
+bleprph_gap_event(struct ble_gap_event *event, void *arg)
+{
+    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. */
+        BLEPRPH_LOG(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);
+            bleprph_print_conn_desc(&desc);
+        }
+        BLEPRPH_LOG(INFO, "\n");
+
+        if (event->connect.status != 0) {
+            /* Connection failed; resume advertising. */
+            bleprph_advertise();
+        }
+        return 0;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        BLEPRPH_LOG(INFO, "disconnect; reason=%d ", event->disconnect.reason);
+        bleprph_print_conn_desc(&event->disconnect.conn);
+        BLEPRPH_LOG(INFO, "\n");
+
+        /* Connection terminated; resume advertising. */
+        bleprph_advertise();
+        return 0;
+
+    case BLE_GAP_EVENT_CONN_UPDATE:
+        /* The central has updated the connection parameters. */
+        BLEPRPH_LOG(INFO, "connection updated; status=%d ",
+                    event->conn_update.status);
+        rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+        assert(rc == 0);
+        bleprph_print_conn_desc(&desc);
+        BLEPRPH_LOG(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_ENC_CHANGE:
+        /* Encryption has been enabled or disabled for this connection. */
+        BLEPRPH_LOG(INFO, "encryption change event; status=%d ",
+                    event->enc_change.status);
+        rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+        assert(rc == 0);
+        bleprph_print_conn_desc(&desc);
+        BLEPRPH_LOG(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_SUBSCRIBE:
+        BLEPRPH_LOG(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
+                          "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
+                    event->subscribe.conn_handle,
+                    event->subscribe.attr_handle,
+                    event->subscribe.reason,
+                    event->subscribe.prev_notify,
+                    event->subscribe.cur_notify,
+                    event->subscribe.prev_indicate,
+                    event->subscribe.cur_indicate);
+        return 0;
+    }
+
+    return 0;
+}
+```
+
+<br>
+
+Connection callbacks are used to communicate a variety of events related to a
+connection.  An application determines the type of event that occurred by
+inspecting the value of the *event->type* parameter.  The full list of event
+codes can be found on the [GAP events](../../../network/ble/ble_hs/ble_gap/definitions/ble_gap_defs/) page.
+
+#### Guarantees
+
+It is important to know what your application code is allowed to do from within
+a connection callback.
+
+**No restrictions on NimBLE operations**
+
+Your app is free to make calls into the NimBLE stack from within a connection
+callback.  *bleprph* takes advantage of this freedom when it resumes
+advertising upon connection termination.  All other NimBLE operations are also
+allowed (service discovery, pairing initiation, etc).
+
+**All context data is transient**
+
+Pointers in the context object point to data living on the stack.  Your
+callback is free to read (or write, if appropriate) through these pointers, but
+you should not store these pointers for later use.  If your application needs
+to retain some data from a context object, it needs to make a copy.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-intro.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-intro.md b/docs/os/tutorials/bleprph/bleprph-intro.md
index 77a72b9..f03f1d7 100644
--- a/docs/os/tutorials/bleprph/bleprph-intro.md
+++ b/docs/os/tutorials/bleprph/bleprph-intro.md
@@ -8,9 +8,10 @@
 
 *bleprph* is an example app included in the apache-mynewt-core repository.  This app implements a simple BLE peripheral with the following properties:
 
-* Supports three services: GAP, GATT, and alert notification service (ANS).
 * Supports a single concurrent connection.
 * Automatically advertises connectability when not connected to a central device.
+* Supports pairing and bonding.
+* Supports five services.
 
 This tutorial aims to provide a guided tour through the *bleprph* app source
 code.  This document builds on some concepts described elsewhere in the Apache
@@ -32,5 +33,3 @@ these concepts, you will probably want to check out this
 from the Bluetooth Developer's site before proceeding.
 
 Now let's dig in to some C code.
-<br>
-

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/docs/os/tutorials/bleprph/bleprph-svc-reg.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/bleprph/bleprph-svc-reg.md b/docs/os/tutorials/bleprph/bleprph-svc-reg.md
index dc8747d..a40e772 100644
--- a/docs/os/tutorials/bleprph/bleprph-svc-reg.md
+++ b/docs/os/tutorials/bleprph/bleprph-svc-reg.md
@@ -8,33 +8,38 @@
 
 The NimBLE host uses a table-based design for GATT server configuration.  The
 set of supported attributes are expressed as a series of tables that resides in
-your C code.  When possible, we recommend using a single monolithic table, as
-it results in code that is simpler and less error prone.  Multiple tables
-can be used if it is impractical for the entire attribute set to live in one
-place in your code.
+your C code.
 
-*bleprph* uses a single attribute table located in the *gatt_svr.c* file,
-so let's take a look at that now.  The attribute table is called
-`gatt_svr_svcs`; here are the first several lines from this table:
+*bleprph* supports the following services:
+
+* GAP
+* GATT
+* newtmgr
+* Alert Notification
+* Security Test
+
+The first two services (GAP and GATT) are mandatory services that all BLE peripherals must support.  These are implemented in a separate package which the *bleprph* app depends on.  Later, we will see how the *main()* function initializes and registers this package.  Your app will follow the same procedure when using GATT service libraries.
+
+The third service, newtmgr, is vendor-specific service supported by most Mynewt devices.  This service is used for remote configuration, status queries, and firmware updates.  As with GAP and GATT, this service is implemented in a package separate from the *bleprph* app.
+
+The final two services, *Alert Notification* and *Security Test*, are not implemented in separate libraries.  Rather, these services are specific to the app, so they are implemented the *bleprph* app itself.  The attribute table used to express these services is located in the *gatt_svr.c* file, so let's take a look at that now.  The attribute table is called `gatt_svr_svcs`; here are the first several lines from this table:
 
 <br>
 
 ```c
 static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
     {
-        /*** Service: GAP. */
-        .type               = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128            = BLE_UUID16(BLE_GAP_SVC_UUID16),
-        .characteristics    = (struct ble_gatt_chr_def[]) { {
-            /*** Characteristic: Device Name. */
-            .uuid128            = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME),
-            .access_cb          = gatt_svr_chr_access_gap,
-            .flags              = BLE_GATT_CHR_F_READ,
+        /*** Alert Notification Service. */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(GATT_SVR_SVC_ALERT_UUID),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_READ,
         }, {
-            /*** Characteristic: Appearance. */
-            .uuid128            = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE),
-            .access_cb          = gatt_svr_chr_access_gap,
-            .flags              = BLE_GATT_CHR_F_READ,
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_NEW_ALERT),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_NOTIFY,
         }, {
     // [...]
 ```
@@ -43,16 +48,14 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
 
 As you can see, the table is an array of service definitions (
 `struct ble_gatt_svc_def`).  This code excerpt contains a small part of the
-*GAP service*.  The GAP service exposes generic information about a device,
-such as its name and appearance.  Support for the GAP service is mandatory for
-all BLE peripherals.  Let's now consider the contents of this table in more
-detail.
+Alert Notification service.  Let's now consider the contents of this table in
+more detail.
 
 A service definition consists of the following fields:
 
-| *Field* | *Meaning* | *Notes* |
-| ------- | --------- | ------- |
-| type        | Specifies whether this is a primary or secondary service. | Secondary services are not very common.  When in doubt, specify *BLE_GATT_SVC_TYPE_PRIMARY* for new services. |
+| *Field*         | *Meaning* | *Notes* |
+| --------------- | --------- | ------- |
+| type            | Specifies whether this is a primary or secondary service. | Secondary services are not very common.  When in doubt, specify *BLE_GATT_SVC_TYPE_PRIMARY* for new services. |
 | uuid128         | The 128-bit UUID of this service. | If the service has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the `BLE_UUID16()` macro. |
 | characteristics | The array of characteristics that belong to this service.   | |
 
@@ -65,10 +68,10 @@ definition consists of the following fields:
 | *Field* | *Meaning* | *Notes* |
 | ------- | --------- | ------- |
 | uuid128     | The 128-bit UUID of this characteristic. | If the characteristic has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the `BLE_UUID16()` macro. |
-| access_cb   | A callback function that gets executed whenever a peer device accesses this characteristic. | *For reads:* this function generates the value that gets sent back to the peer.<br>*For writes:* this function provides the written value as an argument. |
+| access\_cb  | A callback function that gets executed whenever a peer device accesses this characteristic. | *For reads:* this function generates the value that gets sent back to the peer.<br>*For writes:* this function receives the written value as an argument. |
 | flags       | Indicates which operations are permitted for this characteristic.  The NimBLE stack responds negatively when a peer attempts an unsupported operation. | The full list of flags can be found under `ble_gatt_chr_flags` in [net/nimble/host/include/host/ble_gatt.h](https://github.com/apache/incubator-mynewt-core/blob/master/net/nimble/host/include/host/ble_gatt.h).|
 
-The access callback is what implements the characteristic's behavior.  Access
+A characteristic's access callback implements its behavior.  Access
 callbacks are described in detail in the next section:
 [BLE Peripheral - Characteristic Access](bleprph-chr-access/).
 
@@ -81,29 +84,20 @@ characteristic array and service array.
 
 ```c hl_lines="26 31"
     {
-        /*** Alert Notification Service. */
+        /*** Service: Security test. */
         .type = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128 = BLE_UUID16(GATT_SVR_SVC_ALERT_UUID),
+        .uuid128 = gatt_svr_svc_sec_test_uuid,
         .characteristics = (struct ble_gatt_chr_def[]) { {
-            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID),
-            .access_cb = gatt_svr_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            .uuid128 = BLE_UUID16(GATT_SVR_CHR_NEW_ALERT),
-            .access_cb = gatt_svr_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_NOTIFY,
+            /*** Characteristic: Random number generator. */
+            .uuid128 = gatt_svr_chr_sec_test_rand_uuid,
+            .access_cb = gatt_svr_chr_access_sec_test,
+            .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
         }, {
-            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID),
-            .access_cb = gatt_svr_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            .uuid128 = BLE_UUID16(GATT_SVR_CHR_UNR_ALERT_STAT_UUID),
-            .access_cb = gatt_svr_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_NOTIFY,
-        }, {
-            .uuid128 = BLE_UUID16(GATT_SVR_CHR_ALERT_NOT_CTRL_PT),
-            .access_cb = gatt_svr_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_WRITE,
+            /*** Characteristic: Static value. */
+            .uuid128 = gatt_svr_chr_sec_test_static_uuid,
+            .access_cb = gatt_svr_chr_access_sec_test,
+            .flags = BLE_GATT_CHR_F_READ |
+                     BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
         }, {
             0, /* No more characteristics in this service. */
         } },
@@ -118,35 +112,33 @@ characteristic array and service array.
 
 #### Registration function
 
-After you have created your service table, your app needs to register it with the NimBLE stack.  This is done by calling the following function:
+After you have created your service table, your app needs to register it with the NimBLE stack.  This is done by calling the [ble_gatts_add_svcs()](../../../network/ble/ble_hs/ble_gatts/functions/ble_gatts_add_svcs.md) function.  There is a small complication, though.  The NimBLE host needs to allocate sufficient resources upfront to accommodate all of your peripheral's services.  You can ensure your GATT services are accounted for in the host configuration object by calling the [ble_gatts_count_cfg()](../../../network/ble/ble_hs/ble_gatts/functions/ble_gatts_count_cfg.md) function.
+
+The *bleprph* app registers its services in *gatt_svr.c* as follows:
 
 ```c
 int
-ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs,
-                        ble_gatt_register_fn *cb, void *cb_arg)
-```
+gatt_svr_init(struct ble_hs_cfg *cfg)
+{
+    int rc;
 
-The function parameters are documented below.
+    rc = ble_gatts_count_cfg(gatt_svr_svcs, cfg);
+    if (rc != 0) {
+        return rc;
+    }
 
-| *Parameter* | *Meaning* | *Notes* |
-| ----------- | --------- | ------- |
-| svcs        | The table of services to register. | |
-| cb          | A callback that gets executed each time a service, characteristic, or descriptor is registered. | Optional; pass NULL if you don't want to be notified. |
-| cb\_arg     | An argument that gets passed to the callback function on each invocation. | Optional; pass NULL if there is no callback or if you don't need a special argument. |
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
 
-The `ble_gatts_register_svcs()` function returns 0 on success, or a
-*BLE_HS_E[...]* error code on failure.
+    return 0;
+}
 
-More detailed information about the registration callback function can be found
-in the [BLE User Guide](../../../network/ble/ble_intro/) (TBD).
-
-The *bleprph* app registers its services as follows:
-
-```c
-    rc = ble_gatts_register_svcs(gatt_svr_svcs, gatt_svr_register_cb, NULL);
-    assert(rc == 0);
 ```
 
+You application will perform the above two-step process for each service definition array that you wish to register.  Libraries that implement GATT services will generally expose an initialization function which does this for you.
+
 <br>
 
 #### Descriptors and Included Services

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/43a2bbac/mkdocs.yml
----------------------------------------------------------------------
diff --git a/mkdocs.yml b/mkdocs.yml
index 4dfb059..aff4e5b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -53,7 +53,7 @@ pages:
             - 'Service Registration': 'os/tutorials/bleprph/bleprph-svc-reg.md'
             - 'Characteristic Access': 'os/tutorials/bleprph/bleprph-chr-access.md'
             - 'Advertising': 'os/tutorials/bleprph/bleprph-adv.md'
-            - 'Connection Callbacks': 'os/tutorials/bleprph/bleprph-conn.md'
+            - 'GAP Event Callbacks': 'os/tutorials/bleprph/bleprph-gap-event.md'
         - 'BLE iBeacon': 'os/tutorials/ibeacon.md'
         - 'BLE HCI interface': 'os/tutorials/blehci_project.md'
     - OS User Guide: