Skip to content

Commit 6a431ff

Browse files
authored
Merge pull request #13055 from paul-szczepanek-arm/cordio-rf-tester
BLE: RF tester commands (and Cordio unhandled command complete)
2 parents d971d4e + a882d2d commit 6a431ff

File tree

10 files changed

+230
-1
lines changed

10 files changed

+230
-1
lines changed

features/FEATURE_BLE/targets/TARGET_CORDIO/doc/HCIAbstraction.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,7 @@ A partial implementation is present in the file
4242
delivering memory to the stack and a complete reset sequence. However, it does
4343
not define any initialization for the Bluetooth controller, this part being
4444
specific to the controller used.
45+
46+
The driver also provides an interface to perform RF testing on the BLE trasnmitter.
47+
This is done using the LE Receiver/Transmitter Test command and LE Test End command
48+
as described in the Bluetooth Core spec in Vol.2, Part E, 7.8.28-30.

features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,83 @@ uint16_t CordioHCIDriver::write(uint8_t type, uint16_t len, uint8_t *pData)
286286
void CordioHCIDriver::on_host_stack_inactivity()
287287
{
288288
}
289+
void CordioHCIDriver::handle_test_end(bool success, uint16_t packets) {
290+
if (_test_end_handler) {
291+
_test_end_handler(success, packets);
292+
_test_end_handler = nullptr;
293+
}
294+
}
295+
296+
ble_error_t CordioHCIDriver::rf_test_start_le_receiver_test(
297+
test_end_handler_t test_end_handler, uint8_t channel
298+
)
299+
{
300+
if (_test_end_handler) {
301+
return BLE_ERROR_INVALID_STATE;
302+
}
303+
304+
if (!test_end_handler) {
305+
return BLE_ERROR_INVALID_PARAM;
306+
}
307+
308+
_test_end_handler = test_end_handler;
309+
uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_RECEIVER_TEST, HCI_LEN_LE_RECEIVER_TEST);
310+
311+
if (buf) {
312+
uint8_t* p = buf + HCI_CMD_HDR_LEN;
313+
UINT8_TO_BSTREAM(p, channel);
314+
hciCmdSend(buf);
315+
316+
return BLE_ERROR_NONE;
317+
}
318+
319+
return BLE_ERROR_NO_MEM;
320+
}
321+
322+
ble_error_t CordioHCIDriver::rf_test_start_le_transmitter_test(
323+
test_end_handler_t test_end_handler, uint8_t channel, uint8_t length, uint8_t type
324+
)
325+
{
326+
if (_test_end_handler) {
327+
return BLE_ERROR_INVALID_STATE;
328+
}
329+
330+
if (!test_end_handler) {
331+
return BLE_ERROR_INVALID_PARAM;
332+
}
333+
334+
_test_end_handler = test_end_handler;
335+
uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_TRANSMITTER_TEST, HCI_LEN_LE_TRANSMITTER_TEST);
336+
337+
if (buf) {
338+
uint8_t* p = buf + HCI_CMD_HDR_LEN;
339+
UINT8_TO_BSTREAM(p, channel);
340+
UINT8_TO_BSTREAM(p, length);
341+
UINT8_TO_BSTREAM(p, type);
342+
hciCmdSend(buf);
343+
344+
return BLE_ERROR_NONE;
345+
}
346+
347+
return BLE_ERROR_NO_MEM;
348+
}
349+
350+
ble_error_t CordioHCIDriver::rf_test_end()
351+
{
352+
if (!_test_end_handler) {
353+
return BLE_ERROR_INVALID_STATE;
354+
}
355+
356+
uint8_t *buf = hciCmdAlloc(HCI_OPCODE_LE_TEST_END, HCI_LEN_LE_TEST_END);
357+
358+
if (buf) {
359+
hciCmdSend(buf);
360+
361+
return BLE_ERROR_NONE;
362+
}
363+
364+
return BLE_ERROR_NO_MEM;
365+
}
289366

290367
} // namespace cordio
291368
} // namespace vendor

features/FEATURE_BLE/targets/TARGET_CORDIO/driver/CordioHCIDriver.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <BLETypes.h>
2323
#include "wsf_buf.h"
2424
#include "CordioHCITransportDriver.h"
25+
#include "ble/blecommon.h"
26+
#include "mbed.h"
2527

