mynewt-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ccoll...@apache.org
Subject [2/4] incubator-mynewt-larva git commit: Notifications and indications.
Date Tue, 05 Jan 2016 23:14:44 GMT
Notifications and indications.


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/8764e91d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/8764e91d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/8764e91d

Branch: refs/heads/master
Commit: 8764e91d808bb997ee8b73cb8ea81d203e6d3652
Parents: 2d07190
Author: Christopher Collins <ccollins476ad@gmail.com>
Authored: Tue Jan 5 14:12:52 2016 -0800
Committer: Christopher Collins <ccollins476ad@gmail.com>
Committed: Tue Jan 5 14:12:52 2016 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_att.h  |   9 ++
 net/nimble/host/include/host/ble_gatt.h |   2 +-
 net/nimble/host/src/ble_att.c           |   3 +
 net/nimble/host/src/ble_att_clt.c       | 132 +++++++++++++++--
 net/nimble/host/src/ble_att_cmd.c       |  78 ++++++++++
 net/nimble/host/src/ble_att_cmd.h       |  36 +++++
 net/nimble/host/src/ble_att_priv.h      |  20 +++
 net/nimble/host/src/ble_att_svr.c       | 138 ++++++++++++++++-
 net/nimble/host/src/ble_gatt_priv.h     |   5 +
 net/nimble/host/src/ble_gattc.c         | 214 ++++++++++++++++++++++++++-
 net/nimble/host/src/ble_gatts.c         |  63 +++++++-
 11 files changed, 672 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/include/host/ble_att.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_att.h b/net/nimble/host/include/host/ble_att.h
index a0d36e3..929df5b 100644
--- a/net/nimble/host/include/host/ble_att.h
+++ b/net/nimble/host/include/host/ble_att.h
@@ -56,6 +56,9 @@
 #define BLE_ATT_OP_PREP_WRITE_RSP           0x17
 #define BLE_ATT_OP_EXEC_WRITE_REQ           0x18
 #define BLE_ATT_OP_EXEC_WRITE_RSP           0x19
+#define BLE_ATT_OP_NOTIFY_REQ               0x1b
+#define BLE_ATT_OP_INDICATE_REQ             0x1d
+#define BLE_ATT_OP_INDICATE_RSP             0x1e
 #define BLE_ATT_OP_WRITE_CMD                0x52
 
 #define BLE_ATT_ATTR_MAX_LEN                512
@@ -99,4 +102,10 @@ int ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags,
                                 uint16_t *handle_id, ble_att_svr_access_fn *cb,
                                 void *cb_arg);
 
+typedef int ble_att_svr_notify_fn(uint16_t conn_handle, uint16_t attr_handle,
+                                  uint8_t *attr_val, uint16_t attr_len,
+                                  void *arg);
+
+void ble_att_set_notify_cb(ble_att_svr_notify_fn *cb, void *cb_arg);
+
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/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 0a9d35f..f076b04 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -86,7 +86,6 @@ int ble_gatt_init(void);
 #define BLE_GATT_ACCESS_OP_WRITE_CHR        1
 #define BLE_GATT_ACCESS_OP_READ_DSC         2
 #define BLE_GATT_ACCESS_OP_WRITE_DSC        3
-/* XXX: Notify, listen. */
 
 union ble_gatt_access_ctxt;
 typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle,
