diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index ba3255dba..40f0d1d4f 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -163,6 +163,7 @@ struct hci_conn_update; #define BLE_GAP_EVENT_EATT 34 #define BLE_GAP_EVENT_PER_SUBEV_DATA_REQ 35 #define BLE_GAP_EVENT_PER_SUBEV_RESP 36 +#define BLE_GAP_EVENT_PERIODIC_TRANSFER_V2 37 /* DTM events */ #define BLE_GAP_DTM_TX_START_EVT 0 diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 78385509f..8baeb6bd6 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -2103,7 +2103,11 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_ memset(&event, 0, sizeof event); +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER_V2; +#else event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER; +#endif // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) event.periodic_transfer.status = ev->status; /* only sync handle is not valid on error */ @@ -2214,6 +2218,31 @@ ble_gap_rx_periodic_adv_response(const struct ble_gap_periodic_adv_response resp ble_gap_event_listener_call(&event); } + +void +ble_gap_rx_conn_comp_failed(const struct ble_gap_conn_complete *evt) +{ + struct ble_gap_event event; + ble_gap_event_fn *cb; + void *cb_arg; + + memset(&event, 0x0, sizeof event); + + event.type = BLE_GAP_EVENT_CONNECT; + event.connect.conn_handle = evt->connection_handle; + event.connect.status = BLE_ERR_CONN_ESTABLISHMENT; + + event.connect.sync_handle = evt->sync_handle; + event.connect.adv_handle = evt->adv_handle; + + ble_gap_master_reset_state(); + ble_gap_slave_extract_cb(evt->adv_handle, &cb, &cb_arg); + if (cb != NULL) { + cb(&event, cb_arg); + } + + ble_gap_event_listener_call(&event); +} #endif #if NIMBLE_BLE_CONNECT @@ -2254,10 +2283,16 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) struct ble_hs_conn *conn; int rc; #if MYNEWT_VAL(BLE_GATT_CACHING) - struct ble_hs_conn_addrs addrs + struct ble_hs_conn_addrs addrs; #endif STATS_INC(ble_gap_stats, rx_conn_complete); +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t v1_evt = 0; + if (evt->adv_handle == 0xFF && evt->sync_handle == 0xFFFF) { + v1_evt = 1; + } +#endif // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) /* in that case *only* status field is valid so we determine role * based on error code @@ -2286,6 +2321,13 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) } } break; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + case BLE_ERR_CONN_ESTABLISHMENT: + if (!v1_evt) { + ble_gap_rx_conn_comp_failed(evt); + } + break; +#endif // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) default: /* this should never happen, unless controller is broken */ BLE_HS_LOG(INFO, "controller reported invalid error code in conn" @@ -2332,21 +2374,6 @@ 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; @@ -2354,6 +2381,17 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type; ble_gap_master_reset_state(); } else { +#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + if (!v1_evt) { + conn->bhc_cb = ble_gap_master.cb; + conn->bhc_cb_arg = ble_gap_master.cb_arg; + conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type; + } 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; + } +#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; @@ -2361,8 +2399,8 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) memcpy(conn->bhc_our_rnd_addr, ble_gap_slave[instance].rnd_addr, 6); #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); @@ -5186,7 +5224,10 @@ int ble_gap_periodic_adv_set_response_data(uint16_t sync_handle, struct ble_hci_le_set_periodic_adv_response_data *cmd; uint16_t opcode; int len = sizeof(*cmd); - int data_len = OS_MBUF_PKTLEN(data); + int data_len = 0; + if (data) { + 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. @@ -5200,7 +5241,9 @@ int ble_gap_periodic_adv_set_response_data(uint16_t sync_handle, 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); + if (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); diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index e9909aeb2..e26f84d8c 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -97,10 +97,6 @@ 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 -#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); @@ -125,6 +121,11 @@ struct ble_gap_conn_complete #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); +void ble_gap_rx_conn_comp_failed(const struct ble_gap_conn_complete *evt); +#endif int ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance); void ble_gap_rx_disconn_complete(const struct ble_hci_ev_disconn_cmp *ev); void ble_gap_rx_update_complete(const struct ble_hci_ev_le_subev_conn_upd_complete *ev); diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 26f7eed55..54dacf359 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -511,8 +511,13 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data, #endif #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) - evt.adv_handle = ev->adv_handle; - evt.sync_handle = ev->sync_handle; + if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) { + evt.adv_handle = 0xFF; + evt.sync_handle = 0xFF; + } else { + evt.adv_handle = ev->adv_handle; + evt.sync_handle = ev->sync_handle; + } #endif return ble_gap_rx_conn_complete(&evt, 0); @@ -1077,8 +1082,14 @@ ble_hs_hci_evt_le_periodic_adv_subev_resp_rep(uint8_t subevent, const void *data 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; + uint32_t size; - if (len < (sizeof(*ev) + ev->num_responses * sizeof(struct periodic_adv_response))) { + /* TODO: compare with the total length including the response data. */ + size = sizeof(*ev); + for (uint8_t i = 0; i < ev->num_responses; i ++) { + size += sizeof(struct periodic_adv_response) + ev->responses[i].data_length; + } + if (len < size) { return BLE_HS_ECONTROLLER; } @@ -1221,8 +1232,8 @@ ble_hs_hci_evt_process(const struct ble_hci_ev *ev) if(ev->opcode == BLE_HCI_EVCODE_COMMAND_COMPLETE) { /* Check if this Command complete has a parsable opcode */ - struct ble_hci_ev_command_complete *cmd_complete = (void *) ev->data; - entry = ble_hs_hci_evt_dispatch_find(cmd_complete->opcode); + struct ble_hci_ev_command_complete *cmd_complete = (void *) ev->data; + entry = ble_hs_hci_evt_dispatch_find(cmd_complete->opcode); } else { entry = ble_hs_hci_evt_dispatch_find(ev->opcode); diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index a99f5ae26..239d16480 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1797,6 +1797,21 @@ struct ble_hci_ev_le_subev_periodic_adv_rpt { uint8_t data[0]; } __attribute__((packed)); +struct ble_hci_ev_le_subev_periodic_adv_rpt_v2 { + 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 // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) + uint8_t data_status; + uint8_t data_len; + uint8_t data[0]; +} __attribute__((packed)); + #define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_LOST (0x10) struct ble_hci_ev_le_subev_periodic_adv_sync_lost { uint8_t subev_code;