Zephyr: Dynamically set TX power of BLE Radio

Created on 23 Jul 2019  路  21Comments  路  Source: zephyrproject-rtos/zephyr

Is your feature request related to a problem? Please describe.
Currently TX power of the BLE radio is fixed at some power level, which can be configured through kconfig. A use case for dynamically changing the TX power of the radio are BLE beacons (for instance https://kontakt.io/ble-beacons-tags/ support multiple TX power settings).

Describe the solution you'd like
An API is needed in order to dynamically set radio TX power settings. A default power level should be available through kconfig.

Describe alternatives you've considered
The current implementation leaves no alternatives for this problem, as TX value is a hardcoded defined by kconfig.

Additional context
Initial request on slack:

Mattia [Yesterday at 4:13 PM]
Is there a way to dynamically set the radio TX power levels?
3 replies

vich [15 hours ago]
No, there is no API to dynamically set the radio Tx power. If you can put down a use case description in github issue, we can discuss further there on how it can be implemented. For now, the controller picks a hard-coded value defined by Kconfig, implementing a dynamic value is not difficult, we need to get the API right.

I'm open to discuss implementation / how the API should look.

Feature Request RFC Bluetooth

Most helpful comment

Actually, I just implemented a working solution and I plan to submit the PR today or tomorrow.

To touch on your comments. The solution proposed actually does not take care of the legacy and split BLE arch introduced in v2.0. To address that one needs to implement the power change logic slightly differently, but the basic ideas you put forward still remain.

In addition:

Here is an example of how it would look to the user by modifying slightly the beacon sample with some definitions

#define DEVICE_BEACON_TXPOWER_NUM  8
const u32_t txp[DEVICE_BEACON_TXPOWER_NUM] = {0x4UL, 0x0UL, 0xFCUL, 0xF8UL, 0xF4UL, 0xECUL, 0xE8UL, 0xE2UL};

const struct bt_le_adv_param *param = BT_LE_ADV_PARAM(0, 0x0020, 0x0020);

and the main example logic

void main(void)
{
    int err;
    u8_t idx = 0;

    printk("Starting Beacon Demo\n");

    /* Initialize the Bluetooth Subsystem */
    err = bt_enable(bt_ready);
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
    }

    k_sleep(K_MSEC(5000));

    printk("Entering loop...\n");
    while (1) {
        /* code */

        err = bt_ctrl_set_tx_power(txp[idx]);
        if (err) {
            printk("Failed to set tx power to %d (err %d)\n", (s8_t)txp[idx], err);
        } else {
            printk("Set Tx power level to %d\n", (s8_t)txp[idx]);
        }
        k_sleep(K_MSEC(5000));

        idx = (idx+1) % DEVICE_BEACON_TXPOWER_NUM;
    }

}

This works then for both LL_SW version - split and legacy. Here is a snapshot outlining the dynamic Tx change with microbit, where the KConfig power was set to 0 and then there is a decreasing staircase of 4, 0, -4, -8, -12, -16, -20, -30

WhatsApp Image 2019-10-11 at 12 20 38

All 21 comments

@mfiumara : Please note that slack history is lost after a few days, so links to slack are of little use. Please paste or summarize in the issue itself any relevant part of that discussion.

@mfiumara : Please note that slack history is lost after a few days, so links to slack are of little use. Please paste or summarize in the issue itself any relevant part of that discussion.

I updated the issue with the original slack discussion.

@mfiumara Do you have any suggestion on an API?

I tried to use radio_tx_power_set(u32_t power) (with different power argument) before and after bt_enable(), but it's not work :(

As I understand it, the power should be initialized before starting bluetooth. But inside the bluetooth initialization used RADIO_TXP_DEFAULT definition because of which we cannot set or change the power. And I do not quite understand how this can be fixed.

Maybe @cvinayak can shine some light on this issue. How could this be implemented? Is it even possible to change dynamically?

@tsvehagen I can propose an API, should I do it in this issue or create a separate issue for it?

I think you can create a pull request and add a link to this issue

For our platform, I've implemented a vendor specific TX power level interface. It operates with two different types of TX power level; _System TX power level_ and _connection TX power level_.

By calling the host function with conn == NULL, the system power level is set.
System level is used by advertising and scan req/resp, and connections established "inherit" the system power level, i.e. slave ADV power level becomes slave TX-, and scan request power level becomes master TX power level.

On an established connection, the TX power level may be set dynamically using the conn instance.
The system also uses a default value via propietary settings, which is applied until level is changed via the interface.

For our platform, I've implemented a vendor specific TX power level interface. It operates with two different types of TX power level; _System TX power level_ and _connection TX power level_.

