diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 3d26d3cab..ba3255dba 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -221,6 +221,18 @@ struct ble_gap_sec_state { }; +/** Read Remote Version parameters **/ +struct ble_gap_read_rem_ver_params { + /** Version of the Current LMP **/ + uint8_t version; + + /** Company Identifier **/ + uint16_t manufacturer; + + /** Revision of the LMP **/ + uint16_t subversion; +}; + /** Advertising parameters */ struct ble_gap_adv_params { /** Advertising mode. Can be one of following constants: @@ -3025,6 +3037,19 @@ int ble_gap_dtm_enh_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t pay */ int ble_gap_dtm_enh_rx_start(uint8_t rx_chan, uint8_t index, uint8_t phy); +/** + * Set Read Remote Version Information is used to retrieve the version, manufacturer, + * and subversion information of remote controller after connection established + * + * @param conn_handle Connection handle + * @param version Defines the specification version of the LE Controller + * @param manufacturer Indicates the manufacturer of the remote Controller + * @param subversion Manufacturer specific version + + * @return 0 on success; nonzero on failure +*/ +int ble_gap_read_rem_ver_info(uint16_t conn_handle, uint8_t *version, uint16_t *manufacturer, uint16_t *subversion); + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index c1159dcc3..3b6dc982b 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -553,6 +553,30 @@ ble_gap_conn_find(uint16_t handle, struct ble_gap_conn_desc *out_desc) #endif } +int +ble_gap_read_rem_ver_info(uint16_t conn_handle, uint8_t *version, uint16_t *manufacturer, uint16_t *subversion) +{ +#if NIMBLE_BLE_CONNECT + struct ble_hs_conn *conn; + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + + ble_hs_unlock(); + + if (conn == NULL ) { + return BLE_HS_ENOTCONN; + } + + *version = conn->bhc_rd_rem_ver_params.version; + *manufacturer = conn->bhc_rd_rem_ver_params.manufacturer; + *subversion = conn->bhc_rd_rem_ver_params.subversion; + + return 0; +#endif +} + int ble_gap_conn_find_by_addr(const ble_addr_t *addr, struct ble_gap_conn_desc *out_desc) @@ -2198,6 +2222,18 @@ ble_gap_rd_rem_sup_feat_tx(uint16_t handle) &cmd, sizeof(cmd), NULL, 0); } #endif +static int +ble_gap_rd_rem_ver_tx(uint16_t handle) +{ + struct ble_hci_rd_rem_ver_info_cp cmd; + + cmd.conn_handle = htole16(handle); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_RD_REM_VER_INFO), + &cmd, sizeof(cmd), NULL, 0); +} + /** * Processes an incoming connection-complete HCI event. @@ -2381,7 +2417,11 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, evt->connection_handle); - ble_gap_rd_rem_sup_feat_tx(evt->connection_handle); + if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) { + ble_gap_rd_rem_ver_tx(evt->connection_handle); + } else { + ble_gap_rd_rem_sup_feat_tx(evt->connection_handle); + } return 0; #else @@ -2389,6 +2429,31 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) #endif } +void +ble_gap_link_estab_call(uint16_t conn_handle, int status) +{ + struct ble_gap_event event; + uint16_t handle = le16toh(conn_handle); + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_LINK_ESTAB; + event.link_estab.status = status; + event.link_estab.conn_handle = handle; + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.link_estab.sync_handle = pawr_sync_handle; + event.link_estab.adv_handle = pawr_adv_handle; +#endif + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, handle); + +#if !SOC_ESP_NIMBLE_CONTROLLER + ble_hs_hci_util_set_data_len(le16toh(conn_handle), BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX, + BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX); +#endif +} + void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used_feat *ev) { @@ -2398,32 +2463,44 @@ ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used ble_hs_lock(); conn = ble_hs_conn_find(le16toh(ev->conn_handle)); - if ((conn != NULL) && (ev->status == 0)) { - conn->supported_feat = get_le32(ev->features); - - struct ble_gap_event event; - uint16_t conn_handle = le16toh(ev->conn_handle); - - memset(&event, 0, sizeof event); - event.type = BLE_GAP_EVENT_LINK_ESTAB; - event.link_estab.status = ev->status; - event.link_estab.conn_handle = conn_handle; - -#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) - event.link_estab.sync_handle = pawr_sync_handle; - event.link_estab.adv_handle = pawr_adv_handle; -#endif - - ble_gap_event_listener_call(&event); - ble_gap_call_conn_event_cb(&event, conn_handle); - -#if !SOC_ESP_NIMBLE_CONTROLLER - ble_hs_hci_util_set_data_len(le16toh(ev->conn_handle), BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX, - BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX); -#endif - } ble_hs_unlock(); + + if ((conn != NULL) && (conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { + conn->supported_feat = get_le32(ev->features); + ble_gap_rd_rem_ver_tx(ev->conn_handle); + } else { + if ((conn != NULL) && (ev->status == 0)) { + conn->supported_feat = get_le32(ev->features); + ble_gap_link_estab_call(ev->conn_handle, ev->status); + } + } +#endif +} + +void +ble_gap_rx_rd_rem_ver_info_complete(const struct ble_hci_ev_rd_rem_ver_info_cmp *ev) +{ +#if NIMBLE_BLE_CONNECT + struct ble_hs_conn *conn; + + ble_hs_lock(); + + conn = ble_hs_conn_find(le16toh(ev->conn_handle)); + + ble_hs_unlock(); + + conn->bhc_rd_rem_ver_params.version = ev->version; + conn->bhc_rd_rem_ver_params.manufacturer = ev->manufacturer; + conn->bhc_rd_rem_ver_params.subversion = ev->subversion; + + if ((conn != NULL) && !(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { + ble_gap_rd_rem_sup_feat_tx(ev->conn_handle); + } else { + if ((conn != NULL) && (ev->status == 0)) { + ble_gap_link_estab_call(ev->conn_handle, ev->status); + } + } #endif } diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index b5d063822..e9909aeb2 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -92,6 +92,8 @@ void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev #endif void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc); void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used_feat *ev); +void ble_gap_rx_rd_rem_ver_info_complete(const struct ble_hci_ev_rd_rem_ver_info_cmp *ev); +void ble_gap_link_estab_call(uint16_t conn_handle, int status); #if MYNEWT_VAL(BLE_CONN_SUBRATING) void ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev); #endif diff --git a/nimble/host/src/ble_hs_conn_priv.h b/nimble/host/src/ble_hs_conn_priv.h index 07773f2e3..c994ed220 100644 --- a/nimble/host/src/ble_hs_conn_priv.h +++ b/nimble/host/src/ble_hs_conn_priv.h @@ -95,6 +95,7 @@ struct ble_hs_conn { struct ble_gatts_conn bhc_gatt_svr; struct ble_gap_sec_state bhc_sec_state; + struct ble_gap_read_rem_ver_params bhc_rd_rem_ver_params; ble_gap_event_fn *bhc_cb; void *bhc_cb_arg; diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 8859ae244..26f7eed55 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -59,6 +59,7 @@ typedef int ble_hs_hci_evt_fn(uint8_t event_code, const void *data, unsigned int len); static ble_hs_hci_evt_fn ble_hs_hci_evt_hw_error; static ble_hs_hci_evt_fn ble_hs_hci_evt_num_completed_pkts; +static ble_hs_hci_evt_fn ble_hs_hci_evt_rd_rem_ver_complete; #if NIMBLE_BLE_CONNECT static ble_hs_hci_evt_fn ble_hs_hci_evt_disconn_complete; static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change; @@ -125,6 +126,7 @@ struct ble_hs_hci_evt_dispatch_entry { static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { { BLE_HCI_EVCODE_LE_META, ble_hs_hci_evt_le_meta }, + { BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP, ble_hs_hci_evt_rd_rem_ver_complete }, { BLE_HCI_EVCODE_NUM_COMP_PKTS, ble_hs_hci_evt_num_completed_pkts }, #if NIMBLE_BLE_CONNECT { BLE_HCI_EVCODE_DISCONN_CMP, ble_hs_hci_evt_disconn_complete }, @@ -725,6 +727,22 @@ ble_hs_hci_evt_le_rd_rem_used_feat_complete(uint8_t subevent, const void *data, return 0; } +static int +ble_hs_hci_evt_rd_rem_ver_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_rd_rem_ver_info_cmp *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_rd_rem_ver_info_complete(ev); + + return 0; +} + + #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN static int ble_hs_hci_decode_legacy_type(uint16_t evt_type) diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index a7cd4dc2f..0730608ef 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -309,12 +309,13 @@ ble_hs_startup_set_evmask_tx(void) * Enable the following events: * 0x0000000000000010 Disconnection Complete Event * 0x0000000000000080 Encryption Change Event + * 0x0000000000000800 Read Remote Version Information Complete event * 0x0000000000008000 Hardware Error Event * 0x0000000002000000 Data Buffer Overflow Event * 0x0000800000000000 Encryption Key Refresh Complete Event * 0x2000000000000000 LE Meta-Event */ - cmd.event_mask = htole64(0x2000800002008090); + cmd.event_mask = htole64(0x2000800002008890); rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK),