This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

What is the Max PDU for BLE Stack Function HCI_SendControllerToHostEvent

Other Parts Discussed in Thread: CC2650, CC2640, CC2541

Hello,

I'm using CC2650 Host_Test project in the Network Processor Mode by using UART to communicate with HCITester on the computer. 

In order to test the max PDU for BLE Stack function "HCI_SendControllerToHostEvent", I've created a new function HCI_EXT_UTIL_TEST_FUNCTION (opcode: 0xFE87) encapsulated under "processExtMsgUTIL" to be called by HCITester. 

Here is my code (red part) in ble_dispatch.c:

/*********************************************************************
 * @fn      processExtMsgUTIL
 *
 * @brief   Parse and process incoming HCI extension UTIL messages.
 *
 * @param   cmdID - incoming HCI extension command ID.
 * @param   pCmd - incoming HCI extension message.
 * @param   pRspDataLen - response data length to be returned.
 *
 * @return  SUCCESS, INVALIDPARAMETER and FAILURE.
 */
static uint8 processExtMsgUTIL( uint8 cmdID, hciExtCmd_t *pCmd, uint8 *pRspDataLen )
{
  bStatus_t stat = SUCCESS;
  *pRspDataLen = 0;
  switch( cmdID )
  {
  // Do not use SNV drivers with FPGA. Unverified behavior
#ifndef USE_FPGA
    case HCI_EXT_UTIL_NV_READ:
      {
        uint8 *pBuf = pCmd->pData;
        osalSnvId_t id  = pBuf[0];
        osalSnvLen_t len = pBuf[1];
        // This has a limitation of only allowing a max data length because of the fixed buffer.
        if ( (len < MAX_RSP_DATA_LEN) && (checkNVLen( id, len ) == SUCCESS) )
        {
          stat = osal_snv_read( id, len, &rspBuf[RSP_PAYLOAD_IDX] );
          if ( stat == SUCCESS )
          {
            *pRspDataLen = pBuf[1];
          }
        }
        else
        {
          stat = INVALIDPARAMETER;
        }
      }
      break;
    case HCI_EXT_UTIL_NV_WRITE:
      {
        uint8 *pBuf = pCmd->pData;
        osalSnvId_t id  = pBuf[0];
        osalSnvLen_t len = pBuf[1];
        if ( checkNVLen( id, len ) == SUCCESS )
        {
          stat = osal_snv_write( id, len, &pBuf[2] );
#if defined(HCI_TL_FULL) && defined(HOST_CONFIG)
          if ( id == BLE_NVID_SIGNCOUNTER )
          {
            hciExtSignCounter = BUILD_UINT32(pBuf[2], pBuf[3], pBuf[4], pBuf[5]);
          }
#endif // HCI_TL_FULL && HOST_CONFIG
        }
        else
        {
          stat = INVALIDPARAMETER;
        }
      }
      break;
#endif // USE_FPGA
    case HCI_EXT_UTIL_FORCE_BOOT:
      {
        extern void appForceBoot(void);
        appForceBoot();
        // Should never get here if SBL is present
        stat = INVALIDPARAMETER;
      }
      break;
    case HCI_EXT_UTIL_BUILD_REV:
      {
        ICall_BuildRevision buildRev;
        VOID buildRevision(&buildRev);
        // Stack revision
        //  Byte 0: Major
        //  Byte 1: Minor
        //  Byte 2: Patch
        rspBuf[RSP_PAYLOAD_IDX]   = BREAK_UINT32( buildRev.stackVersion, 0 );
        rspBuf[RSP_PAYLOAD_IDX+1] = BREAK_UINT32( buildRev.stackVersion, 1 );
        rspBuf[RSP_PAYLOAD_IDX+2] = BREAK_UINT32( buildRev.stackVersion, 2 );
        // Build revision
        rspBuf[RSP_PAYLOAD_IDX+3] = LO_UINT16( buildRev.buildVersion );
        rspBuf[RSP_PAYLOAD_IDX+4] = HI_UINT16( buildRev.buildVersion );
        // Stack info (Byte 5)
        rspBuf[RSP_PAYLOAD_IDX+5] = buildRev.stackInfo;
        // Controller info - part 1 (Byte 6)
        rspBuf[RSP_PAYLOAD_IDX+6] = LO_UINT16( buildRev.ctrlInfo );
        // Controller info - part 2 (Byte 7)
        rspBuf[RSP_PAYLOAD_IDX+7] = 0; // reserved
        // Host info - part 1 (Byte 8)
        rspBuf[RSP_PAYLOAD_IDX+8] = LO_UINT16( buildRev.hostInfo );
        // Host info - part 2 (Byte 9)
        rspBuf[RSP_PAYLOAD_IDX+9] = 0; // reserved
        *pRspDataLen = 10;
      }
      break;
      
    case HCI_EXT_UTIL_TEST_FUNCTION:
      {
        uint8 *pBuf = NULL;
        uint8 msgLen = 0;
        uint8 param = pCmd->pData[0];   // size of byte to be sent by HCI_SendControllerToHostEvent function
        uint8 allocLen = (uint8)(7)+(uint8)(param);
        
        pBuf = osal_mem_alloc(allocLen);
        if (pBuf)
        {
          switch (param)
          {
          case 0xEC: //236 bytes
            {
             osal_memset(pBuf, (uint8)1, allocLen);
            }
            break;
          case 0xED: //237 bytes
            {
              osal_memset(pBuf, (uint8)2, allocLen);
            }
            break;
          case 0xEE://238 bytes
            {
              osal_memset(pBuf, (uint8)3, allocLen);
            }
            break;
          case 0xEF: //239 bytes
            {
              osal_memset(pBuf, (uint8)4, allocLen);
            }
            break;
          case 0xF0: //240 bytes
            {
              osal_memset(pBuf, (uint8)5, allocLen);
            }
            break;
          case 0xF1: //241 bytes
            {
              osal_memset(pBuf, (uint8)6, allocLen);
            }
            break;
          default:
            break;
          }
         
          msgLen = buildHCIExtHeader( pBuf, (HCI_EXT_PROFILE_EVENT ), // 0x0780 event code.
                                      SUCCESS, 0x0000 ); // Always success, always conn handle 0
          pBuf[msgLen++] = 0x00;
          pBuf[msgLen++] = (uint8)param;
          msgLen += (uint8)param;
          HCI_SendControllerToHostEvent( HCI_VE_EVENT_CODE,  msgLen, pBuf );  
        }
        else{ /* do nothing */}
        
        if (pBuf != NULL)
        {
          osal_mem_free( pBuf );
        }
      }
      break;
    default:
      stat = FAILURE;
      break;
  }
  return ( stat );
}

