| /* |
| * Copyright (c) 2016-2019 Nordic Semiconductor ASA |
| * Copyright (c) 2016 Vinayak Kariappa Chettimada |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <soc.h> |
| #include <zephyr/bluetooth/hci.h> |
| #include <zephyr/bluetooth/hci_vs.h> |
| |
| #include "hal/cpu.h" |
| #include "hal/ccm.h" |
| #include "hal/radio.h" |
| |
| #include "util/util.h" |
| #include "util/memq.h" |
| #include "util/mem.h" |
| #include "util/dbuf.h" |
| |
| #include "pdu.h" |
| |
| #include "lll.h" |
| #include "lll/lll_adv_types.h" |
| #include "lll_adv.h" |
| #include "lll/lll_adv_pdu.h" |
| #include "lll_scan.h" |
| #include "lll/lll_df_types.h" |
| #include "lll_conn.h" |
| |
| #if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) |
| #include "ull_tx_queue.h" |
| #endif |
| |
| #include "ull_adv_types.h" |
| #include "ull_scan_types.h" |
| #include "ull_conn_types.h" |
| |
| #include "ull_adv_internal.h" |
| #include "ull_scan_internal.h" |
| #include "ull_conn_internal.h" |
| |
| #include "ll.h" |
| |
| uint8_t ll_tx_pwr_lvl_get(uint8_t handle_type, |
| uint16_t handle, uint8_t type, int8_t *tx_pwr_lvl) |
| { |
| switch (handle_type) { |
| #if defined(CONFIG_BT_BROADCASTER) &&\ |
| defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): { |
| struct ll_adv_set *adv; |
| |
| #if !defined(CONFIG_BT_CTLR_ADV_EXT) |
| /* Ignore handle if AE not enabled */ |
| handle = 0; |
| #endif /* CONFIG_BT_CTLR_ADV_EXT */ |
| /* Allow the app to get Tx power |
| * when advertising is off |
| */ |
| adv = ull_adv_set_get(handle); |
| if (!adv) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| *tx_pwr_lvl = adv->lll.tx_pwr_lvl; |
| break; |
| } |
| #endif /* CONFIG_BT_BROADCASTER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| #if defined(CONFIG_BT_OBSERVER) &&\ |
| defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): { |
| struct ll_scan_set *scan; |
| |
| /* Ignore handle in case of scanner |
| * as for mesh extensions and scanning |
| * sets this control is handled |
| * at a lower-level in the stack. |
| */ |
| handle = 0; |
| /* Allow the app to get Tx power |
| * when scanning is off |
| */ |
| scan = ull_scan_set_get(handle); |
| if (!scan) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| *tx_pwr_lvl = scan->lll.tx_pwr_lvl; |
| break; |
| } |
| #endif /* CONFIG_BT_OBSERVER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL*/ |
| #if defined(CONFIG_BT_CONN) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): { |
| struct ll_conn *conn; |
| |
| conn = ll_connected_get(handle); |
| if (!conn) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| |
| if (type) { |
| #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| /* Level desired is maximum available */ |
| *tx_pwr_lvl = lll_radio_tx_pwr_max_get(); |
| #else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| /* Return default if not multiple TXP */ |
| *tx_pwr_lvl = RADIO_TXP_DEFAULT; |
| #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| } else { |
| #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| /* Current level is requested */ |
| *tx_pwr_lvl = conn->lll.tx_pwr_lvl; |
| #else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| /* Return default if not multiple TXP */ |
| *tx_pwr_lvl = RADIO_TXP_DEFAULT; |
| #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| } |
| break; |
| } |
| #endif /* CONFIG_BT_CONN */ |
| default: { |
| return BT_HCI_ERR_UNKNOWN_CMD; |
| } |
| } |
| |
| return BT_HCI_ERR_SUCCESS; |
| } |
| |
| |
| uint8_t ll_tx_pwr_lvl_set(uint8_t handle_type, uint16_t handle, |
| int8_t *const tx_pwr_lvl) |
| { |
| #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| if (*tx_pwr_lvl == BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF) { |
| /* If no preference selected, then use default Tx power */ |
| *tx_pwr_lvl = RADIO_TXP_DEFAULT; |
| } |
| |
| /** |
| * Check that desired Tx power matches the achievable transceiver |
| * Tx power capabilities by flooring - if selected power matches than |
| * is used, otherwise next smaller power available is used. |
| */ |
| *tx_pwr_lvl = lll_radio_tx_pwr_floor(*tx_pwr_lvl); |
| #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| |
| switch (handle_type) { |
| #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| #if defined(CONFIG_BT_BROADCASTER) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): { |
| struct ll_adv_set *adv; |
| |
| #if !defined(CONFIG_BT_CTLR_ADV_EXT) |
| /* Ignore handle if AE not enabled */ |
| handle = 0; |
| #endif /* CONFIG_BT_CTLR_ADV_EXT */ |
| /* Allow the app to set Tx power |
| * prior to advertising |
| */ |
| adv = ull_adv_set_get(handle); |
| if (!adv) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| adv->lll.tx_pwr_lvl = *tx_pwr_lvl; |
| break; |
| } |
| #endif /* CONFIG_BT_BROADCASTER */ |
| #if defined(CONFIG_BT_OBSERVER) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): { |
| struct ll_scan_set *scan; |
| |
| /* Ignore handle in case of scanner |
| * as for mesh extensions and scanning |
| * sets this control is handled |
| * at a lower-level in the stack. |
| */ |
| handle = 0; |
| /* Allow the app to set Tx power |
| * prior to scanning |
| */ |
| scan = ull_scan_set_get(handle); |
| if (!scan) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| scan->lll.tx_pwr_lvl = *tx_pwr_lvl; |
| break; |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| #if defined(CONFIG_BT_CONN) |
| case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): { |
| struct ll_conn *conn; |
| |
| conn = ll_connected_get(handle); |
| if (!conn) { |
| return BT_HCI_ERR_UNKNOWN_CONN_ID; |
| } |
| conn->lll.tx_pwr_lvl = *tx_pwr_lvl; |
| break; |
| } |
| #endif /* CONFIG_BT_CONN */ |
| #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| default: { |
| return BT_HCI_ERR_UNKNOWN_CMD; |
| } |
| } |
| |
| return BT_HCI_ERR_SUCCESS; |
| } |
| |
| void ll_tx_pwr_get(int8_t *min, int8_t *max) |
| { |
| #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) |
| *min = lll_radio_tx_pwr_min_get(); |
| *max = lll_radio_tx_pwr_max_get(); |
| #else |
| *min = RADIO_TXP_DEFAULT; |
| *max = RADIO_TXP_DEFAULT; |
| #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ |
| } |