1 //! Loads info from the controller at startup
2
3 use crate::{Address, CommandSender};
4 use bt_packets::hci::{
5 Enable, ErrorCode, LeMaximumDataLength, LeReadBufferSizeV1Builder, LeReadBufferSizeV2Builder,
6 LeReadConnectListSizeBuilder, LeReadLocalSupportedFeaturesBuilder,
7 LeReadMaximumAdvertisingDataLengthBuilder, LeReadMaximumDataLengthBuilder,
8 LeReadNumberOfSupportedAdvertisingSetsBuilder, LeReadPeriodicAdvertiserListSizeBuilder,
9 LeReadResolvingListSizeBuilder, LeReadSuggestedDefaultDataLengthBuilder,
10 LeReadSupportedStatesBuilder, LeSetEventMaskBuilder, LocalVersionInformation, OpCode,
11 OpCodeIndex, ReadBdAddrBuilder, ReadBufferSizeBuilder, ReadLocalExtendedFeaturesBuilder,
12 ReadLocalNameBuilder, ReadLocalSupportedCommandsBuilder, ReadLocalVersionInformationBuilder,
13 SetEventMaskBuilder, WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder,
14 };
15 use gddi::{module, provides, Stoppable};
16 use num_traits::ToPrimitive;
17 use std::convert::TryFrom;
18 use std::sync::Arc;
19
20 module! {
21 controller_module,
22 providers {
23 Arc<ControllerExports> => provide_controller,
24 },
25 }
26
27 macro_rules! assert_success {
28 ($hci:ident.send($builder:expr)) => {{
29 let response = $hci.send($builder).await;
30 assert!(response.get_status() == ErrorCode::Success);
31
32 response
33 }};
34 }
35
36 #[provides]
provide_controller(mut hci: CommandSender) -> Arc<ControllerExports>37 async fn provide_controller(mut hci: CommandSender) -> Arc<ControllerExports> {
38 assert_success!(hci.send(LeSetEventMaskBuilder { le_event_mask: 0x0000000000021e7f }));
39 assert_success!(hci.send(SetEventMaskBuilder { event_mask: 0x3dbfffffffffffff }));
40 assert_success!(
41 hci.send(WriteSimplePairingModeBuilder { simple_pairing_mode: Enable::Enabled })
42 );
43 assert_success!(hci.send(WriteLeHostSupportBuilder {
44 le_supported_host: Enable::Enabled,
45 simultaneous_le_host: Enable::Enabled
46 }));
47
48 let name = null_terminated_to_string(
49 assert_success!(hci.send(ReadLocalNameBuilder {})).get_local_name(),
50 );
51
52 let version_info = assert_success!(hci.send(ReadLocalVersionInformationBuilder {}))
53 .get_local_version_information()
54 .clone();
55
56 let commands = SupportedCommands {
57 supported: *assert_success!(hci.send(ReadLocalSupportedCommandsBuilder {}))
58 .get_supported_commands(),
59 };
60
61 let features = read_features(&mut hci).await;
62
63 let buffer_size = assert_success!(hci.send(ReadBufferSizeBuilder {}));
64 let acl_buffer_length = buffer_size.get_acl_data_packet_length();
65 let mut acl_buffers = buffer_size.get_total_num_acl_data_packets();
66
67 let (mut le_buffer_length, mut le_buffers, iso_buffer_length, iso_buffers) =
68 if commands.is_supported(OpCode::LeReadBufferSizeV2) {
69 let response = assert_success!(hci.send(LeReadBufferSizeV2Builder {}));
70 (
71 response.get_le_buffer_size().le_data_packet_length,
72 response.get_le_buffer_size().total_num_le_packets,
73 response.get_iso_buffer_size().le_data_packet_length,
74 response.get_iso_buffer_size().total_num_le_packets,
75 )
76 } else {
77 let response = assert_success!(hci.send(LeReadBufferSizeV1Builder {}));
78 (
79 response.get_le_buffer_size().le_data_packet_length,
80 response.get_le_buffer_size().total_num_le_packets,
81 0,
82 0,
83 )
84 };
85
86 // If the controller reports zero LE buffers, the ACL buffers are shared between classic & LE
87 if le_buffers == 0 {
88 le_buffers = (acl_buffers / 2) as u8;
89 acl_buffers -= le_buffers as u16;
90 le_buffer_length = acl_buffer_length;
91 }
92
93 let le_features = SupportedLeFeatures::new(
94 assert_success!(hci.send(LeReadLocalSupportedFeaturesBuilder {})).get_le_features(),
95 );
96 let le_supported_states =
97 assert_success!(hci.send(LeReadSupportedStatesBuilder {})).get_le_states();
98 let le_connect_list_size =
99 assert_success!(hci.send(LeReadConnectListSizeBuilder {})).get_connect_list_size();
100 let le_resolving_list_size =
101 assert_success!(hci.send(LeReadResolvingListSizeBuilder {})).get_resolving_list_size();
102
103 let le_max_data_length = if commands.is_supported(OpCode::LeReadMaximumDataLength) {
104 assert_success!(hci.send(LeReadMaximumDataLengthBuilder {}))
105 .get_le_maximum_data_length()
106 .clone()
107 } else {
108 LeMaximumDataLength {
109 supported_max_rx_octets: 0,
110 supported_max_rx_time: 0,
111 supported_max_tx_octets: 0,
112 supported_max_tx_time: 0,
113 }
114 };
115
116 let le_suggested_default_data_length =
117 if commands.is_supported(OpCode::LeReadSuggestedDefaultDataLength) {
118 assert_success!(hci.send(LeReadSuggestedDefaultDataLengthBuilder {})).get_tx_octets()
119 } else {
120 0
121 };
122
123 let le_max_advertising_data_length =
124 if commands.is_supported(OpCode::LeReadMaximumAdvertisingDataLength) {
125 assert_success!(hci.send(LeReadMaximumAdvertisingDataLengthBuilder {}))
126 .get_maximum_advertising_data_length()
127 } else {
128 31
129 };
130 let le_supported_advertising_sets =
131 if commands.is_supported(OpCode::LeReadNumberOfSupportedAdvertisingSets) {
132 assert_success!(hci.send(LeReadNumberOfSupportedAdvertisingSetsBuilder {}))
133 .get_number_supported_advertising_sets()
134 } else {
135 1
136 };
137 let le_periodic_advertiser_list_size =
138 if commands.is_supported(OpCode::LeReadPeriodicAdvertisingListSize) {
139 assert_success!(hci.send(LeReadPeriodicAdvertiserListSizeBuilder {}))
140 .get_periodic_advertiser_list_size()
141 } else {
142 0
143 };
144
145 let address = assert_success!(hci.send(ReadBdAddrBuilder {})).get_bd_addr();
146
147 Arc::new(ControllerExports {
148 name,
149 address,
150 version_info,
151 commands,
152 features,
153 acl_buffer_length,
154 acl_buffers,
155 sco_buffer_length: buffer_size.get_synchronous_data_packet_length(),
156 sco_buffers: buffer_size.get_total_num_synchronous_data_packets(),
157 le_buffer_length,
158 le_buffers,
159 iso_buffer_length,
160 iso_buffers,
161 le_features,
162 le_supported_states,
163 le_connect_list_size,
164 le_resolving_list_size,
165 le_max_data_length,
166 le_suggested_default_data_length,
167 le_max_advertising_data_length,
168 le_supported_advertising_sets,
169 le_periodic_advertiser_list_size,
170 })
171 }
172
read_features(hci: &mut CommandSender) -> SupportedFeatures173 async fn read_features(hci: &mut CommandSender) -> SupportedFeatures {
174 let mut features = Vec::new();
175 let mut page_number: u8 = 0;
176 let mut max_page_number: u8 = 1;
177 while page_number < max_page_number {
178 let response = assert_success!(hci.send(ReadLocalExtendedFeaturesBuilder { page_number }));
179 max_page_number = response.get_maximum_page_number();
180 features.push(response.get_extended_lmp_features());
181 page_number += 1;
182 }
183
184 SupportedFeatures::new(features)
185 }
186
187 /// Controller interface
188 #[derive(Clone, Stoppable)]
189 #[allow(missing_docs)]
190 pub struct ControllerExports {
191 pub name: String,
192 pub address: Address,
193 pub version_info: LocalVersionInformation,
194 pub commands: SupportedCommands,
195 pub features: SupportedFeatures,
196 pub acl_buffer_length: u16,
197 pub acl_buffers: u16,
198 pub sco_buffer_length: u8,
199 pub sco_buffers: u16,
200 pub le_buffer_length: u16,
201 pub le_buffers: u8,
202 pub iso_buffer_length: u16,
203 pub iso_buffers: u8,
204 pub le_features: SupportedLeFeatures,
205 pub le_supported_states: u64,
206 pub le_connect_list_size: u8,
207 pub le_resolving_list_size: u8,
208 pub le_max_data_length: LeMaximumDataLength,
209 pub le_suggested_default_data_length: u16,
210 pub le_max_advertising_data_length: u16,
211 pub le_supported_advertising_sets: u8,
212 pub le_periodic_advertiser_list_size: u8,
213 }
214
215 /// Convenience struct for checking what commands are supported
216 #[derive(Clone)]
217 pub struct SupportedCommands {
218 supported: [u8; 64],
219 }
220
221 impl SupportedCommands {
222 /// Check whether a given opcode is supported by the controller
is_supported(&self, opcode: OpCode) -> bool223 pub fn is_supported(&self, opcode: OpCode) -> bool {
224 let converted = OpCodeIndex::try_from(opcode);
225 if converted.is_err() {
226 return false;
227 }
228
229 let index = converted.unwrap().to_usize().unwrap();
230
231 // OpCodeIndex is encoded as octet * 10 + bit for readability
232 self.supported[index / 10] & (1 << (index % 10)) == 1
233 }
234 }
235
236 macro_rules! supported_features {
237 ($($id:ident => $page:literal : $bit:literal),*) => {
238 /// Convenience struct for checking what features are supported
239 #[derive(Clone)]
240 #[allow(missing_docs)]
241 pub struct SupportedFeatures {
242 $(pub $id: bool,)*
243 }
244
245 impl SupportedFeatures {
246 fn new(supported: Vec<u64>) -> Self {
247 Self {
248 $($id: *supported.get($page).unwrap_or(&0) & (1 << $bit) != 0,)*
249 }
250 }
251 }
252 }
253 }
254
255 supported_features! {
256 three_slot_packets => 0:0,
257 five_slot_packets => 0:1,
258 role_switch => 0:5,
259 hold_mode => 0:6,
260 sniff_mode => 0:7,
261 park_mode => 0:8,
262 sco => 0:11,
263 hv2_packets => 0:12,
264 hv3_packets => 0:13,
265 classic_2m_phy => 0:25,
266 classic_3m_phy => 0:26,
267 interlaced_inquiry_scan => 0:28,
268 rssi_with_inquiry_results => 0:30,
269 ev3_packets => 0:31,
270 ev4_packets => 0:32,
271 ev5_packets => 0:33,
272 ble => 0:38,
273 three_slot_edr_packets => 0:39,
274 five_slot_edr_packets => 0:40,
275 sniff_subrating => 0:41,
276 encryption_pause => 0:42,
277 esco_2m_phy => 0:45,
278 esco_3m_phy => 0:46,
279 three_slot_esco_edr_packets => 0:47,
280 extended_inquiry_response => 0:48,
281 simultaneous_le_bredr => 0:49,
282 simple_pairing => 0:51,
283 non_flushable_pb => 0:54,
284 secure_connections => 2:8
285 }
286
287 macro_rules! supported_le_features {
288 ($($id:ident => $bit:literal),*) => {
289 /// Convenience struct for checking what features are supported
290 #[derive(Clone)]
291 #[allow(missing_docs)]
292 pub struct SupportedLeFeatures {
293 $(pub $id: bool,)*
294 }
295
296 impl SupportedLeFeatures {
297 fn new(supported: u64) -> Self {
298 Self {
299 $($id: supported & (1 << $bit) != 0,)*
300 }
301 }
302 }
303 }
304 }
305
306 supported_le_features! {
307 connection_parameter_request => 1,
308 connection_parameters_request => 2,
309 peripheral_initiated_feature_exchange => 3,
310 packet_extension => 5,
311 privacy => 6,
312 ble_2m_phy => 8,
313 ble_coded_phy => 11,
314 extended_advertising => 12,
315 periodic_advertising => 13,
316 periodic_advertising_sync_transfer_sender => 24,
317 periodic_advertising_sync_transfer_recipient => 25,
318 connected_iso_stream_central => 28,
319 connected_iso_stream_peripheral => 29,
320 iso_broadcaster => 30,
321 synchronized_receiver => 31
322 }
323
324 /// Convert a null terminated C string into a Rust String
null_terminated_to_string(slice: &[u8]) -> String325 pub fn null_terminated_to_string(slice: &[u8]) -> String {
326 let temp = std::str::from_utf8(slice).unwrap();
327 temp[0..temp.find('\0').unwrap()].to_string()
328 }
329