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.

CC2340R5: CC2340R53 Connection Parameters

Part Number: CC2340R5
Other Parts Discussed in Thread: SYSCONFIG

Good day.

My team and I are writing some firmware for the CC23, acting as a BLE Peripheral. 

We noticed that, with the default connection parameters, iOS (acting as Central) fails to connect.

Here are our observations:

  • iOS does not report a 'connected' state back to our application
  • Our embedded side shows that a connection has been established

Using a Bluetooth HCI Logging profile on and iPhone, and reading the HCI log via PacketLogger (mac software), we noticed the following:

  • The mobile tries to negotiate connection parameters using 50 (62.5ms) for both min and max connection interval
  • The embedded side responds with an (acceptance) reply containing minConnectionInterval 12 (15ms) and maxConnectionInterval 24 (30ms).
  • (There is no overlap between the two intervals)
  • Here communication just stops, no disconnect, nothing
  • The implication is that: this is not a pairing issue, but a connection issue.

As an experiment, we tried using GAP_UpdateLinkParamReq with the lenient values of 50 for min & max connection interval multipliers, 0 connection latency, and 500 ms connection timeout.

We noticed the following:

  • The mobile tries to negotiate connection parameters using 50 (62.5ms) for both min and max connection interval
  • The embedded side responds with a minConnectionInterval of 50 (62.5ms) and a maxConnectionInterval of 62 (77.5ms)
  • The mobile side sends a connection update complete message, agreeing on a connection interval of 50 (62.ms)
Conclusion:
  • The current default connection parameters on the embedded side are incompatible with iOS.
  • Even after connecting, we can not trigger a pairing attempt; There are no iOS APIs to create a pairing relationship. Instead, pairing is triggered when a characteristic interaction returns insufficient authentication / authorization.

We have the following questions for you at TI:

  • Why does communication between the phone and chip just stop? We would expect it to fail or continue with the current connection parameters; (Who is waiting on who?)
    • If this is a bug of iOS itself, we can not do anything about it, only report it to be solved by Apple in the future
  • When there is no overlap between support connection parameters, should the embedded side respond with a HCI_LE_Remote_Connection_Parameter_Request_Negative_Reply instead?
  • We noticed that the supervision timeout did not update to the requested value (500).
  • We couldn't find the 12/24 default parameters anywhere in the code, does TI use default parameters that are incompatible with iOS? Where are they set?
    • We found ti_ble_config.h, but it mentions intervals of 400 min, 800 max, 0 latancy, and 600 timeout.
    • We also found gap_initator.h, but that mentions 80, 80, 0, and 2000. I also suspect that file is not used in our use case as a Peripheral.
  • What should the correct parameters be?

We found the GapInit_setPhyParam() function, so perhaps we should start with adding that somewhere in our initiation code? 

Something like this: (replacing the values with sensible defaults)

