bt_test_harness/
low_energy_peripheral.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{Context as _, Error};
6use fidl_fuchsia_bluetooth_le::{
7    ConnectionProxy, PeripheralEvent, PeripheralMarker, PeripheralProxy,
8};
9use fidl_fuchsia_hardware_bluetooth::EmulatorProxy;
10use fuchsia_bluetooth::expectation::asynchronous::{
11    expectable, Expectable, ExpectableExt, ExpectableState,
12};
13use fuchsia_bluetooth::types::le::Peer;
14use futures::future::{self, BoxFuture};
15use futures::{FutureExt, TryFutureExt, TryStreamExt};
16use std::ops::{Deref, DerefMut};
17use std::sync::Arc;
18use test_harness::{SharedState, TestHarness, SHARED_STATE_TEST_COMPONENT_INDEX};
19
20use crate::core_realm::{CoreRealm, SHARED_STATE_INDEX};
21use crate::emulator::{watch_advertising_states, EmulatorState};
22use crate::host_watcher::ActivatedFakeHost;
23
24/// A snapshot of the current LE peripheral procedure states of the controller.
25#[derive(Clone, Debug, Default)]
26pub struct PeripheralState {
27    emulator_state: EmulatorState,
28
29    /// Observed peer connections.
30    pub connections: Vec<(Peer, ConnectionProxy)>,
31}
32
33impl PeripheralState {
34    /// Resets to the default state.
35    pub fn reset(&mut self) {
36        self.emulator_state = EmulatorState::default();
37        self.connections.clear();
38    }
39}
40
41impl AsMut<EmulatorState> for PeripheralState {
42    fn as_mut(&mut self) -> &mut EmulatorState {
43        &mut self.emulator_state
44    }
45}
46
47impl AsRef<EmulatorState> for PeripheralState {
48    fn as_ref(&self) -> &EmulatorState {
49        &self.emulator_state
50    }
51}
52
53#[derive(Clone)]
54pub struct PeripheralHarness(Expectable<PeripheralState, Aux>);
55
56impl Deref for PeripheralHarness {
57    type Target = Expectable<PeripheralState, Aux>;
58
59    fn deref(&self) -> &Self::Target {
60        &self.0
61    }
62}
63
64impl DerefMut for PeripheralHarness {
65    fn deref_mut(&mut self) -> &mut Self::Target {
66        &mut self.0
67    }
68}
69
70/// Auxilliary data for the PeripheralHarness
71pub struct Aux {
72    pub peripheral: PeripheralProxy,
73    emulator: EmulatorProxy,
74}
75
76impl AsRef<EmulatorProxy> for Aux {
77    fn as_ref(&self) -> &EmulatorProxy {
78        &self.emulator
79    }
80}
81
82impl TestHarness for PeripheralHarness {
83    type Env = (ActivatedFakeHost, Arc<CoreRealm>);
84    type Runner = BoxFuture<'static, Result<(), Error>>;
85
86    fn init(
87        shared_state: &Arc<SharedState>,
88    ) -> BoxFuture<'static, Result<(Self, Self::Env, Self::Runner), Error>> {
89        let shared_state = shared_state.clone();
90        async move {
91            let test_component: Arc<String> = shared_state
92                .get(SHARED_STATE_TEST_COMPONENT_INDEX)
93                .expect("SharedState must have TEST-COMPONENT")?;
94            let inserter = move || CoreRealm::create(test_component.to_string());
95            let realm = shared_state.get_or_insert_with(SHARED_STATE_INDEX, inserter).await?;
96            let host = ActivatedFakeHost::new(realm.clone()).await?;
97            let peripheral = realm
98                .instance()
99                .connect_to_protocol_at_exposed_dir::<PeripheralMarker>()
100                .context("Failed to connect to BLE Peripheral service")?;
101            let harness = PeripheralHarness(expectable(
102                Default::default(),
103                Aux { peripheral, emulator: host.emulator().clone() },
104            ));
105
106            // Create a task to process the state update watcher
107            let watch_adv = watch_advertising_states(harness.deref().clone());
108            let watch_conn = watch_connections(harness.clone());
109            let run_peripheral =
110                future::try_join(watch_adv, watch_conn).map_ok(|((), ())| ()).boxed();
111
112            Ok((harness, (host, realm), run_peripheral))
113        }
114        .boxed()
115    }
116    fn terminate((emulator, realm): Self::Env) -> BoxFuture<'static, Result<(), Error>> {
117        // The realm must be kept alive in order for emulator.release() to work properly.
118        async move {
119            let _realm = realm;
120            emulator.release().await
121        }
122        .boxed()
123    }
124}
125
126async fn watch_connections(harness: PeripheralHarness) -> Result<(), Error> {
127    let mut events = harness.aux().peripheral.take_event_stream();
128    while let Some(e) = events.try_next().await? {
129        match e {
130            PeripheralEvent::OnPeerConnected { peer, connection } => {
131                harness.write_state().connections.push((peer.try_into()?, connection.into_proxy()));
132            }
133        }
134        harness.notify_state_changed();
135    }
136    Ok(())
137}