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.

CC2650: Handles in central mode

Other Parts Discussed in Thread: CC2650

Hi everyone

I'd like to stream sensor data (20'kHz sampling rate, 16 bit words) from one CC2650+SmartRF06 evaluation board to another. I try to construct my code based on the simpleBLEPeripheral & SimpleBLECentral examples. After reading the CC2650 Developer's guide, I was able to modify the peripheral code and the GATT profile such that I can connect the peripheral device to my phone and exchange some data. Now I'd like to connect two peripheral CC2650 (GATT server) to the other CC2650 (GATT client). Aquestion about that:

I'd like to use notifications. To enable them, I know that the GATT client first needs to write 0x0001 to the configuration attribute of the characteristic that he wants to get notifications. Now in the simpleBLECentral example not UUIDs are used to write to a attribute but handles are used. How exactly is the client able to find out what handle belongs to a known UUID? Why do we use range uf handles (svcStartHdl, svcEndHdl)  in the example? Handle variable declaration from the example:

// Discovered service start and end handle
static uint16_t svcStartHdl = 0;
static uint16_t svcEndHdl = 0;

// Discovered characteristic handle
static uint16_t charHdl = 0;

  • Fabien Vultier said:
    How exactly is the client able to find out what handle belongs to a known UUID? Why do we use range uf handles (svcStartHdl, svcEndHdl)  in the example?

    1st, you'd want to find the correct service (given a UUID). As soon you discovered a service, you are given a range (or location) of handles (svcStartHdl and svcEndHdl) that belong to that service. By definition, a service can have multiple characteristics. Within these handles, you are looking for a specific Characteristic Declaration given with a specific UUID. The Characteristic Declaration contains the properties, a handle to its Characteristic Value and the UUID. Therefore, when you found the Characteristic Declaration, you've also found the handle to the Characteristic Value which is "charHdl".

  • Hi Tom

    Thank you for the answer!

    Tom Kopriva said:

    1st, you'd want to find the correct service (given a UUID). As soon you discovered a service, you are given a range (or location) of handles (svcStartHdl and svcEndHdl) that belong to that service. By definition, a service can have multiple characteristics. Within these handles, you are looking for a specific Characteristic Declaration given with a specific UUID.

    I understood this part. Here is my GATT profile declaration:

      // Simple Profile Service
      {
        { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
        GATT_PERMIT_READ,                         /* permissions */
        0,                                        /* handle */
        (uint8 *)&simpleProfileService            /* pValue */
      },

        // Characteristic Test Declaration
        {
          { ATT_BT_UUID_SIZE, characterUUID },
          GATT_PERMIT_READ,
          0,
          &simpleProfileCharTestProps
        },

      // Characteristic Value Test
      {
        { ATT_BT_UUID_SIZE, simpleProfilecharTestUUID },
        GATT_PERMIT_READ,
        0,
        &simpleProfileCharTest
      },

      // Characteristic Test configuration
      {
        { ATT_BT_UUID_SIZE, clientCharCfgUUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        (uint8 *)&simpleProfileCharTestConfig
      },

      // Characteristic Test User Description
      {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        simpleProfileCharTestUserDesp
      },


    There is one service. What I'like to do is to enable notifications for the test value characteristics. To do so I need to write 0x0001 to the test configuration characteristic. So I need to get a handle to this (the second last characteristic in the above code block) characteristic.


    Now about the second part of yur answer I am not sure wether I understood you correctly. Is the following procedure correct?

    First use

    req.startHandle = svcStartHdl;
    req.endHandle = svcEndHdl;
    req.type.len = ATT_BT_UUID_SIZE;
    req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHARTEST_UUID);
    req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHARTEST_UUID);
    VOID GATT_ReadUsingCharUUID(connHandle, &req, selfEntity);

    and

      else if (discState == BLE_DISC_STATE_CHAR)
      {
        // Characteristic found, store handle
        if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->msg.readByTypeRsp.numPairs > 0))
        {
          charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0], pMsg->msg.readByTypeRsp.pDataList[1]);
          
          LCD_WRITE_STRING_VALUE("charHdl:", charHdl, 10, LCD_PAGE6);

          LCD_WRITE_STRING("Simple Svc Found", LCD_PAGE2);
          procedureInProgress = FALSE;
        }
        
        discState = BLE_DISC_STATE_IDLE;
      }

    to get a handle (charHdl). With this handle I can now read (and eventually write) to the characteristic test declaration (the fourth last characteristic in the above decaration). Correct?

    But my goal is to write to the second last characteristic in the above declaration. So I need to read from the characteristic test declaration to get a handle to the "Characteristic Test configuration". How to do this? This is not done in the simpleBLECentral example.

  • I managed to solve the problem. The handle of the characteristic that I need to write to seems to be 40. How to discover this information is still not clear to me, but it works now and I get notifications.

    Other question:
    How should I design my application to sample at 20kHz 12 bit samples from the ADC and transmit over bluetooth? The sample is properly wroking (I used sensor controller studio to program the sensor controller). So I get alerts if the ring buffer contains 120 samples. Now my idea is that in the interrupt routine I copy these 120 samples to a buffer and add a message with a pointer to that bufferto the RTOS message queue. Then if the message is dequeued and processed, I write the 120 samples to a single characteristic value. This characteristic has notifications enabled.
    Is this the standard approach for high data rates or should I proceed differently? Maybe using multiple characteristics (max 4) with notifications enabled. Can I call the function SimpleProfile_SetParameter(...) twice directly after eachother or will I loose data this way?