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.

SIMPLELINK-CC26X2-SDK: Connection drops when limited discoverable period ends

Part Number: SIMPLELINK-CC26X2-SDK

Using the CC2642R on custom boards, SDK version 2.10.00 (I'm aware this isn't the latest), application based on BLE5 Simple Peripheral.  I'm finding that if I call 

GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_DURATION , DEFAULT_ADVERTISING_DURATION);

and connect to the device while it is discoverable, the device will disconnect when DEFAULT_ADVERTISING_DURATION ends, and further calls to enable advertising are unsuccessful.  I have tried this with a couple different values (3000 and 4500 for 30s and 45s respectively) and have observed that the point of disconnection moves accordingly.

If I don't connect, the device stops advertising at the expected time, and another call to GapAdv_enable() begins another advertising period as expected.  But if I connect, the connection will work fine until exactly when the advertising duration timer would expire, and then my central that's connected to it reports a connection timeout error, and I can't reconnect or restart advertising without resetting the processor.

  • Oh, and for what it's worth, MAX_NUM_BLE_CONNS is set to 1, though I tried setting it to 2 just to see if letting Simple Peripheral restart advertising upon GAP_LINK_ESTABLISHED_EVENT would affect this behavior; it did not.  Of course, there is also still the call to re-enable advertising in the GAP_LINK_TERMINATED_EVENT, and yet advertising never restarted after disconnect automatically either.  I just checked setting a breakpoint in GAP_LINK_TERMINATED_EVENT, and I don't ever hit it when the connection drops right when the advertising timer would have stopped.

    If I change that one line of code back to 

          GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
    

    then I can stay connected indefinitely, and when I disconnect gracefully from the central, I receive GAP_LINK_TERMINATED_EVENT and advertising begins again.  So what's going wrong with limited discoverable mode?

  • Hi,

    I will try to reproduce it and get back to you asap.
  • Hi,

    I was able to see the same issue with the specific STACK version you stated. However, I did the same test with the newest SDK, and the issue is no longer there.

    Please migrate to the newest SDK which can be downloaded here :
    dev.ti.com/.../
  • I updated everything from 2.10, through 2.20, to 2.30 (a very painful process by the way), and I'm still seeing the exact same issue.

  • I believe I've found a bug in the SDK.  From simple_peripheral.c:

    static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg)
    {
      switch(pMsg->opcode)
      {
    ...
        case GAP_LINK_ESTABLISHED_EVENT:
        {
    ...
          uint8_t numActive = linkDB_NumActive();
    ...
          if (numActive < MAX_NUM_BLE_CONNS)
          {
            // Start advertising since there is room for more connections
            GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
          }
          else
          {
            // Stop advertising since there is no room for more connections
            GapAdv_disable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            GapAdv_disable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
          }
    

    If you've maxed out your connections, GapAdv_disable is called on the advertising sets, but there are too many parameters.  See the function prototype from gap_advertiser.h:

    extern bStatus_t GapAdv_disable(uint8 handle);
    

    That's consistent with the documentation here as well: http://dev.ti.com/tirex/content/simplelink_cc26x2_sdk_2_30_00_34/docs/ble5stack/ble_user_guide/doxygen/ble/html/group___gap_adv.html#ga4e45550a6887067a26b8cc797e3d51fe.

    It would seem that the extra parameters are copy/paste errors from GapAdv_enable().  But pushing extra values on the stack that the called function isn't expecting seems really bad, and possibly the source of my problem.  So I changed this in my code to the following:

            GapAdv_disable(advHandleLegacy);

    Sadly, that didn't help me any.  Probably still an issue; just not mine apparently.


    I did try a fresh build of Simple Peripheral on the launchpad at both 2.10 and 2.30, and I likewise see my issue present in the former, but not in the latter.  So is it something I could have carried with me when I ported the project up to the latest SDK version?  If so, since you guys fixed it and therefore hopefully know where it was, can you at least tell me where to look?

  • Hi Chris,

    I apologize for the late reply here. We will look into your finding and come back to you early next week.

    Best regards,
    Fredrik
  • Hi,

    The usage of GapAdv_disable is indeed wrong, so I would file a bug. Thanks for identifying a bug and reporting it back to us.

    However, the STACK only takes the first parameter, that means it will not affect the functionality.

    The reason there is no compilation error is because of icall_ble_api.h redefined the function which disable the parameter check.

    #define GapAdv_disable(...)                                                             (icall_directAPI(ICALL_SERVICE_CLASS_BLE, (uint32_t) IDX_GapAdv_disable , ##__VA_ARGS__))
    

    There has been lots of code update in the STACK so it's very difficult to identify which part of the code in the STACK makes the difference.

    The quickest way for me to help you is for you to provide code snippet and I can do the testing here.

  • I spent a decent amount of time over the last few days trying to narrow the issue down myself.  After I stated last week that I did not see the issue on a fresh workspace/import/build of SimplePeripheral 2.30 running on the Launchpad (it's worth noting this was the first time I had used the built-in target SoC), I replaced simple_peripheral.c, simple_peripheral.h, simple_gatt_profile.c, and simple_gatt_profile.h with the profile/service files from our project with the issue.  When I ran this on the Launchpad (also the first time I've run our code on hardware that wasn't ours), the issue was still present.  Since then, I had been slowly converting everything back to the default versions, function by function, rebuilding and testing every step of the way, assuming that at some point, the issue would go away, and I'd be able to isolate the code that's causing the issue.

    That seemed like a good plan, except the issue never went away.  I've now converted the entire project back to the point where a file diff utility says all the source files are identical (with the exception of the single legacy advertising set using a limited duration), and yet the issue persists.  I then created yet another fresh workspace/import/build of SimplePeripheral 2.30, changed only the advertising, and ran it on the same Launchpad; once again, it disconnected right at the end of the advertising duration timer.  It would seem that it maybe only worked the first time because it was a fresh board that hadn't gone astray yet, and once it did, I can't ever get it to go back, even with a practically unmodified example project.

    Testing this theory, I borrowed my coworker's Launchpad, and with the second clean project still open, loaded the exact same output files.  It did NOT disconnect, even though this was the exact same project that had just disconnected on my Launchpad.  Still keeping the project open, I reconnected my Launchpad again, reran the debugger, loaded the project again, and it continued to have the issue.  I then went back to my coworker's Launchpad and reloaded it again, and this time, it too disconnected.

    I know that's a flurry of test setups, and it might be difficult to keep it all straight, but let me call attention to the fact that my coworker's Launchpad never once had our profile/service loaded on it; the only thing I loaded onto it was the practically-out-of-the-box build of 2.30's SimplePeripheral example with only the basic change to advertising.  And with no changes to any of the files between tests, it worked the first time without disconnecting, and in a few attempts since, it has disconnected every time.

    So even though you saw it work, I did too, once, and I would ask you to test it again a few times.  The extent of the changes I made to simple_peripheral.c are entirely encapsulated in the snippet below:

            // Enable legacy advertising for set #1
    //        status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_DURATION, 4500);
            SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
    /*
            // Use long range params to create long range set #2
            GapAdv_params_t advParamLongRange = GAPADV_PARAMS_AE_LONG_RANGE_CONN;
    
            // Create Advertisement set #2 and assign handle
            status = GapAdv_create(&SimplePeripheral_advCallback, &advParamLongRange,
                                   &advHandleLongRange);
            SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
    
            // Load advertising data for set #2 that is statically allocated by the app
            status = GapAdv_loadByHandle(advHandleLongRange, GAP_ADV_DATA_TYPE_ADV,
                                         sizeof(advertData), advertData);
            SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
    
            // Load scan response data for set #2 that is statically allocated by the app
            status = GapAdv_loadByHandle(advHandleLongRange, GAP_ADV_DATA_TYPE_SCAN_RSP,
                                         sizeof(scanRspData), scanRspData);
            SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
    
            // Set event mask for set #2
            status = GapAdv_setEventMask(advHandleLongRange,
                                         GAP_ADV_EVT_MASK_START_AFTER_ENABLE |
                                         GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                                         GAP_ADV_EVT_MASK_SET_TERMINATED);
    
            // Enable long range advertising for set #2
            status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
    */
            // Display device address
            Display_printf(dispHandle, SP_ROW_IDA, 0, "%s Addr: %s",
                           (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID",
                           Util_convertBdAddr2Str(pPkt->devAddr));
    
            if (addrMode > ADDRMODE_RANDOM)
            {
              SimplePeripheral_updateRPA();
    
              // Create one-shot clock for RPA check event.
              Util_constructClock(&clkRpaRead, SimplePeripheral_clockHandler,
                                  SP_READ_RPA_EVT_PERIOD, 0, true,
                                  (UArg) &argRpaRead);
            }
          }
    
          break;
        }
    
        case GAP_LINK_ESTABLISHED_EVENT:
        {
          gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;
    
          // Display the amount of current connections
          uint8_t numActive = linkDB_NumActive();
          Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d",
                         (uint16_t)numActive);
    
          if (pPkt->hdr.status == SUCCESS)
          {
            // Add connection to list and start RSSI
            SimplePeripheral_addConn(pPkt->connectionHandle);
    
            // Display the address of this connection
            Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Connected to %s",
                           Util_convertBdAddr2Str(pPkt->devAddr));
    
            // Enable connection selection option
            tbm_setItemStatus(&spMenuMain, SP_ITEM_SELECT_CONN, TBM_ITEM_NONE);
    
            // Start Periodic Clock.
            Util_startClock(&clkPeriodic);
          }
    
          if (numActive < MAX_NUM_BLE_CONNS)
          {
            // Start advertising since there is room for more connections
    //        GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_DURATION, 4500);
    //        GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
          }
          else
          {
            // Stop advertising since there is no room for more connections
    //        GapAdv_disable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
            GapAdv_disable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
          }
    
          break;
        }
    
        case GAP_LINK_TERMINATED_EVENT:
        {
          gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg;
    
          // Display the amount of current connections
          uint8_t numActive = linkDB_NumActive();
          Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Device Disconnected!");
          Display_printf(dispHandle, SP_ROW_STATUS_2, 0, "Num Conns: %d",
                         (uint16_t)numActive);
    
          // Remove the connection from the list and disable RSSI if needed
          SimplePeripheral_removeConn(pPkt->connectionHandle);
    
          // If no active connections
          if (numActive == 0)
          {
            // Stop periodic clock
            Util_stopClock(&clkPeriodic);
    
            // Disable Connection Selection option
            tbm_setItemStatus(&spMenuMain, TBM_ITEM_NONE, SP_ITEM_SELECT_CONN);
          }
    
          // Start advertising since there is room for more connections
    //      GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
          GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_DURATION, 4500);
    //      GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);

  • Hi,

    I am looking into this now. I will test more and get back to you.
  • Hi. Thanks for the investigation, this does appear to be a bug. I am investigating whether a fix can be found in released code and thus immediately provided or whether this will need to go in the library and thus released in the next SDK.
  • Any update on this?

  • Hi,

    I was able to reproduce it however it only happen twice during my 1.5hour debugging.
    I was not able to get it to reproduce easily as you mentioned.
    That being said we are not able to identify the issue yet.

    Can you provide the IDE you are using and compiler version if you are using CCS.
  • Code Composer Studio
    Version: 7.2.0.00013

    Compiler version: TI v16.9.4.LTS
  • For SDK 2.30, you need to use 18.01.03.LTS.

    Can you run the software with correct compiler version again?
  • My colleague attempted to do this, and found an 18.9, but it wouldn't let him do 18.01.  It also resulted in a number of errors.  I will see if I can get him to share some details on this, but in the meantime, what is the best way to go about this?  I saw nothing in the documentation here that mentioned this as a requirement.  Where can we find the requirements listed, and a guide that shows the proper way to update?

  • The requirement is listed in release note. Release note comes with the SDK installation:

    ti/simplelink_cc26x2_sdk_2_30_00_34/release_notes_simplelink_cc26x2_sdk_2_30_00_34.html

    You can also use CCS 8.2 to see if it gives you less trouble.

  • Hi,

    Are you able to produce the issue with correct compiler settings?

    I will be off the following days for holidays, will continue working on this thread when I get back.
  • We ran into some issues getting the latest versions of CCS and the compiler to work (https://e2e.ti.com/support/tools/ccs/f/81/t/753415https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/751100).  While Tyler was working on that, I've been focused on a different project, and haven't been able to make it back to this one yet.

  • Checking to see if any progress has been made with this issue. I am seeing the same problem (dropped connection after advertising timeout) with the CC2640R2F SDK (simplelink_cc2640r2_sdk_2_30_00_28) while I am trying to do a BLE5 port of existing 4.2 code on that platform before switching it over to the CC26X2 SDK. I am using CCS Version: 8.2.0.00007, compiler v18.1.3.LTS, and XDCtools 3.50.8.24_core. The code is running on a CC2640R2F LaunchPad.

    This is a peripheral application that uses a button to enable advertising (disabled at startup) for 30 seconds. Only a single connection is allowed, so advertising is disabled until disconnection, after which it is enabled again for another 30 seconds, etc. This code works fine with the 4.2 blestack in the same SDK, using the original peripheral.c methodology. To convert to BLE5, I used ble5_simple_peripheral_cc2640r2lp_app as a reference and documented porting guides (where available; it would be helpful to maintain a better guide comparison between blestack and ble5stack usage). Everything else seems to work, including normal [enable advertise][connect/disable adv][disconnect enable adv] if I disable the advertising timeout feature and use GAP_ADV_ENABLE_OPTIONS_USE_MAX. However, when I use GAP_ADV_ENABLE_OPTIONS_USE_DURATION with duration 30*100, and connect to the device, the connection will drop after the 30 second timeout. If I disconnect on purpose before the timeout, everything works as expected. Here are some more details:

    * I am using the same event mask as SP, i.e. GapAdv_setEventMask(adv_handle_legacy,
    GAP_ADV_EVT_MASK_START_AFTER_ENABLE | GAP_ADV_EVT_MASK_END_AFTER_DISABLE | GAP_ADV_EVT_MASK_SET_TERMINATED);

    * I am not currently using the long range second advertising set; there is only the single legacy set.

    * When a button is pressed (or when the connection terminates), this is called: GapAdv_enable(adv_handle_legacy, GAP_ADV_ENABLE_OPTIONS_USE_DURATION, 30*100);

    * When a connection is made, this is called: GapAdv_disable(adv_handle_legacy);

    * The function for processing advertising events looks like this:
    static void processAdvEvent(gap_adv_event_data_t *event_data)
    {
    System_printf("Adv Evt: %08x\n", event_data->event);
    switch (event_data->event)
    {
    case GAP_EVT_ADV_START_AFTER_ENABLE:
    System_printf("Adv Set %d Enabled\n", *(uint8_t *)(event_data->buf));
    break;

    case GAP_EVT_ADV_END_AFTER_DISABLE:
    System_printf("Adv Set %d Disabled\n", *(uint8_t *)(event_data->buf));
    break;

    case GAP_EVT_ADV_SET_TERMINATED:
    {
    GapAdv_setTerm_t *advSetTerm = (GapAdv_setTerm_t *)(event_data->buf);
    System_printf("Adv Set %d disabled after conn %d\n", advSetTerm->handle, advSetTerm->connHandle );
    break;
    }

    case GAP_EVT_ADV_START:
    System_printf("Adv %d start\n", *(uint8_t *)(event_data->buf));
    break;

    case GAP_EVT_ADV_END:
    System_printf("Adv %d end\n", *(uint8_t *)(event_data->buf));
    break;

    case GAP_EVT_SCAN_REQ_RECEIVED:
    break;

    case GAP_EVT_INSUFFICIENT_MEMORY:
    System_printf("adv event memory fail\n");
    break;

    default:
    break;
    }

    // All events have associated memory to free except the insufficient memory event
    if (event_data->event != GAP_EVT_INSUFFICIENT_MEMORY)
    {
    ICall_free(event_data->buf);
    }
    }

    Given that, here is the sequence of log outputs:

    enable BLE advertising
    call GapAdv_enable status= 0x00
    Adv Evt: 00000001
    Adv Set 0 Enabled

    BLE connected to 5c:f3:70:81:f4:2d
    call GapAdv_disable status= 0x11 [bleAlreadyInRequestedMode]
    Adv Evt: 00000010
    Adv Set 0 disabled after conn 0
    Adv Evt: 00000010
    Adv Set 0 disabled after conn 0

    [30 seconds after enable; connection drops]
    Adv Evt: 00000010
    Adv Set 0 disabled after conn 255
    Adv Evt: 00000010
    Adv Set 0 disabled after conn 255

    Some observations and questions:

    1) the call to GapAdv_disable on connection seems to be unnecessary, and the results are the same if I comment it out.
    2) why are there two GAP_EVT_ADV_SET_TERMINATED each time?
    3) in this case, the app never receives GAP_LINK_TERMINATED_EVENT
    4) If I try to enable advertising again with a button push, GapAdv_enable returns bleInvalidRange and does not work again without a reset.

    Thanks for any new information or feedback you can provide.

    dave
  • Hi,

    Thanks for the information. We are still looking into this issue. Meanwhile can you try to use a software timer to disable advertisement like you did for BLE4.2 STACK?

    We will try to get you an update asap.
  • Hi,

    We are yet not able to identify the root cause. But the current workaround is to use a software time to stop the advertising and re-enable the advertising using software timer.
  • Hi Christin,

    Yeah, that is what I did. Thanks for the update.

    dave