Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Tx power level change not reflected in Tx Power Service

I am changing the Tx power successfully with sd_ble_gap_tx_power_set().  I can see the RSSI value change Nordic Connect to confirm that it really is changing.  But I also have the TX Power Service enabled and do not see the power level updating in its characteristic.  Should that update automatically?  It doesn't.  So I tried using ble_tps_tx_power_level_set() to get the service characteristic value to match, but that always crashes.  Here's my code:

void tx_power_set(int8_t tx_power_level)
{
    ret_code_t err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, tx_power_level);
    APP_ERROR_CHECK(err_code);
    err_code = ble_tps_tx_power_level_set(&m_tps, tx_power_level);
    APP_ERROR_CHECK(err_code);
}
Parents
  • I suspect that ble_tps_tx_power_level_set() is returning an error code here, and that the error check by APP_ERROR_CHECK() cause the application to assert to the fault handler. It would be good if you can find the error code from ble_tps_tx_power_level_set(). The ble_tps_tx_power_level_set() is basically a wrapper around sd_ble_gatts_value_set(), so I guess it is one of the listed errors:

    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v6.0.0/group___b_l_e___g_a_t_t_s___f_u_n_c_t_i_o_n_s.html#ga2760c51ea71853bd74e2e7e7117ef52a

  • You are right.  It was returning a BLE_ERROR_INVALID_CONN_HANDLE.  This was happening when I changed the power level when unconnected.

    I see that other services prevent this problem by either setting the conn_handle to BLE_CONN_HANDLE_INVALID in their service init routine, or they call sd_ble_gatts_value_set() with a first parameter of BLE_CONN_HANDLE_INVALID rather than the current service conn_handle. 

    For example, the Blood Pressure Service init looks like this:

    uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
    {
    ...
    
        p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
    ...
    }
    

    The Battery Service takes the other approach in their wrapper around sd_ble_gatts_value_set():
    ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
                                            uint8_t     battery_level,
                                            uint16_t    conn_handle)
    {
        ...
        
        if (battery_level != p_bas->battery_level_last)
        {
            ...
            
            // Update database.
            err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID,
                                              p_bas->battery_level_handles.value_handle,
                                              &gatts_value);
        ...
    }

    The Tx Power Level Service ble_tps.c library code does neither, so an error is thrown when setting without a connection.  Should the library code be more like the others?  My workaround is to set the conn_handle after calling the library ble_tps_init() function:

        err_code = ble_tps_init(&m_tps, &tps_init_obj);
        m_tps.conn_handle = BLE_CONN_HANDLE_INVALID;
    

    And when it is connected, setting the gatt value through ble_tps_tx_power_level_set() is indeed reflected in the value the host sees.
Reply
  • You are right.  It was returning a BLE_ERROR_INVALID_CONN_HANDLE.  This was happening when I changed the power level when unconnected.

    I see that other services prevent this problem by either setting the conn_handle to BLE_CONN_HANDLE_INVALID in their service init routine, or they call sd_ble_gatts_value_set() with a first parameter of BLE_CONN_HANDLE_INVALID rather than the current service conn_handle. 

    For example, the Blood Pressure Service init looks like this:

    uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
    {
    ...
    
        p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
    ...
    }
    

    The Battery Service takes the other approach in their wrapper around sd_ble_gatts_value_set():
    ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
                                            uint8_t     battery_level,
                                            uint16_t    conn_handle)
    {
        ...
        
        if (battery_level != p_bas->battery_level_last)
        {
            ...
            
            // Update database.
            err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID,
                                              p_bas->battery_level_handles.value_handle,
                                              &gatts_value);
        ...
    }

    The Tx Power Level Service ble_tps.c library code does neither, so an error is thrown when setting without a connection.  Should the library code be more like the others?  My workaround is to set the conn_handle after calling the library ble_tps_init() function:

        err_code = ble_tps_init(&m_tps, &tps_init_obj);
        m_tps.conn_handle = BLE_CONN_HANDLE_INVALID;
    

    And when it is connected, setting the gatt value through ble_tps_tx_power_level_set() is indeed reflected in the value the host sees.
Children
Related