2628
namespace ble {
2729
namespace vendor {
@@ -144,6 +146,47 @@ class CordioHCIDriver {
144146
*/
145147
virtual void on_host_stack_inactivity();
146148

149+
/* BLE Tester commands */
150+
151+
/**
152+
* This will be called by host part of the stack to indicate the end of the test.
153+
*
154+
* @param success True if the TEST END command was a success.
155+
* @param packets Number of packets received during the test.
156+
* @return BLE_ERROR_NONE on success.
157+
*/
158+
void handle_test_end(bool success, uint16_t packets);
159+
160+
/** Callback to inform the caller of the result of the test, the parameters are success and the
161+
* number of packets received.
162+
*/
163+
typedef mbed::Callback<void(bool, uint16_t)> test_end_handler_t;
164+
165+
/**
166+
* Start BLE receiver test. Call rf_test_end when you want to stop.
167+
* @param test_end_handler Handler that will be called with the number of packets received.
168+
* @param channel Channel to use.
169+
* @return BLE_ERROR_NONE on success.
170+
*/
171+
ble_error_t rf_test_start_le_receiver_test(test_end_handler_t test_end_handler, uint8_t channel);
172+
173+
/**
174+
* Start BLE transmitter test. Call rf_test_end when you want to stop.
175+
* @param test_end_handler Handler that will be called with status and the number of packets set to 0.
176+
* @param channel Channel to use.
177+
* @param length Size of payload.
178+
* @param type Type of pattern to transmit @see BLE spec Volume 6 Part F, Section 4.1.5.
179+
* @return BLE_ERROR_NONE on success.
180+
*/
181+
ble_error_t rf_test_start_le_transmitter_test(test_end_handler_t test_end_handler, uint8_t channel,
182+
uint8_t length, uint8_t type);
183+
184+
/**
185+
* Complete the test. This will trigger the end test event which will call handle_test_end
186+
* @return BLE_ERROR_NONE on success.
187+
*/
188+
ble_error_t rf_test_end();
189+
147190
protected:
148191
/**
149192
* Return a default set of memory pool that the Cordio stack can use.
@@ -170,6 +213,9 @@ class CordioHCIDriver {
170213
*/
171214
virtual void do_terminate() = 0;
172215

216+
protected:
217+
test_end_handler_t _test_end_handler;
218+
private:
173219
CordioHCITransportDriver& _transport_driver;
174220
};
175221

features/FEATURE_BLE/targets/TARGET_CORDIO/mbed_lib.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
"help": "Where the CBC MAC calculatio is performed. Valid values are 0 (host) and 1 (controller through HCI).",
6464
"value": 1,
6565
"macro_name": "SEC_CCM_CFG"
66+
},
67+
"route_unhandled_command_complete_events": {
68+
"help": "If enabled the stack will forward to the user all HCI events not handled by the stack.",
69+
"value": 1
6670
}
6771
}
6872
}

features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "hci_drv.h"
3535
#include "CordioBLE.h"
3636
#include "mbed_assert.h"
37+
#include "bstream.h"
3738

3839
#include "CordioPalAttClient.h"
3940
#include "CordioPalSecurityManager.h"
@@ -311,6 +312,22 @@ void BLE::processEvents()
311312
deviceInstance().initialization_status = INITIALIZED;
312313
_init_callback.call(&context);
313314
} break;
315+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
316+
case DM_UNHANDLED_CMD_CMPL_EVT_IND: {
317+
// upcast to unhandled command complete event to access the payload
318+
hciUnhandledCmdCmplEvt_t* unhandled = (hciUnhandledCmdCmplEvt_t*)msg;
319+
if (unhandled->hdr.status == HCI_SUCCESS && unhandled->hdr.param == HCI_OPCODE_LE_TEST_END) {
320+
// unhandled events are not parsed so we need to parse the payload ourselves
321+
uint8_t status;
322+
uint16_t packet_number;
323+
status = unhandled->param[0];
324+
BYTES_TO_UINT16(packet_number, unhandled->param + 1);
325+
326+
_hci_driver->handle_test_end(status == 0, packet_number);
327+
return;
328+
}
329+
}
330+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
314331

315332
default:
316333
impl::PalGapImpl::gap_handler(msg);

