diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 0f18b837b..1ce47df96 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -183,6 +183,9 @@ struct hci_conn_update; #define BLE_GAP_EVENT_BIGINFO_ADV_RPT 49 #define BLE_GAP_EVENT_CIS_ESTAB_V2 50 +#define BLE_GAP_EVENT_RD_ALL_REM_FEAT 51 +#define BLE_GAP_EVENT_MONITOR_ADV_REPORT 52 + /* DTM events */ #define BLE_GAP_DTM_TX_START_EVT 0 #define BLE_GAP_DTM_RX_START_EVT 1 @@ -1986,6 +1989,53 @@ struct ble_gap_event { } cis_estab_v2; #endif /* MYNEWT_VAL(BLE_ISO_CIS_ESTAB_V2) */ #endif /* MYNEWT_VAL(BLE_ISO) */ + + /** + * Represents a read all remote features complet event + * Valid for the following event types: + * o BLE_GAP_EVENT_RD_ALL_REM_FEAT + */ + struct { + /** Status indicating the reason for failure. + * Refer to HCI error codes for detailed status values. + */ + uint8_t status; + + /** Connection handle identifying the connection. */ + uint16_t conn_handle; + + /** Highest numbered page of remote device's supported LE features + * that contains atleast one bit set to 1 + */ + uint8_t max_remote_page; + + /** Number of highest numbered page of LE features that contains + * valid data + */ + uint8_t max_valid_page; + + /** Bit Mask List of LE features */ + uint8_t le_features[248]; + } rd_all_rem_feat; + +#if MYNEWT_VAL(BLE_MONITOR_ADV) + /** + * Represents a read all remote features complet event + * Valid for the following event types: + * o BLE_GAP_EVENT_MONITOR_ADV_REPORT + */ + struct { + /** Address Type [Public/Random...] */ + uint8_t addr_type; + + /** Device Address */ + uint16_t address[6]; + + /** Represents weather RSSI threshold condition is met */ + uint8_t condition; + + } monitor_adv_report; +#endif }; }; diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index f1aa2261c..1e9752e3b 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -2203,6 +2203,44 @@ ble_gap_rx_cis_estab_v2(const struct ble_hci_ev_le_subev_cis_established_v2 *ev) #endif /* MYNEWT_VAL(BLE_ISO_CIS_ESTAB_V2) */ #endif /* MYNEWT_VAL(BLE_ISO) */ +void +ble_gap_rx_rd_all_remote_feat(const struct ble_hci_ev_le_subev_rd_all_rem_feat *ev) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof(event)); + + event.type = BLE_GAP_EVENT_RD_ALL_REM_FEAT; + + event.rd_all_rem_feat.status = ev->status; + event.rd_all_rem_feat.max_remote_page = ev->max_remote_page; + event.rd_all_rem_feat.max_valid_page = ev->max_valid_page; + memcpy(event.rd_all_rem_feat.le_features, ev->le_features, 248); + + ble_gap_event_listener_call(&event); +#if NIMBLE_BLE_CONNECT + ble_gap_call_conn_event_cb(&event, ev->conn_handle); +#endif +} + +#if MYNEWT_VAL(BLE_MONITOR_ADV) +void +ble_gap_rx_rd_monitor_adv_report(const struct ble_hci_ev_le_subev_monitor_adv_report *ev) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof(event)); + + event.type = BLE_GAP_EVENT_MONITOR_ADV_REPORT; + + event.monitor_adv_report.addr_type = ev->addr_type; + event.monitor_adv_report.condition = ev->condition; + memcpy(event.monitor_adv_report.address, ev->address, 6); + + ble_gap_event_listener_call(&event); +} +#endif + void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc) { @@ -9936,6 +9974,18 @@ ble_gap_dtm_enh_rx_start(uint8_t rx_chan, uint8_t index, uint8_t phy) return ble_hs_hci_dtm_enh_rx_start(rx_chan, index, phy); } +int +ble_gap_rd_all_local_supp_features(uint8_t *status, uint8_t *max_page, uint8_t *le_features) +{ + return ble_hs_hci_rd_all_local_supp_features(status, max_page, le_features); +} + +int +ble_gap_rd_all_remote_features(uint16_t conn_handle, uint8_t page_requested) +{ + return ble_hs_hci_rd_all_remote_features(conn_handle, page_requested); +} + void ble_gap_deinit(void) { diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index b76430c2e..0e40b62c5 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -199,6 +199,10 @@ void ble_gap_reattempt_count(uint16_t conn_handle, uint8_t count); #endif void ble_gap_rx_data_len_change(const struct ble_hci_ev_le_subev_data_len_chg *ev); +void ble_gap_rx_rd_all_remote_feat(const struct ble_hci_ev_le_subev_rd_all_rem_feat *ev); +#if MYNEWT_VAL(BLE_MONITOR_ADV) +void ble_gap_rx_rd_monitor_adv_report(const struct ble_hci_ev_le_subev_monitor_adv_report *ev); +#endif #ifdef __cplusplus } diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index f2292368f..3bd5af2ec 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -127,6 +127,12 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_biginfo_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_cis_estab_v2; #endif /* MYNEWT_VAL(BLE_ISO_CIS_ESTAB_V2) */ #endif /* MYNEWT_VAL(BLE_ISO) */ +#if NIMBLE_BLE_CONNECT +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_rd_all_rem_feat; +#endif +#if MYNEWT_VAL(BLE_MONITOR_ADV) +static ble_hs_hci_evt_le_fn ble_hci_ev_le_subev_monitor_adv_report; +#endif /* Statistics */ struct host_hci_stats { @@ -227,7 +233,6 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_CIS_ESTABLISHED_V2] = ble_hs_hci_evt_le_cis_estab_v2, #endif /* MYNEWT_VAL(BLE_ISO_CIS_ESTAB_V2) */ #endif /* MYNEWT_VAL(BLE_ISO) */ - #if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) [BLE_HCI_LE_SUBEV_CS_RD_REM_SUPP_CAP_COMPLETE] = ble_hs_hci_evt_le_cs_rd_rem_supp_cap_complete, [BLE_HCI_LE_SUBEV_CS_RD_REM_FAE_COMPLETE] = ble_hs_hci_evt_le_cs_rd_rem_fae_complete, @@ -238,6 +243,12 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_CS_SUBEVENT_RESULT_CONTINUE] = ble_hs_hci_evt_le_cs_subevent_result_continue, [BLE_HCI_LE_SUBEV_CS_TEST_END_COMPLETE] = ble_hs_hci_evt_le_cs_test_end_complete, #endif +#if NIMBLE_BLE_CONNECT + [BLE_HCI_LE_SUBEV_RD_ALL_REM_FEAT] = ble_hs_hci_evt_le_rd_all_rem_feat, +#endif +#if MYNEWT_VAL(BLE_MONITOR_ADV) + [BLE_HCI_LE_SUBEV_MONITOR_ADV_REPORT] = ble_hci_ev_le_subev_monitor_adv_report, +#endif }; #define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \ @@ -1546,6 +1557,39 @@ ble_hs_hci_evt_le_data_len_change(uint8_t subevent, const void *data, return 0; } + +static int +ble_hs_hci_evt_le_rd_all_rem_feat(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_rd_all_rem_feat *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_rd_all_remote_feat(ev); + + return 0; +} + +#endif + +#if MYNEWT_VAL(BLE_MONITOR_ADV) +static int +ble_hci_ev_le_subev_monitor_adv_report(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_monitor_adv_report *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_rd_monitor_adv_report(ev); + + return 0; +} #endif int diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index db66c3542..2f8ec4ca4 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -140,6 +140,19 @@ int ble_hs_hci_dtm_enh_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload, uint8_t phy); int ble_hs_hci_dtm_stop(void); +int ble_hs_hci_rd_all_local_supp_features(uint8_t *status, uint8_t *max_page, + uint8_t *le_features); +int ble_hs_hci_rd_all_remote_features(uint16_t conn_handle, uint8_t page_requested); + +#if MYNEWT_VAL(BLE_MONITOR_ADV) +int ble_hs_hci_add_monitor_adv_list(uint8_t addr_type, uint8_t *addr, uint8_t rssi_low, + uint8_t rssi_high, uint8_t timeout); +int ble_hs_hci_rmv_monitor_adv_list(uint8_t addr_type, uint8_t *addr); +int ble_hs_hci_clear_monitor_adv_list(void); +int ble_hs_hci_read_monitor_adv_list_size(uint8_t *out_number); +int ble_hs_hci_enable_monitor_adv(uint8_t enable); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_hs_hci_util.c b/nimble/host/src/ble_hs_hci_util.c index f36507859..b9b782517 100644 --- a/nimble/host/src/ble_hs_hci_util.c +++ b/nimble/host/src/ble_hs_hci_util.c @@ -377,3 +377,114 @@ ble_hs_hci_set_host_feature(uint8_t bit_num, uint8_t bit_val) BLE_HCI_OCF_LE_SET_HOST_FEATURE), &cmd, sizeof(cmd), NULL, 0); } + +int +ble_hs_hci_rd_all_local_supp_features(uint8_t* status, uint8_t* max_page, + uint8_t *le_features) +{ + struct ble_hci_le_rd_all_local_feat_rp rsp; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_ALL_LOCAL_SUP_FEAT), NULL, 0, + &rsp, sizeof(rsp)); + + if (rc != 0) { + return rc; + } + + *status = rsp.status; + *max_page = rsp.max_page; + + memcpy(le_features, rsp.le_features, 248); + + return 0; +} + +int +ble_hs_hci_rd_all_remote_features(uint16_t conn_handle, uint8_t page_requested) +{ + struct ble_hci_le_rd_all_remote_feat_cp cmd; + + if (page_requested > 0x0A) { + return BLE_HS_EINVAL; + } + + cmd.conn_handle = htole16(conn_handle); + cmd.page_requested = page_requested; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_ALL_REMOTE_FEAT), &cmd, sizeof(cmd), + NULL, 0); +} + +#if MYNEWT_VAL(BLE_MONITOR_ADV) +int +ble_hs_hci_add_monitor_adv_list(uint8_t addr_type, uint8_t *addr, uint8_t rssi_low, + uint8_t rssi_high, uint8_t timeout) +{ + struct ble_hci_le_add_monitor_adv_list_cp cmd; + + cmd.addr_type = addr_type; + memcpy(cmd.address, addr, 6); + cmd.rssi_low_threshold = rssi_low; + cmd.rssi_high_threshold = rssi_high; + cmd.timeout = timeout; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_MONITOR_ADV_LIST), &cmd, sizeof(cmd), + NULL, 0); +} + +int +ble_hs_hci_rmv_monitor_adv_list(uint8_t addr_type, uint8_t *addr) +{ + struct ble_hci_le_rmv_monitor_adv_list_cp cmd; + + cmd.addr_type = addr_type; + memcpy(cmd.address, addr, 6); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RMV_MONITOR_ADV_LIST), &cmd, sizeof(cmd), + NULL, 0); +} + +int +ble_hs_hci_clear_monitor_adv_list(void) +{ + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CLEAR_MONITOR_ADV_LIST), NULL, 0, + NULL, 0); +} + +int +ble_hs_hci_read_monitor_adv_list_size(uint8_t *out_number) +{ + int rc; + struct ble_hci_le_rd_monitor_adv_list_size_rp rsp; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_READ_MONITOR_ADV_LIST_SIZE), NULL, 0, + &rsp, sizeof(rsp)); + + if (rc != 0) { + return rc; + } + + *out_number = rsp.number; + + return 0; +} + +int +ble_hs_hci_enable_monitor_adv(uint8_t enable) +{ + struct ble_hci_le_enable_monitor_adv_cp cmd; + + cmd.enable = enable; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ENABLE_MONITOR_ADV), &cmd, sizeof(cmd), + NULL, 0); +} +#endif diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index 147b8a0d0..3c5badf23 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -421,6 +421,19 @@ ble_hs_startup_le_set_evmask_tx(void) } #endif + if (version >= BLE_HCI_VER_BCS_6_0) { + /** + * Enable following LE events: + * 0x0000040000000000 LE Read All Remote Features Complete event + * 0x0008000000000000 LE Monitored Advertisers Report event + */ +#if MYNEWT_VAL(BLE_MONITOR_ADV) + mask |= 0x0008000000000000; +#endif + + mask |= 0x0000040000000000; + } + cmd.event_mask = htole64(mask); rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 088ea6466..8ed533718 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1368,6 +1368,19 @@ struct ble_hci_le_set_periodic_adv_params_v2 { uint8_t num_response_slots; } __attribute__((packed)); +#define BLE_HCI_OCF_LE_RD_ALL_LOCAL_SUP_FEAT (0x0087) +struct ble_hci_le_rd_all_local_feat_rp { + uint8_t status; + uint8_t max_page; + uint8_t le_features[248]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_RD_ALL_REMOTE_FEAT (0x0088) +struct ble_hci_le_rd_all_remote_feat_cp { + uint16_t conn_handle; + uint8_t page_requested; +} __attribute__((packed)); + #define BLE_HCI_OCF_LE_CS_RD_LOC_SUPP_CAP (0x0089) struct ble_hci_le_cs_rd_loc_supp_cap_rp { uint8_t num_config_supported; @@ -1542,6 +1555,34 @@ struct ble_hci_le_cs_test_cp { #define BLE_HCI_OCF_LE_CS_TEST_END (0x0096) +#define BLE_HCI_OCF_LE_ADD_MONITOR_ADV_LIST (0x0098) +struct ble_hci_le_add_monitor_adv_list_cp { + uint8_t addr_type; + uint8_t address[6]; + uint8_t rssi_low_threshold; + uint8_t rssi_high_threshold; + uint8_t timeout; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_RMV_MONITOR_ADV_LIST (0x0099) +struct ble_hci_le_rmv_monitor_adv_list_cp { + uint8_t addr_type; + uint8_t address[6]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CLEAR_MONITOR_ADV_LIST (0x009A) + +#define BLE_HCI_OCF_LE_READ_MONITOR_ADV_LIST_SIZE (0x009B) +struct ble_hci_le_rd_monitor_adv_list_size_rp { + uint8_t number; +} __attribute__((packed)); + + +#define BLE_HCI_OCF_LE_ENABLE_MONITOR_ADV (0x009C) +struct ble_hci_le_enable_monitor_adv_cp { + uint8_t enable; +} __attribute__((packed)); + /* --- Vendor specific commands (OGF 0x003F) */ /* Read Random Static Address */ #define BLE_HCI_OCF_VS_RD_STATIC_ADDR (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0001)) @@ -2547,6 +2588,24 @@ struct ble_hci_ev_le_subev_cis_established_v2 { uint8_t framing; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_RD_ALL_REM_FEAT (0x2B) +struct ble_hci_ev_le_subev_rd_all_rem_feat { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t max_remote_page; + uint8_t max_valid_page; + uint8_t le_features[248]; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_MONITOR_ADV_REPORT (0x34) +struct ble_hci_ev_le_subev_monitor_adv_report { + uint8_t subev_code; + uint8_t addr_type; + uint8_t address[6]; + uint8_t condition; +} __attribute__((packed)); + #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) // LE vendor hci event #define BLE_HCI_LE_SUBEV_DISCARD_REPORT_EVT 0XF0 @@ -2726,6 +2785,7 @@ struct ble_hci_ev_le_subev_cs_test_end_complete { #define BLE_HCI_VER_BCS_5_2 (11) #define BLE_HCI_VER_BCS_5_3 (12) #define BLE_HCI_VER_BCS_5_4 (13) +#define BLE_HCI_VER_BCS_6_0 (14) #define BLE_LMP_VER_BCS_1_0b (0) #define BLE_LMP_VER_BCS_1_1 (1) @@ -2741,6 +2801,7 @@ struct ble_hci_ev_le_subev_cs_test_end_complete { #define BLE_LMP_VER_BCS_5_2 (11) #define BLE_LMP_VER_BCS_5_3 (12) #define BLE_LMP_VER_BCS_5_4 (13) +#define BLE_LMP_VER_BCS_6_0 (14) /* selected HCI and LMP version */ #if MYNEWT_VAL(BLE_VERSION) == 50 @@ -2758,6 +2819,11 @@ struct ble_hci_ev_le_subev_cs_test_end_complete { #elif MYNEWT_VAL(BLE_VERSION) == 54 #define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_4 #define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_4 +#elif MYNEWT_VAL(BLE_VERSION) == 60 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_6_0 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_6_0 +#else +#error Unsupported BLE_VERSION selected #endif #define BLE_HCI_DATA_HDR_SZ 4