Bluetooth: Add API to update LE connection parameters
Applications should be able to update the connection parameters. Change-Id: I446f64fcd0b27b605e636e566fb35a362a92de96 Signed-off-by: Louis Caron <louis.caron@intel.com>
This commit is contained in:
parent
bef69b7b96
commit
48802c2212
7 changed files with 102 additions and 44 deletions
|
@ -43,6 +43,12 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_conn_le_param_update(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
|
@ -149,6 +149,16 @@ struct bt_conn_info {
|
||||||
*/
|
*/
|
||||||
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info);
|
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info);
|
||||||
|
|
||||||
|
/** @brief Update the connection parameters.
|
||||||
|
*
|
||||||
|
* @param conn Connection object.
|
||||||
|
* @param param Updated connection parameters.
|
||||||
|
*
|
||||||
|
* @return Zero on success or (negative) error code on failure.
|
||||||
|
*/
|
||||||
|
int bt_conn_le_param_update(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
/** @brief Disconnect from a remote device or cancel pending connection.
|
/** @brief Disconnect from a remote device or cancel pending connection.
|
||||||
*
|
*
|
||||||
* Disconnect an active connection with the specified reason code or cancel
|
* Disconnect an active connection with the specified reason code or cancel
|
||||||
|
@ -265,6 +275,8 @@ uint8_t bt_conn_enc_key_size(struct bt_conn *conn);
|
||||||
struct bt_conn_cb {
|
struct bt_conn_cb {
|
||||||
void (*connected)(struct bt_conn *conn, uint8_t err);
|
void (*connected)(struct bt_conn *conn, uint8_t err);
|
||||||
void (*disconnected)(struct bt_conn *conn, uint8_t reason);
|
void (*disconnected)(struct bt_conn *conn, uint8_t reason);
|
||||||
|
void (*le_param_updated)(struct bt_conn *conn, uint16_t interval,
|
||||||
|
uint16_t latency, uint16_t timeout);
|
||||||
#if defined(CONFIG_BLUETOOTH_SMP)
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
||||||
void (*identity_resolved)(struct bt_conn *conn,
|
void (*identity_resolved)(struct bt_conn *conn,
|
||||||
const bt_addr_le_t *rpa,
|
const bt_addr_le_t *rpa,
|
||||||
|
|
|
@ -104,6 +104,19 @@ static void notify_disconnected(struct bt_conn *conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notify_le_param_updated(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
struct bt_conn_cb *cb;
|
||||||
|
|
||||||
|
for (cb = callback_list; cb; cb = cb->_next) {
|
||||||
|
if (cb->le_param_updated) {
|
||||||
|
cb->le_param_updated(conn, conn->le.interval,
|
||||||
|
conn->le.latency,
|
||||||
|
conn->le.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_SMP)
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
||||||
uint8_t bt_conn_enc_key_size(struct bt_conn *conn)
|
uint8_t bt_conn_enc_key_size(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
|
@ -858,6 +871,12 @@ static int bt_hci_connect_le_cancel(struct bt_conn *conn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_conn_le_param_update(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
|
{
|
||||||
|
return bt_conn_update_param_le(conn, param);
|
||||||
|
}
|
||||||
|
|
||||||
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||||
|
@ -991,8 +1010,8 @@ struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
||||||
|
|
||||||
int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max,
|
int bt_conn_le_conn_update(struct bt_conn *conn,
|
||||||
uint16_t latency, uint16_t timeout)
|
const struct bt_le_conn_param *param)
|
||||||
{
|
{
|
||||||
struct hci_cp_le_conn_update *conn_update;
|
struct hci_cp_le_conn_update *conn_update;
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
@ -1006,10 +1025,10 @@ int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max,
|
||||||
conn_update = net_buf_add(buf, sizeof(*conn_update));
|
conn_update = net_buf_add(buf, sizeof(*conn_update));
|
||||||
memset(conn_update, 0, sizeof(*conn_update));
|
memset(conn_update, 0, sizeof(*conn_update));
|
||||||
conn_update->handle = sys_cpu_to_le16(conn->handle);
|
conn_update->handle = sys_cpu_to_le16(conn->handle);
|
||||||
conn_update->conn_interval_min = sys_cpu_to_le16(min);
|
conn_update->conn_interval_min = sys_cpu_to_le16(param->interval_min);
|
||||||
conn_update->conn_interval_max = sys_cpu_to_le16(max);
|
conn_update->conn_interval_max = sys_cpu_to_le16(param->interval_max);
|
||||||
conn_update->conn_latency = sys_cpu_to_le16(latency);
|
conn_update->conn_latency = sys_cpu_to_le16(param->latency);
|
||||||
conn_update->supervision_timeout = sys_cpu_to_le16(timeout);
|
conn_update->supervision_timeout = sys_cpu_to_le16(param->timeout);
|
||||||
|
|
||||||
return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_UPDATE, buf);
|
return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_UPDATE, buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,8 +137,13 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);
|
||||||
void bt_conn_set_param_le(struct bt_conn *conn,
|
void bt_conn_set_param_le(struct bt_conn *conn,
|
||||||
const struct bt_le_conn_param *param);
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max,
|
int bt_conn_update_param_le(struct bt_conn *conn,
|
||||||
uint16_t latency, uint16_t timeout);
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
|
int bt_conn_le_conn_update(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
|
void notify_le_param_updated(struct bt_conn *conn);
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_SMP)
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
||||||
/* rand and ediv should be in BT order */
|
/* rand and ediv should be in BT order */
|
||||||
|
|
|
@ -493,30 +493,15 @@ static int hci_le_read_remote_features(struct bt_conn *conn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int update_conn_params(struct bt_conn *conn)
|
static int update_conn_param(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
BT_DBG("conn %p features 0x%x", conn, conn->le.features[0]);
|
const struct bt_le_conn_param *param;
|
||||||
|
|
||||||
/* Check if there's a need to update conn params */
|
param = BT_LE_CONN_PARAM(conn->le.interval_min,
|
||||||
if (conn->le.interval >= conn->le.interval_min &&
|
|
||||||
conn->le.interval <= conn->le.interval_max) {
|
|
||||||
return -EALREADY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((conn->role == BT_HCI_ROLE_SLAVE) &&
|
|
||||||
!(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
|
||||||
return bt_l2cap_update_conn_param(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) &&
|
|
||||||
(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
|
||||||
return bt_conn_le_conn_update(conn, conn->le.interval_min,
|
|
||||||
conn->le.interval_max,
|
conn->le.interval_max,
|
||||||
conn->le.latency,
|
conn->le.latency,
|
||||||
conn->le.timeout);
|
conn->le.timeout);
|
||||||
}
|
return bt_conn_update_param_le(conn, param);
|
||||||
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void le_conn_complete(struct net_buf *buf)
|
static void le_conn_complete(struct net_buf *buf)
|
||||||
|
@ -605,7 +590,7 @@ static void le_conn_complete(struct net_buf *buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update_conn_params(conn);
|
update_conn_param(conn);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
bt_conn_unref(conn);
|
bt_conn_unref(conn);
|
||||||
|
@ -629,7 +614,7 @@ static void le_remote_feat_complete(struct net_buf *buf)
|
||||||
sizeof(conn->le.features));
|
sizeof(conn->le.features));
|
||||||
}
|
}
|
||||||
|
|
||||||
update_conn_params(conn);
|
update_conn_param(conn);
|
||||||
|
|
||||||
bt_conn_unref(conn);
|
bt_conn_unref(conn);
|
||||||
}
|
}
|
||||||
|
@ -708,10 +693,9 @@ static void le_conn_update_complete(struct net_buf *buf)
|
||||||
{
|
{
|
||||||
struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data;
|
struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data;
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
uint16_t handle, interval;
|
uint16_t handle;
|
||||||
|
|
||||||
handle = sys_le16_to_cpu(evt->handle);
|
handle = sys_le16_to_cpu(evt->handle);
|
||||||
interval = sys_le16_to_cpu(evt->interval);
|
|
||||||
|
|
||||||
BT_DBG("status %u, handle %u", evt->status, handle);
|
BT_DBG("status %u, handle %u", evt->status, handle);
|
||||||
|
|
||||||
|
@ -722,11 +706,12 @@ static void le_conn_update_complete(struct net_buf *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evt->status) {
|
if (!evt->status) {
|
||||||
conn->le.interval = interval;
|
conn->le.interval = sys_le16_to_cpu(evt->interval);
|
||||||
|
conn->le.latency = sys_le16_to_cpu(evt->latency);
|
||||||
|
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
|
||||||
|
notify_le_param_updated(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Notify about connection */
|
|
||||||
|
|
||||||
bt_conn_unref(conn);
|
bt_conn_unref(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,6 +793,33 @@ void bt_conn_set_param_le(struct bt_conn *conn,
|
||||||
conn->le.latency = param->latency;
|
conn->le.latency = param->latency;
|
||||||
conn->le.timeout = param->timeout;
|
conn->le.timeout = param->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_conn_update_param_le(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
|
{
|
||||||
|
BT_DBG("conn %p features 0x%x params (%d-%d %d %d)", conn,
|
||||||
|
conn->le.features[0], param->interval_min, param->interval_max,
|
||||||
|
param->latency, param->timeout);
|
||||||
|
|
||||||
|
/* Check if there's a need to update conn params */
|
||||||
|
if (conn->le.interval >= param->interval_min &&
|
||||||
|
conn->le.interval <= param->interval_max) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((conn->role == BT_HCI_ROLE_SLAVE) &&
|
||||||
|
!(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
||||||
|
return bt_l2cap_update_conn_param(conn, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) &&
|
||||||
|
(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
||||||
|
return bt_conn_le_conn_update(conn, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BLUETOOTH_CONN */
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR)
|
#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR)
|
||||||
|
|
|
@ -283,6 +283,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
struct net_buf *buf)
|
struct net_buf *buf)
|
||||||
{
|
{
|
||||||
struct bt_conn *conn = l2cap->chan.conn;
|
struct bt_conn *conn = l2cap->chan.conn;
|
||||||
|
const struct bt_le_conn_param *param;
|
||||||
uint16_t min, max, latency, timeout;
|
uint16_t min, max, latency, timeout;
|
||||||
bool params_valid;
|
bool params_valid;
|
||||||
struct bt_l2cap_sig_hdr *hdr;
|
struct bt_l2cap_sig_hdr *hdr;
|
||||||
|
@ -303,6 +304,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
max = sys_le16_to_cpu(req->max_interval);
|
max = sys_le16_to_cpu(req->max_interval);
|
||||||
latency = sys_le16_to_cpu(req->latency);
|
latency = sys_le16_to_cpu(req->latency);
|
||||||
timeout = sys_le16_to_cpu(req->timeout);
|
timeout = sys_le16_to_cpu(req->timeout);
|
||||||
|
param = BT_LE_CONN_PARAM(min, max, latency, timeout);
|
||||||
|
|
||||||
BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x timeout: 0x%4.4x",
|
BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x timeout: 0x%4.4x",
|
||||||
min, max, latency, timeout);
|
min, max, latency, timeout);
|
||||||
|
@ -329,7 +331,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
bt_l2cap_send(l2cap->chan.conn, BT_L2CAP_CID_LE_SIG, buf);
|
bt_l2cap_send(l2cap->chan.conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||||
|
|
||||||
if (params_valid) {
|
if (params_valid) {
|
||||||
bt_conn_le_conn_update(conn, min, max, latency, timeout);
|
bt_conn_le_conn_update(conn, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||||
|
@ -963,7 +965,8 @@ void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf)
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_l2cap_update_conn_param(struct bt_conn *conn)
|
int bt_l2cap_update_conn_param(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
{
|
{
|
||||||
struct bt_l2cap_sig_hdr *hdr;
|
struct bt_l2cap_sig_hdr *hdr;
|
||||||
struct bt_l2cap_conn_param_req *req;
|
struct bt_l2cap_conn_param_req *req;
|
||||||
|
@ -980,10 +983,10 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn)
|
||||||
hdr->len = sys_cpu_to_le16(sizeof(*req));
|
hdr->len = sys_cpu_to_le16(sizeof(*req));
|
||||||
|
|
||||||
req = net_buf_add(buf, sizeof(*req));
|
req = net_buf_add(buf, sizeof(*req));
|
||||||
req->min_interval = sys_cpu_to_le16(conn->le.interval_min);
|
req->min_interval = sys_cpu_to_le16(param->interval_min);
|
||||||
req->max_interval = sys_cpu_to_le16(conn->le.interval_max);
|
req->max_interval = sys_cpu_to_le16(param->interval_max);
|
||||||
req->latency = sys_cpu_to_le16(conn->le.latency);
|
req->latency = sys_cpu_to_le16(param->latency);
|
||||||
req->timeout = sys_cpu_to_le16(conn->le.timeout);
|
req->timeout = sys_cpu_to_le16(param->timeout);
|
||||||
|
|
||||||
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
|
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,8 @@ void bt_l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf);
|
||||||
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
|
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
|
||||||
|
|
||||||
/* Perform connection parameter update request */
|
/* Perform connection parameter update request */
|
||||||
int bt_l2cap_update_conn_param(struct bt_conn *conn);
|
int bt_l2cap_update_conn_param(struct bt_conn *conn,
|
||||||
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
/* Initialize L2CAP and supported channels */
|
/* Initialize L2CAP and supported channels */
|
||||||
void bt_l2cap_init(void);
|
void bt_l2cap_init(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue