From c4b3bec003ff9b113e965b30c2eac84ed013c333 Mon Sep 17 00:00:00 2001 From: Abhinav Kudnar Date: Thu, 29 Aug 2024 15:39:35 +0800 Subject: [PATCH] feat(nimble): Added PAwR support for nimble --- nimble/host/include/host/ble_gap.h | 262 ++++++++++++++ nimble/host/src/ble_gap.c | 560 ++++++++++++++++++++++++++++- nimble/host/src/ble_gap_priv.h | 8 + nimble/host/src/ble_hs_hci_evt.c | 78 +++- nimble/host/src/ble_hs_startup.c | 24 ++ nimble/include/nimble/hci_common.h | 120 ++++++- 6 files changed, 1036 insertions(+), 16 deletions(-) diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index c55577c5e..279e580e1 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -161,6 +161,8 @@ struct hci_conn_update; #define BLE_GAP_EVENT_LINK_ESTAB 32 #define BLE_GAP_EVENT_AUTHORIZE 33 #define BLE_GAP_EVENT_EATT 34 +#define BLE_GAP_EVENT_PER_SUBEV_DATA_REQ 35 +#define BLE_GAP_EVENT_PER_SUBEV_RESP 36 /* DTM events */ #define BLE_GAP_DTM_TX_START_EVT 0 @@ -505,6 +507,66 @@ struct ble_gap_repeat_pairing { uint8_t new_bonding:1; }; + +#define BLE_GAP_PER_ADV_DATA_STATUS_COMPLETE 0x00 +#define BLE_GAP_PER_ADV_DATA_STATUS_INCOMPLETE 0x01 +#define BLE_GAP_PER_ADV_DATA_STATUS_TRUNCATED 0x02 +#define BLE_GAP_PER_ADV_DATA_STATUS_RX_FAILED 0xFF + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +struct ble_gap_periodic_adv_response { + /** The subevent in which the response is received */ + uint8_t subevent; + + /** Status of the subevent indication. + * + * 0 if subevent indication was transmitted. + * 1 if subevent indication was not transmitted. + * All other values RFU. + */ + + /** The adv handle of the adv */ + uint8_t adv_handle; + + uint8_t tx_status; + + /** The TX power of the response in dBm */ + int8_t tx_power; + + /** The RSSI of the response in dBm */ + int8_t rssi; + + /** The Constant Tone Extension (CTE) of the advertisement */ + uint8_t cte_type; + + /** The response slot */ + uint8_t response_slot; + + /** Data status */ + uint8_t data_status; + + /** Data length */ + uint8_t data_length; + + /** response data */ + const uint8_t *data; +}; + +struct ble_gap_periodic_adv_response_params { + /** The periodic advertsing event for which response shall be sent in */ + uint16_t request_event; + + /** The request subevent for which response shall be sent in */ + uint8_t request_subevent; + + /** The subevent the response shall be sent in */ + uint8_t response_subevent; + + /** The response slot the response shall be sent in */ + uint8_t response_slot; +}; +#endif + /** * Represents a GAP-related event. When such an event occurs, the host * notifies the application by passing an instance of this structure to an @@ -538,6 +600,23 @@ struct ble_gap_event { /** The handle of the relevant connection. */ uint16_t conn_handle; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /* + * Adv_Handle is used to identify an advertising set. + * If the connection is established from periodic advertising with responses + * and Role is 0x00 then the Advertising_Handle parameter shall be set + * according to the periodic advertising train the connection was established from + */ + uint8_t adv_handle; + + /* + * Sync_Handle identifying the periodic advertising train + * If the connection is established from periodic advertising with responses + * and Role is 0x01, then the Sync_Handle parameter shall be set according + * to the periodic advertising train the connection was established from + */ + uint16_t sync_handle; +#endif } connect; /** @@ -939,6 +1018,18 @@ struct ble_gap_event { /** Advertiser clock accuracy */ uint8_t adv_clk_accuracy; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /** Number of subevents. If zero, the periodic advertiser will be a broadcaster, + * without responses. + */ + uint8_t num_subevents; + /** Interval between subevents (N * 1.25 ms) */ + uint8_t subevent_interval; + /** Time between the advertising packet and the first response slot (N * 1.25 ms). */ + uint8_t response_slot_delay; + /** Time between response slots (N * 0.125 ms) */ + uint8_t response_slot_spacing; +#endif } periodic_sync; /** @@ -956,10 +1047,24 @@ struct ble_gap_event { /** Received signal strength indication in dBm (127 if unavailable) */ int8_t rssi; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /** + * It indicates the periodic advertising event counter (paEventCounter) of + * the event that the periodic advertising packet was received in. + */ + uint16_t event_counter; + /** + * It indicates Periodic Advertising with Responses subevent in which + * the periodic advertising packet was received in. + */ + uint8_t subevent; +#endif + /** Advertising data status, can be one of following constants: * - BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE * - BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE * - BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED + * - BLE_HCI_PERIODIC_DATA_STATUS_RX_FAILED */ uint8_t data_status; @@ -1041,6 +1146,18 @@ struct ble_gap_event { /** Advertiser clock accuracy */ uint8_t adv_clk_accuracy; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /** Number of subevents. If zero, the periodic advertiser will be a broadcaster,- + * without responses. + */ + uint8_t num_subevents; + /** Interval between subevents (N * 1.25 ms) */ + uint8_t subevent_interval; + /** Time between the advertising packet and the first response slot (N * 1.25 ms). */ + uint8_t response_slot_delay; + /** Time between response slots (N * 0.125 ms) */ + uint8_t response_slot_spacing; +#endif } periodic_transfer; #endif @@ -1119,6 +1236,30 @@ struct ble_gap_event { uint16_t supervision_tmo; } subrate_change; #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /** + * Represents a periodic advertising subevent data request + * with parameters valid for the following event types: + * o BLE_GAP_EVENT_PER_SUBEV_DATA_REQ + */ + struct { + /** Advertising handle */ + uint8_t adv_handle; + + /** Subevent start */ + uint8_t subevent_start; + + /** Number of subevents */ + uint8_t subevent_data_count; + } periodic_adv_subev_data_req; + + /** + * Represents a periodic advertising response + * with parameters valid for the following event types: + * o BLE_GAP_EVENT_PER_SUBEV_RESP + */ + struct ble_gap_periodic_adv_response periodic_adv_response; +#endif /** * GATT Authorization Event. Ask the user to authorize a GATT @@ -1705,6 +1846,34 @@ struct ble_gap_periodic_adv_params { * defaults */ uint16_t itvl_max; + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + /** Number of subevents + * If zero, the periodic advertiser will be a broadcaster, without responses. + */ + uint8_t num_subevents; + + /** Interval between subevents (N * 1.25 ms) + * Shall be between 7.5ms and 318.75 ms. + */ + uint8_t subevent_interval; + + /** Time between the advertising packet in a subevent and the + * first response slot (N * 1.25 ms) + * + */ + uint8_t response_slot_delay; + + /** Time between response slots (N * 0.125 ms) + * Shall be between 0.25 and 31.875 ms. + */ + uint8_t response_slot_spacing; + + /** Number of subevent response slots + * If zero, response_slot_delay and response_slot_spacing are ignored. + */ + uint8_t num_response_slots; +#endif /* PERIODIC_ADV_WITH_RESPONSES */ }; #if MYNEWT_VAL(BLE_PERIODIC_ADV_ENH) @@ -1748,6 +1917,22 @@ struct ble_gap_periodic_sync_params { #endif }; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +struct ble_gap_set_periodic_adv_subev_data_params { + /** The subevent to set data for */ + uint8_t subevent; + + /** The first response slot to listen to */ + uint8_t response_slot_start; + + /** The number of response slots to listen to */ + uint8_t response_slot_count; + + /** The data to send */ + struct os_mbuf *data; +}; +#endif + /** * Configure periodic advertising for specified advertising instance * @@ -1990,6 +2175,18 @@ int ble_gap_clear_periodic_adv_list(void); * @return 0 on success; nonzero on failure. */ int ble_gap_read_periodic_adv_list_size(uint8_t *per_adv_list_size); +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +int +ble_gap_set_periodic_adv_subev_data(uint8_t instance, uint8_t num_subevents, + const struct ble_gap_set_periodic_adv_subev_data_params *params); + +int ble_gap_periodic_adv_set_response_data(uint16_t sync_handle, + struct ble_gap_periodic_adv_response_params *param, + struct os_mbuf *data); + +int ble_gap_periodic_adv_sync_subev(uint16_t sync_handle, uint8_t include_tx_power, + uint8_t num_subevents, uint8_t *subevents); +#endif #endif @@ -2135,6 +2332,71 @@ int ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, const struct ble_gap_conn_params *params, ble_gap_event_fn *cb, void *cb_arg); +/** + * Initiates an Sync connect procedure for PAwR. + * + * @param own_addr_type The type of address the stack should use for + * itself during connection establishment. + * - BLE_OWN_ADDR_PUBLIC + * - BLE_OWN_ADDR_RANDOM + * - BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * - BLE_OWN_ADDR_RPA_RANDOM_DEFAULT + * @param advertising_handle The advertising_Handle identifying the periodic advertising train + * Range: 0x00 to 0xEF or 0xFF + * @param subevent The Subevent parameter is used to identify the subevent where a connection + request shall be initiated from a periodic advertising train. + The Advertising_Handle and Subevent parameters + shall be set to 0xFF if these + parameters are not used. + * @param peer_addr The address of the peer to connect to. + * If this parameter is NULL, the white list + * is used. + * @param duration_ms The duration of the discovery procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_DISC_COMPLETE event is + * reported. Units are milliseconds. + * @param phy_mask Define on which PHYs connection attempt should + * be done + * @param phy_1m_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_1M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_2m_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_2M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_coded_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_CODED_MASK is set in + * phy_mask this parameter can be specify to + * null for default values. + * @param cb The callback to associate with this connect + * procedure. When the connect procedure + * completes, the result is reported through + * this callback. If the connect procedure + * succeeds, the connection inherits this + * callback as its event-reporting mechanism. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; + * BLE_HS_EALREADY if a connection attempt is + * already in progress; + * BLE_HS_EBUSY if initiating a connection is not + * possible because scanning is in progress; + * BLE_HS_EDONE if the specified peer is already + * connected; + * Other nonzero on error. + */ +int ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, + uint8_t subevent, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg); /** * Initiates an extended connect procedure. * diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index f4d327eb7..bcf1cc9db 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -106,7 +106,7 @@ #define BLE_GAP_UPDATE_TIMEOUT_MS 40000 /* ms */ -#if MYNEWT_VAL(BLE_ROLE_CENTRAL) +#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) static const struct ble_gap_conn_params ble_gap_conn_params_dflt = { .scan_itvl = 0x0010, .scan_window = 0x0010, @@ -1314,7 +1314,8 @@ ble_gap_update_next_exp(int32_t *out_ticks_from_now) } -#if NIMBLE_BLE_SCAN +#if (NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)) || \ + (MYNEWT_VAL(BLE_ROLE_CENTRAL) && MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT)) static void ble_gap_master_set_timer(uint32_t ticks_from_now) { @@ -1658,11 +1659,16 @@ ble_gap_accept_master_conn(void) static int ble_gap_accept_slave_conn(uint8_t instance) { - int rc; - + int rc = 0; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) if (instance >= BLE_ADV_INSTANCES) { - rc = BLE_HS_ENOENT; + rc = BLE_HS_ENOENT; +} +#else + if (instance >= BLE_ADV_INSTANCES) { + rc = BLE_HS_ENOENT; } else if (!ble_gap_adv_active_instance(instance)) { + rc = BLE_HS_ENOENT; } else { if (ble_gap_slave[instance].connectable) { @@ -1676,6 +1682,7 @@ ble_gap_accept_slave_conn(uint8_t instance) STATS_INC(ble_gap_stats, connect_slv); } +#endif return rc; } #endif @@ -1810,7 +1817,6 @@ ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev) /* Periodic adv events */ #if MYNEWT_VAL(BLE_PERIODIC_ADV) - void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev) { @@ -1845,6 +1851,12 @@ ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv event.periodic_sync.adv_phy = ev->phy; event.periodic_sync.per_adv_ival = ev->interval; event.periodic_sync.adv_clk_accuracy = ev->aca; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.periodic_sync.num_subevents = ev->num_subevents; + event.periodic_sync.subevent_interval = ev->subevent_interval; + event.periodic_sync.response_slot_delay = ev->response_slot_delay; + event.periodic_sync.response_slot_spacing = ev->response_slot_spacing; +#endif ble_hs_periodic_sync_insert(ble_gap_sync.psync); } else { @@ -1896,6 +1908,10 @@ ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_rpt *e event.periodic_report.data_status = ev->data_status; event.periodic_report.data_length = ev->data_len; event.periodic_report.data = ev->data; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.periodic_report.event_counter = ev->event_counter; + event.periodic_report.subevent = ev->subevent; +#endif /* TODO should we allow for listener too? this can be spammy and is more * like ACL data, not general event @@ -2076,7 +2092,12 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_ event.periodic_transfer.adv_phy = ev->phy; event.periodic_transfer.per_adv_itvl = le16toh(ev->interval); event.periodic_transfer.adv_clk_accuracy = ev->aca; - +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.periodic_transfer.num_subevents = ev->num_subevents; + event.periodic_transfer.subevent_interval = ev->subevent_interval; + event.periodic_transfer.response_slot_delay = ev->response_slot_delay; + event.periodic_transfer.response_slot_spacing = ev->response_slot_spacing; +#endif ble_hs_unlock(); ble_gap_event_listener_call(&event); @@ -2110,6 +2131,51 @@ ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev) } #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +void +ble_gap_rx_periodic_adv_subev_data_req(const struct ble_hci_ev_le_subev_periodic_adv_subev_data_req *ev) +{ + struct ble_gap_event event; + ble_gap_event_fn *cb; + void *cb_arg; + + memset(&event, 0x0, sizeof event); + + event.type = BLE_GAP_EVENT_PER_SUBEV_DATA_REQ; + event.periodic_adv_subev_data_req.adv_handle = ev->adv_handle; + event.periodic_adv_subev_data_req.subevent_start = ev->subevent_start; + event.periodic_adv_subev_data_req.subevent_data_count = ev->subevent_data_count; + + ble_gap_slave_extract_cb(ev->adv_handle, &cb, &cb_arg); + if (cb != NULL) { + cb(&event, cb_arg); + } + + ble_gap_event_listener_call(&event); +} + +void +ble_gap_rx_periodic_adv_response(const struct ble_gap_periodic_adv_response resp) +{ + struct ble_gap_event event; + ble_gap_event_fn *cb; + void *cb_arg; + + memset(&event, 0x0, sizeof event); + + event.type = BLE_GAP_EVENT_PER_SUBEV_RESP; + memcpy(&event.periodic_adv_response, &resp, + sizeof(struct ble_gap_periodic_adv_response)); + + ble_gap_slave_extract_cb(resp.adv_handle, &cb, &cb_arg); + if (cb != NULL) { + cb(&event, cb_arg); + } + + ble_gap_event_listener_call(&event); +} +#endif + #if NIMBLE_BLE_CONNECT static int ble_gap_rd_rem_sup_feat_tx(uint16_t handle) @@ -2214,6 +2280,21 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) conn->bhc_latency = evt->conn_latency; conn->bhc_supervision_timeout = evt->supervision_timeout; conn->bhc_master_clock_accuracy = evt->master_clk_acc; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + if (ble_gap_master.cb) { + conn->bhc_cb = ble_gap_master.cb; + conn->bhc_cb_arg = ble_gap_master.cb_arg; + conn->bhc_flags |= BLE_HS_CONN_F_MASTER; + conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type; + ble_gap_master_reset_state(); + } + else { + conn->bhc_cb = ble_gap_slave[instance].cb; + conn->bhc_cb_arg = ble_gap_slave[instance].cb_arg; + conn->bhc_our_addr_type = ble_gap_slave[instance].our_addr_type; + ble_gap_slave_reset_state(instance); + } +#else if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER) { conn->bhc_cb = ble_gap_master.cb; conn->bhc_cb_arg = ble_gap_master.cb_arg; @@ -2229,6 +2310,7 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) #endif ble_gap_slave_reset_state(instance); } +#endif conn->bhc_peer_addr.type = evt->peer_addr_type; memcpy(conn->bhc_peer_addr.val, evt->peer_addr, 6); @@ -2278,6 +2360,10 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) } } } +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.connect.sync_handle = evt->sync_handle; + event.connect.adv_handle = evt->adv_handle; #endif ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, evt->connection_handle); @@ -3966,7 +4052,11 @@ ble_gap_periodic_adv_params_tx(uint8_t instance, const struct ble_gap_periodic_adv_params *params) { +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + struct ble_hci_le_set_periodic_adv_params_v2 cmd; +#else struct ble_hci_le_set_periodic_adv_params_cp cmd; +#endif uint16_t opcode; cmd.adv_handle = instance; @@ -3987,8 +4077,19 @@ ble_gap_periodic_adv_params_tx(uint8_t instance, cmd.props = 0; } - opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS); +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + cmd.num_subevents = params->num_subevents; + cmd.subevent_interval = params->subevent_interval; + cmd.response_slot_delay = params->response_slot_delay; + cmd.response_slot_spacing = params->response_slot_spacing; + cmd.num_response_slots = params->num_response_slots; +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS_V2); +#else + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS); +#endif return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); } @@ -4025,7 +4126,7 @@ ble_gap_periodic_adv_configure(uint8_t instance, rc = ble_gap_periodic_adv_params_validate(params); if (rc) { - return rc; + return rc; } ble_hs_lock(); @@ -4888,6 +4989,152 @@ ble_gap_read_periodic_adv_list_size(uint8_t *per_adv_list_size) return 0; } +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +static int +ble_gap_calc_periodic_adv_data_size(uint8_t num_subevents, + const struct ble_gap_set_periodic_adv_subev_data_params *params) { + int len = 0; + const struct ble_gap_set_periodic_adv_subev_data_params *param; + int raw_subev_size = sizeof(*param) - sizeof(struct os_mbuf*); + + for(int i = 0; i < num_subevents; i++) { + param = params + i; + len += raw_subev_size; + len += OS_MBUF_PKTLEN(param->data); + } + return len; +} +int +ble_gap_set_periodic_adv_subev_data(uint8_t instance, uint8_t num_subevents, + const struct ble_gap_set_periodic_adv_subev_data_params *params) +{ + struct ble_hci_le_set_periodic_adv_subev_data_cp *cmd; + struct periodic_adv_subevents *subevents; + uint8_t len = ble_gap_calc_periodic_adv_data_size(num_subevents, params); + uint8_t buf[len + 2]; + uint16_t opcode; + uint16_t subev_data_len; + int rc; + + if (instance >= BLE_ADV_INSTANCES) { + rc = BLE_HS_EINVAL; + goto done; + } + + if (!ble_hs_is_enabled()) { + rc = BLE_HS_EDISABLED; + goto done; + } + + /* Check if we can set all of data in one hci command. */ + if ((len + 2) >= 0xff) { + rc = BLE_HS_EINVAL; + goto done; + } + + ble_hs_lock(); + + /* Periodic advertising cannot start unless it is configured before */ + if (!ble_gap_slave[instance].periodic_configured) { + ble_hs_unlock(); + rc = BLE_HS_EINVAL; + goto done; + } + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_SUBEV_DATA); + + cmd = (void *) buf; + subevents = cmd->subevents; + + cmd->adv_handle = instance; + cmd->num_subevents = num_subevents; + + for (int i = 0; i < num_subevents; i++) { + subevents->subevent = params[i].subevent; + subevents->response_slot_start = params[i].response_slot_start; + subevents->response_slot_count = params[i].response_slot_count; + ble_hs_mbuf_to_flat(params[i].data, subevents->subevent_data, OS_MBUF_PKTLEN(params[i].data), + (void*)&subev_data_len); + subevents->subevent_data_length = OS_MBUF_PKTLEN(params[i].data); + subevents = (struct periodic_adv_subevents *)( + (uint32_t)subevents + sizeof(struct periodic_adv_subevents) + subev_data_len); + } + + rc = ble_hs_hci_cmd_tx(opcode, cmd, len + 2, NULL, 0); + if (rc != 0) { + ble_hs_unlock(); + goto done; + } + + ble_gap_slave[instance].periodic_op = BLE_GAP_OP_S_PERIODIC_ADV; + + ble_hs_unlock(); + +done: + for (int i = 0; i < num_subevents; i++) { + os_mbuf_free_chain(params[i].data); + } + return rc; +} + +int ble_gap_periodic_adv_set_response_data(uint16_t sync_handle, + struct ble_gap_periodic_adv_response_params *param, + struct os_mbuf *data) +{ + struct ble_hci_le_set_periodic_adv_response_data *cmd; + uint16_t opcode; + int len = sizeof(*cmd); + int data_len = OS_MBUF_PKTLEN(data); + uint8_t buf[len + data_len]; + + //!TODO: Check if we can set all of data in one hci command. + + cmd = (void *) buf; + + (void)memset(cmd, 0, sizeof(*cmd)); + put_le16(&cmd->sync_handle, sync_handle); + put_le16(&cmd->request_event, param->request_event); + cmd->request_subevent = param->request_subevent; + cmd->response_subevent = param->response_subevent; + cmd->response_slot = param->response_slot; + cmd->response_data_length = data_len; + ble_hs_mbuf_to_flat(data, cmd->response_data, data_len, NULL); + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_RESPONSE_DATA); + + return ble_hs_hci_cmd_tx(opcode, cmd, len + data_len, NULL, 0); +} + +int ble_gap_periodic_adv_sync_subev(uint16_t sync_handle, uint8_t include_tx_power, + uint8_t num_subevents, uint8_t *subevents) +{ + struct ble_hci_le_set_periodic_adv_sync_subevent *cmd; + struct ble_hci_le_set_periodic_adv_sync_subevent_rp rsp; + struct ble_hs_periodic_sync *psync; + uint8_t cmd_buf[sizeof(*cmd) + num_subevents]; + uint16_t opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_SYNC_SUBEVENT); + int rc; + + psync = ble_hs_periodic_sync_find_by_handle(sync_handle); + if (!psync) { + ble_hs_unlock(); + return BLE_HS_ENOTCONN; + } + + cmd = (void *)cmd_buf; + + put_le16(&cmd->sync_handle, sync_handle); + put_le16(&cmd->periodic_adv_properties, (uint16_t)(include_tx_power << 6)); + cmd->num_subevents = num_subevents; + memcpy(cmd->subevents, subevents, num_subevents); + + rc = ble_hs_hci_cmd_tx(opcode, cmd, sizeof(*cmd) + num_subevents, &rsp, sizeof(rsp)); + if (!rc) { + BLE_HS_DBG_ASSERT(le16toh(rsp.sync_handle) == sync_handle); + } + return rc; +} +#endif #endif /***************************************************************************** @@ -5487,8 +5734,7 @@ ble_gap_subrate_req(uint16_t conn_handle, uint16_t subrate_min, uint16_t subrate } #endif -#if MYNEWT_VAL(BLE_EXT_ADV) -#if MYNEWT_VAL(BLE_ROLE_CENTRAL) +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) || MYNEWT_VAL(BLE_EXT_ADV) static int ble_gap_check_conn_params(uint8_t phy, const struct ble_gap_conn_params *params) { @@ -5532,6 +5778,243 @@ ble_gap_check_conn_params(uint8_t phy, const struct ble_gap_conn_params *params) return 0; } +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +static int +ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, + uint8_t advertising_handle, uint8_t subevent, + const ble_addr_t *peer_addr, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params) +{ + struct ble_hci_le_ext_create_conn_v2_cp *cmd; + struct conn_params *params; + uint8_t buf[sizeof(*cmd) + 3 * sizeof(*params)]; + uint8_t len = sizeof(*cmd); + int rc; + + /* Check own addr type */ + if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (phy_mask > (BLE_HCI_LE_PHY_1M_PREF_MASK | + BLE_HCI_LE_PHY_2M_PREF_MASK | + BLE_HCI_LE_PHY_CODED_PREF_MASK)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + cmd = (void *) buf; + params = cmd->conn_params; + if (peer_addr == NULL) { + /* Application wants to connect to any device in the white list. The + * peer address type and peer address fields are ignored by the + * controller; fill them with dummy values. + */ + cmd->filter_policy = BLE_HCI_CONN_FILT_USE_WL; + cmd->peer_addr_type = 0; + memset(cmd->peer_addr, 0, sizeof(cmd->peer_addr)); + } else { + /* Check peer addr type */ + if (peer_addr->type > BLE_HCI_CONN_PEER_ADDR_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + cmd->filter_policy = BLE_HCI_CONN_FILT_NO_WL; + cmd->peer_addr_type = peer_addr->type; + memcpy(cmd->peer_addr, peer_addr->val, sizeof(cmd->peer_addr)); + } + + cmd->own_addr_type = own_addr_type; + cmd->init_phy_mask = phy_mask; + + cmd->adv_handle = advertising_handle; + cmd->subevent = subevent; + + if (phy_mask & BLE_GAP_LE_PHY_1M_MASK) { + rc = ble_gap_check_conn_params(BLE_HCI_LE_PHY_1M, phy_1m_conn_params); + if (rc) { + return rc; + } + + params->scan_itvl = htole16(phy_1m_conn_params->scan_itvl); + params->scan_window = htole16(phy_1m_conn_params->scan_window); + params->conn_min_itvl = htole16(phy_1m_conn_params->itvl_min); + params->conn_max_itvl = htole16(phy_1m_conn_params->itvl_max); + params->conn_latency = htole16(phy_1m_conn_params->latency); + params->supervision_timeout = htole16(phy_1m_conn_params->supervision_timeout); + params->min_ce = htole16(phy_1m_conn_params->min_ce_len); + params->max_ce = htole16(phy_1m_conn_params->max_ce_len); + + params++; + len += sizeof(*params); + } + + if (phy_mask & BLE_GAP_LE_PHY_2M_MASK) { + rc = ble_gap_check_conn_params(BLE_HCI_LE_PHY_2M, phy_2m_conn_params); + if (rc) { + return rc; + } + + params->scan_itvl = htole16(phy_2m_conn_params->scan_itvl); + params->scan_window = htole16(phy_2m_conn_params->scan_window); + params->conn_min_itvl = htole16(phy_2m_conn_params->itvl_min); + params->conn_max_itvl = htole16(phy_2m_conn_params->itvl_max); + params->conn_latency = htole16(phy_2m_conn_params->latency); + params->supervision_timeout = htole16(phy_2m_conn_params->supervision_timeout); + params->min_ce = htole16(phy_2m_conn_params->min_ce_len); + params->max_ce = htole16(phy_2m_conn_params->max_ce_len); + + params++; + len += sizeof(*params); + } + + if (phy_mask & BLE_GAP_LE_PHY_CODED_MASK) { + rc = ble_gap_check_conn_params(BLE_HCI_LE_PHY_CODED, phy_coded_conn_params); + if (rc) { + return rc; + } + + params->scan_itvl = htole16(phy_coded_conn_params->scan_itvl); + params->scan_window = htole16(phy_coded_conn_params->scan_window); + params->conn_min_itvl = htole16(phy_coded_conn_params->itvl_min); + params->conn_max_itvl = htole16(phy_coded_conn_params->itvl_max); + params->conn_latency = htole16(phy_coded_conn_params->latency); + params->supervision_timeout = htole16(phy_coded_conn_params->supervision_timeout); + params->min_ce = htole16(phy_coded_conn_params->min_ce_len); + params->max_ce = htole16(phy_coded_conn_params->max_ce_len); + + params++; + len += sizeof(*params); + } + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_LE_EXT_CREATE_CONN_V2), + cmd, len, NULL, 0); +} + + +int +ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, + uint8_t subevent, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg) +{ + int rc; + + STATS_INC(ble_gap_stats, initiate); + + ble_hs_lock(); + + if (ble_gap_conn_active()) { + rc = BLE_HS_EALREADY; + goto done; + } + + if (ble_gap_disc_active()) { + rc = BLE_HS_EBUSY; + goto done; + } + + if (!ble_hs_is_enabled()) { + rc = BLE_HS_EDISABLED; + goto done; + } + + if (ble_gap_is_preempted()) { + rc = BLE_HS_EPREEMPTED; + goto done; + } + + if (!ble_hs_conn_can_alloc()) { + rc = BLE_HS_ENOMEM; + goto done; + } + + if (peer_addr && + peer_addr->type != BLE_ADDR_PUBLIC && + peer_addr->type != BLE_ADDR_RANDOM && + peer_addr->type != BLE_ADDR_PUBLIC_ID && + peer_addr->type != BLE_ADDR_RANDOM_ID) { + + rc = BLE_HS_EINVAL; + goto done; + } + + if ((phy_mask & BLE_GAP_LE_PHY_1M_MASK) && phy_1m_conn_params == NULL) { + phy_1m_conn_params = &ble_gap_conn_params_dflt; + } + + if ((phy_mask & BLE_GAP_LE_PHY_2M_MASK) && phy_2m_conn_params == NULL) { + phy_2m_conn_params = &ble_gap_conn_params_dflt; + } + + if ((phy_mask & BLE_GAP_LE_PHY_CODED_MASK) && + phy_coded_conn_params == NULL) { + + phy_coded_conn_params = &ble_gap_conn_params_dflt; + } + + if (duration_ms == 0) { + duration_ms = BLE_GAP_CONN_DUR_DFLT; + } + + /* The connection creation timeout is not really useful for PAwR. + * The controller will give a result for the connection attempt + * within a periodic interval. We do not know the periodic interval + * used, so disable the timeout. + */ + + /* Verify peer not already connected. */ + if (ble_hs_conn_find_by_addr(peer_addr) != NULL) { + rc = BLE_HS_EDONE; + goto done; + } + + /* XXX: Verify conn_params. */ + + rc = ble_hs_id_use_addr(own_addr_type); + if (rc != 0) { + goto done; + } + + BLE_HS_LOG(INFO, "GAP procedure initiated: extended connect; \n"); + + ble_gap_master.cb = cb; + ble_gap_master.cb_arg = cb_arg; + ble_gap_master.conn.using_wl = peer_addr == NULL; + ble_gap_master.conn.our_addr_type = own_addr_type; + + ble_gap_master.op = BLE_GAP_OP_M_CONN; + + rc = ble_gap_ext_conn_create_conn_synced_tx(own_addr_type,advertising_handle,subevent, peer_addr, phy_mask, + phy_1m_conn_params, phy_2m_conn_params, + phy_coded_conn_params); + if (rc != 0) { + ble_gap_master_reset_state(); + goto done; + } + + rc = 0; + +done: + ble_hs_unlock(); + + if (rc != 0) { + STATS_INC(ble_gap_stats, initiate_fail); + } + return rc; + +} +#endif + +#if MYNEWT_VAL(BLE_EXT_ADV) +#if MYNEWT_VAL(BLE_ROLE_CENTRAL) + static int ble_gap_ext_conn_create_tx( @@ -5643,7 +6126,60 @@ ble_gap_ext_conn_create_tx( BLE_HCI_OCF_LE_EXT_CREATE_CONN), cmd, len, NULL, 0); } -#endif + +/** + * Initiates a connect procedure. + * + * @param own_addr_type The type of address the stack should use for + * itself during connection establishment. + * o BLE_OWN_ADDR_PUBLIC + * o BLE_OWN_ADDR_RANDOM + * o BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * o BLE_OWN_ADDR_RPA_RANDOM_DEFAULT + * @param peer_addr The address of the peer to connect to. + * If this parameter is NULL, the white list + * is used. + * @param duration_ms The duration of the discovery procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_DISC_COMPLETE event is + * reported. Units are milliseconds. + * @param phy_mask Define on which PHYs connection attempt should + * be done + * @param phy_1m_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_1M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_2m_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_2M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_coded_conn_params Additional arguments specifying the + * particulars of the connect procedure. When + * BLE_GAP_LE_PHY_CODED_MASK is set in + * phy_mask this parameter can be specify to + * null for default values. + * @param cb The callback to associate with this connect + * procedure. When the connect procedure + * completes, the result is reported through + * this callback. If the connect procedure + * succeeds, the connection inherits this + * callback as its event-reporting mechanism. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; + * BLE_HS_EALREADY if a connection attempt is + * already in progress; + * BLE_HS_EBUSY if initiating a connection is not + * possible because scanning is in progress; + * BLE_HS_EDONE if the specified peer is already + * connected; + * Other nonzero on error. + */ + +#endif // MYNEWT_VAL(BLE_ROLE_CENTRAL) /** * Initiates a connect procedure. diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index a25da1bed..b5d063822 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -95,6 +95,10 @@ void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem #if MYNEWT_VAL(BLE_CONN_SUBRATING) void ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev); #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +void ble_gap_rx_periodic_adv_subev_data_req(const struct ble_hci_ev_le_subev_periodic_adv_subev_data_req *ev); +void ble_gap_rx_periodic_adv_response(const struct ble_gap_periodic_adv_response resp); +#endif #if MYNEWT_VAL(BLE_POWER_CONTROL) void ble_gap_rx_transmit_power_report(const struct ble_hci_ev_le_subev_transmit_power_report *ev); void ble_gap_rx_le_pathloss_threshold(const struct ble_hci_ev_le_subev_path_loss_threshold *ev); @@ -113,6 +117,10 @@ struct ble_gap_conn_complete uint8_t master_clk_acc; uint8_t local_rpa[BLE_DEV_ADDR_LEN]; uint8_t peer_rpa[BLE_DEV_ADDR_LEN]; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t adv_handle; + uint16_t sync_handle; +#endif }; int ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance); diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index c5768e2cc..263d35e51 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -102,6 +102,10 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_transmit_power_report; #if MYNEWT_VAL(BLE_CONN_SUBRATING) static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_subrate_change; #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_subev_data_req; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_subev_resp_rep; +#endif /* Statistics */ struct host_hci_stats { @@ -173,6 +177,14 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { #if MYNEWT_VAL(BLE_CONN_SUBRATING) [BLE_HCI_LE_SUBEV_SUBRATE_CHANGE] = ble_hs_hci_evt_le_subrate_change, #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB_V2] = ble_hs_hci_evt_le_periodic_adv_sync_estab, + [BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT_V2] = ble_hs_hci_evt_le_periodic_adv_rpt, + [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER_V2] = ble_hs_hci_evt_le_periodic_adv_sync_transfer, + [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SUBEV_DATA_REQ] = ble_hs_hci_evt_le_periodic_adv_subev_data_req, + [BLE_HCI_LE_SUBEV_PERIODIC_ADV_RESP_REPORT] = ble_hs_hci_evt_le_periodic_adv_subev_resp_rep, + [BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE_V2] = ble_hs_hci_evt_le_enh_conn_complete, +#endif }; #define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \ @@ -202,7 +214,6 @@ ble_hs_hci_evt_le_dispatch_find(uint8_t event_code) if (event_code >= BLE_HS_HCI_EVT_LE_DISPATCH_SZ) { return NULL; } - return ble_hs_hci_evt_le_dispatch[event_code]; } @@ -484,7 +495,7 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data, evt.connection_handle = BLE_HS_CONN_HANDLE_NONE; #endif } -#if MYNEWT_VAL(BLE_EXT_ADV) +#if MYNEWT_VAL(BLE_EXT_ADV) && !MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) if (evt.status == BLE_ERR_DIR_ADV_TMO || evt.role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) { /* store this until we get set terminated event with adv handle */ @@ -492,6 +503,11 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data, return 0; } #endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + evt.adv_handle = ev->adv_handle; + evt.sync_handle = ev->sync_handle; +#endif return ble_gap_rx_conn_complete(&evt, 0); } @@ -968,6 +984,64 @@ ble_hs_hci_evt_le_subrate_change(uint8_t subevent, const void *data, } #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) +static int +ble_hs_hci_evt_le_periodic_adv_subev_data_req(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_periodic_adv_subev_data_req *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_periodic_adv_subev_data_req(ev); + + return 0; +} + +static int +ble_hs_hci_evt_le_periodic_adv_subev_resp_rep(uint8_t subevent, const void *data, unsigned int len) +{ + const struct ble_hci_ev_le_subev_periodic_adv_resp_rep *ev = data; + const struct periodic_adv_response *response; + struct ble_gap_periodic_adv_response resp; + + if (len < (sizeof(*ev) + ev->num_responses * sizeof(struct periodic_adv_response))) { + return BLE_HS_ECONTROLLER; + } + + len -= sizeof(*ev); + data += sizeof(*ev); + + resp.adv_handle = ev->adv_handle; + resp.subevent = ev->subevent; + resp.tx_status = ev->tx_status; + + for (uint8_t i = 0; i < ev->num_responses; i++) { + response = data; + if (len < sizeof(*response) + response->data_length) { + return BLE_HS_ECONTROLLER; + } + + len -= sizeof(*response) + response->data_length; + data += sizeof(*response) + response->data_length; + + resp.tx_power = response->tx_power; + resp.rssi = response->rssi; + resp.cte_type = response->cte_type; + resp.response_slot = response->response_slot; + resp.data_length = response->data_length; + resp.data = response->data; + resp.data_status = response->data_status; + + ble_gap_rx_periodic_adv_response(resp); + } + + return 0; +} +#endif + #if NIMBLE_BLE_CONNECT static int ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, const void *data, diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index 5faf028cf..a7cd4dc2f 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -259,6 +259,30 @@ ble_hs_startup_le_set_evmask_tx(void) } #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + if (version >= BLE_HCI_VER_BCS_5_4) { + /** + * Enable the following LE events: + * 0x0000000800000000 LE Periodic Advertising Sync Established event V2 + * 0x0000001000000000 LE Periodic Advertising Report Event V2 + * 0x0000004000000000 LE Periodic Advertising Subevent Data Request event + * 0x0000008000000000 LE Periodic Advertising Response Report event + * 0x0000010000000000 LE Enhanced Connection Complete event V2 + */ + mask |= 0x000001d800000000; + } +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) + if (version >= BLE_HCI_VER_BCS_5_4) { + /** + * Enable the following LE events: + * 0x0000002000000000 LE Periodic Advertising Sync Transfer Received event V2 + */ + mask |= 0x0000002000000000; + } +#endif + 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 012f13b62..b0981e19b 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -706,6 +706,18 @@ struct ble_hci_le_ext_create_conn_cp { struct conn_params conn_params[0]; } __attribute__((packed)); +#define BLE_HCI_LE_EXT_CREATE_CONN_V2 (0x0085) +struct ble_hci_le_ext_create_conn_v2_cp { + uint8_t adv_handle; + uint8_t subevent; + uint8_t filter_policy; + uint8_t own_addr_type; + uint8_t peer_addr_type; + uint8_t peer_addr[6]; + uint8_t init_phy_mask; + struct conn_params conn_params[0]; +} __attribute__((packed)); + #define BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER 0x01 #define BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED 0x02 @@ -1123,6 +1135,57 @@ struct ble_hci_le_subrate_req_cp { /* --- Vendor specific commands (OGF 0x00FF) */ #define BLE_HCI_OCF_VS_RD_STATIC_ADDR (0x0001) + +#define BLE_HCI_OCF_LE_SET_PERIODIC_ADV_SUBEV_DATA (0x0082) +struct periodic_adv_subevents { + uint8_t subevent; + uint8_t response_slot_start; + uint8_t response_slot_count; + uint8_t subevent_data_length; + uint8_t subevent_data[0]; +} __attribute__((packed)); + +struct ble_hci_le_set_periodic_adv_subev_data_cp { + uint8_t adv_handle; + uint8_t num_subevents; + struct periodic_adv_subevents subevents[0]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PERIODIC_ADV_RESPONSE_DATA (0x0083) +struct ble_hci_le_set_periodic_adv_response_data { + uint16_t sync_handle; + uint16_t request_event; + uint8_t request_subevent; + uint8_t response_subevent; + uint8_t response_slot; + uint8_t response_data_length; + uint8_t response_data[0]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PERIODIC_ADV_SYNC_SUBEVENT (0x0084) +struct ble_hci_le_set_periodic_adv_sync_subevent { + uint16_t sync_handle; + uint16_t periodic_adv_properties; + uint8_t num_subevents; + uint8_t subevents[0]; +} __attribute__((packed)); +struct ble_hci_le_set_periodic_adv_sync_subevent_rp { + uint16_t sync_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PERIODIC_ADV_PARAMS_V2 (0x0086) +struct ble_hci_le_set_periodic_adv_params_v2 { + uint8_t adv_handle; + uint16_t min_itvl; + uint16_t max_itvl; + uint16_t props; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; + uint8_t num_response_slots; +} __attribute__((packed)); + struct ble_hci_vs_rd_static_addr_rp { uint8_t addr[6]; } __attribute__((packed)); @@ -1374,6 +1437,7 @@ struct ble_hci_vs_duplicate_exception_list_cp { #define BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE 0x00 #define BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE 0x01 #define BLE_HCI_PERIODIC_DATA_STATUS_TRUNCATED 0x02 +#define BLE_HCI_PERIODIC_DATA_STATUS_RX_FAILED 0xFF /* --- LE set privacy mode (OCF 0x004E) */ #define BLE_HCI_PRIVACY_NETWORK (0) @@ -1630,6 +1694,7 @@ struct ble_hci_ev_le_subev_gen_dhkey_complete { } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE (0x0A) +#define BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE_V2 (0x29) struct ble_hci_ev_le_subev_enh_conn_complete { uint8_t subev_code; uint8_t status; @@ -1643,6 +1708,10 @@ struct ble_hci_ev_le_subev_enh_conn_complete { uint16_t conn_latency; uint16_t supervision_timeout; uint8_t mca; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t adv_handle; + uint16_t sync_handle; +#endif } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT (0x0B) @@ -1691,7 +1760,8 @@ struct ble_hci_ev_le_subev_ext_adv_rpt { struct ext_adv_report reports[0]; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB (0x0E) +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB (0x0E) +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB_V2 (0x24) struct ble_hci_ev_le_subev_periodic_adv_sync_estab { uint8_t subev_code; uint8_t status; @@ -1702,15 +1772,26 @@ struct ble_hci_ev_le_subev_periodic_adv_sync_estab { uint8_t phy; uint16_t interval; uint8_t aca; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +#endif } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT (0x0F) +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT_V2 (0x25) struct ble_hci_ev_le_subev_periodic_adv_rpt { uint8_t subev_code; uint16_t sync_handle; int8_t tx_power; int8_t rssi; uint8_t cte_type; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint16_t event_counter; + uint8_t subevent; +#endif uint8_t data_status; uint8_t data_len; uint8_t data[0]; @@ -1755,7 +1836,8 @@ struct ble_hci_ev_le_subev_chan_sel_alg { #define BLE_HCI_LE_SUBEV_CONN_IQ_RPT (0x16) #define BLE_HCI_LE_SUBEV_CTE_REQ_FAILED (0x17) -#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER (0x18) +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER (0x18) +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER_V2 (0x26) struct ble_hci_ev_le_subev_periodic_adv_sync_transfer { uint8_t subev_code; uint8_t status; @@ -1768,6 +1850,12 @@ struct ble_hci_ev_le_subev_periodic_adv_sync_transfer { uint8_t phy; uint16_t interval; uint8_t aca; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +#endif } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_CIS_ESTAB (0x19) @@ -1905,6 +1993,34 @@ struct ble_hci_ev_le_subev_subrate_change { uint16_t supervision_tmo; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SUBEV_DATA_REQ (0x27) +struct ble_hci_ev_le_subev_periodic_adv_subev_data_req { + uint8_t subev_code; + uint8_t adv_handle; + uint8_t subevent_start; + uint8_t subevent_data_count; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_PERIODIC_ADV_RESP_REPORT (0x28) +struct periodic_adv_response { + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t response_slot; + uint8_t data_status; + uint8_t data_length; + uint8_t data[0]; +} __attribute__((packed)); + +struct ble_hci_ev_le_subev_periodic_adv_resp_rep { + uint8_t subev_code; + uint8_t adv_handle; + uint8_t subevent; + uint8_t tx_status; + uint8_t num_responses; + struct periodic_adv_response responses[0]; +} __attribute__((packed)); + #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) // LE vendor hci event #define BLE_HCI_LE_SUBEV_DISCARD_REPORT_EVT 0XF0