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
  • can you give the code snippets for your customer service definition so othat i can try it on my end?

  • 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);
    }

Reply
  • 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);
    }

Children
No Data
Related