You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/01/23 04:20:03 UTC

[6/8] incubator-mynewt-larva git commit: Reliable Writes GATT procedure.

Reliable Writes GATT procedure.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/5dd3cc0d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/5dd3cc0d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/5dd3cc0d

Branch: refs/heads/master
Commit: 5dd3cc0d6d3917133d84d838706bc3bbc6fe0abb
Parents: 1ede1c7
Author: Christopher Collins <cc...@gmail.com>
Authored: Fri Jan 22 13:09:08 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Fri Jan 22 19:19:44 2016 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_gatt.h        |   7 +
 net/nimble/host/src/ble_gattc.c                | 273 +++++++++++++++++++-
 net/nimble/host/src/test/ble_gatt_write_test.c | 121 +++++++++
 3 files changed, 391 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/5dd3cc0d/net/nimble/host/include/host/ble_gatt.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gatt.h b/net/nimble/host/include/host/ble_gatt.h
index 849f3a3..67332c4 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -71,6 +71,10 @@ typedef int ble_gatt_mult_attr_fn(uint16_t conn_handle,
                                   uint8_t num_attr_handles,
                                   uint8_t *attr_data, uint16_t attr_data_len,
                                   void *arg);
+typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle,
+                                      struct ble_gatt_error *error,
+                                      struct ble_gatt_attr *attrs,
+                                      uint8_t num_attrs, void *arg);
 
 typedef int ble_gatt_chr_fn(uint16_t conn_handle, struct ble_gatt_error *error,
                             struct ble_gatt_chr *chr, void *arg);
@@ -115,6 +119,9 @@ int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value,
 int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
                          void *value, uint16_t value_len, ble_gatt_attr_fn *cb,
                          void *cb_arg);
+int ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs,
+                             int num_attrs, ble_gatt_reliable_attr_fn *cb,
+                             void *cb_arg);
 int ble_gattc_read_dsc(uint16_t conn_handle, uint16_t attr_handle,
                        ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_read_long_dsc(uint16_t conn_handle, uint16_t attr_handle,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/5dd3cc0d/net/nimble/host/src/ble_gattc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c
index c0870ce..864feb6 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -52,8 +52,9 @@
 #define BLE_GATT_OP_WRITE_NO_RSP                11
 #define BLE_GATT_OP_WRITE                       12
 #define BLE_GATT_OP_WRITE_LONG                  13
-#define BLE_GATT_OP_INDICATE                    14
-#define BLE_GATT_OP_MAX                         15
+#define BLE_GATT_OP_WRITE_RELIABLE              14
+#define BLE_GATT_OP_INDICATE                    15
+#define BLE_GATT_OP_MAX                         16
 
 /** Represents an in-progress GATT procedure. */
 struct ble_gattc_proc {
@@ -158,6 +159,14 @@ struct ble_gattc_proc {
         } write_long;
 
         struct {
+            struct ble_gatt_attr *attrs;
+            int num_attrs;
+            int cur_attr;
+            ble_gatt_reliable_attr_fn *cb;
+            void *cb_arg;
+        } write_reliable;
+
+        struct {
             struct ble_gatt_attr attr;
             ble_gatt_attr_fn *cb;
             void *cb_arg;
@@ -205,6 +214,7 @@ static int ble_gattc_read_mult_kick(struct ble_gattc_proc *proc);
 static int ble_gattc_write_no_rsp_kick(struct ble_gattc_proc *proc);
 static int ble_gattc_write_kick(struct ble_gattc_proc *proc);
 static int ble_gattc_write_long_kick(struct ble_gattc_proc *proc);
+static int ble_gattc_write_reliable_kick(struct ble_gattc_proc *proc);
 static int ble_gattc_indicate_kick(struct ble_gattc_proc *proc);
 
 /**
@@ -237,6 +247,8 @@ static void ble_gattc_write_err(struct ble_gattc_proc *proc, int status,
                                 uint16_t att_handle);
 static void ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
                                      uint16_t att_handle);
+static void ble_gattc_write_reliable_err(struct ble_gattc_proc *proc,
+                                         int status, uint16_t att_handle);
 static void ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status,
                                    uint16_t att_handle);
 
@@ -297,6 +309,16 @@ static int
 ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc,
                              struct ble_hs_conn *conn, int status);
 
+static int
+ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn,
+                                 int status,
+                                 struct ble_att_prep_write_cmd *rsp,
+                                 void *attr_data, uint16_t attr_len);
+static int
+ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn, int status);
+
 
 typedef int ble_gattc_rx_adata_fn(struct ble_gattc_proc *proc,
                                   struct ble_hs_conn *conn,
@@ -322,6 +344,25 @@ struct ble_gattc_rx_attr_entry {
     ble_gattc_rx_attr_fn *cb;
 };
 
+typedef int ble_gattc_rx_prep_fn(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn,
+                                 int status,
+                                 struct ble_att_prep_write_cmd *rsp,
+                                 void *attr_data, uint16_t attr_len);
+
+struct ble_gattc_rx_prep_entry {
+    uint8_t op;
+    ble_gattc_rx_prep_fn *cb;
+};
+
+typedef int ble_gattc_rx_exec_fn(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn, int status);
+
+struct ble_gattc_rx_exec_entry {
+    uint8_t op;
+    ble_gattc_rx_exec_fn *cb;
+};
+
 static const struct ble_gattc_rx_adata_entry
     ble_gattc_rx_read_type_elem_entries[] = {
 
@@ -346,6 +387,16 @@ static const struct ble_gattc_rx_attr_entry ble_gattc_rx_read_rsp_entries[] = {
     { BLE_GATT_OP_FIND_INC_SVCS,    ble_gattc_find_inc_svcs_rx_read_rsp },
 };
 
+static const struct ble_gattc_rx_prep_entry ble_gattc_rx_prep_entries[] = {
+    { BLE_GATT_OP_WRITE_LONG,       ble_gattc_write_long_rx_prep },
+    { BLE_GATT_OP_WRITE_RELIABLE,   ble_gattc_write_reliable_rx_prep },
+};
+
+static const struct ble_gattc_rx_exec_entry ble_gattc_rx_exec_entries[] = {
+    { BLE_GATT_OP_WRITE_LONG,       ble_gattc_write_long_rx_exec },
+    { BLE_GATT_OP_WRITE_RELIABLE,   ble_gattc_write_reliable_rx_exec },
+};
+
 /**
  * Dispatch entries - this array maps GATT procedure types to their
  * corresponding kick and error functions.
@@ -410,6 +461,10 @@ static const struct ble_gattc_dispatch_entry {
         .kick_cb = ble_gattc_write_long_kick,
         .err_cb = ble_gattc_write_long_err,
     },
+    [BLE_GATT_OP_WRITE_RELIABLE] = {
+        .kick_cb = ble_gattc_write_reliable_kick,
+        .err_cb = ble_gattc_write_reliable_err,
+    },
     [BLE_GATT_OP_INDICATE] = {
         .kick_cb = ble_gattc_indicate_kick,
         .err_cb = ble_gattc_indicate_err,
@@ -3022,7 +3077,7 @@ err:
 
 /**
  * Handles an incoming execute-write-response for the specified
- * write-long-cahracteristic-values proc.
+ * write-long-characteristic-values proc.
  */
 static int
 ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc,
@@ -3069,6 +3124,195 @@ ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, void *value,
 }
 
 /*****************************************************************************
+ * $write reliable                                                           *
+ *****************************************************************************/
+
+/**
+ * Calls a write-long-characteristic-value proc's callback with the specified
+ * parameters.  If the proc has no callback, this function is a no-op.
+ *
+ * @return                      The return code of the callback (or 0 if there
+ *                                  is no callback).
+ */
+static int
+ble_gattc_write_reliable_cb(struct ble_gattc_proc *proc, int status,
+                            uint16_t att_handle)
+{
+    int rc;
+
+    if (proc->write_reliable.cb == NULL) {
+        rc = 0;
+    } else {
+        rc = proc->write_reliable.cb(proc->conn_handle,
+                                     ble_gattc_error(status, att_handle),
+                                     proc->write_reliable.attrs,
+                                     proc->write_reliable.num_attrs,
+                                     proc->write_reliable.cb_arg);
+    }
+
+    return rc;
+}
+
+/**
+ * Triggers a pending transmit for the specified
+ * write-reliable-characteristic-value proc.
+ */
+static int
+ble_gattc_write_reliable_kick(struct ble_gattc_proc *proc)
+{
+    struct ble_att_prep_write_cmd prep_req;
+    struct ble_att_exec_write_req exec_req;
+    struct ble_gatt_attr *attr;
+    struct ble_hs_conn *conn;
+    int attr_idx;
+    int rc;
+
+    conn = ble_hs_conn_find(proc->conn_handle);
+    if (conn == NULL) {
+        rc = BLE_HS_ENOTCONN;
+        goto err;
+    }
+
+    attr_idx = proc->write_reliable.cur_attr;
+    if (attr_idx < proc->write_reliable.num_attrs) {
+        attr = proc->write_reliable.attrs + attr_idx;
+        prep_req.bapc_handle = attr->handle;
+        prep_req.bapc_offset = 0;
+        rc = ble_att_clt_tx_prep_write(conn, &prep_req, attr->value,
+                                       attr->value_len);
+    } else {
+        exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM;
+        rc = ble_att_clt_tx_exec_write(conn, &exec_req);
+    }
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    if (ble_gattc_tx_postpone_chk(proc, rc)) {
+        return BLE_HS_EAGAIN;
+    }
+
+    ble_gattc_write_reliable_cb(proc, rc, 0);
+    return BLE_HS_EDONE;
+}
+
+/**
+ * Handles an incoming ATT error response for the specified
+ * write-reliable-characteristic-value proc.
+ */
+static void
+ble_gattc_write_reliable_err(struct ble_gattc_proc *proc, int status,
+                             uint16_t att_handle)
+{
+    ble_gattc_write_reliable_cb(proc, status, att_handle);
+}
+
+/**
+ * Handles an incoming prepare-write-response for the specified
+ * write-reliable-cahracteristic-values proc.
+ */
+static int
+ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn,
+                                 int status,
+                                 struct ble_att_prep_write_cmd *rsp,
+                                 void *attr_data, uint16_t attr_len)
+{
+    struct ble_gatt_attr *attr;
+    int rc;
+
+    if (status != 0) {
+        rc = status;
+        goto err;
+    }
+
+    if (proc->write_reliable.cur_attr >= proc->write_reliable.num_attrs) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+    attr = proc->write_reliable.attrs + proc->write_reliable.cur_attr;
+
+    /* Verify the response. */
+    if (rsp->bapc_handle != attr->handle) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+    if (rsp->bapc_offset != 0) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+    if (attr_len != attr->value_len) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+    if (memcmp(attr_data, attr->value, attr_len) != 0) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+
+    proc->write_reliable.cur_attr++;
+    ble_gattc_proc_set_pending(proc);
+
+    return 0;
+
+err:
+    /* XXX: Might need to cancel pending writes. */
+    ble_gattc_write_reliable_cb(proc, rc, 0);
+    return 1;
+}
+
+/**
+ * Handles an incoming execute-write-response for the specified
+ * write-reliable-characteristic-values proc.
+ */
+static int
+ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc,
+                                 struct ble_hs_conn *conn, int status)
+{
+    ble_gattc_write_reliable_cb(proc, status, 0);
+    return 1;
+}
+
+/**
+ * Initiates GATT procedure: Write Long Characteristic Values.
+ *
+ * @param conn_handle           The connection over which to execute the
+ *                                  procedure.
+ * @param attr_handle           The handle of the characteristic value to write
+ *                                  to.
+ * @param value                 The value to write to the characteristic.
+ * @param value_len             The number of bytes to write.
+ * @param cb                    The function to call to report procedure status
+ *                                  updates; null for no callback.
+ * @param cb_arg                The argument to pass to the callback function.
+ */
+int
+ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs,
+                         int num_attrs, ble_gatt_reliable_attr_fn *cb,
+                         void *cb_arg)
+{
+    struct ble_gattc_proc *proc;
+    int rc;
+
+    rc = ble_gattc_new_proc(conn_handle, BLE_GATT_OP_WRITE_RELIABLE, &proc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    proc->write_reliable.attrs = attrs;
+    proc->write_reliable.num_attrs = num_attrs;
+    proc->write_reliable.cur_attr = 0;
+    proc->write_reliable.cb = cb;
+    proc->write_reliable.cb_arg = cb_arg;
+    ble_gattc_proc_set_pending(proc);
+
+    return 0;
+}
+
+/*****************************************************************************
  * $notify                                                                   *
  *****************************************************************************/
 
@@ -3720,21 +3964,25 @@ ble_gattc_rx_prep_write_rsp(struct ble_hs_conn *conn, int status,
                             struct ble_att_prep_write_cmd *rsp,
                             void *attr_data, uint16_t attr_data_len)
 {
+    const struct ble_gattc_rx_prep_entry *rx_entry;
     struct ble_gattc_proc *proc;
     struct ble_gattc_proc *prev;
     int rc;
 
     ble_gattc_assert_sanity();
 
-    proc = ble_gattc_proc_find(conn->bhc_handle, BLE_GATT_OP_WRITE_LONG, 1,
-                               &prev);
+    proc = ble_gattc_proc_find(conn->bhc_handle, BLE_GATT_OP_NONE, 1, &prev);
     if (proc == NULL) {
         /* Not expecting a response from this device. */
         return;
     }
+    rx_entry = BLE_GATTC_RX_ENTRY_FIND(proc->op, ble_gattc_rx_prep_entries);
+    if (rx_entry == NULL) {
+        /* Not expecting a response from this device. */
+        return;
+    }
 
-    rc = ble_gattc_write_long_rx_prep(proc, conn, status, rsp, attr_data,
-                                      attr_data_len);
+    rc = rx_entry->cb(proc, conn, status, rsp, attr_data, attr_data_len);
     if (rc != 0) {
         ble_gattc_proc_remove_free(proc, prev);
     }
@@ -3747,20 +3995,25 @@ ble_gattc_rx_prep_write_rsp(struct ble_hs_conn *conn, int status,
 void
 ble_gattc_rx_exec_write_rsp(struct ble_hs_conn *conn, int status)
 {
+    const struct ble_gattc_rx_exec_entry *rx_entry;
     struct ble_gattc_proc *proc;
     struct ble_gattc_proc *prev;
     int rc;
 
     ble_gattc_assert_sanity();
 
-    proc = ble_gattc_proc_find(conn->bhc_handle, BLE_GATT_OP_WRITE_LONG, 1,
-                               &prev);
+    proc = ble_gattc_proc_find(conn->bhc_handle, BLE_GATT_OP_NONE, 1, &prev);
     if (proc == NULL) {
         /* Not expecting a response from this device. */
         return;
     }
+    rx_entry = BLE_GATTC_RX_ENTRY_FIND(proc->op, ble_gattc_rx_exec_entries);
+    if (rx_entry == NULL) {
+        /* Not expecting a response from this device. */
+        return;
+    }
 
-    rc = ble_gattc_write_long_rx_exec(proc, conn, status);
+    rc = rx_entry->cb(proc, conn, status);
     if (rc != 0) {
         ble_gattc_proc_remove_free(proc, prev);
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/5dd3cc0d/net/nimble/host/src/test/ble_gatt_write_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_write_test.c b/net/nimble/host/src/test/ble_gatt_write_test.c
index 7730b4c..019eac8 100644
--- a/net/nimble/host/src/test/ble_gatt_write_test.c
+++ b/net/nimble/host/src/test/ble_gatt_write_test.c
@@ -27,11 +27,17 @@
 #include "ble_hs_conn.h"
 #include "ble_hs_test_util.h"
 
+#define BLE_GATT_WRITE_TEST_MAX_ATTRS   128
+
 static int ble_gatt_write_test_cb_called;
 
 static uint8_t ble_gatt_write_test_attr_value[BLE_ATT_ATTR_MAX_LEN];
 static struct ble_gatt_error ble_gatt_write_test_error;
 
+static struct ble_gatt_attr *
+ble_gatt_write_test_attrs[BLE_GATT_WRITE_TEST_MAX_ATTRS];
+static int ble_gatt_write_test_num_attrs;
+
 static void
 ble_gatt_write_test_init(void)
 {
@@ -39,6 +45,7 @@ ble_gatt_write_test_init(void)
 
     ble_hs_test_util_init();
     ble_gatt_write_test_cb_called = 0;
+    ble_gatt_write_test_num_attrs = 0;
 
     for (i = 0; i < sizeof ble_gatt_write_test_attr_value; i++) {
         ble_gatt_write_test_attr_value[i] = i;
@@ -263,6 +270,74 @@ ble_gatt_write_test_misc_long_fail_length(struct ble_hs_conn *conn,
         len - 1);
 }
 
+static int
+ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle,
+                                     struct ble_gatt_error *error,
+                                     struct ble_gatt_attr *attrs,
+                                     uint8_t num_attrs, void *arg)
+{
+    int i;
+
+    TEST_ASSERT_FATAL(num_attrs <= BLE_GATT_WRITE_TEST_MAX_ATTRS);
+
+    TEST_ASSERT(conn_handle == 2);
+
+    ble_gatt_write_test_num_attrs = num_attrs;
+    for (i = 0; i < num_attrs; i++) {
+        ble_gatt_write_test_attrs[i] = attrs + i;
+    }
+
+    ble_gatt_write_test_cb_called = 1;
+
+    return 0;
+}
+
+static void
+ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs)
+{
+    struct ble_hs_conn *conn;
+    int num_attrs;
+    int attr_idx;
+    int rc;
+    int i;
+
+    ble_gatt_write_test_init();
+
+    for (num_attrs = 0; attrs[num_attrs].handle != 0; num_attrs++)
+        ;
+
+    conn = ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                        NULL, NULL);
+
+    rc = ble_gattc_write_reliable(conn->bhc_handle, attrs, num_attrs,
+                                  ble_gatt_write_test_reliable_cb_good, NULL);
+    TEST_ASSERT(rc == 0);
+
+    for (attr_idx = 0; attr_idx < num_attrs; attr_idx++) {
+        /* Send the pending ATT Prep Write Command. */
+        ble_hs_test_util_tx_all();
+
+        /* Receive Prep Write response. */
+        ble_gatt_write_test_rx_prep_rsp(conn, attrs[attr_idx].handle, 0,
+                                        attrs[attr_idx].value,
+                                        attrs[attr_idx].value_len);
+
+        /* Verify callback hasn't gotten called. */
+        TEST_ASSERT(!ble_gatt_write_test_cb_called);
+    }
+
+    /* Receive Exec Write response. */
+    ble_hs_test_util_tx_all();
+    ble_gatt_write_test_rx_exec_rsp(conn);
+
+    /* Verify callback got called. */
+    TEST_ASSERT(ble_gatt_write_test_cb_called);
+    TEST_ASSERT(ble_gatt_write_test_num_attrs == num_attrs);
+    for (i = 0; i < num_attrs; i++) {
+        TEST_ASSERT(ble_gatt_write_test_attrs[i] == attrs + i);
+    }
+}
+
 TEST_CASE(ble_gatt_write_test_no_rsp)
 {
     int attr_len;
@@ -401,6 +476,51 @@ TEST_CASE(ble_gatt_write_test_long_bad_length)
         ble_gatt_write_test_misc_long_fail_length);
 }
 
+TEST_CASE(ble_gatt_write_test_reliable_good)
+{
+    /*** 1 attribute. */
+    ble_gatt_write_test_misc_reliable_good(
+        ((struct ble_gatt_attr[]) { {
+            .handle = 100,
+            .value_len = 2,
+            .value = (uint8_t[]){ 1, 2 },
+        }, {
+            0
+        } }));
+
+    /*** 2 attributes. */
+    ble_gatt_write_test_misc_reliable_good(
+        ((struct ble_gatt_attr[]) { {
+            .handle = 100,
+            .value_len = 2,
+            .value = (uint8_t[]){ 1,2 },
+        }, {
+            .handle = 113,
+            .value_len = 6,
+            .value = (uint8_t[]){ 5,6,7,8,9,10 },
+        }, {
+            0
+        } }));
+
+    /*** 3 attributes. */
+    ble_gatt_write_test_misc_reliable_good(
+        ((struct ble_gatt_attr[]) { {
+            .handle = 100,
+            .value_len = 2,
+            .value = (uint8_t[]){ 1,2 },
+        }, {
+            .handle = 113,
+            .value_len = 6,
+            .value = (uint8_t[]){ 5,6,7,8,9,10 },
+        }, {
+            .handle = 144,
+            .value_len = 1,
+            .value = (uint8_t[]){ 0xff },
+        }, {
+            0
+        } }));
+}
+
 TEST_SUITE(ble_gatt_write_test_suite)
 {
     ble_gatt_write_test_no_rsp();
@@ -410,6 +530,7 @@ TEST_SUITE(ble_gatt_write_test_suite)
     ble_gatt_write_test_long_bad_offset();
     ble_gatt_write_test_long_bad_value();
     ble_gatt_write_test_long_bad_length();
+    ble_gatt_write_test_reliable_good();
 }
 
 int