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