Problems with sd_ble_gattc_write()

Hello everyone,

I used the Multirole example as base for my code. My target is to make a communication with two NRF52382. I changed the HRS (heart rate servide) to my custom service and custom characteristic. After that I implemented the function sd_ble_gattc_read to the code and this also works. The Central is able to read out the characteristic data (500 bytes) of the Peripheral.

My next target is now to write into the characteristic with the function sd_ble_gattc_write(). My MAX_MTU_SIZE is 103 therefore I checked the MSC for the usage of sd_ble_gattc_write. I made it really similar to the read function, but I get always the err_code =1 which is SVC Handler is Missing. I am not 100% sure what this means and what could cause this problem. As handler for the write function I used the same one like in the read.

void ble_hrs_c_local_data_write(ble_hrs_c_t const *p_ble_hrs_c)
{     

      ble_gattc_write_params_t write_params;
      ret_code_t             err_code;
      uint8_t writestatus = 0;

      uint8_t data_write_one[100];
      uint8_t data_write_two[100];
      uint8_t data_write_three[100];
      uint8_t data_write_four[100];
      uint8_t data_write_five[100];

      for(int i = 0; i<=99; i++)
      {
        data_write_one[i]= 57;
        data_write_two[i]= 57;
        data_write_three[i]= 57;
        data_write_four[i]= 57;
        data_write_five[i]= 57;
        //Data of the own characteristic ist here: hrs_init_params.data
        // Data split into parts
      }

      nrf_delay_ms(300);
        
      write_params.len = 100;
      write_params.offset = 0;
   //  write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
       write_params.handle = p_ble_hrs_c->peer_hrs_db.hrm_handle;


       for(int i = 0; i<=5; i++)
       { 
      write_params.write_op = BLE_GATT_OP_PREP_WRITE_REQ;

      switch (writestatus)
      {
      case 0:
      write_params.p_value = &data_write_one[100];
      break;
      case 1:
      write_params.p_value = &data_write_two[100];
      break;
            case 2:
      write_params.p_value = &data_write_three[100];
      break;
            case 3:
      write_params.p_value = &data_write_four[100];
      break;
            case 4:
      write_params.p_value = &data_write_five[100];
      break;
       case 5:
      write_params.write_op = BLE_GATT_OP_EXEC_WRITE_REQ;
      write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
      break;
      }
      err_code = sd_ble_gattc_write(p_ble_hrs_c->conn_handle,&write_params);
      
      if(err_code=!0)
      {
      nrf_delay_ms(500);
      
      }
      APP_ERROR_CHECK(err_code);
      
      write_params.offset=write_params.offset+100;
      writestatus= writestatus+1;
      nrf_delay_ms(300);
      }
}

Currently I work with delays because I hadn´t time yet to understand and implement the QWR. Can you also give me some hints how I can improve this?

If you need more Information from the code please inform me. I think I overseen something but I am not able to find it. I hope you guys can help me.

Best regards

Hani

