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 thread_rloc16 = match self.device_test.read().as_ref() {
52 Some(device_test) => device_test.get_thread_rloc16().await?,
53 _ => bail!("DeviceTest proxy is not set"),
54 };
55 Ok(thread_rloc16)
56 }
57
58 pub async fn get_ncp_mac_address(&self) -> Result<[u8; 8], Error> {
61 let current_mac_address = match self.device_test.read().as_ref() {
62 Some(device_test) => device_test.get_current_mac_address().await?,
63 _ => bail!("DeviceTest proxy is not set"),
64 };
65 Ok(current_mac_address.octets)
66 }
67
68 pub async fn get_ncp_channel(&self) -> Result<u16, Error> {
70 let current_channel = match self.device_test.read().as_ref() {
71 Some(device_test) => device_test.get_current_channel().await?,
72 _ => bail!("DeviceTest proxy is not set"),
73 };
74 Ok(current_channel)
75 }
76
77 pub async fn get_ncp_rssi(&self) -> Result<i32, Error> {
79 let ncp_rssi = match self.device_test.read().as_ref() {
80 Some(device_test) => device_test.get_current_rssi().await?,
81 _ => bail!("DeviceTest proxy is not set"),
82 };
83 Ok(ncp_rssi.into())
84 }
85
86 pub async fn get_weave_node_id(&self) -> Result<[u8; 8], Error> {
88 let factory_mac_address = match self.device_test.read().as_ref() {
89 Some(device_test) => device_test.get_factory_mac_address().await?,
90 _ => bail!("DeviceTest proxy is not set"),
91 };
92 Ok(factory_mac_address.octets)
93 }
94
95 pub async fn get_network_name(&self) -> Result<Vec<u8>, Error> {
97 let raw_name = match self.device_extra.read().as_ref() {
98 Some(device_extra) => device_extra.watch_identity().await?.raw_name,
99 _ => bail!("DeviceExtra proxy is not set"),
100 };
101 match raw_name {
102 Some(raw_name) => Ok(raw_name),
103 None => bail!("Network name is not specified!"),
104 }
105 }
106
107 pub async fn get_partition_id(&self) -> Result<u32, Error> {
109 let partition_id = match self.device_test.read().as_ref() {
110 Some(device_test) => device_test.get_partition_id().await?,
111 _ => bail!("DeviceTest proxy is not set"),
112 };
113 Ok(partition_id)
114 }
115
116 pub async fn get_thread_router_id(&self) -> Result<u8, Error> {
118 let router_id = match self.device_test.read().as_ref() {
119 Some(device_test) => device_test.get_thread_router_id().await?,
120 _ => bail!("DeviceTest proxy is not set"),
121 };
122 Ok(router_id)
123 }
124
125 pub async fn get_ncp_device_state(&self) -> Result<DeviceStateDto, Error> {
127 let device_state = match self.device.read().as_ref() {
128 Some(device) => device.watch_device_state().await?,
129 _ => bail!("DeviceTest proxy is not set"),
130 };
131 Ok(device_state.into())
132 }
133
134 pub async fn get_ncp_state(&self) -> Result<ConnectivityState, Error> {
136 let device_state = match self.device.read().as_ref() {
137 Some(device) => device.watch_device_state().await?.connectivity_state,
138 _ => bail!("DeviceTest proxy is not set"),
139 };
140 match device_state {
141 Some(connectivity_state) => Ok(connectivity_state.into()),
142 None => bail!("Device state is not defined!"),
143 }
144 }
145
146 pub async fn get_is_commissioned(&self) -> Result<bool, Error> {
148 let ncp_state = self.get_ncp_state().await?;
149 let is_commissioned = match ncp_state {
150 ConnectivityState::Attached
151 | ConnectivityState::Attaching
152 | ConnectivityState::Isolated
153 | ConnectivityState::Ready => true,
154 _ => false,
155 };
156 Ok(is_commissioned)
157 }
158
159 pub async fn get_panid(&self) -> Result<u16, Error> {
161 match self.device_extra.read().as_ref() {
162 Some(device_extra) => match device_extra.watch_identity().await?.panid {
163 Some(panid) => Ok(panid),
164 None => bail!("Pan id is not specified!"),
165 },
166 _ => bail!("DeviceExtra proxy is not set"),
167 }
168 }
169
170 pub async fn get_mac_address_filter_settings(
172 &self,
173 ) -> Result<MacAddressFilterSettingsDto, Error> {
174 let settings = match self.device_test.read().as_ref() {
175 Some(device_test) => device_test.get_mac_address_filter_settings().await?,
176 _ => bail!("DeviceTest proxy is not set!"),
177 };
178 Ok(settings.into())
179 }
180
181 pub async fn replace_mac_address_filter_settings(
183 &self,
184 settings: MacAddressFilterSettingsDto,
185 ) -> Result<(), Error> {
186 match self.device_test.read().as_ref() {
187 Some(device_test) => {
188 device_test.replace_mac_address_filter_settings(&settings.into()).await?
189 }
190 None => bail!("DeviceTest proxy is not set!"),
191 }
192 Ok(())
193 }
194
195 pub async fn get_neighbor_table(&self) -> Result<Vec<NeighborInfoDto>, Error> {
197 let settings = match self.device_test.read().as_ref() {
198 Some(device_test) => device_test.get_neighbor_table().await?,
199 _ => bail!("DeviceTest proxy is not set!"),
200 };
201 Ok(settings.into_iter().map(|setting| setting.into()).collect())
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use crate::wpan::types::{MacAddressFilterItemDto, MacAddressFilterModeDto};
209 use fidl::endpoints::ProtocolMarker;
210 use fidl_fuchsia_lowpan_device::{DeviceExtraMarker, DeviceMarker};
211 use fidl_fuchsia_lowpan_test::DeviceTestMarker;
212 use fuchsia_async as fasync;
213 use futures::prelude::*;
214 use lowpan_driver_common::{DummyDevice, ServeTo};
215 use std::sync::LazyLock;
216
217 static MOCK_TESTER: LazyLock<MockTester> = LazyLock::new(|| MockTester::new());
218
219 struct MockTester {
220 dummy_device: DummyDevice,
221 }
222 impl MockTester {
223 fn new() -> Self {
224 Self { dummy_device: DummyDevice::default() }
225 }
226
227 fn create_endpoints<T: ProtocolMarker>() -> (RwLock<Option<T::Proxy>>, T::RequestStream) {
228 let (client_ep, server_ep) = fidl::endpoints::create_endpoints::<T>();
229 (RwLock::new(Some(client_ep.into_proxy())), server_ep.into_stream())
230 }
231
232 pub fn create_facade_and_serve(
233 &'static self,
234 ) -> (
235 WpanFacade,
236 (
237 impl Future<Output = anyhow::Result<()>>,
238 impl Future<Output = anyhow::Result<()>>,
239 impl Future<Output = anyhow::Result<()>>,
240 ),
241 ) {
242 let (device_proxy, device_server) = MockTester::create_endpoints::<DeviceMarker>();
243 let (device_test_proxy, device_test_server) =
244 MockTester::create_endpoints::<DeviceTestMarker>();
245 let (device_extra_proxy, device_extra_server) =
246 MockTester::create_endpoints::<DeviceExtraMarker>();
247
248 let facade = WpanFacade {
249 device: device_proxy,
250 device_test: device_test_proxy,
251 device_extra: device_extra_proxy,
252 };
253
254 (
255 facade,
256 (
257 self.dummy_device.serve_to(device_server),
258 self.dummy_device.serve_to(device_test_server),
259 self.dummy_device.serve_to(device_extra_server),
260 ),
261 )
262 }
263
264 pub async fn assert_wpan_fn<TResult>(
265 func: impl Future<Output = Result<TResult, Error>>,
266 server_future: (
267 impl Future<Output = anyhow::Result<()>>,
268 impl Future<Output = anyhow::Result<()>>,
269 impl Future<Output = anyhow::Result<()>>,
270 ),
271 ) {
272 let facade_fut = async move {
273 let awaiting = func.await;
274 awaiting.expect("No value returned!");
275 };
276 futures::select! {
277 err = server_future.0.fuse() => panic!("Server task stopped: {:?}", err),
278 err = server_future.1.fuse() => panic!("Server task stopped: {:?}", err),
279 err = server_future.2.fuse() => panic!("Server task stopped: {:?}", err),
280 _ = facade_fut.fuse() => (),
281 }
282 }
283 }
284
285 #[fasync::run_singlethreaded(test)]
286 async fn test_get_thread_rloc16() {
287 let facade = MOCK_TESTER.create_facade_and_serve();
288 MockTester::assert_wpan_fn(facade.0.get_thread_rloc16(), facade.1).await;
289 }
290
291 #[fasync::run_singlethreaded(test)]
292 async fn test_get_ncp_channel() {
293 let facade = MOCK_TESTER.create_facade_and_serve();
294 MockTester::assert_wpan_fn(facade.0.get_ncp_channel(), facade.1).await;
295 }
296
297 #[fasync::run_singlethreaded(test)]
298 async fn test_get_ncp_mac_address() {
299 let facade = MOCK_TESTER.create_facade_and_serve();
300 MockTester::assert_wpan_fn(facade.0.get_ncp_mac_address(), facade.1).await;
301 }
302
303 #[fasync::run_singlethreaded(test)]
304 async fn test_get_ncp_rssi() {
305 let facade = MOCK_TESTER.create_facade_and_serve();
306 MockTester::assert_wpan_fn(facade.0.get_ncp_rssi(), facade.1).await;
307 }
308
309 #[fasync::run_singlethreaded(test)]
310 async fn test_get_weave_node_id() {
311 let facade = MOCK_TESTER.create_facade_and_serve();
312 MockTester::assert_wpan_fn(facade.0.get_weave_node_id(), facade.1).await;
313 }
314
315 #[fasync::run_singlethreaded(test)]
316 async fn test_get_network_name() {
317 let facade = MOCK_TESTER.create_facade_and_serve();
318 MockTester::assert_wpan_fn(facade.0.get_network_name(), facade.1).await;
319 }
320
321 #[fasync::run_singlethreaded(test)]
322 async fn test_get_partition_id() {
323 let facade = MOCK_TESTER.create_facade_and_serve();
324 MockTester::assert_wpan_fn(facade.0.get_partition_id(), facade.1).await;
325 }
326
327 #[fasync::run_singlethreaded(test)]
328 async fn test_get_thread_router_id() {
329 let facade = MOCK_TESTER.create_facade_and_serve();
330 MockTester::assert_wpan_fn(facade.0.get_thread_router_id(), facade.1).await;
331 }
332
333 #[fasync::run_singlethreaded(test)]
334 async fn test_get_ncp_device_state() {
335 let facade = MOCK_TESTER.create_facade_and_serve();
336 MockTester::assert_wpan_fn(facade.0.get_ncp_device_state(), facade.1).await;
337 }
338
339 #[fasync::run_singlethreaded(test)]
340 async fn test_get_ncp_state() {
341 let facade = MOCK_TESTER.create_facade_and_serve();
342 MockTester::assert_wpan_fn(facade.0.get_ncp_state(), facade.1).await;
343 }
344
345 #[fasync::run_singlethreaded(test)]
346 async fn test_get_is_commissioned() {
347 let facade = MOCK_TESTER.create_facade_and_serve();
348 MockTester::assert_wpan_fn(facade.0.get_is_commissioned(), facade.1).await;
349 }
350
351 #[fasync::run_singlethreaded(test)]
352 async fn test_get_panid() {
353 let facade = MOCK_TESTER.create_facade_and_serve();
354 MockTester::assert_wpan_fn(facade.0.get_panid(), facade.1).await;
355 }
356
357 #[fasync::run_singlethreaded(test)]
358 async fn test_get_mac_address_filter_settings() {
359 let facade = MOCK_TESTER.create_facade_and_serve();
360 MockTester::assert_wpan_fn(facade.0.get_mac_address_filter_settings(), facade.1).await;
361 }
362
363 #[fasync::run_singlethreaded(test)]
364 async fn test_replace_mac_address_filter_settings() {
365 let facade = MOCK_TESTER.create_facade_and_serve();
366 MockTester::assert_wpan_fn(
367 facade.0.replace_mac_address_filter_settings(MacAddressFilterSettingsDto {
368 mode: Some(MacAddressFilterModeDto::Allow),
369 items: Some(vec![MacAddressFilterItemDto {
370 mac_address: Some([0, 1, 2, 3, 4, 5, 6, 7]),
371 rssi: None,
372 }]),
373 }),
374 facade.1,
375 )
376 .await;
377 }
378
379 #[fasync::run_singlethreaded(test)]
380 async fn test_get_neigbor_table() {
381 let facade = MOCK_TESTER.create_facade_and_serve();
382 MockTester::assert_wpan_fn(facade.0.get_neighbor_table(), facade.1).await;
383 }
384}