features/FEATURE_BLE/targets/TARGET_CORDIO/stack/ble-host/include/dm_api.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,9 @@ enum
511511
DM_ERROR_IND, /*!< \brief General error */
512512
DM_HW_ERROR_IND, /*!< \brief Hardware error */
513513
DM_VENDOR_SPEC_IND /*!< \brief Vendor specific event */
514+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
515+
, DM_UNHANDLED_CMD_CMPL_EVT_IND, /*!< \brief Unhandled command complete events */
516+
#endif
514517
};
515518

516519
#define DM_CBACK_END DM_VENDOR_SPEC_IND /*!< \brief DM callback event ending value */
@@ -763,6 +766,9 @@ typedef union
763766
hciLeConnCteRspEnableCmdCmplEvt_t connCteRspStart; /*!< \brief handles \ref DM_CONN_CTE_RSP_START_IND */
764767
hciLeConnCteRspEnableCmdCmplEvt_t connCteRspStop; /*!< \brief handles \ref DM_CONN_CTE_RSP_STOP_IND */
765768
hciLeReadAntennaInfoCmdCmplEvt_t readAntennaInfo; /*!< \brief handles \ref DM_READ_ANTENNA_INFO_IND */
769+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
770+
hciUnhandledCmdCmplEvt_t unhandledCmdCmplEvt;
771+
#endif
766772
dmL2cCmdRejEvt_t l2cCmdRej; /*!< \brief handles \ref DM_L2C_CMD_REJ_IND */
767773
/* common header used by DM_ERROR_IND */
768774
hciHwErrorEvt_t hwError; /*!< \brief handles \ref DM_HW_ERROR_IND */

features/FEATURE_BLE/targets/TARGET_CORDIO/stack/ble-host/include/hci_api.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ extern "C" {
115115
#define HCI_CIS_EST_CBACK_EVT 68 /*!< \brief CIS established event */
116116
#define HCI_CIS_REQ_CBACK_EVT 69 /*!< \brief CIS request event */
117117
#define HCI_REQ_PEER_SCA_CBACK_EVT 70 /*!< \brief Request peer SCA complete */
118+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
119+
#define HCI_UNHANDLED_CMD_CMPL_CBACK_EVT 71 /*!< \brief Unhandled event */
120+
#endif
118121
/**@}*/
119122

120123
/**************************************************************************************************
@@ -679,6 +682,15 @@ typedef struct
679682
uint8_t cteMaxLen; /*!< \brief Max CTE Length. */
680683
} hciLeReadAntennaInfoCmdCmplEvt_t;
681684

685+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
686+
/*! \brief LE read antenna information command complete event */
687+
typedef struct
688+
{
689+
wsfMsgHdr_t hdr; /*!< \brief Event header containing the opcode in hdr.param. */
690+
uint8_t param[1]; /*!< \brief Unhandled event payload. */
691+
} hciUnhandledCmdCmplEvt_t;
692+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
693+
682694
/*! \brief Local version information */
683695
typedef struct
684696
{
@@ -754,6 +766,9 @@ typedef union
754766
hciLeConnCteReqEnableCmdCmplEvt_t leConnCteReqEnableCmdCmpl; /*!< \brief LE connection CTE request enable command complete. */
755767
hciLeConnCteRspEnableCmdCmplEvt_t leConnCteRspEnableCmdCmpl; /*!< \brief LE connection CTE response enable command complete. */
756768
hciLeReadAntennaInfoCmdCmplEvt_t leReadAntennaInfoCmdCmpl; /*!< \brief LE read antenna information command complete. */
769+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
770+
hciUnhandledCmdCmplEvt_t unhandledCmdCmpl; /*!< \brief Unhandled events. */
771+
#endif
757772
} hciEvt_t;
758773

759774
/*! \} */ /* STACK_HCI_EVT_API */

features/FEATURE_BLE/targets/TARGET_CORDIO/stack/ble-host/sources/hci/dual_chip/hci_evt.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,13 +2048,42 @@ void hciEvtProcessCmdCmpl(uint8_t *p, uint8_t len)
20482048
{
20492049
cbackEvt = hciCoreVsCmdCmplRcvd(opcode, p, len);
20502050
}
2051+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
2052+
else
2053+
{
2054+
cbackEvt = HCI_UNHANDLED_CMD_CMPL_CBACK_EVT;
2055+
}
2056+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
20512057
break;
20522058
}
20532059

20542060
/* if callback is executed for this event */
20552061
if (cbackEvt != 0)
20562062
{
20572063
/* allocate temp buffer */
2064+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
2065+
if (cbackEvt == HCI_UNHANDLED_CMD_CMPL_CBACK_EVT) {
2066+
const uint8_t structSize = sizeof(hciUnhandledCmdCmplEvt_t) - 1 /* removing the fake 1-byte array */;
2067+
const uint8_t remainingLen = len - 3 /* we already read opcode and numPkts */;
2068+
const uint8_t msgSize = structSize + remainingLen;
2069+
2070+
pMsg = WsfBufAlloc(msgSize);
2071+
if (pMsg != NULL) {
2072+
pMsg->hdr.param = opcode;
2073+
pMsg->hdr.event = HCI_UNHANDLED_CMD_CMPL_CBACK_EVT;
2074+
pMsg->hdr.status = HCI_SUCCESS;
2075+
/* copy the payload */
2076+
memcpy(pMsg->unhandledCmdCmpl.param, p, remainingLen);
2077+
2078+
/* execute callback */
2079+
(*cback)(pMsg);
2080+
2081+
/* free buffer */
2082+
WsfBufFree(pMsg);
2083+
}
2084+
}
2085+
else
2086+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
20582087
if ((pMsg = WsfBufAlloc(hciEvtCbackLen[cbackEvt])) != NULL)
20592088
{
20602089
/* initialize message header */

features/FEATURE_BLE/targets/TARGET_CORDIO/stack/ble-host/sources/stack/dm/dm_dev.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,23 @@ static void dmDevHciEvtHwError(hciEvt_t *pEvent)
128128
(*dmCb.cback)((dmEvt_t *) pEvent);
129129
}
130130

131+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
132+
/*************************************************************************************************/
133+
/*!
134+
* \brief Handle unhandled command complete events from HCI.
135+
*
136+
* \param pEvent Pointer to HCI callback event structure.
137+
*
138+
* \return None.
139+
*/
140+
/*************************************************************************************************/
141+
static void dmDevHciEvtUnhandledCmdCmpl(hciEvt_t *pEvent)
142+
{
143+
pEvent->hdr.event = DM_UNHANDLED_CMD_CMPL_EVT_IND;
144+
(*dmCb.cback)((dmEvt_t *) pEvent);
145+
}
146+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
147+
131148
/*************************************************************************************************/
132149
/*!
133150
* \brief DM dev HCI event handler.
@@ -153,6 +170,12 @@ void dmDevHciHandler(hciEvt_t *pEvent)
153170
dmDevHciEvtHwError(pEvent);
154171
break;
155172

173+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
174+
case HCI_UNHANDLED_CMD_CMPL_CBACK_EVT:
175+
dmDevHciEvtUnhandledCmdCmpl(pEvent);
176+
break;
177+
#endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
178+
156179
default:
157180
/* ignore event */
158181
break;

features/FEATURE_BLE/targets/TARGET_CORDIO/stack/ble-host/sources/stack/dm/dm_main.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ static const uint8_t dmHciToIdTbl[] =
107107
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_REQ_ENABLE_CMD_CMPL_CBACK_EVT */
108108
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_RSP_ENABLE_CMD_CMPL_CBACK_EVT */
109109
DM_ID_CONN_CTE /* HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT */
110+
#if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS
111+
/* these 3 were inexplicably missing */
112+
, DM_ID_DEV /* HCI_CIS_EST_CBACK_EVT */
113+
, DM_ID_DEV /* HCI_CIS_REQ_CBACK_EVT */
114+
, DM_ID_DEV /* HCI_REQ_PEER_SCA_CBACK_EVT */
115+
116+
, DM_ID_DEV /* HCI_UNHANDLED_CMD_COMPL_CBACK_EVT */
117+
#endif
110118
};
111119

112120
/* DM callback event length table */
@@ -230,7 +238,7 @@ dmCb_t dmCb;
230238
/*************************************************************************************************/
231239
static void dmHciEvtCback(hciEvt_t *pEvent)
232240
{
233-
WSF_ASSERT(pEvent->hdr.event <= HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT);
241+
WSF_ASSERT(pEvent->hdr.event < sizeof(dmHciToIdTbl));
234242

235243
/* if DM not resetting or resetting but incoming event is HCI reset sequence complete event */
236244
if (!dmCb.resetting || (pEvent->hdr.event == HCI_RESET_SEQ_CMPL_CBACK_EVT))

0 commit comments

Comments
 (0)