GapInit_setPhyParam(INIT_PHY_1M, INIT_PHYPARAM_CONN_INT_MIN, 50);
GapInit_setPhyParam(INIT_PHY_1M, INIT_PHYPARAM_CONN_INT_MAX, 50);
GapInit_setPhyParam(INIT_PHY_1M, INIT_PHYPARAM_CONN_LATENCY, 0);
GapInit_setPhyParam(INIT_PHY_1M, INIT_PHYPARAM_SUP_TIMEOUT, 500);

 

  • Few more notes.

    1. I'm wondering if GapInit_setPhyParam is only usable for a central? So perhaps that's not a solution for us (as we only need to write a Peripheral)

    2. I found out that we had a rogue decorator somewhere calling a Set Connection Parameters function with the relatively strict values of 6 minInterval, 6 maxInterval. These worked fine for Android, but supposedly are too tight for iOS. Replacing these with 30 minInterval and 60 maxInterval seems to allow for a connection to iOS, while still working for Android. I still don't fully understand why we were seeing values 12 and 24 in the HCI scanner.

    I'd like to know what a suitable set of parameters are. What would you recommend?

  • Hello Xavier,

    Thank you for reaching out! This is definitely strange behavior. What SDK version are you using?

    Why does communication between the phone and chip just stop? We would expect it to fail or continue with the current connection parameters; (Who is waiting on who?)

    In BLE, the central controls the connection parameters, the peripheral can only request new parameters. In the out of box examples, connection parameter update requests are handled inside the BLEAPPUTIL_LINK_PARAM_UPDATE_REQ_EVENT case. As seen in the screenshot, the device will respond with an acceptance using the parameters sent in the request. 

    If this is a bug of iOS itself, we can not do anything about it, only report it to be solved by Apple in the future

    I have personally connected to IOS devices numerous times, using different versions, so I don't think this is a bug on either side. This might just be a small misconfiguration.

    When there is no overlap between support connection parameters, should the embedded side respond with a HCI_LE_Remote_Connection_Parameter_Request_Negative_Reply instead?

    Could you elaborate on what you mean here? As a BLE peripheral, the device is able to support connection interval as small as 7.5 ms and as large as 4 seconds. The "supported" connection parameters would rely completely on your desire for your application. It is worth mentioning that the peripheral can only accept or reject connection parameter update requests. It cannot send a response with different parameters.

    We noticed that the supervision timeout did not update to the requested value (500).

     Is it not changing at all? Please keep in mind that the supervision timeout is in units of 10 ms, not 1 ms.

    We couldn't find the 12/24 default parameters anywhere in the code, does TI use default parameters that are incompatible with iOS? Where are they set?
    • We found ti_ble_config.h, but it mentions intervals of 400 min, 800 max, 0 latancy, and 600 timeout.
    • We also found gap_initator.h, but that mentions 80, 80, 0, and 2000. I also suspect that file is not used in our use case as a Peripheral.

    The default parameters are set in sysconfig, which generate the ti_ble_config.h file. The TI default parameters are irrelevant when connecting to an IOS central. This is because the central determines the initial connection parameters.

    I found out that we had a rogue decorator somewhere calling a Set Connection Parameters function with the relatively strict values of 6 minInterval, 6 maxInterval. These worked fine for Android, but supposedly are too tight for iOS. Replacing these with 30 minInterval and 60 maxInterval seems to allow for a connection to iOS, while still working for Android. I still don't fully understand why we were seeing values 12 and 24 in the HCI scanner.

    The connection interval values are in units of 1.25 ms, so 24 x 1.25 = 30. 

    I'm wondering if GapInit_setPhyParam is only usable for a central? So perhaps that's not a solution for us (as we only need to write a Peripheral)

    Since the peripheral does not initiate any connections, GapInit_setPhyParams is essentially useless for peripherals.

    I hope this answers provide you with a better understanding. If not, please let me know what you're trying to accomplish with your device and I'll help you do that! Also, I would recommend taking a look at our BLE connections SimpleLink academy.

    Best Regards,

    Tarek D

  • Hello Tarek, thanks for the quick response.

     What SDK version are you using?

    simplelink_lowpower_f3_sdk_9_11_00_18

     I have personally connected to IOS devices numerous times, using different versions, so I don't think this is a bug on either side. This might just be a small misconfiguration.

    What connection parameters would you recommend, based on experience?

     Is it not changing at all? Please keep in mind that the supervision timeout is in units of 10 ms, not 1 ms.

    I'll need to re-run the tests, but the logs suggested that supervision timeout wasn't changing. I'll check again.

     The default parameters are set in sysconfig, which generate the ti_ble_config.h file. The TI default parameters are irrelevant when connecting to an IOS central. This is because the central determines the initial connection parameters.

    Okay, presumably the default params we're seeing are coming from Apple's side, then. 

     The connection interval values are in units of 1.25 ms, so 24 x 1.25 = 30.

     Thanks for clarifying, but in this case, we were seeing 12 min, 24 max in the HCI logs before we changed our peripheral to request 30, 60. At the time, we were requesting 6, 6. I'm guessing that the 12, 24 was coming from iOS (?)

     Since the peripheral does not initiate any connections, GapInit_setPhyParams is essentially useless for peripherals.

    Alright, thanks for confirming that.

     

    Our current plans with the CC23 chip involve using it as a BLE peripheral. 

    We have an existing application that we need to run on it. This application needs to communicate with Android & iOS devices (as the Central). 

    The TI-CC23 specific layer that we're currently building bypasses the BLEAppUtil framework in favour of directly managing the ICall APIs. 

     

    Currently, we've not had much trouble with Android - it's just iOS that seems to be causing a headache. Have you had a similar experience?

    I'll need to further look into how we handle the 'update connection parameters' request/response.

    If the Central (iOS) is the one to initiate the ConnParams request, it's strange that our peripheral is doing anything other than suggesting values. It's extra strange that the values suggested by the peripheral (seemingly) cause a communication desync between both devices.

    For more info, when recreating the bug mentioned in the first post, the Ti chip continues on happily, under the presumption that a connection has completed. The iPhone is left waiting for the 'connection completed' response. Why we don't see this on Android, or when using different ConnParams values, continues to be a mystery.

  • Hey Xavier,

    Could you share some code snippets that show how you handle the connection parameter update requests? The issue may lie there.

    Best Regards,

    Tarek D

  • Could you share some code snippets that show how you handle the connection parameter update requests? The issue may lie there.

    On init, we execute GAP_SetParamValue(GAP_PARAM_LINK_UPDATE_DECISION, GAP_UPDATE_REQ_ACCEPT_ALL);

    We do not handle GAP_UPDATE_LINK_PARAM_REQ_EVENT, as we have the flag set to 'Accept All'.

    The bug was occurring when we called the following function with values min = 6, max = 6. This is called immidiately after connection.

    gapUpdateLinkParamReq_t req{
                .connectionHandle = connectionContext.connectionHandle,
                .intervalMin = connectionContext.parameters.minConnIntMultiplier,
                .intervalMax = connectionContext.parameters.maxConnIntMultiplier,
                .connLatency = connectionContext.parameters.slaveLatency,
                .connTimeout = connectionContext.parameters.supervisorTimeoutMs,
                .signalIdentifier = 0
            };

            bStatus_t status = GAP_UpdateLinkParamReq(&req);

    This is all we do on our side, in regards to ConnParams.

  • Hey Xavier,

    I would expect a GAP_UpdateLinkParamReq to fail when connected to an IOS device. IOS devices are very strict with their connection parameters. However, unless your application code forces a disconnection, a disconnection should not be happening.

    Just as an "extra" check, do you have the "Parameters Updates Request Decision" set to "Accept All" in the syscfg file? (BLE -> Peripheral Configuration)

    Also, can you maintain the connection if you don't send the connection parameter update request from your peripheral?

    Best Regards,

    Tarek D

  • Just as an "extra" check, do you have the "Parameters Updates Request Decision" set to "Accept All" in the syscfg file? (BLE -> Peripheral Configuration)

    Can you explain what you mean by this? Do you mean changing the following line in ti_ble_config.h? 

    #define DEFAULT_PARAM_UPDATE_REQ_DECISION GAP_UPDATE_REQ_PASS_TO_APP
    to
    #define DEFAULT_PARAM_UPDATE_REQ_DECISION GAP_UPDATE_REQ_ACCEPT_ALL

    I'm not certain that we should be modifying this file directly. I'm also not sure that changing this would affect anything, considering we don't read this DEFAULT_PARAM_UPDATE_REQ_DECISION variable when calling GAP_SetParamValue upon initialising our transport layer.

    Also, can you maintain the connection if you don't send the connection parameter update request from your peripheral?

    If we remove the parameter update request, the connection seemes to maintain fine. There's clearly a problem occuring somewhere after GAP_UpdateLinkParamReq. You mention that iOS aught to reject most (all?) connection parameter requests, so perhaps we need to see how that's being handled. I don't see any logs for HCI events for us to hook into after the faulty request is sent, presumably because of that 'ACCEPT_ALL' flag. Should we try using PASS_TO_APP and overriding it ourselves?

  • Hello Xavier,

    I'm not certain that we should be modifying this file directly. I'm also not sure that changing this would affect anything, considering we don't read this DEFAULT_PARAM_UPDATE_REQ_DECISION variable when calling GAP_SetParamValue upon initialising our transport layer.

    Yes, if you're not calling GAP_SetParamValue, you are correct, it won't affect anything.

    If we remove the parameter update request, the connection seemes to maintain fine. There's clearly a problem occuring somewhere after GAP_UpdateLinkParamReq. You mention that iOS aught to reject most (all?) connection parameter requests, so perhaps we need to see how that's being handled. I don't see any logs for HCI events for us to hook into after the faulty request is sent, presumably because of that 'ACCEPT_ALL' flag. Should we try using PASS_TO_APP and overriding it ourselves?

    I'm looking further into IOS connection parameter update requests, but in the meantime, I ran a quick test and I was able to send the connection parameter update request, and everything worked as expected. I have attached a packet sniffer log screenshot, showing the update request being accepted. 

    As for the HCI event, you should still be receiving the  BLEAPPUTIL_LINK_PARAM_UPDATE_EVENT event. By default, the basic_ble project will simply print a message saying "Conn Status: Params update failed". Could you share your project or the code you have to handle this event?

    Also, as a test on your end, could you attempt importing a basic_ble example, and without any modifications, flash it onto the board and attempt to connect to the board using an IOS device. Once the connection is established, use the device's interactive menu to send a connection parameter update request. This will help us in identifying whether the issue is on the IOS side or the CC2340 side.

    Best Regards,

    Tarek D

  • Yes, if you're not calling GAP_SetParamValue, you are correct, it won't affect anything.

    We are calling GAP_SetParamValue, we're just not using that #default variable mentioned in ti_ble_config.h

    As for the HCI event, you should still be receiving the  BLEAPPUTIL_LINK_PARAM_UPDATE_EVENT event. By default, the basic_ble project will simply print a message saying "Conn Status: Params update failed". Could you share your project or the code you have to handle this event?

    As mentioned before, we're bypassing BleAppUtils in favour of calling the stack directly.

    We don't receive a HCI event when passing in the strict 6 min 6 max connparams request.

    I still assume this is because we have the setting 'ACCEPT_ALL' active.

    To capture ICallEvents, we do the following:

    //...

    namespace
        {
            infra::Function<uint8_t(uint8_t event, uint8* pMessage)> onICallEvent;

            uint8_t ICallEventHandler(uint8_t event, uint8* pMessage)
            {
                return onICallEvent(event, pMessage);
            }
        }
    // constructor
        {
    ...
     
    onICallEvent = [this](uint8_t event, uint8* pMessage)
            {
                return this->HandleHciEvent(reinterpret_cast<ICall_Hdr&>(*pMessage));
            };
            ICall_init();
            ICall_createRemoteTasks();
            really_assert(ICall_registerAppCback(&selfEntity, ICallEventHandler) == SUCCESS);
        }
    //...
    If we are meant to still receive PARAM_LINK_UPDATE_EVENTS despite 'ACCEPT_ALL', we should see them within that onICallEvent lambda.
    Also, as a test on your end, could you attempt importing a basic_ble example, and without any modifications, flash it onto the board and attempt to connect to the board using an IOS device. Once the connection is established, use the device's interactive menu to send a connection parameter update request. This will help us in identifying whether the issue is on the IOS side or the CC2340 side.

    Is this the correct project: simplelink_lowpower_f3_sdk_8_40_02_01\examples\rtos\LP_EM_CC2340R53\ble5stack\basic_ble ?

    I presume we need to use CodeComposerStudio for that? We do not use that tool in our workflow, but I'll see if I can work it out.

    You mention using the device's interactive menu - what method do recommend to accomplish this?

    For your info, we have the CC23 installed on a custom board, we are not using the launchpad test board.

    In our code, we currently use UART for output only. Does basic_ble provide a setup for sending inputs over UART, or something similar?

  • I'm looking further into IOS connection parameter update requests, but in the meantime, I ran a quick test and I was able to send the connection parameter update request, and everything worked as expected. I have attached a packet sniffer log screenshot, showing the update request being accepted. 

    Also, thank you for checking this - I'll check myself to see if we get the same result.

  • Hello, I was able to set up Code Composer Studio. Using that, I created a new project for the CC2340R53, using the template for FreeRTOS, basic_ble, TI Arm Clang. 

    I built Release\basic_ble_LP_EM_CC2340R53_freertos_ticlang.hex and flashed it to the board via J-Link, which reported no erros.

    From here, I'm not sure how to proceed. I'm unable to open a serial connection to the device.

    What do you suggest? Should I try creating a run configuration in launch.json to try and debug with CCS? Do you have an example of how that might look?

  • Hey Xavier,

    The basic_ble example uses UART the output information, however, to use the interactive menu, you will need to use the buttons on the launchpad (seems like that isn't an option, since you're on a custom board).

    No worries, I will make the necessary modifications so that the peripheral automatically sends a connection parameter update request after a few seconds of the connection being established. I will share the code in my next response, as well as an explanation of how to use it.

    Best Regards,

    Tarek D

  • Hey Xavier,

    Please find attached a modified app_connection.c file, which you can replace in the out of box basic_ble example. 

    This file will allow the device to continuously and autonomously send connection parameter update requests, every few seconds, to the central it's connected to.

    /******************************************************************************
    
    @file  app_connection.c
    
    @brief This example file demonstrates how to activate the central role with
    the help of BLEAppUtil APIs.
    
    Group: WCS, BTS
    Target Device: cc23xx
    
    ******************************************************************************
    
     Copyright (c) 2022-2025, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    ******************************************************************************
    
    
    *****************************************************************************/
    #if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) )
    
    //*****************************************************************************
    //! Includes
    //*****************************************************************************
    #include <string.h>
    #include <stdarg.h>
    
    #include "ti_ble_config.h"
    #include "ti/ble/app_util/framework/bleapputil_api.h"
    #include "ti/ble/app_util/menu/menu_module.h"
    #include <app_main.h>
    
    #include <ti/drivers/dpl/ClockP.h>
    #include <ti/drivers/dpl/HwiP.h>
    
    #include <unistd.h>
    #include <stdint.h>
    #include <stddef.h>
    
    #include "ti_drivers_config.h"
    //*****************************************************************************
    //! Prototypes
    //*****************************************************************************
    void Connection_ConnEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
    void Connection_HciGAPEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
    
    static uint8_t Connection_addConnInfo(uint16_t connHandle, uint8_t *pAddr);
    static uint8_t Connection_removeConnInfo(uint16_t connHandle);
    
    //*****************************************************************************
    //! Globals
    //*****************************************************************************
    
    // Events handlers struct, contains the handlers and event masks
    // of the application central role module
    BLEAppUtil_EventHandler_t connectionConnHandler =
    {
        .handlerType    = BLEAPPUTIL_GAP_CONN_TYPE,
        .pEventHandler  = Connection_ConnEventHandler,
        .eventMask      = BLEAPPUTIL_LINK_ESTABLISHED_EVENT |
                          BLEAPPUTIL_LINK_TERMINATED_EVENT |
                          BLEAPPUTIL_LINK_PARAM_UPDATE_EVENT |
                          BLEAPPUTIL_LINK_PARAM_UPDATE_REQ_EVENT
    };
    
    BLEAppUtil_EventHandler_t connectionHciGAPHandler =
    {
        .handlerType    = BLEAPPUTIL_HCI_GAP_TYPE,
        .pEventHandler  = Connection_HciGAPEventHandler,
        .eventMask      = BLEAPPUTIL_HCI_COMMAND_STATUS_EVENT_CODE |
                          BLEAPPUTIL_HCI_LE_EVENT_CODE
    };
    
    // Holds the connection handles
    static App_connInfo connectionConnList[MAX_NUM_BLE_CONNS];
    
    // ClockP Variables
    static ClockP_Handle c_handle;
    static ClockP_Params c_params;
    uint8_t connHandle1;
    
    void updateWrapper()
    {
        gapUpdateLinkParamReq_t pParamUpdateReq =
        {
         .connectionHandle = connHandle1,
         .intervalMin = 400,
         .intervalMax = 800,
         .connLatency = 0,
         .connTimeout = 600
        };
    
        // Send a connection param update request
        BLEAppUtil_paramUpdateReq(&pParamUpdateReq);
    }
    void clock_fxn(uintptr_t arg)
    {
        gapUpdateLinkParamReq_t pParamUpdateReq =
        {
         .connectionHandle = connHandle1,
         .intervalMin = 400,
         .intervalMax = 800,
         .connLatency = 0,
         .connTimeout = 600
        };
    
        // Send a connection param update request
        BLEAppUtil_invokeFunctionNoData(updateWrapper);
    }
    //*****************************************************************************
    //! Functions
    //*****************************************************************************
    
    /*********************************************************************
     * @fn      Connection_ConnEventHandler
     *
     * @brief   The purpose of this function is to handle connection related
     *          events that rise from the GAP and were registered in
     *          @ref BLEAppUtil_registerEventHandler
     *
     * @param   event - message event.
     * @param   pMsgData - pointer to message data.
     *
     * @return  none
     */
    void Connection_ConnEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
        switch(event)
        {
            case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
            {
                gapEstLinkReqEvent_t *gapEstMsg = (gapEstLinkReqEvent_t *)pMsgData;
    
                // Add the connection to the connected device list
                Connection_addConnInfo(gapEstMsg->connectionHandle, gapEstMsg->devAddr);
    
                /*! Print the peer address and connection handle number */
                MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Established - "
                                  "Connected to " MENU_MODULE_COLOR_YELLOW "%s " MENU_MODULE_COLOR_RESET
                                  "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d" MENU_MODULE_COLOR_RESET,
                                  BLEAppUtil_convertBdAddr2Str(gapEstMsg->devAddr), gapEstMsg->connectionHandle);
    
                /*! Print the number of current connections */
                MenuModule_printf(APP_MENU_NUM_CONNS, 0, "Connections number: "
                                  MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                  linkDB_NumActive());
    
                // Start a timer for 5 seconds. After the 5 seconds is up, send a connection parameter update request
                ClockP_start(c_handle);
                connHandle1 = gapEstMsg->connectionHandle;
    
                break;
            }
    
            case BLEAPPUTIL_LINK_TERMINATED_EVENT:
            {
                gapTerminateLinkEvent_t *gapTermMsg = (gapTerminateLinkEvent_t *)pMsgData;
    
                // Remove the connection from the conneted device list
                Connection_removeConnInfo(gapTermMsg->connectionHandle);
    
                /*! Print the peer address and connection handle number */
                MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Terminated - "
                                  "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET
                                  "reason = " MENU_MODULE_COLOR_YELLOW "%d" MENU_MODULE_COLOR_RESET,
                                  gapTermMsg->connectionHandle, gapTermMsg->reason);
    
                /*! Print the number of current connections */
                MenuModule_printf(APP_MENU_NUM_CONNS, 0, "Connections number: "
                                  MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                  linkDB_NumActive());
    
                break;
            }
    
            case BLEAPPUTIL_LINK_PARAM_UPDATE_REQ_EVENT:
            {
                gapUpdateLinkParamReqEvent_t *pReq = (gapUpdateLinkParamReqEvent_t *)pMsgData;
    
                // Only accept connection intervals with slave latency of 0
                // This is just an example of how the application can send a response
                if(pReq->req.connLatency == 0)
                {
                    BLEAppUtil_paramUpdateRsp(pReq,TRUE);
                }
                else
                {
                    BLEAppUtil_paramUpdateRsp(pReq,FALSE);
                }
    
                break;
            }
    
            case BLEAPPUTIL_LINK_PARAM_UPDATE_EVENT:
            {
                gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsgData;
    
                // Get the address from the connection handle
                linkDBInfo_t linkInfo;
                if (linkDB_GetInfo(pPkt->connectionHandle, &linkInfo) ==  SUCCESS)
                {
                  // The status HCI_ERROR_CODE_PARAM_OUT_OF_MANDATORY_RANGE indicates that connection params did not change but the req and rsp still transpire
                  if(pPkt->status == SUCCESS)
                  {
                      MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Params update - "
                                        "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                        pPkt->connectionHandle);
                  }
                  else
                  {
                      MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Params update failed - "
                                        MENU_MODULE_COLOR_YELLOW "0x%x " MENU_MODULE_COLOR_RESET
                                        "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                        pPkt->opcode, pPkt->connectionHandle);
                  }
                }
    
                break;
            }
    
            default:
            {
                break;
            }
        }
    }
    
    /*********************************************************************
     * @fn      Connection_HciGAPEventHandler
     *
     * @brief   The purpose of this function is to handle HCI GAP events
     *          that rise from the HCI and were registered in
     *          @ref BLEAppUtil_registerEventHandler
     *
     * @param   event - message event.
     * @param   pMsgData - pointer to message data.
     *
     * @return  none
     */
    void Connection_HciGAPEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
    
        switch (event)
        {
            case BLEAPPUTIL_HCI_COMMAND_STATUS_EVENT_CODE:
            {
                hciEvt_CommandStatus_t *pHciMsg = (hciEvt_CommandStatus_t *)pMsgData;
                switch ( event )
                {
                  case HCI_LE_SET_PHY:
                  {
                      if (pHciMsg->cmdStatus ==
                          HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE)
                      {
                          MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Phy update - failure, peer does not support this");
                      }
                      else
                      {
                          MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Phy update - "
                                            MENU_MODULE_COLOR_YELLOW "0x%02x" MENU_MODULE_COLOR_RESET,
                                            pHciMsg->cmdStatus);
                      }
                      break;
                  }
    
    
                  default:
                  {
                      break;
                  }
                  break;
                }
            }
    
            case BLEAPPUTIL_HCI_LE_EVENT_CODE:
            {
                hciEvt_BLEPhyUpdateComplete_t *pPUC = (hciEvt_BLEPhyUpdateComplete_t*) pMsgData;
    
                if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT)
                {
                  if (pPUC->status != SUCCESS)
                  {
                      MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Phy update failure - connHandle = %d",
                                        pPUC->connHandle);
                  }
                  else
                  {
    #if !defined(Display_DISABLE_ALL)
                      char * currPhy =
                              (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1 Mbps" :
                              (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2 Mbps" :
                              (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "CODED" : "Unexpected PHY Value";
                      MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Phy update - connHandle = %d PHY = %s",
                                        pPUC->connHandle, currPhy);
    #endif // #if !defined(Display_DISABLE_ALL)
                  }
                }
    
                break;
            }
    
            default:
            {
                break;
            }
    
        }
    }
    
    /*********************************************************************
     * @fn      Connection_addConnInfo
     *
     * @brief   Add a device to the connected device list
     *
     * @return  index of the connected device list entry where the new connection
     *          info is put in.
     *          If there is no room, MAX_NUM_BLE_CONNS will be returned.
     */
    static uint8_t Connection_addConnInfo(uint16_t connHandle, uint8_t *pAddr)
    {
      uint8_t i = 0;
    
      for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
      {
        if (connectionConnList[i].connHandle == LINKDB_CONNHANDLE_INVALID)
        {
          // Found available entry to put a new connection info in
          connectionConnList[i].connHandle = connHandle;
          memcpy(connectionConnList[i].peerAddress, pAddr, B_ADDR_LEN);
    
          break;
        }
      }
    
      return i;
    }
    
    /*********************************************************************
     * @fn      Connection_removeConnInfo
     *
     * @brief   Remove a device from the connected device list
     *
     * @return  index of the connected device list entry where the new connection
     *          info is removed from.
     *          If connHandle is not found, MAX_NUM_BLE_CONNS will be returned.
     */
    static uint8_t Connection_removeConnInfo(uint16_t connHandle)
    {
      uint8_t i = 0;
      uint8_t index = 0;
      uint8_t maxNumConn = MAX_NUM_BLE_CONNS;
    
      for (i = 0; i < maxNumConn; i++)
      {
        if (connectionConnList[i].connHandle == connHandle)
        {
          // Mark the entry as deleted
          connectionConnList[i].connHandle = LINKDB_CONNHANDLE_INVALID;
    
          break;
        }
      }
    
      // Save the index to return
      index = i;
    
      // Shift the items in the array
      for(i = 0; i < maxNumConn - 1; i++)
      {
          if (connectionConnList[i].connHandle == LINKDB_CONNHANDLE_INVALID &&
              connectionConnList[i + 1].connHandle == LINKDB_CONNHANDLE_INVALID)
          {
            break;
          }
          if (connectionConnList[i].connHandle == LINKDB_CONNHANDLE_INVALID &&
              connectionConnList[i + 1].connHandle != LINKDB_CONNHANDLE_INVALID)
          {
            memmove(&connectionConnList[i], &connectionConnList[i+1], sizeof(App_connInfo));
            connectionConnList[i + 1].connHandle = LINKDB_CONNHANDLE_INVALID;
          }
      }
    
      return index;
    }
    
    /*********************************************************************
     * @fn      Connection_getConnList
     *
     * @brief   Get the connection list
     *
     * @return  connection list
     */
    App_connInfo *Connection_getConnList(void)
    {
      return connectionConnList;
    }
    
    /*********************************************************************
     * @fn      Connection_getConnhandle
     *
     * @brief   Find connHandle in the connected device list by index
     *
     * @return  the connHandle found. If there is no match,
     *          MAX_NUM_BLE_CONNS will be returned.
     */
    uint16_t Connection_getConnhandle(uint8_t index)
    {
    
        if (index < MAX_NUM_BLE_CONNS)
        {
          return connectionConnList[index].connHandle;
        }
    
      return MAX_NUM_BLE_CONNS;
    }
    
    // void timeoutHandler1(uintptr_t arg)
    // {
    //   // BLEAppUtil_invokeFunctionNoData(InvokeFromBLEAppUtilContext_t callback)
    //   gapUpdateLinkParamReq_t pParamUpdateReq =
    //   {
    //     .connectionHandle = connHandle1,
    //     .intervalMin = 400,
    //     .intervalMax = 800,
    //     .connLatency = 0,
    //     .connTimeout = 600
    //   };
    
    //   // Send a connection param update request
    //   BLEAppUtil_paramUpdateReq(&pParamUpdateReq);
      
    //   // ClockP_stop(clockHandle1);
    // }
    /*********************************************************************
     * @fn      Connection_start
     *
     * @brief   This function is called after stack initialization,
     *          the purpose of this function is to initialize and
     *          register the specific events handlers of the connection
     *          application module
     *
     * @return  SUCCESS, errorInfo
     */
    bStatus_t Connection_start()
    {
        bStatus_t status = SUCCESS;
        uint8 i;
    
        // Initialize the connList handles
        for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
        {
            connectionConnList[i].connHandle = LINKDB_CONNHANDLE_INVALID;
        }
    
        status = BLEAppUtil_registerEventHandler(&connectionConnHandler);
        if(status != SUCCESS)
        {
            return(status);
        }
    
        status = BLEAppUtil_registerEventHandler(&connectionHciGAPHandler);
        if(status != SUCCESS)
        {
            return(status);
        }
    
        // Intialize ClockP instance
        ClockP_Params_init(&c_params);
        c_params.period = 4800000;
        c_params.startFlag = false;
        c_handle = ClockP_create(clock_fxn, 0, &c_params);
    
        return status;
    }
    
    /*********************************************************************
     * @fn      Connection_getConnIndex
     *
     * @brief   Find index in the connected device list by connHandle
     *
     * @return  the index of the entry that has the given connection handle.
     *          if there is no match, LL_INACTIVE_CONNECTIONS will be returned.
     */
    uint16_t Connection_getConnIndex(uint16_t connHandle)
    {
      uint8_t i;
    
      for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
      {
        if (connectionConnList[i].connHandle == connHandle)
        {
          return i;
        }
      }
    
      return LL_INACTIVE_CONNECTIONS;
    }
    
    #endif // ( HOST_CONFIG & (CENTRAL_CFG | PERIPHERAL_CFG) )
    

    Please let me know if you continue seeing the issue, or if you have any more questions!

    Best Regards,

    Tarek D

  • Hi,

    I'm able to build a hex with your provided changes to app_connection.c & connect an iPhone to 'Basic BLE project' via NRF connect.

    I'm not sure how to proceed from here, as I have no logs. I'm able to open a serial connection via my JLink, but I don't see any logs coming through.

    I'd like to be able to validate how the stack is handling the connparam exchange, and to be able to try out a few things like changing


    // Pass parameter updates to the app for it to decide.
    #define DEFAULT_PARAM_UPDATE_REQ_DECISION       GAP_UPDATE_REQ_PASS_TO_APP
    to

    // Pass parameter updates to the app for it to decide.
    #define DEFAULT_PARAM_UPDATE_REQ_DECISION       GAP_UPDATE_REQ_ACCEPT_ALL
  • Hey Xavier,

    My apologies for the delay! I was out of office.

    You can validate this in a few different ways:

    • You can modify the code to light any led you have on your custom board, once the connection parameter update request sent
    • You can modify the code to output to your jlink once the connection parameter update request is sent
    • Via a packet sniffer

    I apologize for not being able to provide a more detailed solution, but I don't have enough info regarding your custom board.

    I hope this helps! Please let me know if you have any more questions or if you need my help implementing this.

    Best Regards,

    Tarek D