By calling the host function with conn == NULL, the system power level is set.
System level is used by advertising and scan req/resp, and connections established "inherit" the system power level, i.e. slave ADV power level becomes slave TX-, and scan request power level becomes master TX power level.

On an established connection, the TX power level may be set dynamically using the conn instance.
The system also uses a default value via propietary settings, which is applied until level is changed via the interface.

Can I see an example somewhere?

For our platform, I've implemented a vendor specific TX power level interface. It operates with two different types of TX power level; _System TX power level_ and _connection TX power level_.
By calling the host function with conn == NULL, the system power level is set.
System level is used by advertising and scan req/resp, and connections established "inherit" the system power level, i.e. slave ADV power level becomes slave TX-, and scan request power level becomes master TX power level.
On an established connection, the TX power level may be set dynamically using the conn instance.
The system also uses a default value via propietary settings, which is applied until level is changed via the interface.

Can I see an example somewhere?

Sorry, this is not upstreamed. However, I can construct an example from our test code if you are interested?

Sorry, this is not upstreamed. However, I can construct an example from our test code if you are interested?

I am interested

@mtpr-ot Thanks, but it won鈥檛 help me.

I've looked a bit more into implementation and would suggest the following:

@cvinayak , @carlescufi could you comment on this proposal? Not sure how to add RFC label to this issue.

@mfiumara I think your suggestion looks good but I'm just wondering if it might be a good idea to be able to specify different power for advertising and "user generated" packets for example? Maybe that can be another PR for later if needed.

@tsvehagen Sorry for the late reply: what do you mean exactly with the difference in advertising and "user generated" packets? Aren't advertisements always user generated? I think adding multiple power levels will only result in confusion, so probably as initial PR I would implement a single power level.

If you agree I can start the PR.

@tsvehagen Sorry for the late reply: what do you mean exactly with the difference in advertising and "user generated" packets? Aren't advertisements always user generated? I think adding multiple power levels will only result in confusion, so probably as initial PR I would implement a single power level.

If you agree I can start the PR.

No worries :)

I think what I meant was to have one level for things like beacons where you advertise your capabilities and such. Anyway, I agree that it is a good idea to just get an interface for changing the power level globally to start things off. I'd be happy to see a PR for that.

@mfiumara thanks a lot for opening this feature request! Any updates on the PR regarding this ?

@rstoica This is currently on a low priority for me, I am planning to open a PR for this within 2 weeks.

Actually, I just implemented a working solution and I plan to submit the PR today or tomorrow.

To touch on your comments. The solution proposed actually does not take care of the legacy and split BLE arch introduced in v2.0. To address that one needs to implement the power change logic slightly differently, but the basic ideas you put forward still remain.

In addition:

Here is an example of how it would look to the user by modifying slightly the beacon sample with some definitions

#define DEVICE_BEACON_TXPOWER_NUM  8
const u32_t txp[DEVICE_BEACON_TXPOWER_NUM] = {0x4UL, 0x0UL, 0xFCUL, 0xF8UL, 0xF4UL, 0xECUL, 0xE8UL, 0xE2UL};

const struct bt_le_adv_param *param = BT_LE_ADV_PARAM(0, 0x0020, 0x0020);

and the main example logic

void main(void)
{
    int err;
    u8_t idx = 0;

    printk("Starting Beacon Demo\n");

    /* Initialize the Bluetooth Subsystem */
    err = bt_enable(bt_ready);
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
    }

    k_sleep(K_MSEC(5000));

    printk("Entering loop...\n");
    while (1) {
        /* code */

        err = bt_ctrl_set_tx_power(txp[idx]);
        if (err) {
            printk("Failed to set tx power to %d (err %d)\n", (s8_t)txp[idx], err);
        } else {
            printk("Set Tx power level to %d\n", (s8_t)txp[idx]);
        }
        k_sleep(K_MSEC(5000));

        idx = (idx+1) % DEVICE_BEACON_TXPOWER_NUM;
    }

}

This works then for both LL_SW version - split and legacy. Here is a snapshot outlining the dynamic Tx change with microbit, where the KConfig power was set to 0 and then there is a decreasing staircase of 4, 0, -4, -8, -12, -16, -20, -30

WhatsApp Image 2019-10-11 at 12 20 38

Closing issue as it has been merged in #19779. Thanks for the hard work!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dhavalpanchalispl picture dhavalpanchalispl  路  3Comments

pabigot picture pabigot  路  4Comments

pdunaj picture pdunaj  路  3Comments

rosterloh picture rosterloh  路  4Comments

mike-scott picture mike-scott  路  4Comments