API bt_hci_cmd_send_sync() is returning -5 error

Hello,

I am trying to write some code that sets the BLE Tx power on the nRF52833 SoC.

I have based my code on the sample example code provided at C:\Zypher\v1.7.0\zephyr\samples\bluetooth\hci_pwr_ctrl\src\main.c and in particular in the function set_tx_power().

static result_t bluetooth_set_ble_tx_power( uint8_t handle_type, uint16_t handle, int8_t tx_pwr_lvl )
{
    struct bt_hci_cp_vs_write_tx_power_level    *cp;
    struct bt_hci_rp_vs_write_tx_power_level    *rp;
    struct net_buf                              *buf, *rsp = NULL;
    result_t                                    result = RESULT_ERROR;

    buf = bt_hci_cmd_create( BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, sizeof(*cp) );
    if ( buf )
    {
        cp                  = net_buf_add( buf, sizeof(*cp) );
        cp->handle          = sys_cpu_to_le16( handle );
        cp->handle_type     = handle_type;
        cp->tx_power_level  = tx_pwr_lvl;

        result = bt_hci_cmd_send_sync( BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp );
        if ( result )
        {
            uint8_t reason = rsp ? ((struct bt_hci_rp_vs_write_tx_power_level *) rsp->data)->status : 0;
            LOG_WRN( "Set Tx power err: %d reason 0x%02x\n", result, reason );
            result = RESULT_ERROR;
        }
        else
        {
            rp = (void *)rsp->data;
            LOG_INF( "Actual Tx Power: %d\n", rp->selected_tx_power );
            net_buf_unref( rsp );
            result = RESULT_OK;
        }
    }
    else
    {
        LOG_WRN( "Unable to allocate command buffer\n" );
    }

    return result;
}

I am seeing the function bt_hci_cmd_send_sync() returning error -5.

Can you please help me find the cause of this error.

Thank you.

Kind regards
Mohamed
Parents
  • I would recommend to enable the BT_LOG to right level to be able to get more context on the error.

    which controller are you using Softdevice Controller(SDC) or Zephyr Controller? The setting you have for CONFIG_BT_LL_SW_SPLIT?

  • Good Morning Susheel,

    I am developing under zephyr using

    Zephyr OS build v2.6.99-ncs1 
    nRF Connect SDK v1.7.0 

    LOG_MODULE_REGISTER(bt, LOG_LEVEL_INF);

    This is the error I am getting:

    <wrn> bt: Set Tx power err: -5 reason 0x00

    Below is the content of my prj_debug.conf file.

    # BLE
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_GATT_DYNAMIC_DB=y
    
    # Turn off/reduce Bluetooth aspects
    CONFIG_BT_LL_SW_SPLIT=y
    CONFIG_BT_PHY_UPDATE=n
    CONFIG_BT_GATT_CACHING=n
    CONFIG_BT_GATT_SERVICE_CHANGED=y
    CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n
    CONFIG_BT_HCI_VS_EXT=n
    CONFIG_BT_CTLR_PRIVACY=n
    CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1
    CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=251
    CONFIG_BT_CTLR_PHY_2M=n
    CONFIG_BT_USER_DATA_LEN_UPDATE=n
    CONFIG_BT_USER_PHY_UPDATE=n
    
    # Increase BLE packet sizes
    CONFIG_BT_DATA_LEN_UPDATE=y
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
    CONFIG_BT_BUF_ACL_RX_SIZE=255
    CONFIG_BT_ATT_PREPARE_COUNT=1
    #Maximum number of pending TX buffers with a callback
    #CONFIG_BT_CONN_TX_MAX=2
    CONFIG_BT_CONN_TX_MAX=10
    #Number of L2CAP TX buffers
    CONFIG_BT_L2CAP_TX_BUF_COUNT=10
    #CONFIG_BT_L2CAP_TX_BUF_COUNT=2
    CONFIG_BT_L2CAP_TX_MTU=247
    CONFIG_BT_CTLR_RX_BUFFERS=1
    CONFIG_BT_BUF_ACL_TX_COUNT=1
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    #NRF_SDH_BLE_GATT_MAX_MTU_SIZE=247
    

    Can you spot anything in my config that could explain the error I am getting?

    Thank you for your help.

    Kind regards
    Mohamed
  • You are using the Zephyr implementation of the controller (CONFIG_BT_LL_SW_SPLIT=y). I am not sure if this is due to this config and also not sure if the this hci command is supported in that version. 
    Can you quickly test your application when you set BT_LL_SOFTDEVICE=y instead of CONFIG_BT_LL_SW_SPLIT?

