diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 37ac79746..b132189a0 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -139,6 +139,7 @@ struct hci_conn_update; #define BLE_GAP_EVENT_TRANSMIT_POWER 26 #define BLE_GAP_EVENT_PARING_COMPLETE 27 #define BLE_GAP_EVENT_SUBRATE_CHANGE 28 +#define BLE_GAP_EVENT_VS_HCI 29 /*** Reason codes for the subscribe GAP event. */ @@ -1071,6 +1072,19 @@ struct ble_gap_event { uint16_t supervision_tmo; } subrate_change; #endif + +#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 739eea926..237712080 100644 --- a/nimble/host/include/host/ble_hs_hci.h +++ b/nimble/host/include/host/ble_hs_hci.h @@ -102,6 +102,24 @@ int ble_hs_hci_set_chan_class(const uint8_t *chan_map); */ int ble_hs_hci_rand(void *dst, int len); +#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 952b59b0a..f72689950 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -6083,6 +6083,21 @@ ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu) #endif } +#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 0e4947f15..5b627d105 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -138,6 +138,7 @@ 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_pairing_complete_event(uint16_t conn_handle, int status); +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 0624e387d..af61b5454 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -349,6 +349,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 f7113f631..9437e755c 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -38,6 +38,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 typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, const void *data, unsigned int len); @@ -93,6 +96,9 @@ static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { { BLE_HCI_EVCODE_ENC_KEY_REFRESH, ble_hs_hci_evt_enc_key_refresh }, #endif { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error }, +#if MYNEWT_VAL(BLE_HCI_VS) + { BLE_HCI_EVCODE_VS, ble_hs_hci_evt_vs }, +#endif }; #define BLE_HS_HCI_EVT_DISPATCH_SZ \ @@ -274,6 +280,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_le_meta(uint8_t event_code, const void *data, unsigned int len) {