1use 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#[derive(Debug)]
18pub struct WpanFacade {
19 device: RwLock<Option<DeviceProxy>>,
21 device_test: RwLock<Option<DeviceTestProxy>>,
23 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}