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.

CC1350: Characteristic stops sending data when client sets notify

Part Number: CC1350

I am working on a BLE application with the CC1350 and when I am reading from the sensor it works fine but when I set to notify it no longer updates the value

bStatus_t ADXL_setParameter(uint8_t param, uint8_t len, void *value)
{
  bStatus_t ret = SUCCESS;

  switch (param)
  {
    case SENSOR_DATA:
    if (len == SENSOR_DATA_LEN)
    {
      memcpy(sensorData, value, SENSOR_DATA_LEN);
      // See if Notification has been enabled
      ret = GATTServApp_ProcessCharCfg(sensorDataConfig, sensorData, FALSE,
                                 sensorAttrTable,
                                 GATT_NUM_ATTRS(sensorAttrTable),
                                 INVALID_TASK_ID, sensor_ReadAttrCB);
    }
    else
    {
      ret = bleInvalidRange;
    }
    break;

    case SENSOR_CONF:
      if (len == sizeof(uint8_t))
      {
        sensorCfg = *((uint8_t*)value);
      }
      else
      {
        ret = bleInvalidRange;
      }
      break;

    case SENSOR_PERI:
      if (len == sizeof(uint8_t))
      {
        sensorPeriod = *((uint8_t*)value);
      }
      else
      {
        ret = bleInvalidRange;
      }
      break;

    default:
      ret = INVALIDPARAMETER;
      break;
  }

  return (ret);
}

This is the code to set the parameter and here is my task loop for reading the sensor

static void sensorTaskFxn(UArg a0, UArg a1)
{
  uint8_t data[SENSOR_DATA_LEN];

  if(!adxlRegistered){
     DELAY_MS(100);
  }
  // Register task with BLE stack
  ICall_registerApp(&sensorSelfEntity, &sensorSem);

  // Deactivate task (active only when measurement is enabled)
  Task_setPri(Task_handle(&sensorTask), -1);

  // Task loop
  while (true)
  {
     data[0] = 0;
    if (sensorConfig == ST_CFG_SENSOR_ENABLE)
    {

      // Read data
      ADXL_read(data);

      // Update GATT
      ADXL_setParameter(SENSOR_DATA, SENSOR_DATA_LEN, data);

      // Next cycle
      DELAY_MS(100000);
    }
    else
    {
      DELAY_MS(SENSOR_DEFAULT_PERIOD);
    }
  }
}

