bt_test_harness/
low_energy_central.rs1use anyhow::{Context as _, Error};
6use fidl_fuchsia_bluetooth_le::{CentralEvent, CentralMarker, CentralProxy};
7use fidl_fuchsia_hardware_bluetooth::EmulatorProxy;
8use fuchsia_bluetooth::expectation::asynchronous::{
9 expectable, Expectable, ExpectableExt, ExpectableState,
10};
11use fuchsia_bluetooth::types::le::RemoteDevice;
12use futures::future::BoxFuture;
13use futures::{FutureExt, TryStreamExt};
14use std::ops::{Deref, DerefMut};
15use std::sync::Arc;
16use test_harness::{SharedState, TestHarness, SHARED_STATE_TEST_COMPONENT_INDEX};
17
18use crate::core_realm::{CoreRealm, SHARED_STATE_INDEX};
19use crate::host_watcher::ActivatedFakeHost;
20
21#[derive(PartialEq, Debug, Clone, Copy)]
22pub enum ScanStateChange {
23 ScanEnabled,
24 ScanDisabled,
25}
26
27#[derive(Clone, Default)]
29pub struct CentralState {
30 pub scan_state_changes: Vec<ScanStateChange>,
32
33 pub remote_devices: Vec<RemoteDevice>,
35}
36
37pub struct Aux {
39 pub central: CentralProxy,
40 emulator: EmulatorProxy,
41}
42
43impl AsRef<EmulatorProxy> for Aux {
44 fn as_ref(&self) -> &EmulatorProxy {
45 &self.emulator
46 }
47}
48
49#[derive(Clone)]
50pub struct CentralHarness(Expectable<CentralState, Aux>);
51
52impl Deref for CentralHarness {
53 type Target = Expectable<CentralState, Aux>;
54
55 fn deref(&self) -> &Self::Target {
56 &self.0
57 }
58}
59
60impl DerefMut for CentralHarness {
61 fn deref_mut(&mut self) -> &mut Self::Target {
62 &mut self.0
63 }
64}
65
66impl TestHarness for CentralHarness {
67 type Env = (ActivatedFakeHost, Arc<CoreRealm>);
68 type Runner = BoxFuture<'static, Result<(), Error>>;
69
70 fn init(
71 shared_state: &Arc<SharedState>,
72 ) -> BoxFuture<'static, Result<(Self, Self::Env, Self::Runner), Error>> {
73 let shared_state = shared_state.clone();
74 async move {
75 let test_component: Arc<String> = shared_state
76 .get(SHARED_STATE_TEST_COMPONENT_INDEX)
77 .expect("SharedState must have TEST-COMPONENT")?;
78 let inserter = move || CoreRealm::create(test_component.to_string());
79 let realm = shared_state.get_or_insert_with(SHARED_STATE_INDEX, inserter).await?;
80 let fake_host = ActivatedFakeHost::new(realm.clone()).await?;
81 let central = realm
82 .instance()
83 .connect_to_protocol_at_exposed_dir::<CentralMarker>()
84 .context("Failed to connect to BLE Central service")?;
85
86 let harness = CentralHarness(expectable(
87 Default::default(),
88 Aux { central, emulator: fake_host.emulator().clone() },
89 ));
90 let run_central = handle_central_events(harness.clone()).boxed();
91 Ok((harness, (fake_host, realm), run_central))
92 }
93 .boxed()
94 }
95
96 fn terminate((emulator, realm): Self::Env) -> BoxFuture<'static, Result<(), Error>> {
97 async move {
99 let _realm = realm;
100 emulator.release().await
101 }
102 .boxed()
103 }
104}
105
106async fn handle_central_events(harness: CentralHarness) -> Result<(), Error> {
107 let mut events = harness.aux().central.take_event_stream();
108
109 while let Some(e) = events.try_next().await? {
110 match e {
111 CentralEvent::OnDeviceDiscovered { device } => {
112 harness.write_state().remote_devices.push(device.try_into()?);
113 harness.notify_state_changed();
114 }
115 CentralEvent::OnScanStateChanged { scanning } => {
116 let change = if scanning {
117 ScanStateChange::ScanEnabled
118 } else {
119 ScanStateChange::ScanDisabled
120 };
121 harness.write_state().scan_state_changes.push(change);
122 harness.notify_state_changed();
123 }
124 CentralEvent::OnPeripheralDisconnected { identifier: _ } => {}
125 };
126 }
127 Ok(())
128}