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.
@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 This should be possible but I think the implementation would be vendor specific.
I am currently using a Nordic platform and have looked a bit in how an API would look. It would need changes in the lower link layer:
https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_master.c#L142
https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c#L149
https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_slave.c#L163
https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c#L146
I can propose an API, should I do it in this issue or create a separate issue for it?
@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:
Move radio_tx_power_set from lower link layer into https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c#L117
Add dynamic power variable in the BLE controller https://github.com/zephyrproject-rtos/zephyr/blob/82c25587a2bc7610530154df4d984bdfa2add594/subsys/bluetooth/controller/ll_sw/ctrl.c#L272
Add an API in the BLE controller which enables the user to set the radio TX power to some supported value.
Have the BLE controller set the initial default power to the KConfig one RADIO_TXP_DEFAULT
@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:
int bt_ctrl_set_tx_power(const u32_t tx_power_lvl) defined by the controller interface https://github.com/zephyrproject-rtos/zephyr/blob/4d59ef306bf26527947fb54185045dc4a2ddce5b/include/bluetooth/controller.h#L2Here 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

Closing issue as it has been merged in #19779. Thanks for the hard work!
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:
int bt_ctrl_set_tx_power(const u32_t tx_power_lvl)defined by the controller interface https://github.com/zephyrproject-rtos/zephyr/blob/4d59ef306bf26527947fb54185045dc4a2ddce5b/include/bluetooth/controller.h#L2Here is an example of how it would look to the user by modifying slightly the beacon sample with some definitions
and the main example logic
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