diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 35dd203fd..7be756a13 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -1130,6 +1130,19 @@ struct ble_gap_event { */ uint8_t num_pkt; } dtm_state; + +#if MYNEWT_VAL(BLE_HCI_VS) + /** + * Represents a received vendor-specific HCI event + * + * Valid for the following event types: + * o BLE_GAP_EVENT_VS_HCI + */ + struct { + const void *ev; + uint8_t length; + } vs_hci; +#endif }; }; diff --git a/nimble/host/include/host/ble_hs_hci.h b/nimble/host/include/host/ble_hs_hci.h index e10b8e62a..56f8bcc4f 100644 --- a/nimble/host/include/host/ble_hs_hci.h +++ b/nimble/host/include/host/ble_hs_hci.h @@ -87,6 +87,24 @@ int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map); */ int ble_hs_hci_set_chan_class(const uint8_t *chan_map); +#if MYNEWT_VAL(BLE_HCI_VS) +/** + * Send an arbitrary HCI command to the controller. + * + * The command has to be a vendor-specific command, i.e. OGF=0x3f is always + * assumed. + * + * @param ocf OCF for vendor-specific HCI command + * @param cmdbuf command buffer + * @param cmdlen length of command buffer + * @param rspbuf response buffer + * @param rsplen length of response buffer + * @return 0 on success, error code on failure + */ +int ble_hs_hci_send_vs_cmd(uint16_t ocf, const void *cmdbuf, uint8_t cmdlen, + void *rspbuf, uint8_t rsplen); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 7ad0e8740..1425d34ae 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -6678,6 +6678,20 @@ ble_gap_end_test_evt(const void *buf, uint8_t len) ble_gap_event_listener_call(&event); } +#if MYNEWT_VAL(BLE_HCI_VS) +void +ble_gap_vs_hci_event(const void *buf, uint8_t len) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_VS_HCI; + event.vs_hci.ev = buf; + event.vs_hci.length = len; + + ble_gap_event_listener_call(&event); +} +#endif /***************************************************************************** * $preempt * diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index 7810b691e..1133cd124 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -137,6 +137,7 @@ void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, void ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu); void ble_gap_identity_event(uint16_t conn_handle); int ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp); +void ble_gap_vs_hci_event(const void *buf, uint8_t len); int ble_gap_master_in_progress(void); void ble_gap_preempt(void); diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index fd599f668..ac0c26abe 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -362,6 +362,20 @@ done: return rc; } +#if MYNEWT_VAL(BLE_HCI_VS) +int +ble_hs_hci_send_vs_cmd(uint16_t ocf, const void *cmdbuf, uint8_t cmdlen, + void *rspbuf, uint8_t rsplen) +{ + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_VENDOR, ocf), + cmdbuf, cmdlen, rspbuf, rsplen); + + return rc; +} +#endif + static void ble_hs_hci_rx_ack(uint8_t *ack_ev) { diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 432298121..288a93611 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -64,6 +64,9 @@ static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change; static ble_hs_hci_evt_fn ble_hs_hci_evt_enc_key_refresh; #endif static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta; +#if MYNEWT_VAL(BLE_HCI_VS) +static ble_hs_hci_evt_fn ble_hs_hci_evt_vs; +#endif static ble_hs_hci_evt_fn ble_hs_hci_evt_rx_test; static ble_hs_hci_evt_fn ble_hs_hci_evt_tx_test; @@ -128,6 +131,9 @@ static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { { BLE_HCI_OCF_LE_TEST_END, ble_hs_hci_evt_end_test }, { BLE_HCI_OCF_LE_RX_TEST_V2, ble_hs_hci_evt_rx_test }, { BLE_HCI_OCF_LE_TX_TEST_V2, ble_hs_hci_evt_tx_test }, +#if MYNEWT_VAL(BLE_HCI_VS) + { BLE_HCI_EVCODE_VS, ble_hs_hci_evt_vs }, +#endif }; #define BLE_HS_HCI_EVT_DISPATCH_SZ \ @@ -357,6 +363,22 @@ ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, const void *data, return 0; } +#if MYNEWT_VAL(BLE_HCI_VS) +static int +ble_hs_hci_evt_vs(uint8_t event_code, const void *data, unsigned int len) +{ + const struct ble_hci_ev_vs *ev = data; + + if (len < sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_vs_hci_event(data, len); + + return 0; +} +#endif + static int ble_hs_hci_evt_rx_test(uint8_t event_code, const void *data, unsigned int len) {