NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
BLE HostTest Add Cmds
ContentsIntroduction[edit]Note: The content on this wiki is no longer maintained. Designs that require network processor peripheral role support are encouraged to utilize the CC2640 Simple Network Processor configuration from BLE-Stack v2.2.0+. It can sometimes be useful to add one's own commands to the Network Processor project to perhaps utilize the CC2540/41's peripherals or otherwise perform remote procedure calls from an external MCU. The below example shows how to do this, but there is no guarantee that the OpCode space used in the example will be available in later versions of the BLE stack.
External Command Data Flow[edit]
Code implementation[edit]This example will show how to add some commands in the PROFILE subgroup of the HCI OpCode space. It will operate on a service - Intercept PROFILE commands[edit]By default there is no handler for PROFILE commands (Opcodes 0xFF80 to 0xFFFF), and HCI commands with these opcodes are simply discarded. We simply add an extra case in the <syntaxhighlight lang="c"> case HCI_EXT_PROFILE_SUBGRP: stat = processExMsgPROFILE( (msg.opCode & 0x007F), &msg, &rspDataLen ); break; </syntaxhighlight> Handle the incoming commands[edit]It is not strictly necessary, but for clarity's sake it is useful to have some defines for the commands we wish to create. We add these defines to hci_ext_app.h <syntaxhighlight lang="c"> // Commands
// An event that we will make later
</syntaxhighlight> Once we have these defines, it's easy to do some actions based on the incoming data. The function below shows how to use the parameters sent after the opcode in the serial command. We have defined four commands to be able to manipulate a service that we have made.
<syntaxhighlight lang="c"> // Declaration static uint8 processExMsgPROFILE( uint8 cmdID, hciExtCmd_t *pCmd, uint8 *pRspDataLen ); static uint8 processExMsgPROFILE( uint8 cmdID, hciExtCmd_t *pCmd, uint8 *pRspDataLen ) { bStatus_t stat = SUCCESS; *pRspDataLen = 0; switch( cmdID ) { case HCI_EXT_PROFILE_ADD_ARB_SVC: stat = ArbitraryService_AddService( ); break;
case HCI_EXT_PROFILE_REG_WRT_CB: stat = ArbitraryService_RegisterAppCBs( &hci_ext_ArbitraryServiceCBs ); break;
case HCI_EXT_PROFILE_SETPARAM: { uint8 param = pCmd->pData[0]; uint8 len = pCmd->len - 1; uint8 *value = &pCmd->pData[1]; if ( len > 0 ) stat = ArbitraryService_SetParameter( param, len, (void *)value ); else stat = INVALIDPARAMETER; } break; case HCI_EXT_PROFILE_GETPARAM: { uint8 param = pCmd->pData[0]; // Which parameter uint8 len = pCmd->pData[1]; // Need to know how much to return stat = ArbitraryService_GetParameter( param, (void *)(rspBuf+6) ); if (stat == SUCCESS) *pRspDataLen = len; else stat = INVALIDPARAMETER; } break; default: stat = FAILURE; break; } return ( stat ); } </syntaxhighlight> Note that a CommandStatus will always be returned for these commands. The command status's Status field is determined by the value returned in ret above. You can also append more data to the CommandStatus event by doing as the GETPARAM example; namely changing the value of rspBuf (global) from the 6th offset and onwards, then setting the pRspDataLen accordingly. A maximum of 50 bytes can be sent this way. Emitting an asynchronous event[edit]Calling the HCI_EXT_PROFILE_REG_WRT_CB above will cause writes to our service to give a callback. The callback function is shown below, and it shows how to send out an event that is not CommandStatus. <syntaxhighlight lang="c"> // Local function declaration for hci_ext_app.c static void arbitraryServiceChangeCB( uint8 paramID, uint16 len, uint16 connHandle ); // Structure used in the call to RegisterAppCBs. static arbitraryServiceCBs_t hci_ext_ArbitraryServiceCBs = { arbitraryServiceChangeCB }; // Service write callback static void arbitraryServiceChangeCB( uint8 paramID, uint16 len, uint16 connHandle ) { // Send an event. uint8 msgLen = 0; // Build the message header first msgLen = buildHCIExtHeader( out_msg, (HCI_EXT_PROFILE_EVENT | 0x01), // 0x0781 event code, randomly chosen. SUCCESS, connHandle ); // Always success, always conn handle 0. ArbitraryService_GetParameter( paramID, (void *)(out_msg + msgLen) ); msgLen += len; HCI_SendControllerToHostEvent( HCI_VE_EVENT_CODE, msgLen, out_msg ); } </syntaxhighlight> Testing the new commands[edit]Using BTool it's easy to send custom commands by going to the Advanced Pane, then Misc and Generic Command. The image below shows how to read out the contents of Characteristic 1 of our arbitraryService. The value has been changed by a remote peer to be 08:09. When testing this example with remote hosts, remember to configure the NWP as a periperhal
Download[edit]Download the below file and unzip it into <stack install>/Projects/ble.
|