From 396f1e6ebdd3f4050d24e567ece7e3bc6421a0eb Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 14 Nov 2023 13:40:35 +0530 Subject: [PATCH] Add support for dtm related functions --- nimble/host/include/host/ble_esp_gap.h | 4 ++ nimble/host/include/host/ble_gap.h | 96 ++++++++++++++++++++++++++ nimble/host/src/ble_gap.c | 90 ++++++++++++++++++++++++ nimble/host/src/ble_hs_hci.c | 11 +++ nimble/host/src/ble_hs_hci_evt.c | 42 ++++++++++- nimble/host/src/ble_hs_hci_priv.h | 8 +++ nimble/host/src/ble_hs_hci_util.c | 69 ++++++++++++++++++ 7 files changed, 319 insertions(+), 1 deletion(-) diff --git a/nimble/host/include/host/ble_esp_gap.h b/nimble/host/include/host/ble_esp_gap.h index 47bcb3e0e..64aa1104d 100644 --- a/nimble/host/include/host/ble_esp_gap.h +++ b/nimble/host/include/host/ble_esp_gap.h @@ -197,6 +197,10 @@ int ble_gap_set_chan_select(uint8_t select); #endif +void ble_gap_rx_test_evt(const void *buf, uint8_t len); +void ble_gap_tx_test_evt(const void *buf, uint8_t len); +void ble_gap_end_test_evt(const void *buf, uint8_t len); + #ifdef __cplusplus } #endif diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 2e0fbc4ba..e1578e80d 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -159,6 +159,13 @@ struct hci_conn_update; #define BLE_GAP_EVENT_BIGINFO_REPORT 30 #define BLE_GAP_EVENT_REATTEMPT_COUNT 31 #define BLE_GAP_EVENT_AUTHORIZE 32 +#define BLE_GAP_EVENT_TEST_UPDATE 33 + + +/* DTM events */ +#define BLE_GAP_DTM_TX_START_EVT 0 +#define BLE_GAP_DTM_RX_START_EVT 1 +#define BLE_GAP_DTM_END_EVT 2 /*** Reason codes for the subscribe GAP event. */ @@ -1212,6 +1219,30 @@ struct ble_gap_event { uint8_t count; } reattempt_cnt; #endif + /** + * Represent a event for DTM test results + * + * Valid for the following event types: + * o BLE_GAP_EVENT_TEST_UPDATE + */ + struct { + /* Indicate DTM operation status */ + uint8_t status; + + /* DTM state change event. Can be following constants: + * o BLE_GAP_DTM_TX_START_EVT + * o BLE_GAP_DTM_RX_START_EVT + * o BLE_GAP_DTM_END_EVT + */ + uint8_t update_evt; + + /* Number of packets received. + * + * Valid only for BLE_GAP_DTM_END_EVT + * shall be 0 for a transmitter. + */ + uint8_t num_pkt; + } dtm_state; }; }; @@ -2740,6 +2771,71 @@ int ble_gap_set_path_loss_reporting_param(uint16_t conn_handle, uint8_t high_thr */ int ble_gap_set_data_related_addr_change_param(uint8_t adv_handle, uint8_t change_reason); +/** + * Start a test where the DUT generates reference packets at a fixed interval. + * + * @param tx_chan Channel for sending test data, + * tx_channel = (Frequency -2402)/2, tx_channel range = 0x00-0x27, + * Frequency range = 2402 MHz to 2480 MHz. + * + * @param test_data_len Length in bytes of payload data in each packet + * @param payload Packet Payload type. Valid range: 0x00 - 0x07 + * + * @return 0 on success; nonzero on failure + */ + +int ble_gap_dtm_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload); + +/** + * Start a test where the DUT receives test reference packets at a fixed interval. + * + * @param rx_chan Channel for test data reception, + * rx_channel = (Frequency -2402)/2, tx_channel range = 0x00-0x27, + * Frequency range = 2402 MHz to 2480 MHz. + * + * @return 0 on success; nonzero on failure + */ + +int ble_gap_dtm_rx_start(uint8_t rx_chan); + +/** + * Stop any test which is in progress + * + * @return 0 on success; nonzero on failure + */ + +int ble_gap_dtm_stop(void); + +/** + * Start a test where the DUT generates reference packets at a fixed interval. + * + * @param tx_chan Channel for sending test data, + * tx_channel = (Frequency -2402)/2, tx_channel range = 0x00-0x27, + * Frequency range: 2402 MHz to 2480 MHz + * + * @param test_data_len Length in bytes of payload data in each packet + * @param payload Packet payload type. Valid range: 0x00 - 0x07 + * @param phy Phy used by transmitter 1M phy: 0x01, 2M phy:0x02, coded phy:0x03. + * + * @return 0 on sucess; nonzero on failure + */ +int ble_gap_dtm_enh_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload, + uint8_t phy); + +/** + * Start a test where the DUT receives test reference packets at fixed interval + * + * @param rx_chan Channel for test data reception, + * rx_channel = (Frequency -2402)/2, tx_channel range = 0x00-0x27, + * Frequency range: 2402 MHz to 2480 MHz + * + * @param index modulation index, 0x00:standard modulation index, 0x01:stable modulation index + * @param phy Phy type used by the receiver, 1M phy: 0x01, 2M phy:0x02, coded phy:0x03 + * + * @return 0 on success; nonzero on failure + */ +int ble_gap_dtm_enh_rx_start(uint8_t rx_chan, uint8_t index, uint8_t phy); + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 4fb803c9e..1791063e6 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -7153,6 +7153,65 @@ ble_gap_authorize_event(uint16_t conn_handle, uint16_t attr_handle, return BLE_GAP_AUTHORIZE_REJECT; } +void +ble_gap_rx_test_evt(const void *buf, uint8_t len) +{ + struct ble_gap_event event; + struct ble_hci_ev_command_complete *cmd_complete = (void *) buf; + uint8_t status; + + status = cmd_complete->status; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_TEST_UPDATE; + event.dtm_state.status = status ; + event.dtm_state.update_evt = BLE_GAP_DTM_RX_START_EVT; + event.dtm_state.num_pkt = 0; + + ble_gap_event_listener_call(&event); +} + +void +ble_gap_tx_test_evt(const void *buf, uint8_t len) +{ + struct ble_gap_event event; + struct ble_hci_ev_command_complete *cmd_complete = (void *) buf; + uint8_t status; + + status = cmd_complete->status; + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_TEST_UPDATE; + event.dtm_state.status = status ; + event.dtm_state.update_evt = BLE_GAP_DTM_TX_START_EVT; + event.dtm_state.num_pkt = 0; + + ble_gap_event_listener_call(&event); +} + +void +ble_gap_end_test_evt(const void *buf, uint8_t len) +{ + struct ble_gap_event event; + struct ble_hci_ev_command_complete *cmd_complete = (void *) buf; + uint8_t status, *ptr; + uint16_t num_pkt; + + status = cmd_complete->status; + ptr = (uint8_t *)cmd_complete->return_params; + + num_pkt = htole16(*ptr); + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_TEST_UPDATE; + event.dtm_state.status = status ; + event.dtm_state.update_evt = BLE_GAP_DTM_END_EVT; + event.dtm_state.num_pkt = num_pkt; + + ble_gap_event_listener_call(&event); +} + /***************************************************************************** * $preempt * *****************************************************************************/ @@ -7665,6 +7724,37 @@ ble_gap_set_data_related_addr_change_param(uint8_t adv_handle, uint8_t change_re return ble_hs_hci_util_set_data_addr_change(adv_handle, change_reason); } +int +ble_gap_dtm_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload) +{ + return ble_hs_hci_dtm_tx_start(tx_chan, test_data_len, payload); +} + +int +ble_gap_dtm_rx_start(uint8_t rx_chan) +{ + return ble_hs_hci_dtm_rx_start(rx_chan); +} + +int +ble_gap_dtm_stop(void) +{ + return ble_hs_hci_dtm_stop(); +} + +int +ble_gap_dtm_enh_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload, + uint8_t phy) +{ + return ble_hs_hci_dtm_enh_tx_start(tx_chan, test_data_len, payload, phy); +} + +int +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); +} + void ble_gap_deinit(void) { diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index c50b61321..c77b1c2ac 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -400,6 +400,17 @@ ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg) switch (ev->opcode) { case BLE_HCI_EVCODE_COMMAND_COMPLETE: enqueue = (cmd_complete->opcode == BLE_HCI_OPCODE_NOP); + + /* Check for BLE transmit opcodes which come in command complete */ + switch(cmd_complete->opcode) { + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RX_TEST): + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TX_TEST): + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TEST_END): + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RX_TEST_V2): + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TX_TEST_V2): + enqueue = 1; + break; + } break; case BLE_HCI_EVCODE_COMMAND_STATUS: enqueue = (cmd_status->opcode == BLE_HCI_OPCODE_NOP); diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index b9088dc55..f14a4f1d7 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -67,6 +67,10 @@ static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta; 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; +static ble_hs_hci_evt_fn ble_hs_hci_evt_end_test; + typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, const void *data, unsigned int len); static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_adv_rpt; @@ -127,6 +131,11 @@ static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { #if MYNEWT_VAL(BLE_HCI_VS) { BLE_HCI_EVCODE_VS, ble_hs_hci_evt_vs }, #endif + { BLE_HCI_OCF_LE_RX_TEST, ble_hs_hci_evt_rx_test }, + { BLE_HCI_OCF_LE_TX_TEST, ble_hs_hci_evt_tx_test }, + { 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 }, }; #define BLE_HS_HCI_EVT_DISPATCH_SZ \ @@ -410,6 +419,30 @@ ble_hs_hci_evt_vs(uint8_t event_code, const void *data, unsigned int len) } #endif +static int +ble_hs_hci_evt_rx_test(uint8_t event_code, const void *data, unsigned int len) +{ + ble_gap_rx_test_evt(data, len); + + return 0; +} + +static int +ble_hs_hci_evt_tx_test(uint8_t event_code, const void *data, unsigned int len) +{ + ble_gap_tx_test_evt(data, len); + + return 0; +} + +static int +ble_hs_hci_evt_end_test(uint8_t event_code, const void *data, unsigned int len) +{ + ble_gap_end_test_evt(data, len); + + return 0; +} + static int ble_hs_hci_evt_le_meta(uint8_t event_code, const void *data, unsigned int len) { @@ -1066,8 +1099,15 @@ ble_hs_hci_evt_process(struct ble_hci_ev *ev) /* Count events received */ STATS_INC(ble_hs_stats, hci_event); + 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); + } + else { + entry = ble_hs_hci_evt_dispatch_find(ev->opcode); + } - entry = ble_hs_hci_evt_dispatch_find(ev->opcode); if (entry == NULL) { STATS_INC(ble_hs_stats, hci_unknown_event); rc = BLE_HS_ENOTSUP; diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 693154103..ab862dc54 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -126,6 +126,14 @@ int ble_hs_hci_frag_num_mbufs(void); int ble_hs_hci_frag_num_mbufs_free(void); int ble_hs_hci_util_set_data_addr_change(uint8_t adv_handle, uint8_t change_reason); + +int ble_hs_hci_dtm_tx_start(uint8_t tx_chan, uint8_t test_data_len, uint8_t payload); +int ble_hs_hci_dtm_rx_start(uint8_t rx_chan); +int ble_hs_hci_dtm_enh_rx_start(uint8_t rx_chan, uint8_t index, uint8_t phy); +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); + #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_hs_hci_util.c b/nimble/host/src/ble_hs_hci_util.c index 7154632d9..573b44252 100644 --- a/nimble/host/src/ble_hs_hci_util.c +++ b/nimble/host/src/ble_hs_hci_util.c @@ -291,3 +291,72 @@ ble_hs_hci_util_set_data_addr_change(uint8_t adv_handle, uint8_t change_reason) return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); } + +int +ble_hs_hci_dtm_tx_start(const uint8_t tx_chan, const uint8_t test_data_len, + const uint8_t payload) +{ + struct ble_hci_le_tx_test_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TX_TEST); + + cmd.tx_chan = tx_chan; + cmd.test_data_len = test_data_len; + cmd.payload = payload; + + return ble_hs_hci_cmd_tx_no_rsp(opcode, &cmd, sizeof(cmd)); +} + +int +ble_hs_hci_dtm_rx_start(const uint8_t rx_chan) +{ + struct ble_hci_le_rx_test_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RX_TEST); + + cmd.rx_chan = rx_chan; + + return ble_hs_hci_cmd_tx_no_rsp(opcode, &cmd, sizeof(cmd)); +} + +int +ble_hs_hci_dtm_stop(void) +{ + return ble_hs_hci_cmd_tx_no_rsp(BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TEST_END), + NULL, 0); +} + +int +ble_hs_hci_dtm_enh_tx_start(const uint8_t tx_chan, const uint8_t test_data_len, + const uint8_t payload, const uint8_t phy) +{ + struct ble_hci_le_tx_test_v2_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TX_TEST_V2); + + cmd.tx_chan = tx_chan; + cmd.test_data_len = test_data_len; + cmd.payload = payload; + cmd.phy = phy; + + return ble_hs_hci_cmd_tx_no_rsp(opcode, &cmd, sizeof(cmd)); +} + +int +ble_hs_hci_dtm_enh_rx_start(const uint8_t rx_chan, const uint8_t index, + const uint8_t phy) +{ + struct ble_hci_le_rx_test_v2_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RX_TEST_V2); + + cmd.rx_chan = rx_chan; + cmd.index = index; + cmd.phy = phy; + + return ble_hs_hci_cmd_tx_no_rsp(opcode, &cmd, sizeof(cmd)); +}