Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Custom characteristic, update value for read

I'm trying toa custom nRF52840 board using SDK 17.02 and SD 7.01

I create a read/Write only service, it shows up in nRF Connect just fine

I can write to the service using the NRFConnect app and catching the event BLE_GATTS_EVT_WRITE, then checking the handle to determine which characteristic got called.

That works, but how the heck do I save that value so when I do a read from the nRFConnet app I get that same value??

else if (p_evt_write->handle == p_mtgw->LoRSync_handles.value_handle)
    {

      uint16_t ScanRate;

      if(p_evt_write->len == 2)
      {
         ScanRate = uint16_big_decode(p_evt_write->data);
         BLEScanRateCallback(ScanRate);

         ble_gatts_value_t val;
         uint8_t data[2];

         uint16_big_encode(ScanRate, data);

         val.len = 2;
         val.offset = 0;
         val.p_value = data;
         ret_code_t err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID/*p_ble_evt->evt.gatts_evt.conn_handle*/,  p_mtgw->LoRSync_handles.value_handle, &val);

         if (err_code == NRF_SUCCESS)
        {
            NRF_LOG_INFO("Sync rate has been updated: %x %x", data[0], data[1])

            // Save new battery value.
           // p_bas->battery_level_last = battery_level;
        }
        else
        {
            NRF_LOG_DEBUG("Error during Sync rate update: 0x%08X", err_code)

            return;// err_code;
        }

         NRF_LOG_INFO("Lora Sync Rate: %x", ScanRate);
      }
    }

Parents
  • Thanks for the help Karl,

    Here is some more detail

    What is your p_evt_write variable? Have you used the folloiwing initialization?

    Yes, like this:

    static void on_write(ble_mtgw_t * p_mtgw, ble_evt_t const * p_ble_evt)
    {
        ret_code_t                    err_code;
        ble_mtb_evt_t                 evt;
        ble_mtb_client_context_t    * p_client;
        ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

    On_write() is called from the ble event handler:

    void ble_mtb_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
       if ((p_context == NULL) || (p_ble_evt == NULL))
       {
           return;
       }
    
       ble_mtgw_t * p_mtgw = (ble_mtgw_t *)p_context;
    
       switch (p_ble_evt->header.evt_id)
       {
          case BLE_GAP_EVT_CONNECTED:
             on_connect(p_mtgw, p_ble_evt);
             break;
    
          case BLE_GATTS_EVT_WRITE:
             on_write(p_mtgw, p_ble_evt);
             break;

    I am not sure what you are doing in the code snippet you have provided, with the ScanRate callback

    That code Just updates another system with the new scan rate. It's not actually implemented yet

    ScanRate = uint16_big_decode(p_evt_write->data);
    BLEScanRateCallback(ScanRate);

    but what does your logger output when you run this code? How does it differ from what you would have expected?

    Using nRF Connect I can write the characteristic. Here I wrote 12 34

    Then in my Code in the original post I get the value and print it.

    This works just fine

    I am trying to update the value using sd_ble_gatts_value_set(), as shown in the original post

    Ive tried both:

    ret_code_t err_code = sd_ble_gatts_value_set(p_ble_evt->evt.gatts_evt.conn_handle,  p_mtgw->LoRSync_handles.value_handle, &val);

    and

    ret_code_t err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID,  p_mtgw->LoRSync_handles.value_handle, &val);

    Neither way seems to update the system with the new value

    So the whole problem really is this:

    When I use nRF Connect again to read the value just written,

    It's wrong, it's always 00 04, it should be 12 34 ( or what ever I write to the characteristic )

    So maybe the question is, how do I update a custom characteristic with read / write permissions so it can be read ?

    Do I need to do authenticated reads on them all?

  • Hello again,

    Keith V said:
    Thanks for the help Karl,

    No problem at all, Keith - I am happy to help!

    Keith V said:
    So maybe the question is, how do I update a custom characteristic with read / write permissions so it can be read ?

    You will need to configure the characteristic to allow reads and writes, but from your screenshot it looks like you have already done so successfully.
    This is how you could go about updating a value in the SoftDevice database.

    ..
        ble_gatts_value_t gatts_value;
    
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));
    
        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &custom_value;
        
        err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                          p_cus->custom_value_handles.value_handle,
                                          &gatts_value);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    ..

    Which is similar to what you have already done, it seems.
    Does your call to sd_ble_gatts_value_set return any error codes other than NRF_SUCCESS?
    Please make sure to have DEBUG defined in your preprocessor defines, like shown in the included image:

    This will make your logger output a detailed error message whenever a non-NRF_SUCCESS error code is passed to an APP_ERROR_CHECK.

    Keith V said:
    Do I need to do authenticated reads on them all?

    This depends on whether you have configured the characteristics to require authentication or encryption prior to being read - this is configured during the initial setup of the characteristic.

    Best regards,
    Karl

Reply
  • Hello again,

    Keith V said:
    Thanks for the help Karl,

    No problem at all, Keith - I am happy to help!

    Keith V said:
    So maybe the question is, how do I update a custom characteristic with read / write permissions so it can be read ?

    You will need to configure the characteristic to allow reads and writes, but from your screenshot it looks like you have already done so successfully.
    This is how you could go about updating a value in the SoftDevice database.

    ..
        ble_gatts_value_t gatts_value;
    
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));
    
        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &custom_value;
        
        err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                          p_cus->custom_value_handles.value_handle,
                                          &gatts_value);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    ..

    Which is similar to what you have already done, it seems.
    Does your call to sd_ble_gatts_value_set return any error codes other than NRF_SUCCESS?
    Please make sure to have DEBUG defined in your preprocessor defines, like shown in the included image:

    This will make your logger output a detailed error message whenever a non-NRF_SUCCESS error code is passed to an APP_ERROR_CHECK.

    Keith V said:
    Do I need to do authenticated reads on them all?

    This depends on whether you have configured the characteristics to require authentication or encryption prior to being read - this is configured during the initial setup of the characteristic.

    Best regards,
    Karl

Children
No Data
Related