From fbe93123a5a3a7e92d310e129e41b84b47ef1941 Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Tue, 2 Jun 2020 15:12:44 +0100 Subject: [PATCH] Add rf tester commands to cordio hci driver. This adds commands that allow you to send the HCI commands HCI_LE_Receiver_Test, HCI_LE_Transmitter_Test and HCI_LE_Test_End. The results of the test are obtained by the command complete command for HCI_LE_Test_End and passed to the user by the callback register in the test start calls. --- .../TARGET_CORDIO/driver/CordioHCIDriver.cpp | 77 +++++++++++++++++++ .../TARGET_CORDIO/driver/CordioHCIDriver.h | 46 +++++++++++ .../TARGET_CORDIO/source/CordioBLE.cpp | 17 ++++ 3 files changed, 140 insertions(+) diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.cpp index bdca48f634..70e5616cc1 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.cpp @@ -286,6 +286,83 @@ uint16_t CordioHCIDriver::write(uint8_t type, uint16_t len, uint8_t *pData) void CordioHCIDriver::on_host_stack_inactivity() { } +void CordioHCIDriver::handle_test_end(bool success, uint16_t packets) { + if (_test_end_handler) { + _test_end_handler(success, packets); + _test_end_handler = nullptr; + } +} + +ble_error_t CordioHCIDriver::rf_test_start_le_receiver_test( + test_end_handler_t test_end_handler, uint8_t channel +) +{ + if (_test_end_handler) { + return BLE_ERROR_INVALID_STATE; + } + + if (!test_end_handler) { + return BLE_ERROR_INVALID_PARAM; + } + + _test_end_handler = test_end_handler; + uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_RECEIVER_TEST, HCI_LEN_LE_RECEIVER_TEST); + + if (buf) { + uint8_t* p = buf + HCI_CMD_HDR_LEN; + UINT8_TO_BSTREAM(p, channel); + hciCmdSend(buf); + + return BLE_ERROR_NONE; + } + + return BLE_ERROR_NO_MEM; +} + +ble_error_t CordioHCIDriver::rf_test_start_le_transmitter_test( + test_end_handler_t test_end_handler, uint8_t channel, uint8_t length, uint8_t type +) +{ + if (_test_end_handler) { + return BLE_ERROR_INVALID_STATE; + } + + if (!test_end_handler) { + return BLE_ERROR_INVALID_PARAM; + } + + _test_end_handler = test_end_handler; + uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_TRANSMITTER_TEST, HCI_LEN_LE_TRANSMITTER_TEST); + + if (buf) { + uint8_t* p = buf + HCI_CMD_HDR_LEN; + UINT8_TO_BSTREAM(p, channel); + UINT8_TO_BSTREAM(p, length); + UINT8_TO_BSTREAM(p, type); + hciCmdSend(buf); + + return BLE_ERROR_NONE; + } + + return BLE_ERROR_NO_MEM; +} + +ble_error_t CordioHCIDriver::rf_test_end() +{ + if (!_test_end_handler) { + return BLE_ERROR_INVALID_STATE; + } + + uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_TEST_END, HCI_LEN_LE_TEST_END); + + if (buf) { + hciCmdSend(buf); + + return BLE_ERROR_NONE; + } + + return BLE_ERROR_NO_MEM; +} } // namespace cordio } // namespace vendor diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.h index e620748e49..e491e20335 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.h @@ -22,6 +22,8 @@ #include #include "wsf_buf.h" #include "CordioHCITransportDriver.h" +#include "ble/blecommon.h" +#include "mbed.h" namespace ble { namespace vendor { @@ -144,6 +146,47 @@ public: */ virtual void on_host_stack_inactivity(); + /* BLE Tester commands */ + + /** + * This will be called by host part of the stack to indicate the end of the test. + * + * @param success True if the TEST END command was a success. + * @param packets Number of packets received during the test. + * @return BLE_ERROR_NONE on success. + */ + void handle_test_end(bool success, uint16_t packets); + + /** Callback to inform the caller of the result of the test, the parameters are success and the + * number of packets received. + */ + typedef mbed::Callback test_end_handler_t; + + /** + * Start BLE receiver test. Call rf_test_end when you want to stop. + * @param test_end_handler Handler that will be called with the number of packets received. + * @param channel Channel to use. + * @return BLE_ERROR_NONE on success. + */ + ble_error_t rf_test_start_le_receiver_test(test_end_handler_t test_end_handler, uint8_t channel); + + /** + * Start BLE transmitter test. Call rf_test_end when you want to stop. + * @param test_end_handler Handler that will be called with status and the number of packets set to 0. + * @param channel Channel to use. + * @param length Size of payload. + * @param type Type of pattern to transmit @see BLE spec Volume 6 Part F, Section 4.1.5. + * @return BLE_ERROR_NONE on success. + */ + ble_error_t rf_test_start_le_transmitter_test(test_end_handler_t test_end_handler, uint8_t channel, + uint8_t length, uint8_t type); + + /** + * Complete the test. This will trigger the end test event which will call handle_test_end + * @return BLE_ERROR_NONE on success. + */ + ble_error_t rf_test_end(); + protected: /** * Return a default set of memory pool that the Cordio stack can use. @@ -170,6 +213,9 @@ private: */ virtual void do_terminate() = 0; +protected: + test_end_handler_t _test_end_handler; +private: CordioHCITransportDriver& _transport_driver; }; diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp index 5085bc29f0..89e9a66cab 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp @@ -34,6 +34,7 @@ #include "hci_drv.h" #include "CordioBLE.h" #include "mbed_assert.h" +#include "bstream.h" #include "CordioPalAttClient.h" #include "CordioPalSecurityManager.h" @@ -311,6 +312,22 @@ void BLE::processEvents() deviceInstance().initialization_status = INITIALIZED; _init_callback.call(&context); } break; +#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS + case DM_UNHANDLED_CMD_CMPL_EVT_IND: { + // upcast to unhandled command complete event to access the payload + hciUnhandledCmdCmplEvt_t* unhandled = (hciUnhandledCmdCmplEvt_t*)msg; + if (unhandled->hdr.status == HCI_SUCCESS && unhandled->hdr.param == HCI_OPCODE_LE_TEST_END) { + // unhandled events are not parsed so we need to parse the payload ourselves + uint8_t status; + uint16_t packet_number; + status = unhandled->param[0]; + BYTES_TO_UINT16(packet_number, unhandled->param + 1); + + _hci_driver->handle_test_end(status == 0, packet_number); + return; + } + } +#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS default: impl::PalGapImpl::gap_handler(msg);