1 /*
2  * Copyright (c) 2016-2019 Nordic Semiconductor ASA
3  * Copyright (c) 2016 Vinayak Kariappa Chettimada
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <soc.h>
10 #include <zephyr/bluetooth/hci_types.h>
11 #include <zephyr/bluetooth/hci_vs.h>
12 
13 #include "hal/cpu.h"
14 #include "hal/ccm.h"
15 #include "hal/radio.h"
16 
17 #include "util/util.h"
18 #include "util/memq.h"
19 #include "util/mem.h"
20 #include "util/dbuf.h"
21 
22 #include "pdu_df.h"
23 #include "lll/pdu_vendor.h"
24 #include "pdu.h"
25 
26 #include "lll.h"
27 #include "lll/lll_adv_types.h"
28 #include "lll_adv.h"
29 #include "lll/lll_adv_pdu.h"
30 #include "lll_scan.h"
31 #include "lll/lll_df_types.h"
32 #include "lll_conn.h"
33 
34 #include "ll_sw/ull_tx_queue.h"
35 
36 #include "ull_adv_types.h"
37 #include "ull_scan_types.h"
38 #include "ull_conn_types.h"
39 
40 #include "ull_adv_internal.h"
41 #include "ull_scan_internal.h"
42 #include "ull_conn_internal.h"
43 
44 #include "ll.h"
45 
ll_tx_pwr_lvl_get(uint8_t handle_type,uint16_t handle,uint8_t type,int8_t * tx_pwr_lvl)46 uint8_t ll_tx_pwr_lvl_get(uint8_t handle_type,
47 		       uint16_t handle, uint8_t type, int8_t *tx_pwr_lvl)
48 {
49 	switch (handle_type) {
50 #if defined(CONFIG_BT_BROADCASTER) &&\
51 	defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
52 		case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
53 			struct ll_adv_set *adv;
54 
55 #if !defined(CONFIG_BT_CTLR_ADV_EXT)
56 			/* Ignore handle if AE not enabled */
57 			handle = 0;
58 #endif /* CONFIG_BT_CTLR_ADV_EXT */
59 			/* Allow the app to get Tx power
60 			 * when advertising is off
61 			 */
62 			adv = ull_adv_set_get(handle);
63 			if (!adv) {
64 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
65 			}
66 			*tx_pwr_lvl = adv->lll.tx_pwr_lvl;
67 			break;
68 		}
69 #endif /* CONFIG_BT_BROADCASTER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
70 #if defined(CONFIG_BT_OBSERVER) &&\
71 	defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
72 		case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
73 			struct ll_scan_set *scan;
74 
75 			/* Ignore handle in case of scanner
76 			 * as for mesh extensions and scanning
77 			 * sets this control  is handled
78 			 * at a lower-level in the stack.
79 			 */
80 			handle = 0;
81 			/* Allow the app to get Tx power
82 			 * when scanning is off
83 			 */
84 			scan = ull_scan_set_get(handle);
85 			if (!scan) {
86 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
87 			}
88 			*tx_pwr_lvl = scan->lll.tx_pwr_lvl;
89 			break;
90 		}
91 #endif /* CONFIG_BT_OBSERVER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL*/
92 #if defined(CONFIG_BT_CONN)
93 		case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
94 			struct ll_conn *conn;
95 
96 			conn = ll_connected_get(handle);
97 			if (!conn) {
98 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
99 			}
100 
101 			if (type) {
102 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
103 				/* Level desired is maximum available */
104 				*tx_pwr_lvl = lll_radio_tx_pwr_max_get();
105 #else  /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
106 				/* Return default if not multiple TXP */
107 				*tx_pwr_lvl = RADIO_TXP_DEFAULT;
108 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
109 			} else {
110 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
111 				/* Current level is requested */
112 				*tx_pwr_lvl = conn->lll.tx_pwr_lvl;
113 #else  /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
114 				/* Return default if not multiple TXP */
115 				*tx_pwr_lvl = RADIO_TXP_DEFAULT;
116 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
117 			}
118 			break;
119 		}
120 #endif /* CONFIG_BT_CONN */
121 		default: {
122 			return BT_HCI_ERR_UNKNOWN_CMD;
123 		}
124 	}
125 
126 	return BT_HCI_ERR_SUCCESS;
127 }
128 
129 
ll_tx_pwr_lvl_set(uint8_t handle_type,uint16_t handle,int8_t * const tx_pwr_lvl)130 uint8_t ll_tx_pwr_lvl_set(uint8_t handle_type, uint16_t handle,
131 			  int8_t *const tx_pwr_lvl)
132 {
133 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
134 	if (*tx_pwr_lvl == BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF) {
135 		/* If no preference selected, then use default Tx power */
136 		*tx_pwr_lvl = RADIO_TXP_DEFAULT;
137 	}
138 
139 	/**
140 	 * Check that desired Tx power matches the achievable transceiver
141 	 * Tx power capabilities by flooring - if selected power matches than
142 	 * is used, otherwise next smaller power available is used.
143 	 */
144 	*tx_pwr_lvl = lll_radio_tx_pwr_floor(*tx_pwr_lvl);
145 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
146 
147 	switch (handle_type) {
148 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
149 #if defined(CONFIG_BT_BROADCASTER)
150 		case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
151 			struct ll_adv_set *adv;
152 
153 #if !defined(CONFIG_BT_CTLR_ADV_EXT)
154 			/* Ignore handle if AE not enabled */
155 			handle = 0;
156 #endif /* CONFIG_BT_CTLR_ADV_EXT */
157 			/* Allow the app to set Tx power
158 			 * prior to advertising
159 			 */
160 			adv = ull_adv_set_get(handle);
161 			if (!adv) {
162 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
163 			}
164 			adv->lll.tx_pwr_lvl = *tx_pwr_lvl;
165 			break;
166 		}
167 #endif /* CONFIG_BT_BROADCASTER */
168 #if defined(CONFIG_BT_OBSERVER)
169 		case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
170 			struct ll_scan_set *scan;
171 
172 			/* Ignore handle in case of scanner
173 			 * as for mesh extensions and scanning
174 			 * sets this control is handled
175 			 * at a lower-level in the stack.
176 			 */
177 			handle = 0;
178 			/* Allow the app to set Tx power
179 			 * prior to scanning
180 			 */
181 			scan = ull_scan_set_get(handle);
182 			if (!scan) {
183 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
184 			}
185 			scan->lll.tx_pwr_lvl = *tx_pwr_lvl;
186 			break;
187 		}
188 #endif /* CONFIG_BT_OBSERVER */
189 #if defined(CONFIG_BT_CONN)
190 		case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
191 			struct ll_conn *conn;
192 
193 			conn = ll_connected_get(handle);
194 			if (!conn) {
195 				return BT_HCI_ERR_UNKNOWN_CONN_ID;
196 			}
197 			conn->lll.tx_pwr_lvl = *tx_pwr_lvl;
198 			break;
199 		}
200 #endif /* CONFIG_BT_CONN */
201 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
202 		default: {
203 			return BT_HCI_ERR_UNKNOWN_CMD;
204 		}
205 	}
206 
207 	return BT_HCI_ERR_SUCCESS;
208 }
209 
ll_tx_pwr_get(int8_t * min,int8_t * max)210 void ll_tx_pwr_get(int8_t *min, int8_t *max)
211 {
212 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
213 	*min = lll_radio_tx_pwr_min_get();
214 	*max = lll_radio_tx_pwr_max_get();
215 #else
216 	*min = RADIO_TXP_DEFAULT;
217 	*max = RADIO_TXP_DEFAULT;
218 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
219 }
220