Then, I've called the correspondant function opCode 0xFE87 in HCITester:

Send_UTIL_TestFunction 0xEC
Wait_HCI_Vendor_Specific_Event , 
Wait_HCI_Vendor_Specific_Event , 
Send_UTIL_TestFunction 0xED
Wait_HCI_Vendor_Specific_Event , 
Wait_HCI_Vendor_Specific_Event , 
Send_UTIL_TestFunction 0xEE
Wait_HCI_Vendor_Specific_Event , 
 
Send_UTIL_TestFunction 0xEF
Wait_HCI_Vendor_Specific_Event , 
Send_UTIL_TestFunction 0xF0
Wait_HCI_Vendor_Specific_Event , 
Send_UTIL_TestFunction 0xF1
Wait_HCI_Vendor_Specific_Event , 
Wait_HCI_Vendor_Specific_Event , 
Normally, we can receive two events from CC2650, the 1st one is 0x0780(sent by my code) and the 2nd one is 0x067f (sent by "processExtMsg" function).
However, I can't get the 1st event 0x0780 when the PDU>=238 bytes and I can't get both of the events when PDU>=239 bytes, here is my HCITester Log:
14:47:39.581 *** Script Started: ***
14:47:39.581 --
14:47:39.581 Packet "UTIL_TestFunction", Opcode 0xfe87
14:47:39.581 Parameters:
14:47:39.581 | Antenna Selection : 0xEC
14:47:39.581 --
14:47:39.581 Outgoing Dump:
14:47:39.581 0000: 01 87 fe 01 ec .....
14:47:39.597 Incoming Dump:
14:47:39.597 0000: 04 ff f3 80 07 00 00 00 00 ec 01 01 01 01 01 01 ................
14:47:39.597 0010: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0020: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0030: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0040: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0050: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0060: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0070: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0080: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 0090: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.597 00a0: 01 .
14:47:39.613 Incoming Dump:
14:47:39.613 0000: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.613 0010: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.613 0020: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.613 0030: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.613 0040: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
14:47:39.613 0050: 01 01 01 01 01 .....
14:47:39.624 --
14:47:39.624 Packet "HCI_Vendor_Specific_Event", Opcode 0x00ff
14:47:39.636 Parameters:
14:47:39.636 | Event Opcode : 0x0780 (UTIL_TestFunction)
14:47:39.636 | Status : 0x00 (SUCCESS)
14:47:39.636 | connectionHandle : 0x0000
14:47:39.636 | CharacId : 0x00
14:47:39.636 | CharactLen : 0xec
14:47:39.636 | value : "01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01:01"
14:47:39.636 --
14:47:39.636 Incoming Dump:
14:47:39.636 0000: 04 ff 06 7f 06 00 87 fe 00 .........
14:47:39.658 --
14:47:39.658 Packet "HCI_Vendor_Specific_Event", Opcode 0x00ff
14:47:39.675 Parameters:
14:47:39.675 | Event Opcode : 0x067f (CommandStatus)
14:47:39.675 | Status : 0x00 (SUCCESS)
14:47:39.675 | opCode : 0xfe87 (UTIL_UTIL_TestFunction)
14:47:39.675 | dataLen : 0x00
14:47:39.675 --
14:47:39.688 --
14:47:39.688 Packet "UTIL_TestFunction", Opcode 0xfe87
14:47:39.688 Parameters:
14:47:39.688 | Antenna Selection : 0xED
14:47:39.688 --
14:47:39.688 Outgoing Dump:
14:47:39.688 0000: 01 87 fe 01 ed .....
14:47:39.694 Incoming Dump:
14:47:39.694 0000: 04 ff f4 80 07 00 00 00 00 ed 02 02 02 02 02 02 ................
14:47:39.694 0010: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ...............
14:47:39.709 Incoming Dump:
14:47:39.709 0000: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0010: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0020: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0030: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0040: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0050: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0060: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0070: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0080: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 0090: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 00a0: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.709 00b0: 02 02 02 02 02 02 02 02 ........
14:47:39.725 Incoming Dump:
14:47:39.725 0000: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.725 0010: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
14:47:39.737 --
14:47:39.737 Packet "HCI_Vendor_Specific_Event", Opcode 0x00ff
14:47:39.749 Parameters:
14:47:39.749 | Event Opcode : 0x0780 (UTIL_TestFunction)
14:47:39.749 | Status : 0x00 (SUCCESS)
14:47:39.749 | connectionHandle : 0x0000
14:47:39.749 | CharacId : 0x00
14:47:39.749 | CharactLen : 0xed
14:47:39.749 | value : "02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02:02"
14:47:39.749 --
14:47:39.749 Incoming Dump:
14:47:39.749 0000: 04 ff 06 7f 06 00 87 fe 00 .........
14:47:39.763 --
14:47:39.763 Packet "HCI_Vendor_Specific_Event", Opcode 0x00ff
14:47:39.776 Parameters:
14:47:39.776 | Event Opcode : 0x067f (CommandStatus)
14:47:39.776 | Status : 0x00 (SUCCESS)
14:47:39.776 | opCode : 0xfe87 (UTIL_UTIL_TestFunction)
14:47:39.776 | dataLen : 0x00
14:47:39.776 --
14:47:39.789 --
14:47:39.789 Packet "UTIL_TestFunction", Opcode 0xfe87
14:47:39.789 Parameters:
14:47:39.789 | Antenna Selection : 0xEE
14:47:39.789 --
14:47:39.789 Outgoing Dump:
14:47:39.789 0000: 01 87 fe 01 ee .....
14:47:39.805 Incoming Dump:
14:47:39.805 0000: 04 ff 06 7f 06 00 87 fe 00 .........
14:47:39.819 --
14:47:39.819 Packet "HCI_Vendor_Specific_Event", Opcode 0x00ff
14:47:39.832 Parameters:
14:47:39.832 | Event Opcode : 0x067f (CommandStatus)
14:47:39.832 | Status : 0x00 (SUCCESS)
14:47:39.832 | opCode : 0xfe87 (UTIL_UTIL_TestFunction)
14:47:39.832 | dataLen : 0x00
14:47:39.832 --
14:47:39.845 --
14:47:39.845 Packet "UTIL_TestFunction", Opcode 0xfe87
14:47:39.845 Parameters:
14:47:39.845 | Antenna Selection : 0xEF
14:47:39.845 --
14:47:39.845 Outgoing Dump:
14:47:39.845 0000: 01 87 fe 01 ef .....