I used the SensorTag example code for reference but I cannot see what I am doing wrong.

  • Hi, 

    Someone has been assigned to look into this. Meanwhile, please can you mention which SDK version you are using?

    Regards,
    Sid

  • Hi,

    1. As Siddanth asks, which version of the SimpleLink CC13x0 SDk are you using?

    2. Did you see the simple peripheral example, simple gatt profile? Characteristic 4 has the notify property. You can take this as an example implementation.

    3. If you need more help moving forward, please capture a sniffer log of the full process.

    Cheers,

    Marie H

  • I am using 13x0 2.20.1.8 and BLE 2.02.01.18

  • I have seen this example but it does not fit my needs. I am trying to make something like the 2650stk so that I can use the app I developed with both

  • nRF Connect, 2022-03-21
    YSU SensorTag (C4:64:E3:B4:DE:F4)
    V 16:27:25.415 Connecting to C4:64:E3:B4:DE:F4...
    D 16:27:25.415 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
    D 16:27:25.854 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
    I 16:27:25.854 Connected to C4:64:E3:B4:DE:F4
    D 16:27:25.870 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
    I 16:27:26.298 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
    V 16:27:26.823 Discovering services...
    D 16:27:26.823 gatt.discoverServices()
    D 16:27:26.850 [Callback] Services discovered with status: 0
    I 16:27:26.850 Services discovered
    V 16:27:26.860 Generic Access (0x1800)
    - Device Name [R] (0x2A00)
    - Appearance [R] (0x2A01)
    - Peripheral Preferred Connection Parameters [R] (0x2A04)
    Generic Attribute (0x1801)
    Device Information (0x180A)
    - System ID [R] (0x2A23)
    - Model Number String [R] (0x2A24)
    - Serial Number String [R] (0x2A25)
    - Firmware Revision String [R] (0x2A26)
    - Hardware Revision String [R] (0x2A27)
    - Software Revision String [R] (0x2A28)
    - Manufacturer Name String [R] (0x2A29)
    - IEEE 11073-20601 Regulatory Certification Data List [R] (0x2A2A)
    - PnP ID [R] (0x2A50)
    Unknown Service (0000ad00-0000-1000-8000-00805f9b34fb)
    - Unknown Characteristic [N R] (0000ad01-0000-1000-8000-00805f9b34fb)
       Client Characteristic Configuration (0x2902)
       Characteristic User Description (0x2901)
    - Unknown Characteristic [R W] (0000ad02-0000-1000-8000-00805f9b34fb)
       Characteristic User Description (0x2901)
    - Unknown Characteristic [R W] (0000ad03-0000-1000-8000-00805f9b34fb)
       Characteristic User Description (0x2901)
    Unknown Service (0000bf00-0000-1000-8000-00805f9b34fb)
    - Unknown Characteristic [N R] (0000bf01-0000-1000-8000-00805f9b34fb)
       Client Characteristic Configuration (0x2902)
       Characteristic User Description (0x2901)
    - Unknown Characteristic [R W] (0000bf02-0000-1000-8000-00805f9b34fb)
       Characteristic User Description (0x2901)
    - Unknown Characteristic [R W] (0000bf03-0000-1000-8000-00805f9b34fb)
       Characteristic User Description (0x2901)
    D 16:27:26.860 gatt.setCharacteristicNotification(0000ad01-0000-1000-8000-00805f9b34fb, true)
    D 16:27:26.863 gatt.setCharacteristicNotification(0000bf01-0000-1000-8000-00805f9b34fb, true)
    I 16:27:26.881 Connection parameters updated (interval: 45.0ms, latency: 0, timeout: 5000ms)
    V 16:27:34.898 Writing request to characteristic 0000ad02-0000-1000-8000-00805f9b34fb
    D 16:27:34.898 gatt.writeCharacteristic(0000ad02-0000-1000-8000-00805f9b34fb, value=0x01)
    I 16:27:35.163 Data written to 0000ad02-0000-1000-8000-00805f9b34fb, value: (0x) 01
    A 16:27:35.163 "(0x) 01" sent
    V 16:27:35.888 Reading characteristic 0000ad01-0000-1000-8000-00805f9b34fb
    D 16:27:35.888 gatt.readCharacteristic(0000ad01-0000-1000-8000-00805f9b34fb)
    I 16:27:36.107 Read Response received from 0000ad01-0000-1000-8000-00805f9b34fb, value: (0x) 42-01-E3-FE-75-01
    A 16:27:36.107 "(0x) 42-01-E3-FE-75-01" received
    V 16:27:38.748 Enabling notifications for 0000ad01-0000-1000-8000-00805f9b34fb
    D 16:27:38.748 gatt.setCharacteristicNotification(0000ad01-0000-1000-8000-00805f9b34fb, true)
    D 16:27:38.749 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
    I 16:27:38.896 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
    A 16:27:38.896 "Notifications enabled" sent
    V 16:27:38.910 Notifications enabled for 0000ad01-0000-1000-8000-00805f9b34fb
    V 16:27:44.364 Reading characteristic 0000ad01-0000-1000-8000-00805f9b34fb
    D 16:27:44.364 gatt.readCharacteristic(0000ad01-0000-1000-8000-00805f9b34fb)
    I 16:27:44.521 Read Response received from 0000ad01-0000-1000-8000-00805f9b34fb, value: (0x) 41-01-E4-FE-74-01
    A 16:27:44.521 "(0x) 41-01-E4-FE-74-01" received
    V 16:27:47.849 Reading characteristic 0000ad01-0000-1000-8000-00805f9b34fb
    D 16:27:47.849 gatt.readCharacteristic(0000ad01-0000-1000-8000-00805f9b34fb)
    I 16:27:47.988 Read Response received from 0000ad01-0000-1000-8000-00805f9b34fb, value: (0x) 41-01-E4-FE-74-01
    A 16:27:47.988 "(0x) 41-01-E4-FE-74-01" received
    V 16:28:07.849 Disconnecting...
    D 16:28:07.849 gatt.disconnect()
    D 16:28:07.854 [Callback] Connection state changed with status: 0 and new state: DISCONNECTED (0)
    I 16:28:07.854 Disconnected
    D 16:28:07.855 gatt.close()
    D 16:28:07.858 wait(200)

    This is from the test I just ran. The last two reads were manual to show that it no longer updates the value

  • Hi RJ,

    You need to implement a write callback in your service and check whether the CCC attribute has been written to. You can see a full walkthrough of how to implement a service in the SimpleLink Academy lab Custom Profile: 

    https://dev.ti.com/tirex/explore/node?node=ACAn8XZNDy1n1bEFwSDnJQ__BSEc4rl__LATEST

    Cheers,

    Marie H

  • I think I already have this. 

    static bStatus_t adxl_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
                                        uint8_t *pValue, uint16_t len,
                                        uint16_t offset, uint8_t method)
    {
      bStatus_t status = SUCCESS;
      uint8_t notifyApp = 0xFF;
      uint16_t uuid;
    
    
      if (utilExtractUuid16(pAttr,&uuid) == FAILURE) {
        // Invalid handle
        return ATT_ERR_INVALID_HANDLE;
      }
    
      switch (uuid)
      {
        case ADXL_DATA_UUID:
          // Should not get here
          break;
    
        case ADXL_CONF_UUID:
          // Validate the value
          // Make sure it's not a blob oper
          if (offset == 0)
          {
            if (len != 1)
            {
              status = ATT_ERR_INVALID_VALUE_SIZE;
            }
          }
          else
          {
            status = ATT_ERR_ATTR_NOT_LONG;
          }
    
          // Write the value
          if (status == SUCCESS)
          {
            uint8_t *pCurValue = (uint8_t *)pAttr->pValue;
    
            *pCurValue = pValue[0];
    
            if (pAttr->pValue == &adxlCfg)
            {
              notifyApp = SENSOR_CONF;
            }
          }
          break;
    
        case ADXL_PERI_UUID:
          // Validate the value
          // Make sure it's not a blob oper
          if (offset == 0)
          {
            if (len != 1)
            {
              status = ATT_ERR_INVALID_VALUE_SIZE;
            }
          }
          else
          {
            status = ATT_ERR_ATTR_NOT_LONG;
          }
          // Write the value
          if (status == SUCCESS)
          {
            if (pValue[0]>=(ADXL_MIN_UPDATE_PERIOD/SENSOR_PERIOD_RESOLUTION))
            {
    
              uint8_t *pCurValue = (uint8_t *)pAttr->pValue;
              *pCurValue = pValue[0];
    
              if (pAttr->pValue == &adxlPeriod)
              {
                notifyApp = SENSOR_PERI;
              }
            }
            else
            {
               status = ATT_ERR_INVALID_VALUE;
            }
          }
          break;
    
        case GATT_CLIENT_CHAR_CFG_UUID:
          status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
                                                  offset, GATT_CLIENT_CFG_NOTIFY);
          break;
    
        default:
          // Should never get here!
          status = ATT_ERR_ATTR_NOT_FOUND;
          break;
      }
    
      // If a characteristic value changed then callback function
      // to notify application of change
      if ((notifyApp != 0xFF) && adxl_AppCBs && adxl_AppCBs->pfnSensorChange)
      {
        adxl_AppCBs->pfnSensorChange(notifyApp);
      }
    
      return (status);
    }

  • It seems like it is stopping here:

    case HAL_ASSERT_CAUSE_ICALL_ABORT:
    Display_print0(dispHandle, 0, 0, "***ERROR***");
    Display_print0(dispHandle, 2, 0, ">> ICALL ABORT!");
    HAL_ASSERT_SPINLOCK;
    break;
    

  • Hi,

    Did you allocate the CCCD in your _AddService API?

    Ref. The code snippet from the SimpleLink Academy I posted:

    /*********************************************************************
     * @fn      SimpleProfile_AddService
     *
     * @brief   Initializes the Simple Profile service by registering
     *          GATT attributes with the GATT server.
     *
     * @param   services - services to add. This is a bit map and can
     *                     contain more than one service.
     *
     * @return  Success or Failure
     */
    bStatus_t SimpleProfile_AddService( uint32 services )
    {
      uint8 status;
    
      // Allocate Client Characteristic Configuration table
      simpleProfileChar4Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
                                                                MAX_NUM_BLE_CONNS );
      if ( simpleProfileChar4Config == NULL )
      {
        return ( bleMemAllocError );
      }
    
      // Initialize Client Characteristic Configuration attributes
      GATTServApp_InitCharCfg( LINKDB_CONNHANDLE_INVALID, simpleProfileChar4Config );
    
      if ( services & SIMPLEPROFILE_SERVICE )
      {
        // Register GATT attribute list and CBs with GATT Server App
        status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                              GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                              GATT_MAX_ENCRYPT_KEY_SIZE,
                                              &simpleProfileCBs );
      }
      else
      {
        status = SUCCESS;
      }
    
      return ( status );
    }

    Cheers,

    Marie H

  • The BLE Stack will call ICall_abort() when one of the below happens:

    • Calling a stack function through ICall in a stack callback or TI-RTOS SWI or HWI
    • Misconfiguring of additional ICall tasks or entities (usually when OSAL_MAX_NUM_PROXY_TASKS + 1 < than number of ICall tasks)
    • Incorrect ICall task registering
    • Stack API call timed out while ICall is waiting for a response
    • ICall encountered an error while executing a stack API
    • ICall_primSetTimer() or ICall_setTimer() are unable to create a clock object

    https://dev.ti.com/tirex/explore/content/simplelink_cc13xx_cc26xx_sdk_5_40_00_40/docs/ble5stack/ble_user_guide/html/ble-stack-5.x-guide/debugging-index.html?highlight=icall_abort#icall-abort 

    Cheers,

    Marie H

  • I have that

    bStatus_t ADXL_addService(void)
    {
      // Allocate Client Characteristic Configuration table
      adxlDataConfig = (gattCharCfg_t *)ICall_malloc(sizeof(gattCharCfg_t) *
                                                        linkDBNumConns);
      if (adxlDataConfig == NULL)
      {
        return (bleMemAllocError);
      }
    
      // Register with Link DB to receive link status change callback
      GATTServApp_InitCharCfg(INVALID_CONNHANDLE, adxlDataConfig);
    
      // Register GATT attribute list and CBs with GATT Server App
      return GATTServApp_RegisterService(adxlAttrTable,
                                          GATT_NUM_ATTRS (adxlAttrTable),
                                          GATT_MAX_ENCRYPT_KEY_SIZE,
                                          &adxlCBs);
    }