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.

CC2640R2F: Issues with GATT_readlongcharvalue

Part Number: CC2640R2F

Hi everyone,

We have an issue concern the GATT_ReadLongCharValue function. From the developer's guide (http://www.ti.com/lit/ug/swru393d/swru393d.pdf) we read that 

"If the return status is SUCCESS, the calling application task receives multiple GATT_MSG_EVENT messages with type ATT_READ_BLOB_RSP or ATT_ERROR_RSP (if an error occurred on the server). This subprocedure is complete when either ATT_READ_BLOB_RSP (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP (with SUCCESS status) is received by the calling application task.", 
but when we check the last packet's status, it is SUCCESS, and not bleProcedurComplete, as expected. We have encountered this issue in communication between two cc2640r2 (central on peripheral), while, when we try to do this with btool, the btool get bleProcedureComplete. 
We have encountered another issue, when, after a long read, we try to do a write on another peripheral characteristic. We encounter that the write doesn't return write_rsp callback (see pkt n. 153 of log_pairing.psd)
Hoping in some suggestion, thanks in advance for the help.
  • Hi Roberto,

    Please make sure the ATT_READ_BLOB_RSP is properly handled in SimpleBLECentral_processGATTMsg().
  • Hi Marie,

    I post my processGATTMsg handle (Note that I'm using as start project "Multi role project").

    I handle ATT_READ_BLOB_RSP as below:

    static uint8_t multi_role_processGATTMsg(gattMsgEvent_t *pMsg)
    {
    
      // See if GATT server was unable to transmit an ATT response
      if (pMsg->hdr.status == blePending)
      {
        // No HCI buffer was available. Let's try to retransmit the response
        // on the next connection event.
        if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
                                       MR_CONN_EVT_END_EVT) == SUCCESS)
        {
          // First free any pending response
          multi_role_freeAttRsp(FAILURE);
    
          // Hold on to the response message for retransmission
          pAttRsp = pMsg;
    
          // Don't free the response message yet
          return (FALSE);
        }
      }
      else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
      {
        // ATT request-response or indication-confirmation flow control is
        // violated. All subsequent ATT requests or indications will be dropped.
        // The app is informed in case it wants to drop the connection.
    
        // Display the opcode of the message that caused the violation.
        //Display_print1(dispHandle, MR_ROW_STATUS1, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
          DebugPush("FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
      }
      else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
      {
        // MTU size updated
        Display_print1(dispHandle, MR_ROW_STATUS1, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
      }
      else if(pMsg->method == ATT_HANDLE_VALUE_NOTI){
          //i dati sono contenuti in pMsg->msg.handleValueNoti
          uint8_t notify_packet[2]={0};
          memcpy(&notify_packet, pMsg->msg.handleValueNoti.pValue, 2*sizeof(uint8_t));
          //indica la lettura
          doWrite = FALSE;
          //devo leggere la caratteristica 7 che è la n 6 nel vettore dove mi sono memorizzato
          //le caratteristiche
          assign_char_index=6;
          mr_doGattRw(0);
      }
      // Messages from GATT server
      if (linkDB_NumActive() > 0)
      {
        // Find index from connection handle
        connIndex = multi_role_mapConnHandleToIndex(pMsg->connHandle);
        if ((pMsg->method == ATT_READ_RSP)   ||
            ((pMsg->method == ATT_ERROR_RSP) &&
             (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
        {
          if (pMsg->method == ATT_ERROR_RSP)
          {
            Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Read Error %d", pMsg->msg.errorRsp.errCode);
          }
          else
          {
            // After a successful read, display the read value
            Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Read rsp: %d", pMsg->msg.readRsp.pValue[0]);
            //Test write dopo una semplice read
            multi_role_GetPingHandle(&pingReqArg);
            isOutputBufferWritten=1;
            doWrite = TRUE;
            assign_char_index=4;
            memset(&charVal, GET_PING, sizeof(uint8_t));
            memcpy(&charVal[1],&pingReqArg,4*sizeof(uint8_t));
            DebugPush("%d", charVal);
            message_size_temp[0]=0x00;
            message_size_temp[1]=0x05;
            mr_doGattRw(0);
            //Fine
          }
        }
        else if ((pMsg->method == ATT_WRITE_RSP)  ||
                 ((pMsg->method == ATT_ERROR_RSP) &&
                  (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
        {
            Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Write status: %d", pMsg->hdr.status);
          if (pMsg->method == ATT_ERROR_RSP == ATT_ERROR_RSP)
          {
            Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Write Error %d", pMsg->msg.errorRsp.errCode);
          }
          else
          {
            // After a succesful write, display the value that was written and
            // increment value
              Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Write sent: %d", charVal);
              if(isOutputBufferWritten==1){
                  assign_char_index=3;
                  doWrite = TRUE;
                  memcpy(&charVal, &message_size_temp, 2*sizeof(uint8_t));
                  message_size_temp[0]=0x00;
                  message_size_temp[1]=0x02;
                  mr_doGattRw(0);
                  isOutputBufferWritten=0;
              }
          }
        }
        else if ((pMsg->method == ATT_READ_BLOB_RSP)  ||
                 ((pMsg->method == ATT_ERROR_RSP) &&
                  (pMsg->msg.errorRsp.reqOpcode == ATT_READ_BLOB_REQ))){
            if (pMsg->method == ATT_ERROR_RSP)
                  {
                    Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Blob read Error %d", pMsg->msg.errorRsp.errCode);
                  }
            else{
                Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Read blob status: %d", pMsg->hdr.status);
                if(pMsg->hdr.status!=bleProcedureComplete){
                if(indice_read_blob<PUBLIC_KEY_SIZE+2){
                    if((pMsg->msg.readBlobRsp.pValue[0]==ble_central_cmd_verify)&&(indice_read_blob==0)){
                        memcpy(radio_event_buf+((9+indice_read_blob)*sizeof(uint8_t)),pMsg->msg.readBlobRsp.pValue+(2*sizeof(uint8_t)), (pMsg->msg.readBlobRsp.len-2)*sizeof(uint8_t));
                    }
                    else if((pMsg->msg.readBlobRsp.pValue[0]!=ble_central_cmd_verify)&&(indice_read_blob==0)){
                        indice_read_blob=PUBLIC_KEY_SIZE*10;
                        check_cmd_response=1;
                    }
                    else if(indice_read_blob>0){
                        memcpy(radio_event_buf+((9+indice_read_blob)*sizeof(uint8_t)),pMsg->msg.readBlobRsp.pValue, pMsg->msg.readBlobRsp.len*sizeof(uint8_t));
                    }
                    else{
                        DebugPush("Errore");
                    }
                    indice_read_blob = indice_read_blob + pMsg->msg.readBlobRsp.len;
                    if(indice_read_blob==PUBLIC_KEY_SIZE+2){
                        //workaround
                        doWrite=TRUE;
                        assign_char_index=6;
                        message_size_temp[0]=0x00;
                        message_size_temp[1]=0x01;
                        mr_doGattRw(0);
                    }
                }else{
                    DebugPush("Errore2");
                }
                }
                else{
                    //Display_print1(dispHandle, MR_ROW_STATUS2, 0, "Read blob rsp: %d", &radio_event_buf);
                    indice_read_blob=0;
                    if(check_cmd_response==1){
                        //devo buttare tutto
                        check_cmd_response=0;
                    }else{
                        switch(ble_central_cmd_verify){
                        case GET_PBKEY:
                            switch(centralStatus){
                            case PAIRING_STATUS:
                                //devo inviare una ping request
                                //da verificare se è stata fatta bene
                                multi_role_GetPingHandle(&pingReqArg);
                                isOutputBufferWritten=1;
                                doWrite = TRUE;
                                assign_char_index=4;
                                memset(&charVal, GET_PING, 5*sizeof(uint8_t));
                                //memcpy(&charVal[1],&pingReqArg,4*sizeof(uint8_t));
                                //DebugPush("%d", charVal);
                                message_size_temp[0]=0x00;
                                message_size_temp[1]=0x01;
                                mr_doGattRw(0);
                                break;
                            case CONNECTION_REQUEST_STATUS:
                            case NORMAL_STATUS:
                            default:
                                break;
                            }
                            case GET_PING:
                                if(multi_role_GetPingCheck(radio_event_buf)){
                                    switch(centralStatus){
                                    case PAIRING_STATUS:
                                        radioEventPushFxn(radio_event_buf);
                                        GPIO_writeDio(GD0_PIN,1);
                                        Task_sleep(100);
                                        GPIO_writeDio(GD0_PIN,0);
                                        break;
                                    case CONNECTION_REQUEST_STATUS:
                                        break;
                                    case NORMAL_STATUS:
                                        break;
                                    default:
                                        break;
                                    }
                                }else{
                                    //Se fallisce il confronto del tick
                                    //devo fare i retry
                                }
                                break;
                        }
                    }
                    ble_central_cmd_verify=0xff;
                }
            }
        }
        else if (discInfo[connIndex].discState != BLE_DISC_STATE_IDLE)
        {
          multi_role_processGATTDiscEvent(pMsg);
        }
      } // Else - in case a GATT message came after a connection has dropped, ignore it.
    
      // Free message payload. Needed only for ATT Protocol messages
      GATT_bm_free(&pMsg->msg, pMsg->method);
      // It's safe to free the incoming message
      return (TRUE);
    }

    Thanks for the help.

  • Hi Roberto,

    According to the docmentation, the long read process will be terminated with "either ATT_READ_BLOB_RSP (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP (with SUCCESS status)".

    I can't see that you check for a ATT_ERROR_RSP with SUCCESS status in your code?
  • Also, did you change the MAX_NUM_PDU? (Read about it here: software-dl.ti.com/.../index.html )
  • Hi Marie,

    under condition

    if ((pMsg->method == ATT_READ_BLOB_RSP)  ||
                 ((pMsg->method == ATT_ERROR_RSP) &&
                  (pMsg->msg.errorRsp.reqOpcode == ATT_READ_BLOB_REQ)))
    I handle
       
     if (pMsg->method == ATT_ERROR_RSP){ DebugPush("Read blob error");}
    But the code never reach this point, so, I never see debug print "Read blob error". It seems that the long read end procedure is triggered only when a next ble transaction is requested (write or read long), because, if I request a new write or read long operation after a first read long, the first status returned, is for the method ATT_READ_BLOB_RSP and has value bleProcedureComplete (0x1A).
    The only case the code doesn't enter that is when the condition 
    (pMsg->method == ATT_ERROR_RSP)  is true but the condition (pMsg->msg.errorRsp.reqOpcode == ATT_READ_BLOB_REQ) is false, but the request is a READ_BLOB_REQ!
    I've tried to place a debug print everytime the processGattmsg callback starts, but it prints only 6 times from read long operation starts.
    Do I have to change the condition?
    Thanks in advance for the help!
  • Hi Roberto,
    Did the change proposed in this thread help with the long read? e2e.ti.com/.../2175326