Creating HCI Custom Commands for KW36

Document created by Edgar Eduardo Lomeli Gonzalez Employee on Mar 24, 2020
Version 1Show Document
  • View in full screen mode

Introduction

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.

 

Adding HCI Custom Commands Example

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:

  • 01 50 FC 00 – This command is to send a continuous unmodulated wave using a defined channel and output power (default: frequency 2.402GHz and PA_POWER register set to 0x3E). 
  • 01 4F FC 00 – This command is to stop the continuous unmodulated wave and configure the radio in Bluetooth LE mode again. This way you can continue sending adopted HCI commands.
  • 01 00 FC 00 – Set the Channel 0 Freq 2402 MHz
  • 01 01 FC 00 – Set the Channel 19 Freq 2440 MHz
  • 01 02 FC 00 – Set the Channel 39 Freq 2480 MHz
  • 01 10 FC 00 – Set the PA_POWER 1
  • 01 11 FC 00 – Set the PA_POWER 32
  • 01 12 FC 00 – Set the PA_POWER 62

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)

 

Changes in hci_transport.h

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);

Changes in hcit_serial_interface.c

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();
}

 

Changes in hci_black_box.c

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;

}

Testing Custom HCI Commands Using NXP Test Tool 12

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

Attachments

    Outcomes