diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 6ceebb6669be7..83f9573f57a00 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -1977,6 +1977,7 @@ PREDEFINED = "CONFIG_SYS_CLOCK_EXISTS=y" \ "CONFIG_SYS_POWER_MANAGEMENT=y" \ "CONFIG_DEVICE_POWER_MANAGEMENT=y" \ "CONFIG_BT_SMP=y" \ + "CONFIG_BT_REMOTE_INFO=y" \ "CONFIG_USERSPACE=y" \ "CONFIG_BT_BREDR=y" \ "CONFIG_FLASH_PAGE_LAYOUT=y" \ diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 7c761bbb39517..a7ee9b38e7fa9 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -163,7 +163,6 @@ enum { }; /** @brief Connection Info Structure - * * * @param type Connection Type * @param role Connection Role @@ -185,6 +184,50 @@ struct bt_conn_info { }; }; +/** LE Connection Remote Info Structure */ +struct bt_conn_le_remote_info { + + /** Remote LE feature set (bitmask). */ + const u8_t *features; +}; + +/** BR/EDR Connection Remote Info structure */ +struct bt_conn_br_remote_info { + + /** Remote feature set (pages of bitmasks). */ + const u8_t *features; + + /** Number of pages in the remote feature set. */ + u8_t num_pages; +}; + +/** @brief Connection Remote Info Structure + * + * @note The version, manufacturer and subversion fields will only contain + * valid data if :option:`CONFIG_BT_REMOTE_VERSION` is enabled. + */ +struct bt_conn_remote_info { + /* Connection Type */ + u8_t type; + + /* Remote Link Layer version */ + u8_t version; + + /* Remote manufacturer identifier */ + u16_t manufacturer; + + /* Per-manufacturer unique revision */ + u16_t subversion; + + union { + /* LE connection remote info */ + struct bt_conn_le_remote_info le; + + /* BR/EDR connection remote info */ + struct bt_conn_br_remote_info br; + }; +}; + /** @brief Get connection info * * @param conn Connection object. @@ -194,6 +237,24 @@ struct bt_conn_info { */ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info); +/** @brief Get connection info for the remote device. + * + * @param conn Connection object. + * @param remote_info Connection remote info object. + * + * @note In order to retrieve the remote version (version, manufacturer + * and subversion) :option:`CONFIG_BT_REMOTE_VERSION` must be enabled + * + * @note The remote information is exchanged directly after the connection has + * been established. The application can be notified about when the remote + * information is available through the remote_info_available callback. + * + * @return Zero on success or (negative) error code on failure. + * @return -EBUSY The remote information is not yet available. + */ +int bt_conn_get_remote_info(struct bt_conn *conn, + struct bt_conn_remote_info *remote_info); + /** @brief Update the connection parameters. * * @param conn Connection object. @@ -494,6 +555,17 @@ struct bt_conn_cb { void (*security_changed)(struct bt_conn *conn, bt_security_t level, enum bt_security_err err); #endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */ + +#if defined(CONFIG_BT_REMOTE_INFO) + /** @brief Remote information procedures has completed. + * + * This callback notifies the application that the remote information + * has been retrieved from the remote peer. + */ + void (*remote_info_available)(struct bt_conn *conn, + struct bt_conn_remote_info *remote_info); +#endif /* defined(CONFIG_BT_REMOTE_INFO) */ + struct bt_conn_cb *_next; }; diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index fdf232a75eefd..9cae075e34280 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -3330,6 +3330,29 @@ static void le_data_len_change(struct pdu_data *pdu_data, u16_t handle, } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_REMOTE_VERSION) +void hci_remote_version_info_encode(struct pdu_data *pdu_data, u16_t handle, + struct net_buf *buf) +{ + struct pdu_data_llctrl_version_ind *ver_ind; + struct bt_hci_evt_remote_version_info *ep; + + if (!(event_mask & BT_EVT_MASK_REMOTE_VERSION_INFO)) { + return; + } + + hci_evt_create(buf, BT_HCI_EVT_REMOTE_VERSION_INFO, sizeof(*ep)); + ep = net_buf_add(buf, sizeof(*ep)); + + ver_ind = &pdu_data->llctrl.version_ind; + ep->status = 0x00; + ep->handle = sys_cpu_to_le16(handle); + ep->version = ver_ind->version_number; + ep->manufacturer = ver_ind->company_id; + ep->subversion = ver_ind->sub_version_number; +} +#endif /* CONFIG_BT_REMOTE_VERSION */ + static void encode_data_ctrl(struct node_rx_pdu *node_rx, struct pdu_data *pdu_data, struct net_buf *buf) { @@ -3347,6 +3370,12 @@ static void encode_data_ctrl(struct node_rx_pdu *node_rx, break; #endif /* CONFIG_BT_CTLR_LE_ENC */ +#if defined(CONFIG_BT_REMOTE_VERSION) + case PDU_DATA_LLCTRL_TYPE_VERSION_IND: + hci_remote_version_info_encode(pdu_data, handle, buf); + break; +#endif /* defined(CONFIG_BT_REMOTE_VERSION) */ + case PDU_DATA_LLCTRL_TYPE_FEATURE_RSP: le_remote_feat_complete(0x00, pdu_data, handle, buf); break; @@ -3456,29 +3485,6 @@ void hci_num_cmplt_encode(struct net_buf *buf, u16_t handle, u8_t num) hc->handle = sys_cpu_to_le16(handle); hc->count = sys_cpu_to_le16(num); } - -#if defined(CONFIG_BT_REMOTE_VERSION) -void hci_remote_version_info_encode(struct net_buf *buf, - struct pdu_data *pdu_data, u16_t handle) -{ - struct pdu_data_llctrl_version_ind *ver_ind; - struct bt_hci_evt_remote_version_info *ep; - - if (!(event_mask & BT_EVT_MASK_REMOTE_VERSION_INFO)) { - return; - } - - hci_evt_create(buf, BT_HCI_EVT_REMOTE_VERSION_INFO, sizeof(*ep)); - ep = net_buf_add(buf, sizeof(*ep)); - - ver_ind = &pdu_data->llctrl.version_ind; - ep->status = 0x00; - ep->handle = sys_cpu_to_le16(handle); - ep->version = ver_ind->version_number; - ep->manufacturer = ver_ind->company_id; - ep->subversion = ver_ind->sub_version_number; -} -#endif /* CONFIG_BT_REMOTE_VERSION */ #endif /* CONFIG_BT_CONN */ u8_t hci_get_class(struct node_rx_pdu *node_rx) diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index b6a45f1734f12..439680eb0c99e 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -76,27 +76,7 @@ static s32_t hbuf_count; static struct net_buf *process_prio_evt(struct node_rx_pdu *node_rx) { -/* Currently the only event processed */ -#if defined(CONFIG_BT_REMOTE_VERSION) - struct pdu_data *pdu_data = PDU_DATA(node_rx); - struct net_buf *buf; - u16_t handle; - - /* Avoid using hci_get_class() to speed things up */ - if (node_rx->hdr.user_meta == HCI_CLASS_EVT_LLCP) { - - handle = node_rx->hdr.handle; - if (pdu_data->llctrl.opcode == - PDU_DATA_LLCTRL_TYPE_VERSION_IND) { - - buf = bt_buf_get_evt(BT_HCI_EVT_REMOTE_VERSION_INFO, - false, K_FOREVER); - hci_remote_version_info_encode(buf, pdu_data, handle); - return buf; - } - } - -#endif /* CONFIG_BT_CONN */ + /* Currently there are no events processed */ return NULL; } diff --git a/subsys/bluetooth/controller/hci/hci_internal.h b/subsys/bluetooth/controller/hci/hci_internal.h index 7ff6ba89513e2..fcd22a9fb2ea3 100644 --- a/subsys/bluetooth/controller/hci/hci_internal.h +++ b/subsys/bluetooth/controller/hci/hci_internal.h @@ -46,8 +46,6 @@ u8_t hci_get_class(struct node_rx_pdu *node_rx); int hci_acl_handle(struct net_buf *acl, struct net_buf **evt); void hci_acl_encode(struct node_rx_pdu *node_rx, struct net_buf *buf); void hci_num_cmplt_encode(struct net_buf *buf, u16_t handle, u8_t num); -void hci_remote_version_info_encode(struct net_buf *buf, - struct pdu_data *pdu_data, u16_t handle); #endif int hci_vendor_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt); diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index c7210357970a1..bad45101a8ea1 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -261,6 +261,22 @@ config BT_AUTO_PHY_UPDATE want to rely on remote device to initiate the procedure at its discretion. +config BT_REMOTE_INFO + bool "Enable application access to remote information" + help + Enable application access to the remote information available in the + stack. The remote information is retrieved once a connection has been + established and the application will be notified when this information + is available through the remote_version_available connection callback. + +config BT_REMOTE_VERSION + bool "Enable remote version information" + depends on BT_REMOTE_INFO + help + Enable this to get access to the remote version through + the remote_version_available callback. The host will automatically ask + the remote device after the connection has been established. + config BT_SMP bool "Security Manager Protocol support" select TINYCRYPT diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 2f9ea93c8ea36..cac08419a4ae1 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -154,6 +154,27 @@ static void notify_disconnected(struct bt_conn *conn) } } +#if defined(CONFIG_BT_REMOTE_INFO) +void notify_remote_info(struct bt_conn *conn) +{ + struct bt_conn_remote_info remote_info; + struct bt_conn_cb *cb; + int err; + + err = bt_conn_get_remote_info(conn, &remote_info); + if (err) { + BT_DBG("Notify remote info failed %d", err); + return; + } + + for (cb = callback_list; cb; cb = cb->_next) { + if (cb->remote_info_available) { + cb->remote_info_available(conn, &remote_info); + } + } +} +#endif /* defined(CONFIG_BT_REMOTE_INFO) */ + void notify_le_param_updated(struct bt_conn *conn) { struct bt_conn_cb *cb; @@ -1638,6 +1659,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) bt_conn_unref(conn); break; } + /* Notify disconnection and queue a dummy buffer to wake * up and stop the tx thread for states where it was * running. @@ -1902,6 +1924,42 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) return -EINVAL; } +int bt_conn_get_remote_info(struct bt_conn *conn, + struct bt_conn_remote_info *remote_info) +{ + if (!atomic_test_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH) || + (IS_ENABLED(CONFIG_BT_REMOTE_VERSION) && + !atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO))) { + return -EBUSY; + } + + remote_info->type = conn->type; +#if defined(CONFIG_BT_REMOTE_VERSION) + /* The conn->rv values will be just zeroes if the operation failed */ + remote_info->version = conn->rv.version; + remote_info->manufacturer = conn->rv.manufacturer; + remote_info->subversion = conn->rv.subversion; +#else + remote_info->version = 0; + remote_info->manufacturer = 0; + remote_info->subversion = 0; +#endif + + switch (conn->type) { + case BT_CONN_TYPE_LE: + remote_info->le.features = conn->le.features; + return 0; +#if defined(CONFIG_BT_BREDR) + case BT_CONN_TYPE_BR: + /* TODO: Make sure the HCI commands to read br features and + * extended features has finished. */ + return -ENOTSUP; +#endif + default: + return -EINVAL; + } +} + static int bt_hci_disconnect(struct bt_conn *conn, u8_t reason) { struct net_buf *buf; diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 995a5aea1c44e..f4a02d9217b08 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -31,6 +31,10 @@ enum { BT_CONN_SLAVE_PARAM_L2CAP, /* If should force L2CAP for CPUP */ BT_CONN_FORCE_PAIR, /* Pairing even with existing keys. */ + BT_CONN_AUTO_PHY_COMPLETE, /* Auto-initiated PHY procedure done */ + BT_CONN_AUTO_FEATURE_EXCH, /* Auto-initiated LE Feat done */ + BT_CONN_AUTO_VERSION_INFO, /* Auto-initiated LE version done */ + /* Total number of flags - must be at the end of the enum */ BT_CONN_NUM_FLAGS, }; @@ -143,6 +147,14 @@ struct bt_conn { struct bt_conn_sco sco; #endif }; + +#if defined(CONFIG_BT_REMOTE_VERSION) + struct bt_conn_rv { + u8_t version; + u16_t manufacturer; + u16_t subversion; + } rv; +#endif }; /* Process incoming data for a connection */ @@ -209,6 +221,8 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state); int bt_conn_le_conn_update(struct bt_conn *conn, const struct bt_le_conn_param *param); +void notify_remote_info(struct bt_conn *conn); + void notify_le_param_updated(struct bt_conn *conn); bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index d0ce06dd190bf..b8d40833367cb 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -967,6 +967,33 @@ static int hci_le_read_remote_features(struct bt_conn *conn) return 0; } +static int hci_read_remote_version(struct bt_conn *conn) +{ + struct bt_hci_cp_read_remote_version_info *cp; + struct net_buf *buf; + + if (conn->state != BT_CONN_CONNECTED) { + return -ENOTCONN; + } + + /* Remote version cannot change. */ + if (atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO)) { + return 0; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_VERSION_INFO, + sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + + return bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_VERSION_INFO, buf, + NULL); +} + /* LE Data Length Change Event is optional so this function just ignore * error and stack will continue to use default values. */ @@ -1078,12 +1105,61 @@ static struct bt_conn *find_pending_connect(bt_addr_le_t *peer_addr) return bt_conn_lookup_state_le(peer_addr, BT_CONN_CONNECT_DIR_ADV); } +static void conn_auto_initiate(struct bt_conn *conn) +{ + int err; + + if (conn->state != BT_CONN_CONNECTED) { + /* It is possible that connection was disconnected directly from + * connected callback so we must check state before doing + * connection parameters update. + */ + return; + } + + if (!atomic_test_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH) && + ((conn->role == BT_HCI_ROLE_MASTER) || + BT_FEAT_LE_SLAVE_FEATURE_XCHG(bt_dev.le.features))) { + err = hci_le_read_remote_features(conn); + if (!err) { + return; + } + } + + if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION) && + !atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO)) { + err = hci_read_remote_version(conn); + if (!err) { + return; + } + } + + if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) && + !atomic_test_bit(conn->flags, BT_CONN_AUTO_PHY_COMPLETE) && + BT_FEAT_LE_PHY_2M(bt_dev.le.features)) { + err = hci_le_set_phy(conn); + if (!err) { + atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE); + return; + } + } + + if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) && + BT_FEAT_LE_DLE(bt_dev.le.features)) { + hci_le_set_data_len(conn); + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && + conn->role == BT_CONN_ROLE_SLAVE) { + slave_update_conn_param(conn); + } +} + static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) { u16_t handle = sys_le16_to_cpu(evt->handle); bt_addr_le_t peer_addr, id_addr; struct bt_conn *conn; - int err; BT_DBG("status 0x%02x handle %u role %u %s", evt->status, handle, evt->role, bt_addr_le_str(&evt->peer_addr)); @@ -1256,41 +1332,8 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) bt_conn_set_state(conn, BT_CONN_CONNECTED); - /* - * it is possible that connection was disconnected directly from - * connected callback so we must check state before doing connection - * parameters update - */ - if (conn->state != BT_CONN_CONNECTED) { - goto done; - } - - if ((evt->role == BT_HCI_ROLE_MASTER) || - BT_FEAT_LE_SLAVE_FEATURE_XCHG(bt_dev.le.features)) { - err = hci_le_read_remote_features(conn); - if (!err) { - goto done; - } - } - - if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) && - BT_FEAT_LE_PHY_2M(bt_dev.le.features)) { - err = hci_le_set_phy(conn); - if (!err) { - atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE); - goto done; - } - } - - if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) && - BT_FEAT_LE_DLE(bt_dev.le.features)) { - hci_le_set_data_len(conn); - } - - if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && - conn->role == BT_CONN_ROLE_SLAVE) { - slave_update_conn_param(conn); - } + /* Start auto-initiated procedures */ + conn_auto_initiate(conn); done: bt_conn_unref(conn); @@ -1363,30 +1406,16 @@ static void le_remote_feat_complete(struct net_buf *buf) sizeof(conn->le.features)); } - if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) && - BT_FEAT_LE_PHY_2M(bt_dev.le.features) && - BT_FEAT_LE_PHY_2M(conn->le.features)) { - int err; - - err = hci_le_set_phy(conn); - if (!err) { - atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE); - goto done; - } - } + atomic_set_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH); - if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) && - BT_FEAT_LE_DLE(bt_dev.le.features) && - BT_FEAT_LE_DLE(conn->le.features)) { - hci_le_set_data_len(conn); + if (IS_ENABLED(CONFIG_BT_REMOTE_INFO) && + !IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) { + notify_remote_info(conn); } - if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && - conn->role == BT_CONN_ROLE_SLAVE) { - slave_update_conn_param(conn); - } + /* Continue with auto-initiated procedures */ + conn_auto_initiate(conn); -done: bt_conn_unref(conn); } @@ -1437,16 +1466,9 @@ static void le_phy_update_complete(struct net_buf *buf) goto done; } - if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) && - BT_FEAT_LE_DLE(bt_dev.le.features) && - BT_FEAT_LE_DLE(conn->le.features)) { - hci_le_set_data_len(conn); - } - - if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && - conn->role == BT_CONN_ROLE_SLAVE) { - slave_update_conn_param(conn); - } + atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_COMPLETE); + /* Continue with auto-initiated procedures */ + conn_auto_initiate(conn); done: bt_conn_unref(conn); @@ -3250,6 +3272,39 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf) } #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ +#if defined(CONFIG_BT_REMOTE_VERSION) +static void bt_hci_evt_read_remote_version_complete(struct net_buf *buf) +{ + struct bt_hci_evt_remote_version_info *evt; + struct bt_conn *conn; + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + conn = bt_conn_lookup_handle(evt->handle); + if (!conn) { + BT_ERR("No connection for handle %u", evt->handle); + return; + } + + if (!evt->status) { + conn->rv.version = evt->version; + conn->rv.manufacturer = sys_le16_to_cpu(evt->manufacturer); + conn->rv.subversion = sys_le16_to_cpu(evt->subversion); + } + + atomic_set_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO); + + if (IS_ENABLED(CONFIG_BT_REMOTE_INFO)) { + /* Remote features is already present */ + notify_remote_info(conn); + } + + /* Continue with auto-initiated procedures */ + conn_auto_initiate(conn); + + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_REMOTE_VERSION */ + #if defined(CONFIG_BT_SMP) static void le_ltk_neg_reply(u16_t handle) { @@ -3814,6 +3869,11 @@ static const struct event_handler normal_events[] = { hci_encrypt_key_refresh_complete, sizeof(struct bt_hci_evt_encrypt_key_refresh_complete)), #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ +#if defined(CONFIG_BT_REMOTE_VERSION) + EVENT_HANDLER(BT_HCI_EVT_REMOTE_VERSION_INFO, + bt_hci_evt_read_remote_version_complete, + sizeof(struct bt_hci_evt_remote_version_info)), +#endif /* CONFIG_BT_REMOTE_VERSION */ }; static void hci_event(struct net_buf *buf) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 50e57cc8da648..4584a8c64735e 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -230,6 +230,49 @@ static void security_changed(struct bt_conn *conn, bt_security_t level, } #endif +#if defined(CONFIG_BT_REMOTE_INFO) +static const char *ver_str(u8_t ver) +{ + const char * const str[] = { + "1.0b", "1.1", "1.2", "2.0", "2.1", "3.0", "4.0", "4.1", "4.2", + "5.0", "5.1", + }; + + if (ver < ARRAY_SIZE(str)) { + return str[ver]; + } + + return "unknown"; +} + +static void remote_info_available(struct bt_conn *conn, + struct bt_conn_remote_info *remote_info) +{ + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) { + shell_print(ctx_shell, + "Remote LMP version %s (0x%02x) subversion 0x%04x " + "manufacturer 0x%04x", ver_str(remote_info->version), + remote_info->version, remote_info->subversion, + remote_info->manufacturer); + } + + if (info.type == BT_CONN_TYPE_LE) { + u8_t features[8]; + char features_str[2 * sizeof(features) + 1]; + + sys_memcpy_swap(features, remote_info->le.features, + sizeof(features)); + bin2hex(features, sizeof(features), + features_str, sizeof(features_str)); + shell_print(ctx_shell, "LE Features: 0x%s ", features_str); + } +} +#endif /* defined(CONFIG_BT_REMOTE_INFO) */ + static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, @@ -241,6 +284,9 @@ static struct bt_conn_cb conn_callbacks = { #if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) .security_changed = security_changed, #endif +#if defined(CONFIG_BT_REMOTE_INFO) + .remote_info_available = remote_info_available, +#endif }; #endif /* CONFIG_BT_CONN */ @@ -834,8 +880,8 @@ static void print_le_addr(const char *desc, const bt_addr_le_t *addr) static int cmd_info(const struct shell *shell, size_t argc, char *argv[]) { struct bt_conn *conn = NULL; - bt_addr_le_t addr; struct bt_conn_info info; + bt_addr_le_t addr; int err; switch (argc) { @@ -888,10 +934,10 @@ static int cmd_info(const struct shell *shell, size_t argc, char *argv[]) print_le_addr("Remote on-air", info.le.remote); print_le_addr("Local on-air", info.le.local); - shell_print(ctx_shell, "Interval: 0x%04x (%.2f ms)", - info.le.interval, info.le.interval * 1.25); - shell_print(ctx_shell, "Latency: 0x%04x (%.2f ms)", - info.le.latency, info.le.latency * 1.25); + shell_print(ctx_shell, "Interval: 0x%04x (%u ms)", + info.le.interval, info.le.interval * 5 / 4); + shell_print(ctx_shell, "Latency: 0x%04x (%u ms)", + info.le.latency, info.le.latency * 5 / 4); shell_print(ctx_shell, "Supervision timeout: 0x%04x (%d ms)", info.le.timeout, info.le.timeout * 10); } diff --git a/tests/bluetooth/shell/prj.conf b/tests/bluetooth/shell/prj.conf index 3bf63a7ba632d..5da865b8a6d72 100644 --- a/tests/bluetooth/shell/prj.conf +++ b/tests/bluetooth/shell/prj.conf @@ -24,6 +24,8 @@ CONFIG_BT_ID_MAX=2 CONFIG_BT_GATT_DYNAMIC_DB=y CONFIG_BT_GATT_HRS=y CONFIG_BT_WHITELIST=y +CONFIG_BT_REMOTE_INFO=y +CONFIG_BT_REMOTE_VERSION=y CONFIG_BT_SETTINGS=y CONFIG_FLASH=y