@@ -157,6 +156,7 @@ typedef void ble_gatt_register_fn(uint8_t op,
 int ble_gatt_register_services(const struct ble_gatt_svc_def *svcs,
                                ble_gatt_register_fn *register_cb,
                                void *cb_arg);
+void ble_gatts_chr_updated(uint16_t chr_def_handle);
 
 union ble_gatt_register_ctxt {
     struct {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att.c b/net/nimble/host/src/ble_att.c
index a90a6da..8437389 100644
--- a/net/nimble/host/src/ble_att.c
+++ b/net/nimble/host/src/ble_att.c
@@ -48,6 +48,9 @@ static struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = {
     { BLE_ATT_OP_WRITE_RSP,            ble_att_clt_rx_write },
     { BLE_ATT_OP_PREP_WRITE_REQ,       ble_att_svr_rx_prep_write },
     { BLE_ATT_OP_EXEC_WRITE_REQ,       ble_att_svr_rx_exec_write },
+    { BLE_ATT_OP_NOTIFY_REQ,           ble_att_svr_rx_notify },
+    { BLE_ATT_OP_INDICATE_REQ,         ble_att_svr_rx_indicate },
+    { BLE_ATT_OP_INDICATE_RSP,         ble_att_clt_rx_indicate },
 };
 
 #define BLE_ATT_RX_DISPATCH_SZ \

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att_clt.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_clt.c b/net/nimble/host/src/ble_att_clt.c
index 41fabc5..42934e4 100644
--- a/net/nimble/host/src/ble_att_clt.c
+++ b/net/nimble/host/src/ble_att_clt.c
@@ -627,6 +627,33 @@ ble_att_clt_rx_find_type_value(struct ble_hs_conn *conn,
 }
 
 static int
+ble_att_clt_append_blob(struct ble_l2cap_chan *chan, struct os_mbuf *txom,
+                        void *blob, int blob_len)
+{
+    uint16_t mtu;
+    int extra_len;
+    int cmd_len;
+    int rc;
+
+    mtu = ble_l2cap_chan_mtu(chan);
+    cmd_len = OS_MBUF_PKTLEN(txom) + blob_len;
+    extra_len = cmd_len - mtu;
+    if (extra_len > 0) {
+        blob_len -= extra_len;
+    }
+    if (blob_len <= 0) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    rc = os_mbuf_append(txom, blob, blob_len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
 ble_att_clt_tx_write_req_or_cmd(struct ble_hs_conn *conn,
                                 struct ble_att_write_req *req,
                                 void *value, uint16_t value_len,
@@ -634,8 +661,6 @@ ble_att_clt_tx_write_req_or_cmd(struct ble_hs_conn *conn,
 {
     struct ble_l2cap_chan *chan;
     struct os_mbuf *txom;
-    uint16_t mtu;
-    int extra_len;
     int rc;
 
     txom = NULL;
@@ -652,13 +677,7 @@ ble_att_clt_tx_write_req_or_cmd(struct ble_hs_conn *conn,
     }
     assert(rc == 0);
 
-    mtu = ble_l2cap_chan_mtu(chan);
-    extra_len = BLE_ATT_WRITE_REQ_BASE_SZ + value_len - mtu;
-    if (extra_len > 0) {
-        value_len -= extra_len;
-    }
-
-    rc = os_mbuf_append(txom, value, value_len);
+    rc = ble_att_clt_append_blob(chan, txom, value, value_len);
     if (rc != 0) {
         goto err;
     }
@@ -716,3 +735,98 @@ ble_att_clt_rx_write(struct ble_hs_conn *conn,
 
     return 0;
 }
+
+int
+ble_att_clt_tx_notify(struct ble_hs_conn *conn, struct ble_att_notify_req *req,
+                      void *value, uint16_t value_len)
+{
+    struct ble_l2cap_chan *chan;
+    struct os_mbuf *txom;
+    int rc;
+
+    txom = NULL;
+
+    if (req->banq_handle == 0) {
+        rc = BLE_HS_EINVAL;
+        goto err;
+    }
+
+    rc = ble_att_clt_prep_req(conn, &chan, &txom, BLE_ATT_NOTIFY_REQ_BASE_SZ);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_att_notify_req_write(txom->om_data, txom->om_len, req);
+    assert(rc == 0);
+
+    rc = ble_att_clt_append_blob(chan, txom, value, value_len);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_l2cap_tx(conn, chan, txom);
+    txom = NULL;
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    os_mbuf_free_chain(txom);
+    return rc;
+}
+
+int
+ble_att_clt_tx_indicate(struct ble_hs_conn *conn,
+                        struct ble_att_indicate_req *req,
+                        void *value, uint16_t value_len)
+{
+    struct ble_l2cap_chan *chan;
+    struct os_mbuf *txom;
+    int rc;
+
+    txom = NULL;
+
+    if (req->baiq_handle == 0) {
+        rc = BLE_HS_EINVAL;
+        goto err;
+    }
+
+    rc = ble_att_clt_prep_req(conn, &chan, &txom,
+                              BLE_ATT_INDICATE_REQ_BASE_SZ);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_att_indicate_req_write(txom->om_data, txom->om_len, req);
+    assert(rc == 0);
+
+    rc = ble_att_clt_append_blob(chan, txom, value, value_len);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_l2cap_tx(conn, chan, txom);
+    txom = NULL;
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    os_mbuf_free_chain(txom);
+    return rc;
+}
+
+int
+ble_att_clt_rx_indicate(struct ble_hs_conn *conn,
+                        struct ble_l2cap_chan *chan,
+                        struct os_mbuf **rxom)
+{
+    /* No payload. */
+    ble_gattc_rx_indicate_rsp(conn);
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_cmd.c b/net/nimble/host/src/ble_att_cmd.c
index 2a244d6..cae2189 100644
--- a/net/nimble/host/src/ble_att_cmd.c
+++ b/net/nimble/host/src/ble_att_cmd.c
@@ -660,3 +660,81 @@ ble_att_exec_write_rsp_write(void *payload, int len)
 
     return 0;
 }
+
+int
+ble_att_notify_req_parse(void *payload, int len,
+                         struct ble_att_notify_req *req)
+{
+    uint8_t *u8ptr;
+
+    if (len < BLE_ATT_NOTIFY_REQ_BASE_SZ) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    u8ptr = payload;
+
+    if (u8ptr[0] != BLE_ATT_OP_NOTIFY_REQ) {
+        return BLE_HS_EINVAL;
+    }
+
+    req->banq_handle = le16toh(u8ptr + 1);
+
+    return 0;
+
+}
+
+int
+ble_att_notify_req_write(void *payload, int len,
+                         struct ble_att_notify_req *req)
+{
+    uint8_t *u8ptr;
+
+    if (len < BLE_ATT_NOTIFY_REQ_BASE_SZ) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    u8ptr = payload;
+    u8ptr[0] = BLE_ATT_OP_EXEC_WRITE_RSP;
+    htole16(u8ptr + 1, req->banq_handle);
+
+    return 0;
+}
+
+int
+ble_att_indicate_req_parse(void *payload, int len,
+                           struct ble_att_indicate_req *req)
+{
+    uint8_t *u8ptr;
+
+    if (len < BLE_ATT_INDICATE_REQ_BASE_SZ) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    u8ptr = payload;
+
+    if (u8ptr[0] != BLE_ATT_OP_INDICATE_REQ) {
+        return BLE_HS_EINVAL;
+    }
+
+    req->baiq_handle = le16toh(u8ptr + 1);
+
+    return 0;
+
+}
+
+int
+ble_att_indicate_req_write(void *payload, int len,
+                         struct ble_att_indicate_req *req)
+{
+    uint8_t *u8ptr;
+
+    if (len < BLE_ATT_INDICATE_REQ_BASE_SZ) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    u8ptr = payload;
+    u8ptr[0] = BLE_ATT_OP_EXEC_WRITE_RSP;
+    htole16(u8ptr + 1, req->baiq_handle);
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att_cmd.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_cmd.h b/net/nimble/host/src/ble_att_cmd.h
index dad8623..7028bbb 100644
--- a/net/nimble/host/src/ble_att_cmd.h
+++ b/net/nimble/host/src/ble_att_cmd.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef H_BLE_ATT_CMD_
+#define H_BLE_ATT_CMD_
+
 #include <inttypes.h>
 struct ble_l2cap_chan;
 
@@ -226,6 +229,29 @@ struct ble_att_exec_write_req {
  */
 #define BLE_ATT_EXEC_WRITE_RSP_SZ       1
 
+/**
+ * | Parameter                          | Size (octets)     |
+ * +------------------------------------+-------------------+
+ * | Attribute Opcode                   | 1                 |
+ * | Attribute Handle                   | 2                 |
+ * | Attribute Value                    | 0 to (ATT_MTU-3)  |
+ */
+#define BLE_ATT_NOTIFY_REQ_BASE_SZ      3
+struct ble_att_notify_req {
+    uint16_t banq_handle;
+};
+
+/**
+ * | Parameter                          | Size (octets)     |
+ * +------------------------------------+-------------------+
+ * | Attribute Opcode                   | 1                 |
+ * | Attribute Handle                   | 2                 |
+ * | Attribute Value                    | 0 to (ATT_MTU-3)  |
+ */
+#define BLE_ATT_INDICATE_REQ_BASE_SZ      3
+struct ble_att_indicate_req {
+    uint16_t baiq_handle;
+};
 
 int ble_att_error_rsp_parse(void *payload, int len,
                             struct ble_att_error_rsp *rsp);
@@ -291,3 +317,13 @@ int ble_att_exec_write_req_write(void *payload, int len,
                                  struct ble_att_exec_write_req *req);
 int ble_att_exec_write_rsp_parse(void *payload, int len);
 int ble_att_exec_write_rsp_write(void *payload, int len);
+int ble_att_notify_req_parse(void *payload, int len,
+                             struct ble_att_notify_req *req);
+int ble_att_notify_req_write(void *payload, int len,
+                             struct ble_att_notify_req *req);
+int ble_att_indicate_req_parse(void *payload, int len,
+                               struct ble_att_indicate_req *req);
+int ble_att_indicate_req_write(void *payload, int len,
+                               struct ble_att_indicate_req *req);
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_priv.h b/net/nimble/host/src/ble_att_priv.h
index db8252a..d9f2eed 100644
--- a/net/nimble/host/src/ble_att_priv.h
+++ b/net/nimble/host/src/ble_att_priv.h
@@ -32,6 +32,8 @@ struct ble_att_read_group_type_req;
 struct ble_att_read_group_type_rsp;
 struct ble_att_find_type_value_req;
 struct ble_att_write_req;
+struct ble_att_notify_req;
+struct ble_att_indicate_req;
 
 #define BLE_ATT_MTU_DFLT         23  /* Also the minimum. */
 #define BLE_ATT_MTU_MAX          256 /* XXX: I'm making this up! */
@@ -119,7 +121,16 @@ int ble_att_svr_rx_prep_write(struct ble_hs_conn *conn,
 int ble_att_svr_rx_exec_write(struct ble_hs_conn *conn,
                               struct ble_l2cap_chan *chan,
                               struct os_mbuf **rxom);
+int ble_att_svr_rx_notify(struct ble_hs_conn *conn,
+                          struct ble_l2cap_chan *chan,
+                          struct os_mbuf **rxom);
+int ble_att_svr_rx_indicate(struct ble_hs_conn *conn,
+                            struct ble_l2cap_chan *chan,
+                            struct os_mbuf **rxom);
 void ble_att_svr_prep_clear(struct ble_att_svr_conn *basc);
+int ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle,
+                            struct ble_att_svr_access_ctxt *ctxt,
+                            uint8_t *out_att_err);
 int ble_att_svr_init(void);
 
 /*** @clt */
@@ -165,5 +176,14 @@ int ble_att_clt_tx_write_cmd(struct ble_hs_conn *conn,
 int ble_att_clt_rx_write(struct ble_hs_conn *conn,
                          struct ble_l2cap_chan *chan,
                          struct os_mbuf **rxom);
+int ble_att_clt_tx_notify(struct ble_hs_conn *conn,
+                          struct ble_att_notify_req *req,
+                          void *value, uint16_t value_len);
+int ble_att_clt_tx_indicate(struct ble_hs_conn *conn,
+                            struct ble_att_indicate_req *req,
+                            void *value, uint16_t value_len);
+int ble_att_clt_rx_indicate(struct ble_hs_conn *conn,
+                            struct ble_l2cap_chan *chan,
+                            struct os_mbuf **rxom);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_att_svr.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_svr.c b/net/nimble/host/src/ble_att_svr.c
index 57c705a..8c7e985 100644
--- a/net/nimble/host/src/ble_att_svr.c
+++ b/net/nimble/host/src/ble_att_svr.c
@@ -51,6 +51,9 @@ static struct os_mbuf_pool ble_att_svr_prep_mbuf_pool;
 
 static uint8_t ble_att_svr_flat_buf[BLE_ATT_ATTR_MAX_LEN];
 
+ble_att_svr_notify_fn *ble_att_svr_notify_cb;
+void *ble_att_svr_notify_cb_arg;
+
 /**
  * Locks the host attribute list.
  *
@@ -327,20 +330,20 @@ ble_att_svr_read(struct ble_hs_conn *conn, struct ble_att_svr_entry
*entry,
     uint8_t att_err;
     int rc;
 
-    if (!(entry->ha_flags & HA_FLAG_PERM_READ)) {
-        att_err = BLE_ATT_ERR_READ_NOT_PERMITTED;
-        rc = BLE_HS_ENOTSUP;
-        goto err;
-    }
-
-    /* XXX: Check security. */
-
     if (conn == NULL) {
         conn_handle = 0xffff; /* XXX */
     } else {
         conn_handle = conn->bhc_handle;
+
+        if (!(entry->ha_flags & HA_FLAG_PERM_READ)) {
+            att_err = BLE_ATT_ERR_READ_NOT_PERMITTED;
+            rc = BLE_HS_ENOTSUP;
+            goto err;
+        }
     }
 
+    /* XXX: Check security. */
+
     assert(entry->ha_cb != NULL);
     rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
                       entry->ha_uuid, BLE_ATT_ACCESS_OP_READ, ctxt,
@@ -360,6 +363,29 @@ err:
     return rc;
 }
 
+int
+ble_att_svr_read_handle(struct ble_hs_conn *conn, uint16_t attr_handle,
+                        struct ble_att_svr_access_ctxt *ctxt,
+                        uint8_t *out_att_err)
+{
+    struct ble_att_svr_entry *entry;
+    int rc;
+
+    entry = NULL;
+    rc = ble_att_svr_find_by_handle(attr_handle, &entry);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_att_svr_read(conn, entry, ctxt, out_att_err);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+
 static int
 ble_att_svr_write(struct ble_hs_conn *conn, struct ble_att_svr_entry *entry,
                   struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err)
@@ -2152,6 +2178,101 @@ err:
     return rc;
 }
 
+int
+ble_att_svr_rx_notify(struct ble_hs_conn *conn,
+                      struct ble_l2cap_chan *chan,
+                      struct os_mbuf **rxom)
+{
+    struct ble_att_notify_req req;
+    uint16_t attr_len;
+    void *attr_data;
+    int rc;
+
+    if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_NOTIFY_REQ_BASE_SZ) {
+        return BLE_HS_EBADDATA;
+    }
+
+    *rxom = os_mbuf_pullup(*rxom, BLE_ATT_NOTIFY_REQ_BASE_SZ);
+    if (*rxom == NULL) {
+        return BLE_HS_ENOMEM;
+    }
+
+    rc = ble_att_notify_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
+    assert(rc == 0);
+
+    os_mbuf_adj(*rxom, BLE_ATT_NOTIFY_REQ_BASE_SZ);
+
+    attr_data = ble_att_svr_flat_buf;
+    attr_len = OS_MBUF_PKTLEN(*rxom);
+    os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
+
+    if (ble_att_svr_notify_cb != NULL) {
+        rc = ble_att_svr_notify_cb(conn->bhc_handle, req.banq_handle,
+                                   attr_data, attr_len,
+                                   ble_att_svr_notify_cb_arg);
+        if (rc != 0) {
+            return BLE_HS_EAPP;
+        }
+    }
+
+    return 0;
+}
+
+int
+ble_att_svr_rx_indicate(struct ble_hs_conn *conn,
+                        struct ble_l2cap_chan *chan,
+                        struct os_mbuf **rxom)
+{
+    struct ble_att_indicate_req req;
+    uint16_t err_handle;
+    uint16_t attr_len;
+    uint8_t att_err;
+    void *attr_data;
+    int rc;
+
+    if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_INDICATE_REQ_BASE_SZ) {
+        att_err = BLE_ATT_ERR_INVALID_PDU;
+        err_handle = 0;
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+
+    *rxom = os_mbuf_pullup(*rxom, BLE_ATT_INDICATE_REQ_BASE_SZ);
+    if (*rxom == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        err_handle = 0;
+        rc = BLE_HS_ENOMEM;
+        goto err;
+    }
+
+    rc = ble_att_indicate_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
+    assert(rc == 0);
+
+    os_mbuf_adj(*rxom, BLE_ATT_INDICATE_REQ_BASE_SZ);
+
+    attr_data = ble_att_svr_flat_buf;
+    attr_len = OS_MBUF_PKTLEN(*rxom);
+    os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
+
+    if (ble_att_svr_notify_cb != NULL) {
+        att_err = ble_att_svr_notify_cb(conn->bhc_handle, req.baiq_handle,
+                                        attr_data, attr_len,
+                                        ble_att_svr_notify_cb_arg);
+        if (att_err != 0) {
+            err_handle = req.baiq_handle;
+            rc = BLE_HS_EAPP;
+            goto err;
+        }
+    }
+
+    return 0;
+
+err:
+    ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_INDICATE_REQ, err_handle,
+                             att_err);
+    return rc;
+}
+
 static void
 ble_att_svr_free_mem(void)
 {
@@ -2216,6 +2337,7 @@ ble_att_svr_init(void)
     }
 
     ble_att_svr_id = 0;
+    ble_att_svr_notify_cb = NULL;
 
     return 0;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_gatt_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h
index 2445104..c222f79 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -54,6 +54,10 @@ int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
                            ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_write(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_indicate(uint16_t conn_handle, uint16_t chr_val_handle,
+                       ble_gatt_attr_fn *cb, void *cb_arg);
+int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle,
+                     ble_gatt_attr_fn *cb, void *cb_arg);
 
 int ble_gattc_exchange_mtu(uint16_t conn_handle);
 
@@ -72,6 +76,7 @@ void ble_gattc_rx_find_type_value_hinfo(struct ble_hs_conn *conn,
                                         struct ble_att_clt_adata *adata);
 void ble_gattc_rx_find_type_value_complete(struct ble_hs_conn *conn, int rc);
 void ble_gattc_rx_write_rsp(struct ble_hs_conn *conn);
+void ble_gattc_rx_indicate_rsp(struct ble_hs_conn *conn);
 void ble_gattc_connection_txable(uint16_t conn_handle);
 void ble_gattc_connection_broken(uint16_t conn_handle);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/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 4ad7eba..b44113c 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -74,6 +74,18 @@ struct ble_gattc_entry {
             ble_gatt_attr_fn *cb;
             void *cb_arg;
         } write;
+
+        struct {
+            struct ble_gatt_attr attr;
+            ble_gatt_attr_fn *cb;
+            void *cb_arg;
+        } notify;
+
+        struct {
+            struct ble_gatt_attr attr;
+            ble_gatt_attr_fn *cb;
+            void *cb_arg;
+        } indicate;
     };
 };
 
@@ -88,7 +100,9 @@ struct ble_gattc_entry {
 #define BLE_GATT_OP_READ                        4
 #define BLE_GATT_OP_WRITE_NO_RSP                5
 #define BLE_GATT_OP_WRITE                       6
-#define BLE_GATT_OP_MAX                         7
+#define BLE_GATT_OP_NOTIFY                      7
+#define BLE_GATT_OP_INDICATE                    8
+#define BLE_GATT_OP_MAX                         9
 
 static struct os_callout_func ble_gattc_heartbeat_timer;
 
@@ -102,6 +116,8 @@ static int ble_gattc_kick_disc_all_chars(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_read(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_write_no_rsp(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_write(struct ble_gattc_entry *entry);
+static int ble_gattc_kick_notify(struct ble_gattc_entry *entry);
+static int ble_gattc_kick_indicate(struct ble_gattc_entry *entry);
 
 static void ble_gattc_err_mtu(struct ble_gattc_entry *entry, int status);
 static void ble_gattc_err_disc_all_services(struct ble_gattc_entry *entry,
@@ -112,6 +128,7 @@ static void ble_gattc_err_disc_all_chars(struct ble_gattc_entry *entry,
                                         int status);
 static void ble_gattc_err_read(struct ble_gattc_entry *entry, int status);
 static void ble_gattc_err_write(struct ble_gattc_entry *entry, int status);
+static void ble_gattc_err_indicate(struct ble_gattc_entry *entry, int status);
 
 struct ble_gattc_dispatch_entry {
     ble_gattc_kick_fn *kick_cb;
@@ -149,6 +166,14 @@ static const struct ble_gattc_dispatch_entry
         .kick_cb = ble_gattc_kick_write,
         .err_cb = ble_gattc_err_write,
     },
+    [BLE_GATT_OP_NOTIFY] = {
+        .kick_cb = ble_gattc_kick_notify,
+        .err_cb = NULL,
+    },
+    [BLE_GATT_OP_INDICATE] = {
+        .kick_cb = ble_gattc_kick_indicate,
+        .err_cb = ble_gattc_err_indicate,
+    },
 };
 
 #define BLE_GATT_ENTRY_F_PENDING    0x01
@@ -1152,7 +1177,7 @@ ble_gattc_rx_write_rsp(struct ble_hs_conn *conn)
 
 int
 ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value,
-               uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg)
+                uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg)
 {
     struct ble_gattc_entry *entry;
     int rc;
@@ -1172,6 +1197,191 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, void *value,
 }
 
 /*****************************************************************************
+ * $notify                                                                   *
+ *****************************************************************************/
+
+static int
+ble_gattc_notify_cb(struct ble_gattc_entry *entry, int status)
+{
+    int rc;
+
+    if (entry->notify.cb == NULL) {
+        rc = 0;
+    } else {
+        rc = entry->notify.cb(entry->conn_handle, status, &entry->notify.attr,
+                              entry->notify.cb_arg);
+    }
+
+    return rc;
+}
+
+static int
+ble_gattc_kick_notify(struct ble_gattc_entry *entry)
+{
+    struct ble_att_svr_access_ctxt ctxt;
+    struct ble_att_notify_req req;
+    struct ble_hs_conn *conn;
+    int rc;
+
+    conn = ble_hs_conn_find(entry->conn_handle);
+    if (conn == NULL) {
+        rc = BLE_HS_ENOTCONN;
+        goto err;
+    }
+
+    rc = ble_att_svr_read_handle(NULL, entry->notify.attr.handle, &ctxt,
+                                 NULL);
+    if (rc != 0) {
+        goto err;
+    }
+    entry->notify.attr.value = ctxt.attr_data;
+    entry->notify.attr.value_len = ctxt.attr_len;
+
+    req.banq_handle = entry->notify.attr.handle;
+    rc = ble_att_clt_tx_notify(conn, &req, entry->notify.attr.value,
+                               entry->notify.attr.value_len);
+    if (rc != 0) {
+        goto err;
+    }
+
+    /* No response expected; call callback immediately and return nonzero to
+     * indicate the entry should be freed.
+     */
+    ble_gattc_notify_cb(entry, 0);
+
+    return 1;
+
+err:
+    if (ble_gattc_tx_postpone_chk(entry, rc)) {
+        return BLE_HS_EAGAIN;
+    }
+
+    ble_gattc_notify_cb(entry, rc);
+    return rc;
+}
+
+int
+ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle,
+                 ble_gatt_attr_fn *cb, void *cb_arg)
+{
+    struct ble_gattc_entry *entry;
+    int rc;
+
+    rc = ble_gattc_new_entry(conn_handle, BLE_GATT_OP_NOTIFY, &entry);
+    if (rc != 0) {
+        return rc;
+    }
+
+    entry->notify.attr.handle = chr_val_handle;
+    entry->notify.cb = cb;
+    entry->notify.cb_arg = cb_arg;
+
+    return 0;
+}
+
+/*****************************************************************************
+ * $indicate                                                                   *
+ *****************************************************************************/
+
+static int
+ble_gattc_indicate_cb(struct ble_gattc_entry *entry, int status)
+{
+    int rc;
+
+    if (entry->indicate.cb == NULL) {
+        rc = 0;
+    } else {
+        rc = entry->indicate.cb(entry->conn_handle, status,
+                                &entry->indicate.attr, entry->indicate.cb_arg);
+    }
+
+    return rc;
+}
+
+static int
+ble_gattc_kick_indicate(struct ble_gattc_entry *entry)
+{
+    struct ble_att_svr_access_ctxt ctxt;
+    struct ble_att_indicate_req req;
+    struct ble_hs_conn *conn;
+    int rc;
+
+    conn = ble_hs_conn_find(entry->conn_handle);
+    if (conn == NULL) {
+        rc = BLE_HS_ENOTCONN;
+        goto err;
+    }
+
+    rc = ble_att_svr_read_handle(NULL, entry->indicate.attr.handle, &ctxt,
+                                 NULL);
+    if (rc != 0) {
+        goto err;
+    }
+    entry->indicate.attr.value = ctxt.attr_data;
+    entry->indicate.attr.value_len = ctxt.attr_len;
+
+    req.baiq_handle = entry->indicate.attr.handle;
+    rc = ble_att_clt_tx_indicate(conn, &req, entry->indicate.attr.value,
+                                 entry->indicate.attr.value_len);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    if (ble_gattc_tx_postpone_chk(entry, rc)) {
+        return BLE_HS_EAGAIN;
+    }
+
+    ble_gattc_indicate_cb(entry, rc);
+    return rc;
+}
+
+static void
+ble_gattc_err_indicate(struct ble_gattc_entry *entry, int status)
+{
+    ble_gattc_indicate_cb(entry, status);
+}
+
+void
+ble_gattc_rx_indicate_rsp(struct ble_hs_conn *conn)
+{
+    struct ble_gattc_entry *entry;
+    struct ble_gattc_entry *prev;
+
+    entry = ble_gattc_find(conn->bhc_handle, BLE_GATT_OP_INDICATE, 1, &prev);
+    if (entry == NULL) {
+        /* Not expecting a response from this device. */
+        return;
+    }
+
+    ble_gattc_indicate_cb(entry, 0);
+
+    /* The indicate operation only has a single request / response exchange. */
+    ble_gattc_entry_remove_free(entry, prev);
+}
+
+int
+ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle,
+                   ble_gatt_attr_fn *cb, void *cb_arg)
+{
+    struct ble_gattc_entry *entry;
+    int rc;
+
+    rc = ble_gattc_new_entry(conn_handle, BLE_GATT_OP_INDICATE, &entry);
+    if (rc != 0) {
+        return rc;
+    }
+
+    entry->indicate.attr.handle = chr_val_handle;
+    entry->indicate.cb = cb;
+    entry->indicate.cb_arg = cb_arg;
+
+    return 0;
+}
+
+/*****************************************************************************
  * @misc                                                                     *
  *****************************************************************************/
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8764e91d/net/nimble/host/src/ble_gatts.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatts.c b/net/nimble/host/src/ble_gatts.c
index 505ca67..1c06d4f 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -293,21 +293,35 @@ ble_gatts_chr_clt_cfg_allowed(const struct ble_gatt_chr_def *chr)
     return flags;
 }
 
-static struct ble_gatts_clt_cfg *
-ble_gatts_clt_cfg_find(struct ble_gatts_conn *gatts_conn,
-                       uint16_t chr_def_handle)
+static int
+ble_gatts_clt_cfg_find_idx(struct ble_gatts_clt_cfg *cfgs,
+                           uint16_t chr_def_handle)
 {
     struct ble_gatts_clt_cfg *cfg;
     int i;
 
-    for (i = 0; i < gatts_conn->num_clt_cfgs; i++) {
-        cfg = gatts_conn->clt_cfgs + i;
+    for (i = 0; i < ble_gatts_num_cfgable_chrs; i++) {
+        cfg = cfgs + i;
         if (cfg->chr_def_handle == chr_def_handle) {
-            return cfg;
+            return i;
         }
     }
 
-    return NULL;
+    return -1;
+}
+
+static struct ble_gatts_clt_cfg *
+ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg *cfgs,
+                       uint16_t chr_def_handle)
+{
+    int idx;
+
+    idx = ble_gatts_clt_cfg_find_idx(cfgs, chr_def_handle);
+    if (idx == -1) {
+        return NULL;
+    } else {
+        return cfgs + idx;
+    }
 }
 
 static int
@@ -338,7 +352,8 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
         return BLE_ATT_ERR_UNLIKELY;
     }
 
-    clt_cfg = ble_gatts_clt_cfg_find(&conn->bhc_gatt_svr, attr_handle - 2);
+    clt_cfg = ble_gatts_clt_cfg_find(conn->bhc_gatt_svr.clt_cfgs,
+                                     attr_handle - 2);
     if (clt_cfg == 0) {
         assert(0); // XXX temporary.
         return BLE_ATT_ERR_UNLIKELY;
@@ -827,6 +842,38 @@ ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn)
     return 0;
 }
 
+void
+ble_gatts_chr_updated(uint16_t chr_def_handle)
+{
+    struct ble_gatts_clt_cfg *clt_cfg;
+    struct ble_hs_conn *conn;
+    int idx;
+
+    /* Determine if notifications / indications are enabled for this
+     * characteristic, and remember the client config offset.
+     */
+    idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, chr_def_handle);
+    if (idx == -1) {
+        return;
+    }
+
+    /* XXX: Lock connection list. */
+    for (conn = ble_hs_conn_first();
+         conn != NULL;
+         conn = SLIST_NEXT(conn, bhc_next)) {
+
+        assert(conn->bhc_gatt_svr.num_clt_cfgs > idx);
+        clt_cfg = conn->bhc_gatt_svr.clt_cfgs + idx;
+        assert(clt_cfg->chr_def_handle == chr_def_handle);
+
+        if (clt_cfg->flags & BLE_GATT_CHR_F_INDICATE) {
+            /* XXX: Schedule indication. */
+        } else if (clt_cfg->flags & BLE_GATT_CHR_F_NOTIFY) {
+            /* XXX: Schedule notification. */
+        }
+    }
+}
+
 static void
 ble_gatts_free_mem(void)
 {


Mime
View raw message