Bluetooth: Add support for specifying connection parameters
Applications may want fine-grained control of connection parameters. The two APIs to provide this through are bt_le_set_auto_conn() as well as bt_conn_create_le(). Change-Id: If5cddbbf017b868d768d18d2a09daf4af8aa00d8 Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
da86c397f1
commit
1a32d5ed55
10 changed files with 81 additions and 48 deletions
|
@ -157,12 +157,13 @@ int bt_le_scan_stop(void);
|
||||||
* will be re-established if connectable advertisement from peer is received.
|
* will be re-established if connectable advertisement from peer is received.
|
||||||
*
|
*
|
||||||
* @param addr Remote Bluetooth address.
|
* @param addr Remote Bluetooth address.
|
||||||
* @param auto_conn boolean value. If true, auto connect is enabled,
|
* @param param If non-NULL, auto connect is enabled with the given
|
||||||
* if false, auto connect is disabled.
|
* parameters. If NULL, auto connect is disabled.
|
||||||
*
|
*
|
||||||
* @return Zero on success or error code otherwise.
|
* @return Zero on success or error code otherwise.
|
||||||
*/
|
*/
|
||||||
int bt_le_set_auto_conn(bt_addr_le_t *addr, bool auto_conn);
|
int bt_le_set_auto_conn(bt_addr_le_t *addr,
|
||||||
|
const struct bt_le_conn_param *param);
|
||||||
|
|
||||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,17 @@
|
||||||
/** Opaque type representing a connection to a remote device */
|
/** Opaque type representing a connection to a remote device */
|
||||||
struct bt_conn;
|
struct bt_conn;
|
||||||
|
|
||||||
|
/** Connection parameters for LE connections */
|
||||||
|
struct bt_le_conn_param {
|
||||||
|
uint16_t interval_min;
|
||||||
|
uint16_t interval_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BT_LE_CONN_PARAM_DEFAULT (&(struct bt_le_conn_param) { \
|
||||||
|
.interval_min = BT_GAP_INIT_CONN_INT_MIN, \
|
||||||
|
.interval_max = BT_GAP_INIT_CONN_INT_MAX, \
|
||||||
|
})
|
||||||
|
|
||||||
/** @brief Increment a connection's reference count.
|
/** @brief Increment a connection's reference count.
|
||||||
*
|
*
|
||||||
* Increment the reference count of a connection object.
|
* Increment the reference count of a connection object.
|
||||||
|
@ -125,11 +136,13 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason);
|
||||||
* Allows initiate new LE link to remote peer using its address.
|
* Allows initiate new LE link to remote peer using its address.
|
||||||
* Returns a new reference that the the caller is responsible for managing.
|
* Returns a new reference that the the caller is responsible for managing.
|
||||||
*
|
*
|
||||||
* @param peer Remote address.
|
* @param peer Remote address.
|
||||||
|
* @param param Initial connection parameters.
|
||||||
*
|
*
|
||||||
* @return Valid connection object on success or NULL otherwise.
|
* @return Valid connection object on success or NULL otherwise.
|
||||||
*/
|
*/
|
||||||
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer);
|
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
|
||||||
|
const struct bt_le_conn_param *param);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Security level. */
|
/** Security level. */
|
||||||
|
|
|
@ -527,6 +527,8 @@ struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
|
||||||
conn->required_sec_level = BT_SECURITY_LOW;
|
conn->required_sec_level = BT_SECURITY_LOW;
|
||||||
#endif /* CONFIG_BLUETOOTH_SMP */
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
||||||
conn->type = BT_CONN_TYPE_LE;
|
conn->type = BT_CONN_TYPE_LE;
|
||||||
|
conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN;
|
||||||
|
conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX;
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
@ -824,7 +826,8 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer)
|
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
{
|
{
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
|
|
||||||
|
@ -836,6 +839,9 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer)
|
||||||
if (conn) {
|
if (conn) {
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
case BT_CONN_CONNECT_SCAN:
|
case BT_CONN_CONNECT_SCAN:
|
||||||
|
conn->le.interval_min = param->interval_min;
|
||||||
|
conn->le.interval_max = param->interval_max;
|
||||||
|
return conn;
|
||||||
case BT_CONN_CONNECT:
|
case BT_CONN_CONNECT:
|
||||||
case BT_CONN_CONNECTED:
|
case BT_CONN_CONNECTED:
|
||||||
return conn;
|
return conn;
|
||||||
|
@ -850,6 +856,9 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn->le.interval_min = param->interval_min;
|
||||||
|
conn->le.interval_max = param->interval_max;
|
||||||
|
|
||||||
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
||||||
|
|
||||||
bt_le_scan_update(true);
|
bt_le_scan_update(true);
|
||||||
|
|
|
@ -37,7 +37,11 @@ struct bt_conn_le {
|
||||||
|
|
||||||
bt_addr_le_t init_addr;
|
bt_addr_le_t init_addr;
|
||||||
bt_addr_le_t resp_addr;
|
bt_addr_le_t resp_addr;
|
||||||
uint16_t conn_interval;
|
|
||||||
|
uint16_t interval;
|
||||||
|
uint16_t interval_min;
|
||||||
|
uint16_t interval_max;
|
||||||
|
|
||||||
uint8_t features[8];
|
uint8_t features[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -392,7 +392,7 @@ static void hci_num_completed_packets(struct net_buf *buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hci_le_create_conn(const bt_addr_le_t *addr)
|
static int hci_le_create_conn(const struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
struct bt_hci_cp_le_create_conn *cp;
|
struct bt_hci_cp_le_create_conn *cp;
|
||||||
|
@ -409,9 +409,9 @@ static int hci_le_create_conn(const bt_addr_le_t *addr)
|
||||||
cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL);
|
cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL);
|
||||||
cp->scan_window = cp->scan_interval;
|
cp->scan_window = cp->scan_interval;
|
||||||
|
|
||||||
bt_addr_le_copy(&cp->peer_addr, addr);
|
bt_addr_le_copy(&cp->peer_addr, &conn->le.resp_addr);
|
||||||
cp->conn_interval_max = sys_cpu_to_le16(BT_GAP_INIT_CONN_INT_MAX);
|
cp->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min);
|
||||||
cp->conn_interval_min = sys_cpu_to_le16(BT_GAP_INIT_CONN_INT_MIN);
|
cp->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max);
|
||||||
cp->supervision_timeout = sys_cpu_to_le16(0x07D0);
|
cp->supervision_timeout = sys_cpu_to_le16(0x07D0);
|
||||||
|
|
||||||
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
|
||||||
|
@ -489,8 +489,8 @@ static int update_conn_params(struct bt_conn *conn)
|
||||||
BT_DBG("conn %p features 0x%x", conn, conn->le.features[0]);
|
BT_DBG("conn %p features 0x%x", conn, conn->le.features[0]);
|
||||||
|
|
||||||
/* Check if there's a need to update conn params */
|
/* Check if there's a need to update conn params */
|
||||||
if (conn->le.conn_interval >= LE_CONN_MIN_INTERVAL &&
|
if (conn->le.interval >= conn->le.interval_min &&
|
||||||
conn->le.conn_interval <= LE_CONN_MAX_INTERVAL) {
|
conn->le.interval <= conn->le.interval_max) {
|
||||||
return -EALREADY;
|
return -EALREADY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,9 +501,10 @@ static int update_conn_params(struct bt_conn *conn)
|
||||||
|
|
||||||
if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) &&
|
if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) &&
|
||||||
(bt_dev.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, LE_CONN_MIN_INTERVAL,
|
return bt_conn_le_conn_update(conn, conn->le.interval_min,
|
||||||
LE_CONN_MAX_INTERVAL,
|
conn->le.interval_max,
|
||||||
LE_CONN_LATENCY, LE_CONN_TIMEOUT);
|
LE_CONN_LATENCY,
|
||||||
|
LE_CONN_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -555,7 +556,7 @@ static void le_conn_complete(struct net_buf *buf)
|
||||||
|
|
||||||
conn->handle = handle;
|
conn->handle = handle;
|
||||||
bt_addr_le_copy(&conn->le.dst, id_addr);
|
bt_addr_le_copy(&conn->le.dst, id_addr);
|
||||||
conn->le.conn_interval = sys_le16_to_cpu(evt->interval);
|
conn->le.interval = sys_le16_to_cpu(evt->interval);
|
||||||
conn->role = evt->role;
|
conn->role = evt->role;
|
||||||
|
|
||||||
src.type = BT_ADDR_LE_PUBLIC;
|
src.type = BT_ADDR_LE_PUBLIC;
|
||||||
|
@ -699,7 +700,7 @@ static void le_conn_update_complete(struct net_buf *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evt->status) {
|
if (!evt->status) {
|
||||||
conn->le.conn_interval = interval;
|
conn->le.interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Notify about connection */
|
/* TODO Notify about connection */
|
||||||
|
@ -731,7 +732,9 @@ static void check_pending_conn(const bt_addr_le_t *id_addr,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hci_le_create_conn(addr)) {
|
bt_addr_le_copy(&conn->le.resp_addr, addr);
|
||||||
|
|
||||||
|
if (hci_le_create_conn(conn)) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1214,7 +1217,8 @@ int bt_le_scan_update(bool fast_scan)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||||
int bt_le_set_auto_conn(bt_addr_le_t *addr, bool auto_conn)
|
int bt_le_set_auto_conn(bt_addr_le_t *addr,
|
||||||
|
const struct bt_le_conn_param *param)
|
||||||
{
|
{
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
|
|
||||||
|
@ -1226,7 +1230,10 @@ int bt_le_set_auto_conn(bt_addr_le_t *addr, bool auto_conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto_conn) {
|
if (param) {
|
||||||
|
conn->le.interval_min = param->interval_min;
|
||||||
|
conn->le.interval_max = param->interval_max;
|
||||||
|
|
||||||
if (!atomic_test_and_set_bit(conn->flags,
|
if (!atomic_test_and_set_bit(conn->flags,
|
||||||
BT_CONN_AUTO_CONNECT)) {
|
BT_CONN_AUTO_CONNECT)) {
|
||||||
bt_conn_ref(conn);
|
bt_conn_ref(conn);
|
||||||
|
@ -1243,7 +1250,7 @@ int bt_le_set_auto_conn(bt_addr_le_t *addr, bool auto_conn)
|
||||||
|
|
||||||
if (conn->state == BT_CONN_DISCONNECTED &&
|
if (conn->state == BT_CONN_DISCONNECTED &&
|
||||||
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
||||||
if (auto_conn) {
|
if (param) {
|
||||||
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
||||||
}
|
}
|
||||||
bt_le_scan_update(false);
|
bt_le_scan_update(false);
|
||||||
|
|
|
@ -33,8 +33,6 @@
|
||||||
#define lmp_le_capable(dev) ((dev).features[4] & BT_LMP_LE)
|
#define lmp_le_capable(dev) ((dev).features[4] & BT_LMP_LE)
|
||||||
|
|
||||||
/* LL connection parameters */
|
/* LL connection parameters */
|
||||||
#define LE_CONN_MIN_INTERVAL 0x0028
|
|
||||||
#define LE_CONN_MAX_INTERVAL 0x0038
|
|
||||||
#define LE_CONN_LATENCY 0x0000
|
#define LE_CONN_LATENCY 0x0000
|
||||||
#define LE_CONN_TIMEOUT 0x002a
|
#define LE_CONN_TIMEOUT 0x002a
|
||||||
|
|
||||||
|
|
|
@ -974,8 +974,8 @@ 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(LE_CONN_MIN_INTERVAL);
|
req->min_interval = sys_cpu_to_le16(conn->le.interval_min);
|
||||||
req->max_interval = sys_cpu_to_le16(LE_CONN_MAX_INTERVAL);
|
req->max_interval = sys_cpu_to_le16(conn->le.interval_max);
|
||||||
req->latency = sys_cpu_to_le16(LE_CONN_LATENCY);
|
req->latency = sys_cpu_to_le16(LE_CONN_LATENCY);
|
||||||
req->timeout = sys_cpu_to_le16(LE_CONN_TIMEOUT);
|
req->timeout = sys_cpu_to_le16(LE_CONN_TIMEOUT);
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,6 @@ static void connected(struct bt_conn *conn)
|
||||||
static bool eir_found(const struct bt_eir *eir, void *user_data)
|
static bool eir_found(const struct bt_eir *eir, void *user_data)
|
||||||
{
|
{
|
||||||
bt_addr_le_t *addr = user_data;
|
bt_addr_le_t *addr = user_data;
|
||||||
uint16_t u16;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printk("[AD]: %u len %u\n", eir->type, eir->len);
|
printk("[AD]: %u len %u\n", eir->type, eir->len);
|
||||||
|
@ -138,24 +137,29 @@ static bool eir_found(const struct bt_eir *eir, void *user_data)
|
||||||
switch (eir->type) {
|
switch (eir->type) {
|
||||||
case BT_EIR_UUID16_SOME:
|
case BT_EIR_UUID16_SOME:
|
||||||
case BT_EIR_UUID16_ALL:
|
case BT_EIR_UUID16_ALL:
|
||||||
if ((eir->len - sizeof(eir->type)) % sizeof(u16) != 0) {
|
if ((eir->len - sizeof(eir->type)) % sizeof(uint16_t) != 0) {
|
||||||
printk("AD malformed\n");
|
printk("AD malformed\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < eir->len; i += sizeof(u16)) {
|
for (i = 0; i < eir->len; i += sizeof(uint16_t)) {
|
||||||
|
uint16_t u16;
|
||||||
|
int err;
|
||||||
|
|
||||||
memcpy(&u16, &eir->data[i], sizeof(u16));
|
memcpy(&u16, &eir->data[i], sizeof(u16));
|
||||||
if (sys_le16_to_cpu(u16) == BT_UUID_HRS) {
|
if (sys_le16_to_cpu(u16) != BT_UUID_HRS) {
|
||||||
int err = bt_le_scan_stop();
|
continue;
|
||||||
|
|
||||||
if (err) {
|
|
||||||
printk("Stopping scanning failed"
|
|
||||||
" (err %d)\n", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
default_conn = bt_conn_create_le(addr);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bt_le_scan_stop();
|
||||||
|
if (err) {
|
||||||
|
printk("Stop LE scan failed (err %d)\n", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_conn = bt_conn_create_le(addr,
|
||||||
|
BT_LE_CONN_PARAM_DEFAULT);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ static void cmd_connect_le(int argc, char *argv[])
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = bt_conn_create_le(&addr);
|
conn = bt_conn_create_le(&addr, BT_LE_CONN_PARAM_DEFAULT);
|
||||||
|
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
printk("Connection failed\n");
|
printk("Connection failed\n");
|
||||||
|
@ -294,7 +294,6 @@ static void cmd_disconnect(int argc, char *argv[])
|
||||||
static void cmd_auto_conn(int argc, char *argv[])
|
static void cmd_auto_conn(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
bt_addr_le_t addr;
|
bt_addr_le_t addr;
|
||||||
bool enable;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
|
@ -314,17 +313,14 @@ static void cmd_auto_conn(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 4) {
|
if (argc < 4) {
|
||||||
enable = true;
|
bt_le_set_auto_conn(&addr, BT_LE_CONN_PARAM_DEFAULT);
|
||||||
} else if (!strcmp(argv[3], "on")) {
|
} else if (!strcmp(argv[3], "on")) {
|
||||||
enable = true;
|
bt_le_set_auto_conn(&addr, BT_LE_CONN_PARAM_DEFAULT);
|
||||||
} else if (!strcmp(argv[3], "off")) {
|
} else if (!strcmp(argv[3], "off")) {
|
||||||
enable = false;
|
bt_le_set_auto_conn(&addr, NULL);
|
||||||
} else {
|
} else {
|
||||||
printk("Specify \"on\" or \"off\"\n");
|
printk("Specify \"on\" or \"off\"\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_le_set_auto_conn(&addr, enable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_select(int argc, char *argv[])
|
static void cmd_select(int argc, char *argv[])
|
||||||
|
|
|
@ -326,7 +326,8 @@ static void connect(const uint8_t *data, uint16_t len)
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
conn = bt_conn_create_le((bt_addr_le_t *) data);
|
conn = bt_conn_create_le((bt_addr_le_t *) data,
|
||||||
|
BT_LE_CONN_PARAM_DEFAULT);
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
status = BTP_STATUS_FAILED;
|
status = BTP_STATUS_FAILED;
|
||||||
goto rsp;
|
goto rsp;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue