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