This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

sd_ble_gatts_hvx don't update gatt value, sd_ble_gatts_value_set throws unexpected error

I've based my application on ble_peripheral ble_app_blinky example.

So I used the following Code as model:

            NRF_LOG_INFO("Send button state change.");
            err_code = ble_lbs_on_button_change(m_conn_handle, &m_lbs, button_action);
            if (err_code != NRF_SUCCESS &&
                err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
                err_code != NRF_ERROR_INVALID_STATE &&
                err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
            {
                APP_ERROR_CHECK(err_code);
            }
            break;

with:

uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state)
{
    ble_gatts_hvx_params_t params;
    uint16_t len = sizeof(button_state);

    memset(&params, 0, sizeof(params));
    params.type   = BLE_GATT_HVX_NOTIFICATION;
    params.handle = p_lbs->button_char_handles.value_handle;
    params.p_data = &button_state;
    params.p_len  = &len;

    return sd_ble_gatts_hvx(conn_handle, &params);
}

for update and notification of a charachteristic value.

This and the documentation under https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.0.0%2Flib_ble_advertising.html (function sd_ble_gatts_hvx) suggest that the sd_ble_gatts_value_set function is not needed.

With this approach, the value at the client remains 0 when the notification is switched on and the correct value only appears after the first update. This can take a very long time. This is unsatisfactory.

Therefore I tried to set the value before with sd_ble_gatts_value_set.

void ble_temp_char_update(uint16_t conn_handle, ble_mein_service_t *p_mein_service, int16_t data)
{
  ret_code_t rc;
  ble_gatts_hvx_params_t params;
  uint16_t len = sizeof(data);
  ble_gatts_value_t gv;

  memset(&gv, 0, sizeof(gv));
  gv.len     = sizeof(data);
  gv.offset  = 0;
  gv.p_value = (uint8_t *)&data;

  memset(&params, 0, sizeof(params));
  params.type   = BLE_GATT_HVX_NOTIFICATION;
  params.handle = p_mein_service->temp_char_handles.value_handle;
  params.p_data = (uint8_t *)&data;
  params.p_len  = &len;

  rc = sd_ble_gatts_hvx(conn_handle, &params);
  switch (rc) {
    case NRF_SUCCESS:
      break;
    case BLE_ERROR_INVALID_CONN_HANDLE:
    //keine Connection vorhanden
    case NRF_ERROR_INVALID_STATE:
    //Notification nicht eingeschaltet
    //...dann setze den Wert, falls mit Read gelesen wird
      rc = sd_ble_gatts_value_set(conn_handle, p_mein_service->temp_char_handles.value_handle, &gv);
      APP_ERROR_CHECK(rc); // <=== Error 0x3002
      break;
    case BLE_ERROR_GATTS_SYS_ATTR_MISSING:
      //bei einem bekannten Peer muss wohl hier sd_ble_gatts_sys_attr_set() aufgerufen werden
      break;
    default:
      APP_ERROR_CHECK(rc);
  }
}

This works so far. But after disconnecting the connection an error 0x3002 occurs when the update function is called again (Line 29 in the last Codebox).
What can I do?

Parents
  • Hi Stefan, 

    What you described is pretty strange. The function sd_ble_gatts_hvx() should update the characteristic value and then send the notification. 
    Have you made sure the function sd_ble_gatts_hvx() returns NRF_SUCCESS ? 

    Which SDK are you testing with ?

    Please simply test with ble_app_blinky and press the button, would the first press get notified on the phone (you can use nrf blinky app on the phone) ?

    If you receive BLE_ERROR_INVALID_CONN_HANDLE( 0x3002) when calling  sd_ble_gatts_value_set() maybe you are setting the value of a CCCD. Please double check if the handle id was correct. 

  • The timing is as follows (without using function sd_ble_gatts_value_set) :
    1. no BLE connection
    2. a value changes (calling sd_ble_gatts_hvx returns NRF_ERROR_INVALID_STATE)
    3. client connects
    4. client enables notification for the value
    5. client displays the value 0
    6. the value changes again
    7. the value is transmitted

    My problem is step 5. Whenever the initial value is not 0, I have a problem. Why does the function sd_ble_gatts_hvx  not store the new value in Softdevice RAM even when no client is connected.  If a client connects and immediately turns on notification, it does not get the current value. I use the function so that it is only called when the value has changed.

    The value is for example the temperature. Sometimes it does not change for a long time.

    The blinky example is too simple for this. You might have to press the key before a client connects.

    I have tested with sdk 15.3 and Softdevice S140 6.1.1 so far.

    Code snippet for this (first) problem:

    void ble_adc_char_update(uint16_t conn_handle, ble_mein_service_t *p_mein_service, int32_t data)
    {
      ret_code_t rc;
      ble_gatts_hvx_params_t params;
      uint16_t len = sizeof(data);
    
      memset(&params, 0, sizeof(params));
      params.type   = BLE_GATT_HVX_NOTIFICATION;
      params.handle = p_mein_service->adc_char_handles.value_handle;
      params.p_data = (uint8_t *)&data;
      params.p_len  = &len;
    
      rc = sd_ble_gatts_hvx(conn_handle, &params);
      if (rc != NRF_SUCCESS &&
          rc != BLE_ERROR_INVALID_CONN_HANDLE &&
          rc != NRF_ERROR_INVALID_STATE &&
          rc != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
      {
          APP_ERROR_CHECK(rc);
      }
    }

Reply
  • The timing is as follows (without using function sd_ble_gatts_value_set) :
    1. no BLE connection
    2. a value changes (calling sd_ble_gatts_hvx returns NRF_ERROR_INVALID_STATE)
    3. client connects
    4. client enables notification for the value
    5. client displays the value 0
    6. the value changes again
    7. the value is transmitted

    My problem is step 5. Whenever the initial value is not 0, I have a problem. Why does the function sd_ble_gatts_hvx  not store the new value in Softdevice RAM even when no client is connected.  If a client connects and immediately turns on notification, it does not get the current value. I use the function so that it is only called when the value has changed.

    The value is for example the temperature. Sometimes it does not change for a long time.

    The blinky example is too simple for this. You might have to press the key before a client connects.

    I have tested with sdk 15.3 and Softdevice S140 6.1.1 so far.

    Code snippet for this (first) problem:

    void ble_adc_char_update(uint16_t conn_handle, ble_mein_service_t *p_mein_service, int32_t data)
    {
      ret_code_t rc;
      ble_gatts_hvx_params_t params;
      uint16_t len = sizeof(data);
    
      memset(&params, 0, sizeof(params));
      params.type   = BLE_GATT_HVX_NOTIFICATION;
      params.handle = p_mein_service->adc_char_handles.value_handle;
      params.p_data = (uint8_t *)&data;
      params.p_len  = &len;
    
      rc = sd_ble_gatts_hvx(conn_handle, &params);
      if (rc != NRF_SUCCESS &&
          rc != BLE_ERROR_INVALID_CONN_HANDLE &&
          rc != NRF_ERROR_INVALID_STATE &&
          rc != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
      {
          APP_ERROR_CHECK(rc);
      }
    }

Children
Related