So I want to know what is exactly the max PDU for HCI_SendControllerToHostEvent function? And if we can send more then 238 bytes, what I've bad written in my test code?  

Best regards,

Yang

  • Hi Yang

    Can you check if the ICall heap is exhausted when you send the message? Also, what is your configured MAX_PDU_SIZE?

    Best wishes
  • Hi JXS,

    Thanks for answering the question.

    First, I set MAX_PDU_SIZE to 255 to enable the maximum MTU for BLE transmission.

    Then in order to check if the ICall heap exhausted, I set HEAPMGR_METRICS as a defined preprocessor symbol, and I checked these heap global variables for each different PDU, here are the captures:

    this is the capture after calling HCI_SendControllerToHostEvent for 0x0780 event, with PDU = 236 bytes

    here is after the 0x067f event with PDU = 236 bytes

    here is after the 0x0780 event with PDU = 237 bytes

    here is after the 0x067f event with PDU = 237 bytes

    here is after the 0x0780 event with PDU = 238 bytes

    here is after the 0x067f event with PDU = 238 bytes

    and then CC chip is blocked. From the captures, we can tell that ICall Heap is not exhausted (heapmgrMemMax<HEAPMGR_SIZE), and there is a problem when PDU = 238 bytes for the first 0x0780 event.

    So I use Step_Into to debug the HCI_SendControllerToHostEvent function, I found that behind this function, the first osal_msg_allocate function called to allocate memory for message header has the problem with its parameter 'uint16 len' . 

    When PDU = 236 bytes, HCI_SendControllerToHostEvent function gives 0x00FE for 'len'

    When PDU = 237 bytes, HCI_SendControllerToHostEvent function gives 0x00FF for 'len'

    However, when PDU = 238 bytes, HCI_SendControllerToHostEvent function gives 0x0000 for 'len'

    And when PDU = 239 bytes, HCI_SendControllerToHostEvent function gives 0x0001 for 'len'

    I think there is something wrong with this part.

    Looking forward to your further answer.

    Best regards,

    Yang

  • Hi Yang,

    I am unsure about what you are trying to test. The TI BLE Software Developer's Guide covers how to setup your device in order to enable a larger PDU in Section 5.5.2.1 Configuring for Larger MTU values. Did you follow the steps given in the guide?

    If you read the L2CAP section in the User's Guide you will see that MAX_PDU_SIZE can be up to 255 bytes. That is the maximum amount of data that can be sent between the Host and the Controller. That is different than the maximum amount of User Data you can sent from the Application to the Controller. The difference is due to overhead created by L2CAP and GATT headers. L2CAP headers are 4 bytes. GATT headers depend on what command you are sending. You can see the Bluetooth Core Spec v4.2 for information about header sizes for various requests.

    I was able to write a 248 byte value over the air by doing the following:

    1. Using Host Test -> define MAX_PDU_SIZE=255
    2. Using Project Zero -> define MAX_PDU_SIZE=255
    3. In Project Zero data_service.h, changed DS_STRING_LEN to 248
    4. Using BTool, connect to the device running Project Zero
    5. Perform a GATT_Exchange MTU with a clientRxMTU parameter of 255. This gets negotiated to 251 because the L2CAP header is subtracted.
    6.  Perform a GATT discovery to find the handle of the String characteristic we modified in step 3. (should be listed as String Char)
    7. Write a 248 byte value to the String Char.
    8. You should see something similar to the below image. There should be 2 events that return success: GAP_HCI_ExtentionCommandStatus and ATT_WriteRsp

  • Hi Rachel,

    Thanks very much for your answer.

    My question is mainly about the function HCI_SendControllerToHostEvent that is used in the host_test project to send controller (CC2640) message to the Host (PC).

    In order to test the Max Message Length that can be sent by this function from CC2640 to PC, I have modified the ble_dispatch.c like my above post. And then I found that, when even though we can receive 248 bytes from the air for a characteristic, these bytes can not be sent to PC by this function. 

    From your answer, you said that the MAX_PDU_SIZE of 255 bytes is the maximum amount of data that can be sent between the Controller and the Host. For me, that means we can use HCI_SendConbtrllerToHostEvent to send at least 251 bytes to PC, right?  So could you please tell if my above test case has a problem of the use of HCI_SendControllerToHostEvent function? 

    Looking forward to your further answer.

    Best regards,

    Yang

  • Hello. Can we take a step back here?  You're modifying code that is not generally intended to be changed and using functions that should only be used by the controller.  This is highly dangerous, is not easily supported, and there is likely a better way to do this.

    What is the top-level goal here? Since you're using the HostTest project, you must be attempting to implement a network processor solution.  If you are trying to see how much data you can send over-the-air, this can be accomplished using pre-existing GATT commands and events as Rachel previously mentioned.

    Or are you attempting to add some custom functionality to HostTest and send messages asynchronously to your application processor (HCITester in this case)?  If this is the case, you can use the NPI (network processor interface) layer. For example, you can call NPI_WriteTransport to encapsulate your custom message in an NPI frame to send over UART / SPI.

    Perhaps you could give us an example of a message (i.e. just the bytes) that you are attempting to send from HostTest to HCITester and we can provide instructions on how to do this.

  • Hi Tim,

    Thanks for the response.

    What if I want to integrate a HCI_Custom_Command (exp: HCI_EXT_UTIL and HCI_EXT_PROFILE) that will be sent by HCITester from UART, how can I integrate the command in App? By using osal_msg_send function?

    What I found as the exemple from Wiki is for CC2541: CC254X WITH EXT MCU and BLE HostTest Add Cmds. That's why I modified the ble_dispatch.c to support these custom commands.

    Looking forward to your answer.

    Best wishes,

    Yang