Reply Children
  • Hi,

    So, you want me to replace in prj_debug.conf the line 

    CONFIG_BT_LL_SW_SPLIT=y

    with

    BT_LL_SOFTDEVICE=y

    Isn't it CONFIG_BT_LL_SOFTDEVICE i.e. with the prefix 'CONFIG_'?

  • Hi Susheel,

    bt_hci_cmd_send_sync() is working fine now after I made the following changes in prj_debug.conf. Both config items were set to 'n'.

    CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y
    CONFIG_BT_HCI_VS_EXT=y
    Does this make sense?
    Although the error from bt_hci_cmd_send_sync() is gone, the actual BLE TX power settings is not changing. I tried different values -40, -30, -20, 0 and 8 dBm and only -40 seems to work. Also, I noticed upon BLE disconnection the power level goes back to the default 0 dBm.
    Can you please help?
    Kind regards
    Mohamed
  • Learner said:
    CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y
    CONFIG_BT_HCI_VS_EXT=y
    Does this make sense?

    Hi Mohammed,

    Yes, this makes sense and CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL is necessary for the TX power control to work.

    Learner said:
    Although the error from bt_hci_cmd_send_sync() is gone, the actual BLE TX power settings is not changing. I tried different values -40, -30, -20, 0 and 8 dBm and only -40 seems to work.

    There is a known issue with setting TX power before the advertising parameters are set. This is documented in known issues for the SDC. Apart from that, it should work as I tested this on other nRF52 variants. 

    Learner said:
    Also, I noticed upon BLE disconnection the power level goes back to the default 0 dBm.

    This could be true that this setting is per role, I normally would call bluetooth_set_ble_tx_power for every role (just connected, disconnected, advertiser, scanner).

  • Good Morning Susheel,

    Thank you for your response.

    There is a known issue with setting TX power before the advertising parameters are set. This is documented in known issues for the SDC. Apart from that, it should work as I tested this on other nRF52 variants.

    I believe I am setting the advertising parameters before setting the BLE Tx power.

    This is what I have implemented. Please let me know if you spot anything wrong.

    First, I call 

    bluetooth_Initialise();

    result_t bluetooth_Initialise(void)
    {
        int err;
    
        /* Register connection callbacks */
        bt_conn_cb_register(&conn_callbacks);
    
        /* Register custom service */
        err = bt_gatt_service_register(&custom_svc);
        if (err)
        {
            LOG_ERR("Custom service failed to start (err %d)", err);
            return err;
        }
    
        /* Set ID string */
        ...
        
        /* Enable bluetooth with the ready callback */
        return (bt_enable(bluetooth_Ready) == 0 ? RESULT_OK : RESULT_ERROR);
    }
    

    static void bluetooth_Ready(int err)
    {
        if (err)
        {
            LOG_ERR("Bluetooth init failed (err %d)", err);
            return;
        }
    
        LOG_INF("Bluetooth initialised");
    
        /* Start advertising */
        err = bluetooth_start_adv();    
        if (err)
        {
            LOG_ERR("Advertising failed to start (err %d)", err);
            return;
        }
    
        LOG_INF("Advertising successfully started, awaiting connections");
    }
    

    
    static result_t bluetooth_start_adv( void )
    {
        result_t result = RESULT_ERROR;
    
        /* Select the appropriate the BLE advertising period using the current configuration setting.
         * This can be one of these settings. Note, it is a range rather than an abvsolute value.
         *   30 ms -   60 ms
         *  100 ms -  150 ms
         * 1000 ms - 1200 ms
         */
        if ( ( ble_adv_period ) == 0  || ( ble_adv_period >= 200 )   )
        {
            /* 1000 ms - 1200 ms */
            result = bt_le_adv_start(BT_LE_ADV_CONN_SLOW, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
        }
        else if ( ble_adv_period >= 80 )
        {
            /* 100 ms - 150 ms */
            result = bt_le_adv_start(BT_LE_ADV_CONN_FAST_2, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
        }
        else if ( ble_adv_period >= 1 )
        {
            /* 30 ms - 60 ms */
            result = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
        }
    
        return result;
    }
    

    Below are the functions that set the BLE Tx power level. It is called after the BLE initialisation and  advertising have been setup and started.

    result_t bluetooth_set_tx_power( int8_t tx_pwr_lvl_dbm )
    {
        result_t result = RESULT_ERROR;
    
    
        /* Now, set the BLE Tx power level in dBm*/
        if ( !conn )
        {
            result = bluetooth_set_ble_tx_power( BT_HCI_VS_LL_HANDLE_TYPE_ADV, 0, tx_pwr_lvl_dbm );
        }
        else
        {
            result = bluetooth_set_ble_tx_power( BT_HCI_VS_LL_HANDLE_TYPE_CONN, default_conn_handle, tx_pwr_lvl_dbm );
        }
    
        return result;
    }
    

    static result_t bluetooth_set_ble_tx_power( uint8_t handle_type, uint16_t handle, int8_t tx_pwr_lvl )
    {
        struct bt_hci_cp_vs_write_tx_power_level    *cp;
        struct bt_hci_rp_vs_write_tx_power_level    *rp;
        struct net_buf                              *buf, *rsp = NULL;
        result_t                                    result = RESULT_ERROR;
    
        buf = bt_hci_cmd_create( BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, sizeof(*cp) );
        if ( buf )
        {
            cp                  = net_buf_add( buf, sizeof(*cp) );
            cp->handle          = sys_cpu_to_le16( handle );
            cp->handle_type     = handle_type;
            cp->tx_power_level  = tx_pwr_lvl;
    
            LOG_INF( "Set Tx power: %d\n", cp->tx_power_level );
    
            result = bt_hci_cmd_send_sync( BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp );
            if ( result )
            {
                uint8_t reason = rsp ? ((struct bt_hci_rp_vs_write_tx_power_level *) rsp->data)->status : 0;
                LOG_WRN( "Set Tx power err: %d reason 0x%02x\n", result, reason );
                result = RESULT_ERROR;
            }
            else
            {
                rp = (void *)rsp->data;
                LOG_INF( "Actual Tx Power: %d\n", rp->selected_tx_power );
                net_buf_unref( rsp );
                result = RESULT_OK;
            }
        }
        else
        {
            LOG_WRN( "Unable to allocate command buffer\n" );
        }
    
        return result;
    }
    

    Kind regards

    Mohamed

  • I am really sorry for the delays, I could not test your code snippet, but will try to come back to you by tomorrow, thanks for your patience.

Related