Parents Reply Children
  • Meanwhile I solved the issue with SVC Handler is Missing. I don´t know what was the problem, but know its gone.

    My code is now like following:

    void ble_hrs_c_local_data_write(ble_hrs_c_t const *p_ble_hrs_c)
    {     
        //  m_conn_handle_hrs_c = BLE_CONN_HANDLE_INVALID;
    
          ble_gattc_write_params_t write_params;
          ret_code_t             err_code;
    
    
          /**/
          nrf_delay_ms(3000);  
    
    
    /**/
          uint8_t data_write_one[50];
          uint8_t data_write_two[50];
          uint8_t data_write_three[50];
          uint8_t data_write_four[50];
          uint8_t data_write_five[50];
          uint8_t data_write_six[50];
          uint8_t data_write_seven[50];
          uint8_t data_write_eight[50];
          uint8_t data_write_nine[50];
          uint8_t data_write_ten[50];
    
    /**/
            for(int i = 0; i<=49; i++)
            {
                data_write_one[i] =2;
                data_write_two[i] =2;
                data_write_three[i] =2;
                data_write_four[i] =2;
                data_write_five[i] =2;
                data_write_six[i] =2;
                data_write_seven[i] =2;
                data_write_eight[i] =2;
                data_write_nine[i] =2;
                data_write_ten[i] =2;
            }
    
          write_params.len = sizeof(data_write_one);  //// Max size >90
          write_params.offset = 0;
     //   write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
          write_params.handle = p_ble_hrs_c->peer_hrs_db.hrm_handle;
          write_params.write_op = BLE_GATT_OP_PREP_WRITE_REQ;
          write_params.p_value = data_write_one;
    
          for(int i = 0; i<=10; i++)
          {
    /**/
          switch (i)
          {
          case 0:
          write_params.p_value = data_write_one;
          break;
          case 1:
          write_params.p_value = data_write_two;
          break;
          case 2:
          write_params.p_value = data_write_three;
          break;
          case 3:
          write_params.p_value = data_write_four;
          break;
          case 4:
          write_params.p_value = data_write_five;
          break;
                case 5:
          write_params.p_value = data_write_six;
          break;
                case 6:
          write_params.p_value = data_write_seven;
          break;
                case 7:
          write_params.p_value = data_write_eight;
          break;
                case 8:
          write_params.p_value = data_write_nine;
          break;
                case 9:
          write_params.p_value = data_write_ten;
          break;
    
          }
    
          err_code = sd_ble_gattc_write(p_ble_hrs_c->conn_handle,&write_params);
          nrf_delay_ms(300);
          APP_ERROR_CHECK(err_code);
          NRF_LOG_INFO("WRITE COMMAND EXECUTED");
    
          if(i==9)
          {
          write_params.write_op = BLE_GATT_OP_EXEC_WRITE_REQ ;
          write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
          }
           if(i==10)
          {
          status=0;
          }
    
          write_params.offset = write_params.offset+50;
          }
    }

    When I execute the  sd_ble_gattc_write() the event BLE_GATTC_EVT_WRITE_RSP gets triggered.

    static void local_data_write(ble_hrs_c_t*p_ble_hrs_c,const ble_evt_t *p_ble_evt)
    {
          NRF_LOG_INFO("Event write op %d", p_ble_evt->evt.gattc_evt.params.write_rsp.write_op);
    
              if (p_ble_evt->evt.gattc_evt.params.write_rsp.write_op == 4)
              {
              NRF_LOG_INFO("Data request %d", p_ble_evt->evt.gattc_evt.params.write_rsp.data[1]);
              NRF_LOG_INFO("gatt status %d", p_ble_evt->evt.gattc_evt.gatt_status);
    
              if (p_ble_evt->evt.gattc_evt.gatt_status == 0x0)
              {
               NRF_LOG_INFO("Prep write request sucessfull!");
               }
              }
              if (p_ble_evt->evt.gattc_evt.params.write_rsp.write_op == 5)
              {
               NRF_LOG_INFO("Exec write request sucessfull!");
            }
          }
    
    
    void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_context;
    
        if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
      
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTC_EVT_HVX:
                on_hvx(p_ble_hrs_c, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                on_disconnected(p_ble_hrs_c, p_ble_evt);
                break;
            case BLE_GATTC_EVT_READ_RSP:
                local_data_read(p_ble_hrs_c, p_ble_evt);
            break;
              case BLE_GATTC_EVT_WRITE_RSP:
              local_data_write(p_ble_hrs_c, p_ble_evt);
            break;
            default:
                break;
        }
    }

    The write_op is 4 which is correct, but the p_ble_evt->evt.gattc_evt.gatt_status is at 0x0180 which means ATT Error: Application range begin. I am not really sure what this error code really means. I expected for the gatt_status a 0 which means successfull.

    If you need any more information I will send it to you.

  • I tried now to execute the writing not according to the MSC with requesting and executing. I tried to execute only one write command. In this case I get ERROR 7 [NRF_ERROR_INVALID_PARAM].

    Do I have problems with my Data input? I saw it in different examples exactly the same how is this possible?

    void ble_hrs_c_local_data_write(ble_hrs_c_t const *p_ble_hrs_c)
    {     
        //  m_conn_handle_hrs_c = BLE_CONN_HANDLE_INVALID;
    
          ble_gattc_write_params_t write_params;
          ret_code_t             err_code;
    
    
          /**/
          nrf_delay_ms(300);  
    
    
    /**/
          uint8_t data_write_one[50];
    
    
    /**/
            for(int i = 0; i<=49; i++)
            {
                data_write_one[i] =2;
    
            }
    
          write_params.len = sizeof(data_write_one);  //// Max size >90
      //  write_params.offset = 0;
      //  write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
          write_params.handle = p_ble_hrs_c->peer_hrs_db.hrm_handle;
          write_params.write_op = BLE_GATT_OP_WRITE_REQ;
          write_params.p_value = data_write_one;
           
    
          err_code = sd_ble_gattc_write(p_ble_hrs_c->conn_handle, &write_params);
          NRF_LOG_INFO("WRITE COMMAND EXECUTED");
          nrf_delay_ms(300);
          APP_ERROR_CHECK(err_code);

    After I tried again sever times I identified if I set the offset value to 0 in this case my event gets triggered BLE_GATTC_EVT_WRITE_RSP, but if I read out the len, offset and value I get only 0.

    If I comment out the handler I get the NRF error BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED   0x0103 maybe I have an issue with the handler?

    Some code from my custom service:

    #define BLE_HRS_C_DEF(_name)                                                                        \
    static ble_hrs_c_t _name;                                                                           \
    NRF_SDH_BLE_OBSERVER(_name ## _obs,                                                                 \
                         BLE_HRS_C_BLE_OBSERVER_PRIO,                                                   \
                         ble_hrs_c_on_ble_evt, &_name)
    
    
    BLE_HRS_C_DEF(m_hrs_c)
    
    void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt)
    {
        // Check if the Heart Rate Service was discovered.
        if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
            p_evt->params.discovered_db.srv_uuid.uuid == NTM_UUID_DATATRANSFER_SERVICE &&
            p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_VENDOR_BEGIN)
        {
            // Find the CCCD Handle of the Heart Rate Measurement characteristic.
            uint32_t i;
    
            ble_hrs_c_evt_t evt;
    
            evt.evt_type    = BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
            evt.conn_handle = p_evt->conn_handle;
    
            for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
                    NTM_UUID_DATATRANSFER_VALUE_CHAR)
                {
                    // Found Heart Rate characteristic. Store CCCD handle and break.
                    evt.params.peer_db.hrm_cccd_handle =
                        p_evt->params.discovered_db.charateristics[i].cccd_handle;
                    evt.params.peer_db.hrm_handle =
                        p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
                    break;
                }
            }
    
            NRF_LOG_DEBUG("Heart Rate Service discovered at peer.");
            //If the instance has been assigned prior to db_discovery, assign the db_handles.
            if (p_ble_hrs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                if ((p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
                    (p_ble_hrs_c->peer_hrs_db.hrm_handle == BLE_GATT_HANDLE_INVALID))
                {
                    p_ble_hrs_c->peer_hrs_db = evt.params.peer_db;
                }
            }
    
            p_ble_hrs_c->evt_handler(p_ble_hrs_c, &evt);
        }
    }
    
    
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_hrs_on_db_disc_evt(&m_hrs_c, p_evt);
    }
    
    
    /**@brief Function for initializing the database discovery module. */
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(db_init));
    
        db_init.evt_handler =  db_disc_handler;
        db_init.p_gatt_queue = &m_ble_gatt_queue;
    
        ret_code_t err_code = ble_db_discovery_init(&db_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    

    static void hrs_c_init(void)
    {
        ret_code_t       err_code;
        ble_hrs_c_init_t hrs_c_init_obj;
    
        hrs_c_init_obj.evt_handler   = hrs_c_evt_handler;
        hrs_c_init_obj.error_handler = hrs_c_error_handler;
        hrs_c_init_obj.p_gatt_queue  = &m_ble_gatt_queue;
    
        err_code = ble_hrs_c_init(&m_hrs_c, &hrs_c_init_obj);
        APP_ERROR_CHECK(err_code);
    }
    
    static void hrs_init(void)
    {
        ret_code_t     err_code; 
        
        memset(&hrs_init_params, 0, sizeof(hrs_init_params));
    
        hrs_init_params.evt_handler                 = NULL;
    
        // Require LESC with MITM (Numeric Comparison).
        hrs_init_params.hrm_cccd_wr_sec = SEC_OPEN;
        hrs_init_params.hrm_wr_sec = SEC_OPEN;
        hrs_init_params.hrm_rd_sec = SEC_OPEN;
    
        //Example DATA
    /* */
        for(int i = 0; i<=499; i++)
        {
        if(i<=200)
        {
        hrs_init_params.data[i] = i+1;
        }
        if(i<=400&&i>200)
        {
        hrs_init_params.data[i] = i+1-200;
        }
        if(i<=499&&i>400)
        {
        hrs_init_params.data[i] = i+1-400;
        }
        }
    
        err_code = ble_hrs_init(&m_hrs, &hrs_init_params);
        APP_ERROR_CHECK(err_code);
    }

  • SO sorry for the spam on this Ticket... I have again one new finding. If I use BLE_GATT_OP_WRITE_REQ and send only one value it works. I dont get a response with the value and length, but when I read out the characteristic value of the other µC the values are written.

    If I try to use BLE_GATT_OP_PREP_WRITE_REQ I always get the error code BLE_GATT_STATUS_ATTERR_APP_BEGIN                  0x0180

    and I still don´t know what this error code means. Do I have to consider anything special what I forget?

  • If you have taken multirole example as a base, then you are getting this error most likely from the examples\ble_central_and_peripheral\experimental\ble_app_interactive\ble_m.c:1514.

            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply;
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
    
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
                        err_code                            = sd_ble_gatts_rw_authorize_reply(
                            p_ble_evt->evt.gatts_evt.conn_handle,
                            &auth_reply);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            }
            break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST

    The RW Authorize request here only is handling write and read normal request and not a prep request. You app needs to handle prepare write differently so most of the examples are not supporting a prepare write for a characteristic that require authorization.

    Why are you using prepare write request here? do you have lot of data to be written?

Related