Skip to main content

sl4f_lib/wpan/
facade.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 super::types::{
6    ConnectivityState, DeviceStateDto, MacAddressFilterSettingsDto, NeighborInfoDto,
7};
8use crate::common_utils::lowpan_context::LowpanContext;
9use anyhow::Error;
10use fidl_fuchsia_lowpan_device::{DeviceExtraProxy, DeviceProxy};
11use fidl_fuchsia_lowpan_test::DeviceTestProxy;
12use fuchsia_sync::RwLock;
13
14/// Perform Wpan FIDL operations.
15///
16/// Note this object is shared among all threads created by server.
17#[derive(Debug)]
18pub struct WpanFacade {
19    /// The proxy to access the lowpan Device service.
20    device: RwLock<Option<DeviceProxy>>,
21    /// The proxy to access the lowpan DeviceTest service.
22    device_test: RwLock<Option<DeviceTestProxy>>,
23    /// The proxy to access the lowpan DeviceExtra service.
24    device_extra: RwLock<Option<DeviceExtraProxy>>,
25}
26
27impl WpanFacade {
28    pub fn new() -> WpanFacade {
29        WpanFacade {
30            device: RwLock::new(None),
31            device_test: RwLock::new(None),
32            device_extra: RwLock::new(None),
33        }
34    }
35
36    /// Returns the DeviceTestManager proxy provided on instantiation
37    /// or establishes a new connection.
38    pub async fn initialize_proxies(&self) -> Result<(), Error> {
39        let (device, device_extra, device_test) = match LowpanContext::new(None) {
40            Ok(low_pan_context) => low_pan_context.get_default_device_proxies().await?,
41            _ => bail!("Error retrieving default device proxies"),
42        };
43        *self.device.write() = Some(device);
44        *self.device_extra.write() = Some(device_extra);
45        *self.device_test.write() = Some(device_test);
46        Ok(())
47    }
48
49    /// Returns the thread rloc from the DeviceTest proxy service.
50    pub async fn get_thread_rloc16(&self) -> Result<u16, Error> {
51        let device_test_proxy = self.device_test.read().clone();
52        let thread_rloc16 = match device_test_proxy {
53            Some(device_test) => device_test.get_thread_rloc16().await?,
54            _ => bail!("DeviceTest proxy is not set"),
55        };
56        Ok(thread_rloc16)
57    }
58
59    /// Returns the current mac address (thread random mac address) from the DeviceTest
60    /// proxy service.
61    pub async fn get_ncp_mac_address(&self) -> Result<[u8; 8], Error> {
62        let device_test_proxy = self.device_test.read().clone();
63        let current_mac_address = match device_test_proxy {
64            Some(device_test) => device_test.get_current_mac_address().await?,
65            _ => bail!("DeviceTest proxy is not set"),
66        };
67        Ok(current_mac_address.octets)
68    }
69
70    /// Returns the ncp channel from the DeviceTest proxy service.
71    pub async fn get_ncp_channel(&self) -> Result<u16, Error> {
72        let device_test_proxy = self.device_test.read().clone();
73        let current_channel = match device_test_proxy {
74            Some(device_test) => device_test.get_current_channel().await?,
75            _ => bail!("DeviceTest proxy is not set"),
76        };
77        Ok(current_channel)
78    }
79
80    /// Returns the current rssi from the DeviceTest proxy service.
81    pub async fn get_ncp_rssi(&self) -> Result<i32, Error> {
82        let device_test_proxy = self.device_test.read().clone();
83        let ncp_rssi = match device_test_proxy {
84            Some(device_test) => device_test.get_current_rssi().await?,
85            _ => bail!("DeviceTest proxy is not set"),
86        };
87        Ok(ncp_rssi.into())
88    }
89
90    /// Returns the factory mac address from the DeviceTest proxy service.
91    pub async fn get_weave_node_id(&self) -> Result<[u8; 8], Error> {
92        let device_test_proxy = self.device_test.read().clone();
93        let factory_mac_address = match device_test_proxy {
94            Some(device_test) => device_test.get_factory_mac_address().await?,
95            _ => bail!("DeviceTest proxy is not set"),
96        };
97        Ok(factory_mac_address.octets)
98    }
99
100    /// Returns the network name from the DeviceExtra proxy service.
101    pub async fn get_network_name(&self) -> Result<Vec<u8>, Error> {
102        let device_extra_proxy = self.device_extra.read().clone();
103        let raw_name = match device_extra_proxy {
104            Some(device_extra) => device_extra.watch_identity().await?.raw_name,
105            _ => bail!("DeviceExtra proxy is not set"),
106        };
107        match raw_name {
108            Some(raw_name) => Ok(raw_name),
109            None => bail!("Network name is not specified!"),
110        }
111    }
112
113    /// Returns the partition id from the DeviceTest proxy service.
114    pub async fn get_partition_id(&self) -> Result<u32, Error> {
115        let device_test_proxy = self.device_test.read().clone();
116        let partition_id = match device_test_proxy {
117            Some(device_test) => device_test.get_partition_id().await?,
118            _ => bail!("DeviceTest proxy is not set"),
119        };
120        Ok(partition_id)
121    }
122
123    /// Returns the thread router id from the DeviceTest proxy service.
124    pub async fn get_thread_router_id(&self) -> Result<u8, Error> {
125        let device_test_proxy = self.device_test.read().clone();
126        let router_id = match device_test_proxy {
127            Some(device_test) => device_test.get_thread_router_id().await?,
128            _ => bail!("DeviceTest proxy is not set"),
129        };
130        Ok(router_id)
131    }
132
133    /// Returns the device state from the DeviceTest proxy service.
134    pub async fn get_ncp_device_state(&self) -> Result<DeviceStateDto, Error> {
135        let proxy_opt: Option<DeviceProxy> = self.device.read().clone();
136        let device_state = match proxy_opt {
137            Some(device) => device.watch_device_state().await?,
138            _ => bail!("DeviceTest proxy is not set"),
139        };
140        Ok(device_state.into())
141    }
142
143    /// Returns the connectivity state from the DeviceTest proxy service.
144    pub async fn get_ncp_state(&self) -> Result<ConnectivityState, Error> {
145        let proxy_opt: Option<DeviceProxy> = self.device.read().clone();
146        let device_state = match proxy_opt {
147            Some(device) => device.watch_device_state().await?.connectivity_state,
148            _ => bail!("DeviceTest proxy is not set"),
149        };
150        match device_state {
151            Some(connectivity_state) => Ok(connectivity_state.into()),
152            None => bail!("Device state is not defined!"),
153        }
154    }
155
156    /// Returns true if the connectivity state is commissioned.
157    pub async fn get_is_commissioned(&self) -> Result<bool, Error> {
158        let ncp_state = self.get_ncp_state().await?;
159        let is_commissioned = match ncp_state {
160            ConnectivityState::Attached
161            | ConnectivityState::Attaching
162            | ConnectivityState::Isolated
163            | ConnectivityState::Ready => true,
164            _ => false,
165        };
166        Ok(is_commissioned)
167    }
168
169    /// Returns the panid from the DeviceExtra proxy service.
170    pub async fn get_panid(&self) -> Result<u16, Error> {
171        let proxy_opt = self.device_extra.read().clone();
172        match proxy_opt {
173            Some(device_extra) => match device_extra.watch_identity().await?.panid {
174                Some(panid) => Ok(panid),
175                None => bail!("Pan id is not specified!"),
176            },
177            _ => bail!("DeviceExtra proxy is not set"),
178        }
179    }
180
181    /// Returns the mac address filter settings from the DeviceTest proxy service.
182    pub async fn get_mac_address_filter_settings(
183        &self,
184    ) -> Result<MacAddressFilterSettingsDto, Error> {
185        let proxy_opt = self.device_test.read().clone();
186        let settings = match proxy_opt {
187            Some(device_test) => device_test.get_mac_address_filter_settings().await?,
188            _ => bail!("DeviceTest proxy is not set!"),
189        };
190        Ok(settings.into())
191    }
192
193    /// Replaces the mac address filter settings on the DeviceTest proxy service.
194    pub async fn replace_mac_address_filter_settings(
195        &self,
196        settings: MacAddressFilterSettingsDto,
197    ) -> Result<(), Error> {
198        let proxy_opt = self.device_test.read().clone();
199        match proxy_opt {
200            Some(device_test) => {
201                device_test.replace_mac_address_filter_settings(&settings.into()).await?
202            }
203            None => bail!("DeviceTest proxy is not set!"),
204        }
205        Ok(())
206    }
207
208    ///Returns the thread neighbor table from the DeviceTest proxy service.
209    pub async fn get_neighbor_table(&self) -> Result<Vec<NeighborInfoDto>, Error> {
210        let proxy_opt = self.device_test.read().clone();
211        let settings = match proxy_opt {
212            Some(device_test) => device_test.get_neighbor_table().await?,
213            _ => bail!("DeviceTest proxy is not set!"),
214        };
215        Ok(settings.into_iter().map(|setting| setting.into()).collect())
216    }
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222    use crate::wpan::types::{MacAddressFilterItemDto, MacAddressFilterModeDto};
223    use fidl::endpoints::ProtocolMarker;
224    use fidl_fuchsia_lowpan_device::{DeviceExtraMarker, DeviceMarker};
225    use fidl_fuchsia_lowpan_test::DeviceTestMarker;
226    use fuchsia_async as fasync;
227    use futures::prelude::*;
228    use lowpan_driver_common::{DummyDevice, ServeTo};
229    use std::sync::LazyLock;
230
231    static MOCK_TESTER: LazyLock<MockTester> = LazyLock::new(|| MockTester::new());
232
233    struct MockTester {
234        dummy_device: DummyDevice,
235    }
236    impl MockTester {
237        fn new() -> Self {
238            Self { dummy_device: DummyDevice::default() }
239        }
240
241        fn create_endpoints<T: ProtocolMarker>() -> (RwLock<Option<T::Proxy>>, T::RequestStream) {
242            let (client_ep, server_ep) = fidl::endpoints::create_endpoints::<T>();
243            (RwLock::new(Some(client_ep.into_proxy())), server_ep.into_stream())
244        }
245
246        pub fn create_facade_and_serve(
247            &'static self,
248        ) -> (
249            WpanFacade,
250            (
251                impl Future<Output = anyhow::Result<()>>,
252                impl Future<Output = anyhow::Result<()>>,
253                impl Future<Output = anyhow::Result<()>>,
254            ),
255        ) {
256            let (device_proxy, device_server) = MockTester::create_endpoints::<DeviceMarker>();
257            let (device_test_proxy, device_test_server) =
258                MockTester::create_endpoints::<DeviceTestMarker>();
259            let (device_extra_proxy, device_extra_server) =
260                MockTester::create_endpoints::<DeviceExtraMarker>();
261
262            let facade = WpanFacade {
263                device: device_proxy,
264                device_test: device_test_proxy,
265                device_extra: device_extra_proxy,
266            };
267
268            (
269                facade,
270                (
271                    self.dummy_device.serve_to(device_server),
272                    self.dummy_device.serve_to(device_test_server),
273                    self.dummy_device.serve_to(device_extra_server),
274                ),
275            )
276        }
277
278        pub async fn assert_wpan_fn<TResult>(
279            func: impl Future<Output = Result<TResult, Error>>,
280            server_future: (
281                impl Future<Output = anyhow::Result<()>>,
282                impl Future<Output = anyhow::Result<()>>,
283                impl Future<Output = anyhow::Result<()>>,
284            ),
285        ) {
286            let facade_fut = async move {
287                let awaiting = func.await;
288                awaiting.expect("No value returned!");
289            };
290            futures::select! {
291                err = server_future.0.fuse() => panic!("Server task stopped: {:?}", err),
292                err = server_future.1.fuse() => panic!("Server task stopped: {:?}", err),
293                err = server_future.2.fuse() => panic!("Server task stopped: {:?}", err),
294                _ = facade_fut.fuse() => (),
295            }
296        }
297    }
298
299    #[fasync::run_singlethreaded(test)]
300    async fn test_get_thread_rloc16() {
301        let facade = MOCK_TESTER.create_facade_and_serve();
302        MockTester::assert_wpan_fn(facade.0.get_thread_rloc16(), facade.1).await;
303    }
304
305    #[fasync::run_singlethreaded(test)]
306    async fn test_get_ncp_channel() {
307        let facade = MOCK_TESTER.create_facade_and_serve();
308        MockTester::assert_wpan_fn(facade.0.get_ncp_channel(), facade.1).await;
309    }
310
311    #[fasync::run_singlethreaded(test)]
312    async fn test_get_ncp_mac_address() {
313        let facade = MOCK_TESTER.create_facade_and_serve();
314        MockTester::assert_wpan_fn(facade.0.get_ncp_mac_address(), facade.1).await;
315    }
316
317    #[fasync::run_singlethreaded(test)]
318    async fn test_get_ncp_rssi() {
319        let facade = MOCK_TESTER.create_facade_and_serve();
320        MockTester::assert_wpan_fn(facade.0.get_ncp_rssi(), facade.1).await;
321    }
322
323    #[fasync::run_singlethreaded(test)]
324    async fn test_get_weave_node_id() {
325        let facade = MOCK_TESTER.create_facade_and_serve();
326        MockTester::assert_wpan_fn(facade.0.get_weave_node_id(), facade.1).await;
327    }
328
329    #[fasync::run_singlethreaded(test)]
330    async fn test_get_network_name() {
331        let facade = MOCK_TESTER.create_facade_and_serve();
332        MockTester::assert_wpan_fn(facade.0.get_network_name(), facade.1).await;
333    }
334
335    #[fasync::run_singlethreaded(test)]
336    async fn test_get_partition_id() {
337        let facade = MOCK_TESTER.create_facade_and_serve();
338        MockTester::assert_wpan_fn(facade.0.get_partition_id(), facade.1).await;
339    }
340
341    #[fasync::run_singlethreaded(test)]
342    async fn test_get_thread_router_id() {
343        let facade = MOCK_TESTER.create_facade_and_serve();
344        MockTester::assert_wpan_fn(facade.0.get_thread_router_id(), facade.1).await;
345    }
346
347    #[fasync::run_singlethreaded(test)]
348    async fn test_get_ncp_device_state() {
349        let facade = MOCK_TESTER.create_facade_and_serve();
350        MockTester::assert_wpan_fn(facade.0.get_ncp_device_state(), facade.1).await;
351    }
352
353    #[fasync::run_singlethreaded(test)]
354    async fn test_get_ncp_state() {
355        let facade = MOCK_TESTER.create_facade_and_serve();
356        MockTester::assert_wpan_fn(facade.0.get_ncp_state(), facade.1).await;
357    }
358
359    #[fasync::run_singlethreaded(test)]
360    async fn test_get_is_commissioned() {
361        let facade = MOCK_TESTER.create_facade_and_serve();
362        MockTester::assert_wpan_fn(facade.0.get_is_commissioned(), facade.1).await;
363    }
364
365    #[fasync::run_singlethreaded(test)]
366    async fn test_get_panid() {
367        let facade = MOCK_TESTER.create_facade_and_serve();
368        MockTester::assert_wpan_fn(facade.0.get_panid(), facade.1).await;
369    }
370
371    #[fasync::run_singlethreaded(test)]
372    async fn test_get_mac_address_filter_settings() {
373        let facade = MOCK_TESTER.create_facade_and_serve();
374        MockTester::assert_wpan_fn(facade.0.get_mac_address_filter_settings(), facade.1).await;
375    }
376
377    #[fasync::run_singlethreaded(test)]
378    async fn test_replace_mac_address_filter_settings() {
379        let facade = MOCK_TESTER.create_facade_and_serve();
380        MockTester::assert_wpan_fn(
381            facade.0.replace_mac_address_filter_settings(MacAddressFilterSettingsDto {
382                mode: Some(MacAddressFilterModeDto::Allow),
383                items: Some(vec![MacAddressFilterItemDto {
384                    mac_address: Some([0, 1, 2, 3, 4, 5, 6, 7]),
385                    rssi: None,
386                }]),
387            }),
388            facade.1,
389        )
390        .await;
391    }
392
393    #[fasync::run_singlethreaded(test)]
394    async fn test_get_neigbor_table() {
395        let facade = MOCK_TESTER.create_facade_and_serve();
396        MockTester::assert_wpan_fn(facade.0.get_neighbor_table(), facade.1).await;
397    }
398}