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: Getting Char Value 0x00

Part Number: CC2340R5

Tool/software:

Hi Forum,

I have implemented GAP Client Role in which i am trying to discover a char handles using char UUID using API "GATT_DiscCharsByUUID" and finding Handles. Using those Handle i am trying to read a char value using API "GATT_ReadCharValue()". the response i am getting 0x00, but actual char value is 0x02.

I tried with other client(nRF Connect) i tried connecting to Peripheral device and read same char value and i got correct response i.e. 0x02. 

I am sure of "char Handle" value, since i've verified with sniffer.

uint8_t UUID[2] = {0xF0,0xFF};
void disc_services()
{
    switch(Disc_state)
    {
        case MTU_EXCHANGE:
        {
            sprint("\nMTU Exchange");
            uint8_t status;
            attExchangeMTUReq_t req;
            req.clientRxMTU = MAX_PDU_SIZE- L2CAP_HDR_SIZE;
            status = GATT_ExchangeMTU(App_connHndl, &req, BLEAppUtil_getSelfEntity());
            if(status == SUCCESS)
                {
                    Disc_state = DISCOVER_PRIMARY_SERVICE;
                }
            else{
                    Disc_state = DISC_FAIL;
                }
    
            break;
        }
        case DISCOVER_PRIMARY_SERVICE:
         {
                sprint("\nDiscovery Primary Service");
                uint8_t status;
                status = GATT_DiscPrimaryServiceByUUID(App_connHndl,UUID, ATT_BT_UUID_SIZE, BLEAppUtil_getSelfEntity());
                if( status == SUCCESS)
                    {
                        sprint("\nStatus:");print(&status,1);
                        Disc_state = STORE_PRIM_SERVICE_HNDLS;
                    }
                else
                    {
                        Disc_state = DISC_FAIL;
                    }
                           
            break;
         }

        case STORE_PRIM_SERVICE_HNDLS:
                {
                sprint("\nStore Prim Service Hndls");
                if(gattMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP)
                    {
                        startHndl = ATT_ATTR_HANDLE(gattMsg->msg.findByTypeValueRsp.pHandlesInfo,0);
                        endHndl   = ATT_GRP_END_HANDLE(gattMsg->msg.findByTypeValueRsp.pHandlesInfo,0);
                        sprint("\nstart:");print(&startHndl,2);sprint(" | end:");print(&endHndl,2);
                        Disc_state = DISCOVER_SERVICE_CHAR;
                        BLEAppUtil_invokeFunctionNoData(disc_services);
                    }
                    break;
                }

        case DISCOVER_SERVICE_CHAR:
            {
            sprint("\nDiscover_Service_Char");
            uint8_t status;
            uint8_t serUUID[2] = {0xF2,0xFF};
            attReadByTypeReq_t pReq;
            pReq.startHandle   = startHndl;
            pReq.endHandle     = endHndl;
            pReq.type.len          = ATT_BT_UUID_SIZE;
            memcpy(pReq.type.uuid,serUUID,ATT_BT_UUID_SIZE);
    
            status = GATT_DiscCharsByUUID(App_connHndl,&pReq,BLEAppUtil_getSelfEntity());
            sprint("\nStatus:");print(&status,1);
            if(status == SUCCESS)
                {
                    Disc_state =  STORE_SERVICE_HNDL;
                }
            break;
            }

        case STORE_SERVICE_HNDL:
             {
                sprint("\nSTORE_SERVICE_HNDL");
                if(gattMsg->method == ATT_READ_BY_TYPE_RSP )
                    {
                        sprint("\nDataLen:");print(&gattMsg->msg.readByTypeRsp.dataLen,2);
                        sprint("\nnumPair:");print(&gattMsg->msg.readByTypeRsp.numPairs,1);
                        if( gattMsg->msg.readByTypeRsp.numPairs > 0)
                            {
                                uint16_t rspUUID;
                                for(uint8_t i=0; i < gattMsg->msg.readByTypeRsp.numPairs; i++)
                                    {
                                        uint8_t* p = gattMsg->msg.readByTypeRsp.pDataList + i*gattMsg->msg.readByTypeRsp.len;                                        
                                        rspUUID = BUILD_UINT16(p[5], p[6]);
                                        if(rspUUID == 0xFFF2)
                                            {
                                                char_startHndl  = BUILD_UINT16(p[3],p[4]);
                                                char_endHndl    = BUILD_UINT16(p[7],p[8]);
                                                Disc_state = READ_CHAR_VAL;
                                                sprint("\nDone...");sprint("start: ");print(&char_startHndl,2);sprint("EndHndl:");print(&char_endHndl,2);
                                                BLEAppUtil_invokeFunctionNoData(disc_services);
                                            }
                                    }
                            }
                            else
                                sprint("\nNum Pairs are less");
                    }
        break;
        }

        case READ_CHAR_VAL:
        {
            sprint("\nREAD_CHAR_VAL");
            uint8_t status;
            attReadReq_t pReq;
            pReq.handle = char_startHndl;
            sprint(" | Hndl:");print(&pReq.handle,2);
            status =  GATT_ReadCharValue(App_connHndl,&pReq,BLEAppUtil_getSelfEntity());
            if(status == SUCCESS)
                {
                    Disc_state = DISPLAY_CHAR_VAL;
                }
            else
                {
                    sprint(" | status:");print(&status,1);
                    Disc_state = READ_CHAR_VAL;
                    BLEAppUtil_invokeFunctionNoData(disc_services);
                }
            
        break;
        }
        case DISPLAY_CHAR_VAL:
        {
          sprint("\nDISPLAY_CHAR_VAL");
          sprint("\nMsg:");print(&gattMsg->msg.readRsp,2);
          Disc_state = DISC_COMPLETE;
        break;
        }

Please let me know, why i am getting wrong response.

Regards

Vaibhav

  • Hi !

    The way you are reading your characteristic value is a bit unconventional. You are correct that calling GATT_ReadCharValue is the correct way to go, however this function is asynchronous and will not block the program. What will happen is that the function will return 0 because it successfuly sent a ATT value read packet to the peripheral, but it will take some time before the peripheral replies with the value.

    What you should be doing is define a BLEAppUtil_EventHandler_t object to give to the BLEAppUtil_registerEventHandler function. In your BLEAppUtil_EventHandler_t, you can define a event handler, which will be called every time a ATT event in your event mask is received by the BLE stack. This will in turn call your function with a BLEAppUtil_msgHdr_t parameter. You can then cast this parameter into a gattMsgEvent_t, filter for the type of event, and call the appropriate function you want to call.

    As an example, your code could look like this :

    //*****************************************************************************
    //! Includes
    //*****************************************************************************
    
    #include <ti/ble/app_util/menu/menu_module.h>
    #include <ti/ble/app_util/framework/bleapputil_api.h>
    
    //*****************************************************************************
    //! Globals
    //*****************************************************************************
    
    // Events handlers struct, contains the handlers and event masks
    // of the application data module
    BLEAppUtil_EventHandler_t dataGATTHandler =
    {
        .handlerType    = BLEAPPUTIL_GATT_TYPE,
        .pEventHandler  = ATTUtil_EventHandler,
        .eventMask      = BLEAPPUTIL_ATT_READ_RSP |
                          BLEAPPUTIL_ATT_ERROR_RSP
    };
    
    //*****************************************************************************
    //! Functions
    //*****************************************************************************
    
    /*********************************************************************
     * @fn      Data_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 data
     *          application module
     *
     * @return  SUCCESS, errorInfo
     */
    bStatus_t Data_start( void )
    {
      bStatus_t status = SUCCESS;
    
      // Register the handlers
      status = BLEAppUtil_registerEventHandler( &dataGATTHandler );
    
      // Return status value
      return( status );
    }
    
    /*********************************************************************
     * @fn      ATTUtil_EventHandler
     *
     * @brief   This function is called when the BLE stack recieved an ATT
     *          packet. the pMsgData parameter contains all the unformatted
     *          information of the packet.
     * 
     * @param   event - unused
     * @param   pMsgData - data of the event
     *          
     * @return  none
     */
    void ATTUtil_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
        gattMsgEvent_t *gattMsg = ( gattMsgEvent_t * )pMsgData;
        
        switch ( gattMsg->method )
        {
            case ATT_READ_RSP:
            {
                attReadRsp_t readResponse = gattMsg->msg.readRsp;
                uint8_t rspStatus = gattMsg->hdr.status;
    
                # Do something with the response, like displaying it like you did
                GATT_bm_free(&gattMsg->msg, ATT_READ_RSP );
            }
            break;
    
            case ATT_ERROR_RSP:
            {
                attErrorRsp_t errResponse = gattMsg->msg.errorRsp;
                uint8_t rspStatus = gattMsg->hdr.status;
    
                # Handle the error
                GATT_bm_free(&gattMsg->msg, ATT_ERROR_RSP );
            }
            break;
    
    
            default:
                break;
        }
    }

    Please try to adapt your code to use an ATT event handler like I show you in the example, and tell me if you still have the same issue.


    Kind regards,
    Maxence

  • Hi Maxence,

    I have already followed your suggest approach. Please take a look

    /******************************************************************************
    
    @file  app_data.c
    
    @brief This file contains the application data functionality
    
    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.
    
    ******************************************************************************
    
    
    *****************************************************************************/
    
    //*****************************************************************************
    //! Includes
    //*****************************************************************************
    #include <string.h>
    #include "ti/ble/app_util/framework/bleapputil_api.h"
    #include "ti/ble/app_util/menu/menu_module.h"
    #include <app_main.h>
    #include "Client/client.h"
    #include <ti/drivers/UART2.h>
    
    //*****************************************************************************
    //! Defines
    BLEAppUtil_entityId_t getSelfEntity; 
    gattMsgEvent_t *gattMsg;
    //*****************************************************************************
    
    //*****************************************************************************
    //! Globals
    extern UART2_Handle uart;
    extern uint16_t App_connHndl;
    extern void disc_services();
    extern uint8_t Disc_state;
    //*****************************************************************************
    
    static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
    
    // Events handlers struct, contains the handlers and event masks
    // of the application data module
    BLEAppUtil_EventHandler_t dataGATTHandler =
    {
        .handlerType    = BLEAPPUTIL_GATT_TYPE,
        .pEventHandler  = GATT_EventHandler,
        .eventMask      = BLEAPPUTIL_ATT_FLOW_CTRL_VIOLATED_EVENT |
                          BLEAPPUTIL_ATT_EXCHANGE_MTU_RSP |
                          BLEAPPUTIL_ATT_FIND_INFO_RSP |
                          BLEAPPUTIL_ATT_READ_RSP |
                          BLEAPPUTIL_ATT_READ_BY_TYPE_RSP|
                          BLEAPPUTIL_ATT_FIND_BY_TYPE_VALUE_RSP |
                          BLEAPPUTIL_ATT_READ_BY_GRP_TYPE_RSP
    
    };
    
    //*****************************************************************************
    //! Functions
    //*****************************************************************************
    
    /*********************************************************************
     * @fn      GATT_EventHandler
     *
     * @brief   The purpose of this function is to handle GATT events
     *          that rise from the GATT and were registered in
     *          @ref BLEAppUtil_RegisterGAPEvent
     *
     * @param   event - message event.
     * @param   pMsgData - pointer to message data.
     *
     * @return  none
     */
    static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
      getSelfEntity = BLEAppUtil_getSelfEntity();
      gattMsg = ( gattMsgEvent_t * )pMsgData;
    
      // sprint("\nGATT_MSG:");
      // print(&gattMsg->msg,10);
      switch ( gattMsg->method )
      {
        case ATT_FLOW_CTRL_VIOLATED_EVENT:
          {
              
          }
          break;
    
        case ATT_EXCHANGE_MTU_RSP:
          {
              sprint("\nMTU Updated");
               disc_services();
          }
          break;
    
      
        case ATT_READ_RSP :
        case ATT_FIND_INFO_RSP:
        case ATT_READ_BY_TYPE_RSP:   
        case ATT_FIND_BY_TYPE_VALUE_RSP:
          {
          if(Disc_state != DISC_COMPLETE)
              {
                disc_services();
              }
          }
        break;
    
        default:
          break;
      }
      GATT_bm_free(&(gattMsg->msg), gattMsg->method);
    }
    
    /*********************************************************************
     * @fn      Data_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 data
     *          application module
     *
     * @return  SUCCESS, errorInfo
     */
    bStatus_t Data_start( void )
    {
      bStatus_t status = SUCCESS;
    
      // Register the handlers
      status = BLEAppUtil_registerEventHandler( &dataGATTHandler );
    
      // Return status value
      return( status );
    }
    

  • Hi !

    You could try to check if the GATT msg method received is of the right type in the READ_CHAR_VAL case, similar to what you're doing in the STORE_SERVICE_HNDL case.

    You can also try to hardcode the UUID and print the UUID you used to receive to see if you are actually querying the correct GATT attribute.

    Kind regards,
    Maxemce