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.
|
||||
*
|
||||
* @param addr Remote Bluetooth address.
|
||||
* @param auto_conn boolean value. If true, auto connect is enabled,
|
||||
* if false, auto connect is disabled.
|
||||
* @param param If non-NULL, auto connect is enabled with the given
|
||||
* parameters. If NULL, auto connect is disabled.
|
||||
*
|
||||
* @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 */
|
||||
|
||||
|
|
|
@ -28,6 +28,17 @@
|
|||
/** Opaque type representing a connection to a remote device */
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
|
||||
/** 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;
|
||||
#endif /* CONFIG_BLUETOOTH_SMP */
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -836,6 +839,9 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer)
|
|||
if (conn) {
|
||||
switch (conn->state) {
|
||||
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_CONNECTED:
|
||||
return conn;
|
||||
|
@ -850,6 +856,9 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer)
|
|||
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_le_scan_update(true);
|
||||
|
|
|
@ -37,7 +37,11 @@ struct bt_conn_le {
|
|||
|
||||
bt_addr_le_t init_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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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 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_window = cp->scan_interval;
|
||||
|
||||
bt_addr_le_copy(&cp->peer_addr, addr);
|
||||
cp->conn_interval_max = sys_cpu_to_le16(BT_GAP_INIT_CONN_INT_MAX);
|
||||
cp->conn_interval_min = sys_cpu_to_le16(BT_GAP_INIT_CONN_INT_MIN);
|
||||
bt_addr_le_copy(&cp->peer_addr, &conn->le.resp_addr);
|
||||
cp->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min);
|
||||
cp->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max);
|
||||
cp->supervision_timeout = sys_cpu_to_le16(0x07D0);
|
||||
|
||||
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]);
|
||||
|
||||
/* Check if there's a need to update conn params */
|
||||
if (conn->le.conn_interval >= LE_CONN_MIN_INTERVAL &&
|
||||
conn->le.conn_interval <= LE_CONN_MAX_INTERVAL) {
|
||||
if (conn->le.interval >= conn->le.interval_min &&
|
||||
conn->le.interval <= conn->le.interval_max) {
|
||||
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) &&
|
||||
(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
||||
return bt_conn_le_conn_update(conn, LE_CONN_MIN_INTERVAL,
|
||||
LE_CONN_MAX_INTERVAL,
|
||||
LE_CONN_LATENCY, LE_CONN_TIMEOUT);
|
||||
return bt_conn_le_conn_update(conn, conn->le.interval_min,
|
||||
conn->le.interval_max,
|
||||
LE_CONN_LATENCY,
|
||||
LE_CONN_TIMEOUT);
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
|
@ -555,7 +556,7 @@ static void le_conn_complete(struct net_buf *buf)
|
|||
|
||||
conn->handle = handle;
|
||||
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;
|
||||
|
||||
src.type = BT_ADDR_LE_PUBLIC;
|
||||
|
@ -699,7 +700,7 @@ static void le_conn_update_complete(struct net_buf *buf)
|
|||
}
|
||||
|
||||
if (!evt->status) {
|
||||
conn->le.conn_interval = interval;
|
||||
conn->le.interval = interval;
|
||||
}
|
||||
|
||||
/* TODO Notify about connection */
|
||||
|
@ -731,7 +732,9 @@ static void check_pending_conn(const bt_addr_le_t *id_addr,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -1214,7 +1217,8 @@ int bt_le_scan_update(bool fast_scan)
|
|||
}
|
||||
|
||||
#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;
|
||||
|
||||
|
@ -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,
|
||||
BT_CONN_AUTO_CONNECT)) {
|
||||
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 &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
||||
if (auto_conn) {
|
||||
if (param) {
|
||||
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
||||
}
|
||||
bt_le_scan_update(false);
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#define lmp_le_capable(dev) ((dev).features[4] & BT_LMP_LE)
|
||||
|
||||
/* LL connection parameters */
|
||||
#define LE_CONN_MIN_INTERVAL 0x0028
|
||||
#define LE_CONN_MAX_INTERVAL 0x0038
|
||||
#define LE_CONN_LATENCY 0x0000
|
||||
#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));
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->min_interval = sys_cpu_to_le16(LE_CONN_MIN_INTERVAL);
|
||||
req->max_interval = sys_cpu_to_le16(LE_CONN_MAX_INTERVAL);
|
||||
req->min_interval = sys_cpu_to_le16(conn->le.interval_min);
|
||||
req->max_interval = sys_cpu_to_le16(conn->le.interval_max);
|
||||
req->latency = sys_cpu_to_le16(LE_CONN_LATENCY);
|
||||
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)
|
||||
{
|
||||
bt_addr_le_t *addr = user_data;
|
||||
uint16_t u16;
|
||||
int i;
|
||||
|
||||
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) {
|
||||
case BT_EIR_UUID16_SOME:
|
||||
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");
|
||||
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));
|
||||
if (sys_le16_to_cpu(u16) == BT_UUID_HRS) {
|
||||
int err = bt_le_scan_stop();
|
||||
|
||||
if (err) {
|
||||
printk("Stopping scanning failed"
|
||||
" (err %d)\n", err);
|
||||
}
|
||||
|
||||
default_conn = bt_conn_create_le(addr);
|
||||
return false;
|
||||
if (sys_le16_to_cpu(u16) != BT_UUID_HRS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
conn = bt_conn_create_le(&addr);
|
||||
conn = bt_conn_create_le(&addr, BT_LE_CONN_PARAM_DEFAULT);
|
||||
|
||||
if (!conn) {
|
||||
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[])
|
||||
{
|
||||
bt_addr_le_t addr;
|
||||
bool enable;
|
||||
int err;
|
||||
|
||||
if (argc < 2) {
|
||||
|
@ -314,17 +313,14 @@ static void cmd_auto_conn(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if (argc < 4) {
|
||||
enable = true;
|
||||
bt_le_set_auto_conn(&addr, BT_LE_CONN_PARAM_DEFAULT);
|
||||
} 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")) {
|
||||
enable = false;
|
||||
bt_le_set_auto_conn(&addr, NULL);
|
||||
} else {
|
||||
printk("Specify \"on\" or \"off\"\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_le_set_auto_conn(&addr, enable);
|
||||
}
|
||||
|
||||
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;
|
||||
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) {
|
||||
status = BTP_STATUS_FAILED;
|
||||
goto rsp;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue