HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41/KW35/KW36/QN9080 BLE radio part. It enables the user to have a way to control the radio through serial commands. The format of the HCI Command Packet it’s composed of the following parts:
Each command is assigned a 2 byte Opcode which it’s divided into two fields, called the OpCode Group Field (OGF) and OpCode Command Field (OCF). The OGF uses the upper 6 bits of the Opcode, while the OCF corresponds to the remaining 10 bits. The OGF of 0x3F is reserved for vendor-specific debug commands. The organization of the opcodes allows additional information to be inferred without fully decoding the entire Opcode. For further information regarding this topic, please check the BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E, 5.4 EXCHANGE OF HCI-SPECIFIC INFORMATION.
This document will guide you through the implementation of custom HCI commands in the KW36. For this example, we will include the following set of custom commands:
The changes described in the following sections were based on the HCI Black Box SDK example (it is located at wireless_examples -> bluetooth -> hci_bb)
The "hci_transport.h" file is located at bluetooth->hci_transport->interface folder.
Include the following macros in ''Public constants and macros"
#define gHciCustomCommandOpcodeUpper (0xFC50)
#define gHciCustomCommandOpcodeLower (0xFC00)
#define gHciInCustomVendorCommandsRange(x) (((x) <= gHciCustomCommandOpcodeUpper) && \
((x) >= gHciCustomCommandOpcodeLower))
Declare a function to install the custom command as follows:
void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler);
The "hci_transport.h" file is located at bluetooth->hci_transport->source folder.
Add the following in "Private memory declarations"
static hciTransportInterface_t mCustomTransportInterface = NULL;
Modify the Hcit_SendMessage function as follows:
static inline void Hcit_SendMessage(void)
{
uint16_t opcode = 0;
/* verify if this is an event packet */
if(mHcitData.pktHeader.packetTypeMarker == gHciEventPacket_c)
{
/* verify if this is a command complete event */
if(mHcitData.pPacket->raw[0] == gHciCommandCompleteEvent_c)
{
/* extract the first opcode to verify if it is a custom command */
opcode = mHcitData.pPacket->raw[3] | (mHcitData.pPacket->raw[4] << 8);
}
}
/* verify if command packet */
else if(mHcitData.pktHeader.packetTypeMarker == gHciCommandPacket_c)
{
/* extract opcode */
opcode = mHcitData.pPacket->raw[0] | (mHcitData.pPacket->raw[1] << 8);
}
if(gHciInCustomVendorCommandsRange(opcode))
{
if(mCustomTransportInterface)
{
mCustomTransportInterface( mHcitData.pktHeader.packetTypeMarker,
mHcitData.pPacket,
mHcitData.bytesReceived);
}
}
else
{
/* Send the message to HCI */
(void)mTransportInterface(mHcitData.pktHeader.packetTypeMarker,
mHcitData.pPacket,
mHcitData.bytesReceived);
}
mHcitData.pPacket = NULL;
mPacketDetectStep = mDetectMarker_c;
}
Develop the function to install the custom command as follows:
void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler)
{
OSA_InterruptDisable();
mCustomTransportInterface = mCustomInterfaceHandler;
OSA_InterruptEnable();
}
This is the main application file, and it is located at source folder.
Include the following files to support our HCI custom commands
#include "hci_transport.h"
#include "fsl_xcvr.h"
Define the following macros which represent the opcode for each custom command
#define CUSTOM_HCI_CW_ON (0xFC50)
#define CUSTOM_HCI_CW_OFF (0xFC4F)
#define CUSTOM_HCI_CW_SET_CHN_0 (0xFC00) /*Channel 0 Freq 2402 MHz*/
#define CUSTOM_HCI_CW_SET_CHN_19 (0xFC01) /*Channel 19 Freq 2440 MHz*/
#define CUSTOM_HCI_CW_SET_CHN_39 (0xFC02) /*Channel 39 Freq 2480 MHz*/
#define CUSTOM_HCI_CW_SET_PA_PWR_1 (0xFC10) /*PA_POWER 1 */
#define CUSTOM_HCI_CW_SET_PA_PWR_32 (0xFC11) /*PA_POWER 32 */
#define CUSTOM_HCI_CW_SET_PA_PWR_62 (0xFC12) /*PA_POWER 62 */
#define CUSTOM_HCI_CW_EVENT_SIZE (0x04)
#define CUSTOM_HCI_EVENT_SUCCESS (0x00)
#define CUSTOM_HCI_EVENT_FAIL (0x01)
Add the following application variables
static uint16_t channelCC = 2402;
static uint8_t powerCC = 0x3E;
uint8_t eventPacket[6] = {gHciCommandCompleteEvent_c, CUSTOM_HCI_CW_EVENT_SIZE, 1, 0, 0, 0 };
Declare the handler for our custom commands
bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize);
Find the "main_task" function, and register the handler for the custom commands through "Hcit_InstallCustomCommandHandler" function. You can include it just after BleApp_Init();
/* Initialize peripheral drivers specific to the application */
BleApp_Init();
/* Register the callback for the custom commands */
Hcit_InstallCustomCommandHandler((hciTransportInterface_t)&BleApp_CustomCommandsHandle);
/* Create application event */
mAppEvent = OSA_EventCreate(TRUE);
if( NULL == mAppEvent )
{
panic(0,0,0,0);
return;
}
Develop the handler of our custom commands as follows:
bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize)
{
uint16_t opcode = 0;
if(gHciCommandPacket_c == packetType)
{
opcode = ((uint8_t*)pPacket)[0] | (((uint8_t*)pPacket)[1] << 8);
switch(opcode)
{
/*@CC: Set Channel */
case CUSTOM_HCI_CW_SET_CHN_0:
/*@CC: Set Channel 0 Freq 2402 MHz */
channelCC=2402;
break;
case CUSTOM_HCI_CW_SET_CHN_19:
/*@CC: Channel 19 Freq 2440 MHz*/
channelCC=2440;
break;
case CUSTOM_HCI_CW_SET_CHN_39:
/*@CC: Channel 39 Freq 2480 MHz */
channelCC=2480;
break;
/*@CC: Set PA_POWER */
case CUSTOM_HCI_CW_SET_PA_PWR_1:
/*@CC: Set PA_POWER 1 */
powerCC=0x01;
break;
case CUSTOM_HCI_CW_SET_PA_PWR_32:
/*@CC: Set PA_POWER 32 */
powerCC=0x20;
break;
case CUSTOM_HCI_CW_SET_PA_PWR_62:
/*@CC: Set PA_POWER 62 */
powerCC=0x3E;
break;
/*@CC: Generate a Continuous Unmodulated Signal ON / OFF */
case CUSTOM_HCI_CW_ON:
/*@CC: Generate a Continuous Unmodulated Signal when pressing SW3 */
XCVR_DftTxCW(channelCC, 6);
XCVR_ForcePAPower(powerCC);
break;
case CUSTOM_HCI_CW_OFF:
/*@CC: Turn OFF the transmitter */
XCVR_ForceTxWd();
/* Initialize the PHY as BLE */
XCVR_Init(BLE_MODE, DR_1MBPS);
break;
default:
eventPacket[5] = CUSTOM_HCI_EVENT_FAIL;
break;
}
eventPacket[3] = (uint8_t)opcode;
eventPacket[4] = (uint8_t)(opcode >> 8);
eventPacket[5] = CUSTOM_HCI_EVENT_SUCCESS;
Hcit_SendPacket(gHciEventPacket_c, eventPacket, sizeof(eventPacket));
}
else
{
return gBleUnexpectedError_c;
}
return gBleSuccess_c;
}
To test HCI Black Box software, we need to install NXP Test Tool 12, from the NXP Semiconductors | Automotive, Security, IoT official web site.
Once you have installed Test Tool, attach the FRDM-KW36 board to your PC and open the serial port enumerated in the start page clicking twice on the icon.
Then, select "Raw Data" checkbox and type any of our custom commands, for instance, "01 01 FC 00" (Set the Channel 19 Freq 2440 MHz). Shift out the command clicking on the "Send Raw..." button.
You will see the HCI Tx and Rx in the right upper corner of your screen
There is no raw data.
Hello, jictannu@163.com
I have confirmed that the "Raw Data" option is also available in the Test Tool 12 v12.9.1.0. Please ensure that you are in the correct window. After opening the serial port communication, a new window will be displayed (Command Console window) and here you will see this option in the lower part of the screen. Please, see the following picture:
If the option does not appear, I recommend upgrading to the newest version of Test Tool 12 and try again.
Regards.