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/21 23:13:19 UTC
incubator-mynewt-larva git commit: GAP Connection Parameter Update
procedure.
Repository: incubator-mynewt-larva
Updated Branches:
refs/heads/master d979b5186 -> dd338e9e0
GAP Connection Parameter Update procedure.
Timeouts are not yet implemented.
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/dd338e9e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/dd338e9e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/dd338e9e
Branch: refs/heads/master
Commit: dd338e9e0de211982fc039a95c5a0cd17be6db15
Parents: d979b51
Author: Christopher Collins <cc...@gmail.com>
Authored: Thu Jan 21 14:11:56 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Jan 21 14:11:56 2016 -0800
----------------------------------------------------------------------
net/nimble/host/include/host/ble_gap.h | 43 ++-
net/nimble/host/include/host/host_hci.h | 2 +
net/nimble/host/src/ble_att_priv.h | 1 +
net/nimble/host/src/ble_gap_conn.c | 397 +++++++++++++++++++++++++--
net/nimble/host/src/ble_gap_priv.h | 2 +
net/nimble/host/src/ble_hs_conn.h | 10 +
net/nimble/host/src/host_hci_cmd.c | 33 +++
net/nimble/host/src/test/ble_gap_test.c | 10 +-
net/nimble/host/src/test/ble_os_test.c | 30 +-
net/nimble/include/nimble/hci_common.h | 51 +++-
project/bleshell/src/main.c | 20 +-
project/centtest/src/main.c | 16 +-
project/prphtest/src/main.c | 14 +-
13 files changed, 556 insertions(+), 73 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/include/host/ble_gap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h
index 3ea6644..e66adf6 100644
--- a/net/nimble/host/include/host/ble_gap.h
+++ b/net/nimble/host/include/host/ble_gap.h
@@ -20,26 +20,47 @@
#include <inttypes.h>
#include "host/ble_hs.h"
struct hci_le_conn_complete;
+struct hci_conn_update;
#define BLE_GAP_ADDR_TYPE_WL 0xff
#define BLE_GAP_EVENT_CONN 0
-#define BLE_GAP_EVENT_CANCEL_FAILURE 1
-#define BLE_GAP_EVENT_TERM_FAILURE 2
-#define BLE_GAP_EVENT_DISC_SUCCESS 3
-#define BLE_GAP_EVENT_DISC_FINISHED 4
-#define BLE_GAP_EVENT_ADV_FINISHED 5
-#define BLE_GAP_EVENT_ADV_FAILURE 6
-#define BLE_GAP_EVENT_ADV_STOP_FAILURE 7
+#define BLE_GAP_EVENT_CONN_UPDATED 1
+#define BLE_GAP_EVENT_CONN_UPDATE_REQ 2
+#define BLE_GAP_EVENT_CANCEL_FAILURE 3
+#define BLE_GAP_EVENT_TERM_FAILURE 4
+#define BLE_GAP_EVENT_DISC_SUCCESS 5
+#define BLE_GAP_EVENT_DISC_FINISHED 6
+#define BLE_GAP_EVENT_ADV_FINISHED 7
+#define BLE_GAP_EVENT_ADV_FAILURE 8
+#define BLE_GAP_EVENT_ADV_STOP_FAILURE 9
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;
- uint8_t peer_addr[6];
};
-typedef void ble_gap_conn_fn(int event, int status,
- struct ble_gap_conn_desc *desc, void *arg);
+struct ble_gap_conn_params {
+ uint16_t itvl_min;
+ uint16_t itvl_max;
+ uint16_t latency;
+ uint16_t supervision_timeout;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+};
+
+struct ble_gap_conn_ctxt {
+ struct ble_gap_conn_desc desc;
+ struct ble_gap_conn_params *peer_params;
+ struct ble_gap_conn_params *self_params;
+};
+
+typedef int ble_gap_conn_fn(int event, int status,
+ struct ble_gap_conn_ctxt *ctxt, void *arg);
struct ble_gap_disc_desc {
uint8_t event_type;
@@ -83,5 +104,7 @@ int ble_gap_conn_cancel(void);
int ble_gap_conn_wl_set(struct ble_gap_white_entry *white_list,
uint8_t white_list_count, ble_gap_wl_fn *cb,
void *cb_arg);
+int ble_gap_conn_update_params(uint16_t conn_handle,
+ struct ble_gap_conn_params *params);
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index b49e12a..fbf1b02 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -48,6 +48,8 @@ int host_hci_cmd_reset(void);
int host_hci_cmd_read_adv_pwr(void);
int host_hci_cmd_le_create_conn_cancel(void);
int host_hci_cmd_le_conn_update(struct hci_conn_update *hcu);
+int host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr);
+int host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn);
int host_hci_set_buf_size(uint16_t pktlen, uint8_t max_pkts);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/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 a644acb..9c04379 100644
--- a/net/nimble/host/src/ble_att_priv.h
+++ b/net/nimble/host/src/ble_att_priv.h
@@ -90,6 +90,7 @@ SLIST_HEAD(ble_att_clt_entry_list, ble_att_clt_entry);
struct ble_l2cap_chan *ble_att_create_chan(void);
void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
struct os_mbuf *ble_att_get_pkthdr(void);
+void ble_att_init(void);
/*** @svr */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/ble_gap_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_conn.c b/net/nimble/host/src/ble_gap_conn.c
index 731bdcc..ad6c328 100644
--- a/net/nimble/host/src/ble_gap_conn.c
+++ b/net/nimble/host/src/ble_gap_conn.c
@@ -29,6 +29,7 @@
#include "ble_gap_priv.h"
#define BLE_GAP_CONN_OP_NULL 0
+#define BLE_GAP_CONN_STATE_NULL 255
#define BLE_GAP_CONN_OP_M_DISC 1
#define BLE_GAP_CONN_OP_M_CONN 2
@@ -66,6 +67,13 @@
#define BLE_GAP_CONN_STATE_W_CLEAR 0
#define BLE_GAP_CONN_STATE_W_ADD 1
+/** Connection update states. */
+#define BLE_GAP_CONN_STATE_U_UPDATE 0
+#define BLE_GAP_CONN_STATE_U_UPDATE_ACKED 1
+#define BLE_GAP_CONN_STATE_U_REPLY 2
+#define BLE_GAP_CONN_STATE_U_REPLY_ACKED 3
+#define BLE_GAP_CONN_STATE_U_NEG_REPLY 4
+
/** 30 ms. */
#define BLE_GAP_ADV_FAST_INTERVAL1_MIN (30 * 1000 / BLE_HCI_ADV_ITVL)
@@ -99,6 +107,12 @@
/** 10.24 seconds. */
#define BLE_GAP_GEN_DISC_SCAN_MIN (10.24 * 1000)
+/** 1 second. */
+#define BLE_GAP_CONN_PAUSE_CENTRAL (1 * 1000)
+
+/** 5 seconds. */
+#define BLE_GAP_CONN_PAUSE_PERIPHERAL (5 * 1000)
+
/**
* The maximum amount of user data that can be put into the advertising data.
* Six bytes are reserved at the end for the flags field and the transmit power
@@ -106,6 +120,8 @@
*/
#define BLE_GAP_CONN_ADV_DATA_LIMIT (BLE_HCI_MAX_ADV_DATA_LEN - 6)
+#define BLE_GAP_CONN_MAX_UPDATES 4
+
/**
* The state of the in-progress master connection. If no master connection is
* currently in progress, then the op field is set to BLE_GAP_CONN_OP_NULL.
@@ -161,6 +177,17 @@ static struct {
uint8_t cur;
} ble_gap_conn_wl;
+struct ble_gap_conn_update_entry {
+ SLIST_ENTRY(ble_gap_conn_update_entry) next;
+ struct ble_gap_conn_params params;
+ uint16_t conn_handle;
+ uint8_t state;
+};
+static SLIST_HEAD(, ble_gap_conn_update_entry) ble_gap_conn_update_entries;
+
+static os_membuf_t *ble_gap_conn_update_mem;
+static struct os_mempool ble_gap_conn_update_pool;
+
static int ble_gap_conn_adv_params_tx(void *arg);
static int ble_gap_conn_adv_power_tx(void *arg);
static int ble_gap_conn_adv_data_tx(void *arg);
@@ -190,48 +217,105 @@ static struct os_callout_func ble_gap_conn_slave_timer;
* $misc *
*****************************************************************************/
+static struct ble_gap_conn_update_entry *
+ble_gap_conn_update_entry_alloc(void)
+{
+ struct ble_gap_conn_update_entry *entry;
+
+ entry = os_memblock_get(&ble_gap_conn_update_pool);
+ if (entry == NULL) {
+ return NULL;
+ }
+
+ memset(entry, 0, sizeof *entry);
+ SLIST_INSERT_HEAD(&ble_gap_conn_update_entries, entry, next);
+
+ return entry;
+}
+
static void
-ble_gap_conn_call_conn_cb(struct ble_hs_conn *conn, int event, int status)
+ble_gap_conn_update_entry_free(struct ble_gap_conn_update_entry *entry)
{
- struct ble_gap_conn_desc desc;
+ int rc;
+
+ rc = os_memblock_put(&ble_gap_conn_update_pool, entry);
+ assert(rc == 0);
+}
+
+static struct ble_gap_conn_update_entry *
+ble_gap_conn_update_find(uint16_t conn_handle)
+{
+ struct ble_gap_conn_update_entry *entry;
+
+ SLIST_FOREACH(entry, &ble_gap_conn_update_entries, next) {
+ if (entry->conn_handle == conn_handle) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+ble_gap_conn_call_conn_cb(int event, int status, struct ble_hs_conn *conn,
+ struct ble_gap_conn_params *self_params,
+ struct ble_gap_conn_params *peer_params)
+{
+ struct ble_gap_conn_ctxt ctxt;
ble_gap_conn_fn *cb;
void *cb_arg;
+ int rc;
+
+ memset(&ctxt, 0, sizeof ctxt);
if (conn != NULL) {
- desc.conn_handle = conn->bhc_handle;
- desc.peer_addr_type = conn->bhc_addr_type;
- memcpy(desc.peer_addr, conn->bhc_addr, sizeof desc.peer_addr);
+ ctxt.desc.conn_handle = conn->bhc_handle;
+ ctxt.desc.peer_addr_type = conn->bhc_addr_type;
+ memcpy(ctxt.desc.peer_addr, conn->bhc_addr,
+ sizeof ctxt.desc.peer_addr);
+ ctxt.desc.conn_itvl = conn->bhc_itvl;
+ ctxt.desc.conn_latency = conn->bhc_latency;
+ ctxt.desc.supervision_timeout = conn->bhc_supervision_timeout;
+
cb = conn->bhc_cb;
cb_arg = conn->bhc_cb_arg;
} else {
- desc.conn_handle = BLE_HS_CONN_HANDLE_NONE;
- desc.peer_addr_type = ble_gap_conn_master.conn.addr_type;
- memcpy(desc.peer_addr, ble_gap_conn_master.conn.addr,
- sizeof desc.peer_addr);
+ ctxt.desc.conn_handle = BLE_HS_CONN_HANDLE_NONE;
+ ctxt.desc.peer_addr_type = ble_gap_conn_master.conn.addr_type;
+ memcpy(ctxt.desc.peer_addr, ble_gap_conn_master.conn.addr,
+ sizeof ctxt.desc.peer_addr);
cb = ble_gap_conn_master.conn.cb;
cb_arg = ble_gap_conn_master.conn.cb_arg;
}
+ ctxt.self_params = self_params;
+ ctxt.peer_params = peer_params;
+
if (cb != NULL) {
- cb(event, status, &desc, cb_arg);
+ rc = cb(event, status, &ctxt, cb_arg);
+ } else {
+ rc = 0;
}
+
+ return rc;
}
static void
ble_gap_conn_call_slave_cb(int event, int status)
{
- struct ble_gap_conn_desc desc;
+ struct ble_gap_conn_ctxt ctxt;
if (ble_gap_conn_slave.cb == NULL) {
return;
}
- desc.conn_handle = BLE_HS_CONN_HANDLE_NONE;
- desc.peer_addr_type = ble_gap_conn_slave.dir_addr_type;
- memcpy(desc.peer_addr, ble_gap_conn_slave.dir_addr,
- sizeof desc.peer_addr);
+ memset(&ctxt, 0, sizeof ctxt);
+ ctxt.desc.conn_handle = BLE_HS_CONN_HANDLE_NONE;
+ ctxt.desc.peer_addr_type = ble_gap_conn_slave.dir_addr_type;
+ memcpy(ctxt.desc.peer_addr, ble_gap_conn_slave.dir_addr,
+ sizeof ctxt.desc.peer_addr);
- ble_gap_conn_slave.cb(event, status, &desc, ble_gap_conn_slave.cb_arg);
+ ble_gap_conn_slave.cb(event, status, &ctxt, ble_gap_conn_slave.cb_arg);
}
/**
@@ -244,13 +328,14 @@ ble_gap_conn_call_slave_cb(int event, int status)
static void
ble_gap_conn_notify_connect(int status, struct ble_hs_conn *conn)
{
- ble_gap_conn_call_conn_cb(conn, BLE_GAP_EVENT_CONN, status);
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN, status, conn, NULL, NULL);
}
static void
ble_gap_conn_notify_term_failure(int status, struct ble_hs_conn *conn)
{
- ble_gap_conn_call_conn_cb(conn, BLE_GAP_EVENT_TERM_FAILURE, status);
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_TERM_FAILURE, status, conn,
+ NULL, NULL);
}
static void
@@ -278,13 +363,14 @@ ble_gap_conn_notify_disc(struct ble_hs_adv *adv,
static void
ble_gap_conn_notify_master_conn_failure(int status)
{
- ble_gap_conn_call_conn_cb(NULL, BLE_GAP_EVENT_CONN, status);
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN, status, NULL, NULL, NULL);
}
static void
ble_gap_conn_notify_master_cancel_failure(int status)
{
- ble_gap_conn_call_conn_cb(NULL, BLE_GAP_EVENT_CANCEL_FAILURE, status);
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CANCEL_FAILURE, status, NULL,
+ NULL, NULL);
}
static void
@@ -344,6 +430,20 @@ ble_gap_conn_notify_wl(int status)
}
static void
+ble_gap_conn_notify_update(struct ble_gap_conn_update_entry *entry, int status)
+{
+ struct ble_hs_conn *conn;
+
+ conn = ble_hs_conn_find(entry->conn_handle);
+ if (conn == NULL) {
+ return;
+ }
+
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN_UPDATED, status, NULL, NULL,
+ NULL);
+}
+
+static void
ble_gap_conn_master_reset_state(void)
{
os_callout_stop(&ble_gap_conn_master_timer.cf_c);
@@ -406,6 +506,21 @@ ble_gap_conn_wl_failed(int status)
ble_gap_conn_notify_wl(status);
}
+static void
+ble_gap_conn_update_entry_remove_free(struct ble_gap_conn_update_entry *entry)
+{
+ SLIST_REMOVE(&ble_gap_conn_update_entries, entry,
+ ble_gap_conn_update_entry, next);
+ ble_gap_conn_update_entry_free(entry);
+}
+
+static void
+ble_gap_conn_update_failed(struct ble_gap_conn_update_entry *entry, int status)
+{
+ ble_gap_conn_notify_update(entry, status);
+ ble_gap_conn_update_entry_remove_free(entry);
+}
+
void
ble_gap_conn_rx_disconn_complete(struct hci_disconn_complete *evt)
{
@@ -417,7 +532,8 @@ ble_gap_conn_rx_disconn_complete(struct hci_disconn_complete *evt)
if (conn == NULL) {
return;
}
- ble_gap_conn_call_conn_cb(conn, BLE_GAP_EVENT_CONN, BLE_HS_ENOTCONN);
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN, BLE_HS_ENOTCONN, conn,
+ NULL, NULL);
ble_hs_conn_remove(conn);
ble_hs_conn_free(conn);
} else {
@@ -428,6 +544,26 @@ ble_gap_conn_rx_disconn_complete(struct hci_disconn_complete *evt)
ble_gattc_connection_broken(evt->connection_handle);
}
+void
+ble_gap_conn_rx_update_complete(struct hci_le_conn_upd_complete *evt)
+{
+ struct ble_hs_conn *conn;
+
+ conn = ble_hs_conn_find(evt->connection_handle);
+ if (conn == NULL) {
+ return;
+ }
+
+ if (evt->status == 0) {
+ conn->bhc_itvl = evt->conn_itvl;
+ conn->bhc_latency = evt->conn_latency;
+ conn->bhc_supervision_timeout = evt->supervision_timeout;
+ }
+
+ ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN_UPDATED,
+ BLE_HS_HCI_ERR(evt->status), conn, NULL, NULL);
+}
+
/**
* Tells you if the BLE host is in the process of creating a master connection.
*/
@@ -698,7 +834,11 @@ ble_gap_conn_rx_conn_complete(struct hci_le_conn_complete *evt)
conn->bhc_handle = evt->connection_handle;
memcpy(conn->bhc_addr, evt->peer_addr, sizeof conn->bhc_addr);
+ conn->bhc_itvl = evt->conn_itvl;
+ conn->bhc_latency = evt->conn_latency;
+ conn->bhc_supervision_timeout = evt->supervision_timeout;
if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER) {
+ conn->bhc_flags |= BLE_HS_CONN_F_MASTER;
conn->bhc_cb = ble_gap_conn_master.conn.cb;
conn->bhc_cb_arg = ble_gap_conn_master.conn.cb_arg;
ble_gap_conn_master_reset_state();
@@ -1663,6 +1803,189 @@ ble_gap_conn_cancel(void)
}
/*****************************************************************************
+ * $update connection parameters *
+ *****************************************************************************/
+
+static void
+ble_gap_conn_param_neg_reply_ack(struct ble_hci_ack *ack, void *arg)
+{
+ struct ble_gap_conn_update_entry *entry;
+
+ entry = arg;
+
+ assert(entry->state == BLE_GAP_CONN_STATE_U_NEG_REPLY);
+ ble_gap_conn_update_entry_remove_free(entry);
+}
+
+static void
+ble_gap_conn_param_reply_ack(struct ble_hci_ack *ack, void *arg)
+{
+ struct ble_gap_conn_update_entry *entry;
+
+ entry = arg;
+
+ assert(entry->state == BLE_GAP_CONN_STATE_U_REPLY);
+
+ if (ack->bha_status != 0) {
+ ble_gap_conn_update_failed(entry, ack->bha_status);
+ } else {
+ entry->state = BLE_GAP_CONN_STATE_U_REPLY_ACKED;
+ }
+}
+
+void
+ble_gap_conn_rx_param_req(struct hci_le_conn_param_req *evt)
+{
+ struct ble_gap_conn_update_entry *entry;
+ struct hci_conn_param_neg_reply neg_reply;
+ struct hci_conn_param_reply pos_reply;
+ struct ble_gap_conn_params peer_params;
+ struct ble_hs_conn *conn;
+ int rc;
+
+ entry = ble_gap_conn_update_find(evt->connection_handle);
+ if (entry != NULL) {
+ /* Parameter update already in progress; reject peer's attempt. */
+ /* XXX: Is this antisocial? */
+ rc = BLE_ERR_UNSPECIFIED;
+ goto err;
+ }
+
+ conn = ble_hs_conn_find(evt->connection_handle);
+ if (conn == NULL) {
+ return;
+ }
+
+ entry = ble_gap_conn_update_entry_alloc();
+ if (entry == NULL) {
+ /* Out of memory; reject. */
+ rc = BLE_ERR_MEM_CAPACITY;
+ goto err;
+ }
+
+ peer_params.itvl_min = evt->itvl_min;
+ peer_params.itvl_max = evt->itvl_max;
+ peer_params.latency = evt->latency;
+ peer_params.supervision_timeout = evt->timeout;
+ peer_params.min_ce_len = 0;
+ peer_params.max_ce_len = 0;
+
+ rc = ble_gap_conn_call_conn_cb(BLE_GAP_EVENT_CONN_UPDATE_REQ, 0, conn,
+ &entry->params, &peer_params);
+ if (rc != 0) {
+ goto err;
+ }
+
+ pos_reply.handle = entry->conn_handle;
+ pos_reply.conn_itvl_min = entry->params.itvl_min;
+ pos_reply.conn_itvl_max = entry->params.itvl_max;
+ pos_reply.conn_latency = entry->params.latency;
+ pos_reply.supervision_timeout = entry->params.supervision_timeout;
+ pos_reply.min_ce_len = entry->params.min_ce_len;
+ pos_reply.max_ce_len = entry->params.max_ce_len;
+
+ ble_hci_ack_set_callback(ble_gap_conn_param_reply_ack, entry);
+
+ rc = host_hci_cmd_le_conn_param_reply(&pos_reply);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return;
+
+err:
+ ble_gap_conn_update_failed(entry, rc);
+
+ neg_reply.handle = evt->connection_handle;
+ neg_reply.reason = rc;
+
+ ble_hci_ack_set_callback(ble_gap_conn_param_neg_reply_ack, entry);
+
+ host_hci_cmd_le_conn_param_neg_reply(&neg_reply);
+}
+
+static void
+ble_gap_conn_update_ack(struct ble_hci_ack *ack, void *arg)
+{
+ struct ble_gap_conn_update_entry *entry;
+
+ entry = arg;
+
+ assert(entry->state == BLE_GAP_CONN_STATE_U_UPDATE);
+
+ if (ack->bha_status != 0) {
+ ble_gap_conn_update_failed(entry, ack->bha_status);
+ return;
+ }
+
+ entry->state = BLE_GAP_CONN_STATE_U_UPDATE_ACKED;
+}
+
+static int
+ble_gap_conn_update_tx(void *arg)
+{
+ struct ble_gap_conn_update_entry *entry;
+ struct hci_conn_update cmd;
+ int rc;
+
+ entry = arg;
+
+ assert(entry->state == BLE_GAP_CONN_STATE_U_UPDATE);
+
+ cmd.handle = entry->conn_handle;
+ cmd.conn_itvl_min = entry->params.itvl_min;
+ cmd.conn_itvl_max = entry->params.itvl_max;
+ cmd.conn_latency = entry->params.latency;
+ cmd.supervision_timeout = entry->params.supervision_timeout;
+ cmd.min_ce_len = entry->params.min_ce_len;
+ cmd.max_ce_len = entry->params.max_ce_len;
+
+ ble_hci_ack_set_callback(ble_gap_conn_update_ack, entry);
+
+ rc = host_hci_cmd_le_conn_update(&cmd);
+ if (rc != 0) {
+ ble_gap_conn_update_failed(entry, rc);
+ }
+
+ return 0;
+}
+
+int
+ble_gap_conn_update_params(uint16_t conn_handle,
+ struct ble_gap_conn_params *params)
+{
+ struct ble_gap_conn_update_entry *entry;
+ int rc;
+
+ entry = ble_gap_conn_update_find(conn_handle);
+ if (entry != NULL) {
+ return BLE_HS_EALREADY;
+ }
+
+ if (ble_hs_conn_find(conn_handle) == NULL) {
+ return BLE_HS_ENOENT;
+ }
+
+ entry = ble_gap_conn_update_entry_alloc();
+ if (entry == NULL) {
+ return BLE_HS_ENOMEM;
+ }
+
+ entry->conn_handle = conn_handle;
+ entry->params = *params;
+ entry->state = BLE_GAP_CONN_STATE_U_UPDATE;
+
+ rc = ble_hci_sched_enqueue(ble_gap_conn_update_tx, entry);
+ if (rc != 0) {
+ SLIST_REMOVE(&ble_gap_conn_update_entries, entry,
+ ble_gap_conn_update_entry, next);
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
* $init *
*****************************************************************************/
@@ -1680,9 +2003,20 @@ ble_gap_conn_init_slave_params(void)
};
}
+static void
+ble_gap_conn_free_mem(void)
+{
+ free(ble_gap_conn_update_mem);
+ ble_gap_conn_update_mem = NULL;
+}
+
int
ble_gap_conn_init(void)
{
+ int rc;
+
+ ble_gap_conn_free_mem();
+
ble_gap_conn_master.op = BLE_GAP_CONN_OP_NULL;
ble_gap_conn_slave.op = BLE_GAP_CONN_OP_NULL;
ble_gap_conn_wl.op = BLE_GAP_CONN_OP_NULL;
@@ -1693,5 +2027,26 @@ ble_gap_conn_init(void)
ble_gap_conn_master_timer_exp, NULL);
os_callout_func_init(&ble_gap_conn_slave_timer, &ble_hs_evq,
ble_gap_conn_slave_timer_exp, NULL);
+
+ ble_gap_conn_update_mem = malloc(
+ OS_MEMPOOL_BYTES(BLE_GAP_CONN_MAX_UPDATES,
+ sizeof (struct ble_gap_conn_update_entry)));
+ if (ble_gap_conn_update_mem == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto err;
+ }
+ rc = os_mempool_init(&ble_gap_conn_update_pool, BLE_GAP_CONN_MAX_UPDATES,
+ sizeof (struct ble_gap_conn_update_entry),
+ ble_gap_conn_update_mem, "ble_gap_conn_update_pool");
+ if (rc != 0) {
+ rc = BLE_HS_EOS;
+ goto err;
+ }
+
+ SLIST_INIT(&ble_gap_conn_update_entries);
return 0;
+
+err:
+ ble_gap_conn_free_mem();
+ return rc;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/ble_gap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h
index 8c8a6f2..8de65f4 100644
--- a/net/nimble/host/src/ble_gap_priv.h
+++ b/net/nimble/host/src/ble_gap_priv.h
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include "host/ble_gap.h"
+struct hci_le_conn_upd_complete;
struct hci_le_conn_complete;
struct hci_disconn_complete;
struct ble_hci_ack;
@@ -30,6 +31,7 @@ struct ble_hs_adv;
void ble_gap_conn_rx_adv_report(struct ble_hs_adv *adv);
int ble_gap_conn_rx_conn_complete(struct hci_le_conn_complete *evt);
void ble_gap_conn_rx_disconn_complete(struct hci_disconn_complete *evt);
+void ble_gap_conn_rx_update_complete(struct hci_le_conn_upd_complete *evt);
int ble_gap_conn_master_in_progress(void);
int ble_gap_conn_slave_in_progress(void);
int ble_gap_conn_wl_busy(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/ble_hs_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn.h b/net/nimble/host/src/ble_hs_conn.h
index d08713a..a97d160 100644
--- a/net/nimble/host/src/ble_hs_conn.h
+++ b/net/nimble/host/src/ble_hs_conn.h
@@ -26,12 +26,22 @@ struct hci_le_conn_complete;
struct hci_create_conn;
struct ble_l2cap_chan;
+typedef uint8_t ble_hs_conn_flags;
+
+#define BLE_HS_CONN_F_MASTER 0x01
+
struct ble_hs_conn {
SLIST_ENTRY(ble_hs_conn) bhc_next;
uint16_t bhc_handle;
uint8_t bhc_addr_type;
uint8_t bhc_addr[6];
+ uint16_t bhc_itvl;
+ uint16_t bhc_latency;
+ uint16_t bhc_supervision_timeout;
+
+ ble_hs_conn_flags bhc_flags;
+
struct ble_l2cap_chan_list bhc_channels;
uint16_t bhc_outstanding_pkts;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c
index 5ddc570..521639c 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -559,3 +559,36 @@ host_hci_cmd_le_conn_update(struct hci_conn_update *hcu)
return rc;
}
+int
+host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr)
+{
+ uint8_t cmd[BLE_HCI_CONN_PARAM_REPLY_LEN];
+ int rc;
+
+ htole16(cmd + 0, hcr->handle);
+ htole16(cmd + 2, hcr->conn_itvl_min);
+ htole16(cmd + 4, hcr->conn_itvl_max);
+ htole16(cmd + 6, hcr->conn_latency);
+ htole16(cmd + 8, hcr->supervision_timeout);
+ htole16(cmd + 10, hcr->min_ce_len);
+ htole16(cmd + 12, hcr->max_ce_len);
+
+ rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_RR,
+ BLE_HCI_CONN_PARAM_REPLY_LEN, cmd);
+ return rc;
+}
+
+int
+host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn)
+{
+ uint8_t cmd[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN];
+ int rc;
+
+ htole16(cmd + 0, hcn->handle);
+ cmd[2] = hcn->reason;
+
+ rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR,
+ BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, cmd);
+ return rc;
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/test/ble_gap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gap_test.c b/net/nimble/host/src/test/ble_gap_test.c
index a64e257..a2cb9ce 100644
--- a/net/nimble/host/src/test/ble_gap_test.c
+++ b/net/nimble/host/src/test/ble_gap_test.c
@@ -81,14 +81,16 @@ ble_gap_test_util_disc_cb(int event, int status,
ble_gap_test_disc_arg = arg;
}
-static void
+static int
ble_gap_test_util_connect_cb(int event, int status,
- struct ble_gap_conn_desc *desc, void *arg)
+ struct ble_gap_conn_ctxt *ctxt, void *arg)
{
ble_gap_test_conn_event = event;
ble_gap_test_conn_status = status;
- ble_gap_test_conn_desc = *desc;
+ ble_gap_test_conn_desc = ctxt->desc;
ble_gap_test_conn_arg = arg;
+
+ return 0;
}
static int
@@ -395,7 +397,7 @@ TEST_CASE(ble_gap_test_case_conn_wl_bad_args)
/*** White-list-using connection in progress. */
rc = ble_gap_conn_initiate(BLE_GAP_ADDR_TYPE_WL, NULL,
- ble_gap_test_util_connect_cb, NULL);
+ ble_gap_test_util_connect_cb, NULL);
TEST_ASSERT(rc == 0);
TEST_ASSERT(ble_gap_conn_wl_busy());
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/host/src/test/ble_os_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_os_test.c b/net/nimble/host/src/test/ble_os_test.c
index b03ce71..d6862d9 100644
--- a/net/nimble/host/src/test/ble_os_test.c
+++ b/net/nimble/host/src/test/ble_os_test.c
@@ -63,9 +63,9 @@ ble_os_test_misc_rx_le_ack(uint16_t ocf, uint8_t status)
ble_os_test_misc_rx_ack(BLE_HCI_OGF_LE, ocf, status);
}
-static void
+static int
ble_gap_direct_connect_test_connect_cb(int event, int status,
- struct ble_gap_conn_desc *desc,
+ struct ble_gap_conn_ctxt *ctxt,
void *arg)
{
int *cb_called;
@@ -75,9 +75,11 @@ ble_gap_direct_connect_test_connect_cb(int event, int status,
TEST_ASSERT(event == BLE_GAP_EVENT_CONN);
TEST_ASSERT(status == 0);
- TEST_ASSERT(desc->conn_handle == 2);
- TEST_ASSERT(desc->peer_addr_type == BLE_ADDR_TYPE_PUBLIC);
- TEST_ASSERT(memcmp(desc->peer_addr, ble_os_test_peer_addr, 6) == 0);
+ TEST_ASSERT(ctxt->desc.conn_handle == 2);
+ TEST_ASSERT(ctxt->desc.peer_addr_type == BLE_ADDR_TYPE_PUBLIC);
+ TEST_ASSERT(memcmp(ctxt->desc.peer_addr, ble_os_test_peer_addr, 6) == 0);
+
+ return 0;
}
static void
@@ -104,9 +106,8 @@ ble_gap_direct_connect_test_task_handler(void *arg)
TEST_ASSERT(ble_hs_conn_first() == NULL);
/* Initiate a direct connection. */
- ble_gap_conn_initiate(0, addr,
- ble_gap_direct_connect_test_connect_cb,
- &cb_called);
+ ble_gap_conn_initiate(0, addr, ble_gap_direct_connect_test_connect_cb,
+ &cb_called);
TEST_ASSERT(ble_hs_conn_first() == NULL);
TEST_ASSERT(!cb_called);
@@ -224,19 +225,21 @@ TEST_CASE(ble_gap_gen_disc_test_case)
os_start();
}
-static void
+static int
ble_gap_terminate_cb(int event, int status,
- struct ble_gap_conn_desc *desc, void *arg)
+ struct ble_gap_conn_ctxt *ctxt, void *arg)
{
int *disconn_handle;
TEST_ASSERT_FATAL(event == BLE_GAP_EVENT_CONN);
if (status == 0) {
- return;
+ return 0;
}
disconn_handle = arg;
- *disconn_handle = desc->conn_handle;
+ *disconn_handle = ctxt->desc.conn_handle;
+
+ return 0;
}
@@ -267,8 +270,7 @@ ble_gap_terminate_test_task_handler(void *arg)
TEST_ASSERT(!ble_gap_conn_master_in_progress());
/* Create two direct connections. */
- ble_gap_conn_initiate(0, addr1, ble_gap_terminate_cb,
- &disconn_handle);
+ ble_gap_conn_initiate(0, addr1, ble_gap_terminate_cb, &disconn_handle);
ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
memset(&conn_evt, 0, sizeof conn_evt);
conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 1513cf6..528fbeb 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -260,6 +260,12 @@
/* --- LE connection update (OCF 0x0013) */
#define BLE_HCI_CONN_UPDATE_LEN (14)
+/* --- LE remote connection parameter request reply (OCF 0x0020) */
+#define BLE_HCI_CONN_PARAM_REPLY_LEN (14)
+
+/* --- LE remote connection parameter request negative reply (OCF 0x0021) */
+#define BLE_HCI_CONN_PARAM_NEG_REPLY_LEN (3)
+
/* Event Codes */
#define BLE_HCI_EVCODE_INQUIRY_CMP (0x01)
#define BLE_HCI_EVCODE_INQUIRY_RESULT (0x02)
@@ -414,7 +420,7 @@ struct hci_adv_params
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
};
-/* Create connection command */
+/* LE create connection command */
struct hci_create_conn
{
uint16_t scan_itvl;
@@ -431,7 +437,7 @@ struct hci_create_conn
uint16_t max_ce_len;
};
-/* Connection update command */
+/* LE connection update command */
struct hci_conn_update
{
uint16_t handle;
@@ -443,6 +449,25 @@ struct hci_conn_update
uint16_t max_ce_len;
};
+/* LE Remote connection parameter request reply command */
+struct hci_conn_param_reply
+{
+ uint16_t handle;
+ uint16_t conn_itvl_min;
+ uint16_t conn_itvl_max;
+ uint16_t conn_latency;
+ uint16_t supervision_timeout;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+};
+
+/* LE Remote connection parameter request negative reply command */
+struct hci_conn_param_neg_reply
+{
+ uint16_t handle;
+ uint8_t reason;
+};
+
/* Connection complete LE meta subevent */
struct hci_le_conn_complete
{
@@ -458,6 +483,28 @@ struct hci_le_conn_complete
uint8_t master_clk_acc;
};
+/* Connection update complete LE meta subevent */
+struct hci_le_conn_upd_complete
+{
+ uint8_t subevent_code;
+ uint8_t status;
+ uint16_t connection_handle;
+ uint16_t conn_itvl;
+ uint16_t conn_latency;
+ uint16_t supervision_timeout;
+};
+
+/* Remote connection parameter request LE meta subevent */
+struct hci_le_conn_param_req
+{
+ uint8_t subevent_code;
+ uint16_t connection_handle;
+ uint16_t itvl_min;
+ uint16_t itvl_max;
+ uint16_t latency;
+ uint16_t timeout;
+};
+
/* Disconnection complete event (note: fields out of order). */
struct hci_disconn_complete
{
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/project/bleshell/src/main.c
----------------------------------------------------------------------
diff --git a/project/bleshell/src/main.c b/project/bleshell/src/main.c
index 8af8e1f..46ea49b 100755
--- a/project/bleshell/src/main.c
+++ b/project/bleshell/src/main.c
@@ -613,8 +613,8 @@ bleshell_on_notify(uint16_t conn_handle, uint16_t attr_handle,
return 0;
}
-static void
-bleshell_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
+static int
+bleshell_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
void *arg)
{
int conn_idx;
@@ -623,20 +623,20 @@ bleshell_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
case BLE_GAP_EVENT_CONN:
console_printf("connection complete; handle=%d status=%d "
"peer_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
- desc->conn_handle, status,
- desc->peer_addr[0], desc->peer_addr[1],
- desc->peer_addr[2], desc->peer_addr[3],
- desc->peer_addr[4], desc->peer_addr[5]);
+ ctxt->desc.conn_handle, status,
+ ctxt->desc.peer_addr[0], ctxt->desc.peer_addr[1],
+ ctxt->desc.peer_addr[2], ctxt->desc.peer_addr[3],
+ ctxt->desc.peer_addr[4], ctxt->desc.peer_addr[5]);
if (status == 0) {
- bleshell_conn_add(desc);
+ bleshell_conn_add(&ctxt->desc);
} else {
- if (desc->conn_handle == BLE_HS_CONN_HANDLE_NONE) {
+ if (ctxt->desc.conn_handle == BLE_HS_CONN_HANDLE_NONE) {
if (status == BLE_HS_HCI_ERR(BLE_ERR_UNK_CONN_ID)) {
console_printf("connection procedure cancelled.\n");
}
} else {
- conn_idx = bleshell_conn_find_idx(desc->conn_handle);
+ conn_idx = bleshell_conn_find_idx(ctxt->desc.conn_handle);
if (conn_idx == -1) {
console_printf("UNKNOWN CONNECTION\n");
} else {
@@ -647,6 +647,8 @@ bleshell_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
break;
}
+
+ return 0;
}
int
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/project/centtest/src/main.c
----------------------------------------------------------------------
diff --git a/project/centtest/src/main.c b/project/centtest/src/main.c
index fc86a3c..4134b19 100755
--- a/project/centtest/src/main.c
+++ b/project/centtest/src/main.c
@@ -179,26 +179,28 @@ centtest_on_disc_s(uint16_t conn_handle, struct ble_gatt_error *error,
return 0;
}
-static void
-centtest_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
+static int
+centtest_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
void *arg)
{
switch (event) {
case BLE_GAP_EVENT_CONN:
console_printf("connection complete; handle=%d status=%d "
"peer_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
- desc->conn_handle, status,
- desc->peer_addr[0], desc->peer_addr[1],
- desc->peer_addr[2], desc->peer_addr[3],
- desc->peer_addr[4], desc->peer_addr[5]);
+ ctxt->desc.conn_handle, status,
+ ctxt->desc.peer_addr[0], ctxt->desc.peer_addr[1],
+ ctxt->desc.peer_addr[2], ctxt->desc.peer_addr[3],
+ ctxt->desc.peer_addr[4], ctxt->desc.peer_addr[5]);
if (status == 0) {
- ble_gattc_disc_all_svcs(desc->conn_handle,
+ ble_gattc_disc_all_svcs(ctxt->desc.conn_handle,
centtest_on_disc_s, NULL);
}
break;
}
+
+ return 0;
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/dd338e9e/project/prphtest/src/main.c
----------------------------------------------------------------------
diff --git a/project/prphtest/src/main.c b/project/prphtest/src/main.c
index aa9035a..b66fb6b 100755
--- a/project/prphtest/src/main.c
+++ b/project/prphtest/src/main.c
@@ -195,24 +195,26 @@ prphtest_register_attrs(void)
assert(rc == 0);
}
-static void
-prphtest_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
+static int
+prphtest_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
void *arg)
{
switch (event) {
case BLE_GAP_EVENT_CONN:
console_printf("connection event; handle=%d status=%d "
"peer_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
- desc->conn_handle, status,
- desc->peer_addr[0], desc->peer_addr[1],
- desc->peer_addr[2], desc->peer_addr[3],
- desc->peer_addr[4], desc->peer_addr[5]);
+ ctxt->desc.conn_handle, status,
+ ctxt->desc.peer_addr[0], ctxt->desc.peer_addr[1],
+ ctxt->desc.peer_addr[2], ctxt->desc.peer_addr[3],
+ ctxt->desc.peer_addr[4], ctxt->desc.peer_addr[5]);
break;
default:
console_printf("unexpected connection event; type=%d\n", event);
break;
}
+
+ return 0;
}
/**