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 lazy_static::lazy_static;
215 use lowpan_driver_common::{DummyDevice, ServeTo};
216
217 lazy_static! {
218 static ref MOCK_TESTER: MockTester = MockTester::new();
219 }
220
221 struct MockTester {
222 dummy_device: DummyDevice,
223 }
224 impl MockTester {
225 fn new() -> Self {
226 Self { dummy_device: DummyDevice::default() }
227 }
228
229 fn create_endpoints<T: ProtocolMarker>() -> (RwLock<Option<T::Proxy>>, T::RequestStream) {
230 let (client_ep, server_ep) = fidl::endpoints::create_endpoints::<T>();
231 (RwLock::new(Some(client_ep.into_proxy())), server_ep.into_stream())
232 }
233
234 pub fn create_facade_and_serve(
235 &'static self,
236 ) -> (
237 WpanFacade,
238 (
239 impl Future<Output = anyhow::Result<()>>,
240 impl Future<Output = anyhow::Result<()>>,
241 impl Future<Output = anyhow::Result<()>>,
242 ),
243 ) {
244 let (device_proxy, device_server) = MockTester::create_endpoints::<DeviceMarker>();
245 let (device_test_proxy, device_test_server) =
246 MockTester::create_endpoints::<DeviceTestMarker>();
247 let (device_extra_proxy, device_extra_server) =
248 MockTester::create_endpoints::<DeviceExtraMarker>();
249
250 let facade = WpanFacade {
251 device: device_proxy,
252 device_test: device_test_proxy,
253 device_extra: device_extra_proxy,
254 };
255
256 (
257 facade,
258 (
259 self.dummy_device.serve_to(device_server),
260 self.dummy_device.serve_to(device_test_server),
261 self.dummy_device.serve_to(device_extra_server),
262 ),
263 )
264 }
265
266 pub async fn assert_wpan_fn<TResult>(
267 func: impl Future<Output = Result<TResult, Error>>,
268 server_future: (
269 impl Future<Output = anyhow::Result<()>>,
270 impl Future<Output = anyhow::Result<()>>,
271 impl Future<Output = anyhow::Result<()>>,
272 ),
273 ) {
274 let facade_fut = async move {
275 let awaiting = func.await;
276 awaiting.expect("No value returned!");
277 };
278 futures::select! {
279 err = server_future.0.fuse() => panic!("Server task stopped: {:?}", err),
280 err = server_future.1.fuse() => panic!("Server task stopped: {:?}", err),
281 err = server_future.2.fuse() => panic!("Server task stopped: {:?}", err),
282 _ = facade_fut.fuse() => (),
283 }
284 }
285 }
286
287 #[fasync::run_singlethreaded(test)]
288 async fn test_get_thread_rloc16() {
289 let facade = MOCK_TESTER.create_facade_and_serve();
290 MockTester::assert_wpan_fn(facade.0.get_thread_rloc16(), facade.1).await;
291 }
292
293 #[fasync::run_singlethreaded(test)]
294 async fn test_get_ncp_channel() {
295 let facade = MOCK_TESTER.create_facade_and_serve();
296 MockTester::assert_wpan_fn(facade.0.get_ncp_channel(), facade.1).await;
297 }
298
299 #[fasync::run_singlethreaded(test)]
300 async fn test_get_ncp_mac_address() {
301 let facade = MOCK_TESTER.create_facade_and_serve();
302 MockTester::assert_wpan_fn(facade.0.get_ncp_mac_address(), facade.1).await;
303 }
304
305 #[fasync::run_singlethreaded(test)]
306 async fn test_get_ncp_rssi() {
307 let facade = MOCK_TESTER.create_facade_and_serve();
308 MockTester::assert_wpan_fn(facade.0.get_ncp_rssi(), facade.1).await;
309 }
310
311 #[fasync::run_singlethreaded(test)]
312 async fn test_get_weave_node_id() {
313 let facade = MOCK_TESTER.create_facade_and_serve();
314 MockTester::assert_wpan_fn(facade.0.get_weave_node_id(), facade.1).await;
315 }
316
317 #[fasync::run_singlethreaded(test)]
318 async fn test_get_network_name() {
319 let facade = MOCK_TESTER.create_facade_and_serve();
320 MockTester::assert_wpan_fn(facade.0.get_network_name(), facade.1).await;
321 }
322
323 #[fasync::run_singlethreaded(test)]
324 async fn test_get_partition_id() {
325 let facade = MOCK_TESTER.create_facade_and_serve();
326 MockTester::assert_wpan_fn(facade.0.get_partition_id(), facade.1).await;
327 }
328
329 #[fasync::run_singlethreaded(test)]
330 async fn test_get_thread_router_id() {
331 let facade = MOCK_TESTER.create_facade_and_serve();
332 MockTester::assert_wpan_fn(facade.0.get_thread_router_id(), facade.1).await;
333 }
334
335 #[fasync::run_singlethreaded(test)]
336 async fn test_get_ncp_device_state() {
337 let facade = MOCK_TESTER.create_facade_and_serve();
338 MockTester::assert_wpan_fn(facade.0.get_ncp_device_state(), facade.1).await;
339 }
340
341 #[fasync::run_singlethreaded(test)]
342 async fn test_get_ncp_state() {
343 let facade = MOCK_TESTER.create_facade_and_serve();
344 MockTester::assert_wpan_fn(facade.0.get_ncp_state(), facade.1).await;
345 }
346
347 #[fasync::run_singlethreaded(test)]
348 async fn test_get_is_commissioned() {
349 let facade = MOCK_TESTER.create_facade_and_serve();
350 MockTester::assert_wpan_fn(facade.0.get_is_commissioned(), facade.1).await;
351 }
352
353 #[fasync::run_singlethreaded(test)]
354 async fn test_get_panid() {
355 let facade = MOCK_TESTER.create_facade_and_serve();
356 MockTester::assert_wpan_fn(facade.0.get_panid(), facade.1).await;
357 }
358
359 #[fasync::run_singlethreaded(test)]
360 async fn test_get_mac_address_filter_settings() {
361 let facade = MOCK_TESTER.create_facade_and_serve();
362 MockTester::assert_wpan_fn(facade.0.get_mac_address_filter_settings(), facade.1).await;
363 }
364
365 #[fasync::run_singlethreaded(test)]
366 async fn test_replace_mac_address_filter_settings() {
367 let facade = MOCK_TESTER.create_facade_and_serve();
368 MockTester::assert_wpan_fn(
369 facade.0.replace_mac_address_filter_settings(MacAddressFilterSettingsDto {
370 mode: Some(MacAddressFilterModeDto::Allow),
371 items: Some(vec![MacAddressFilterItemDto {
372 mac_address: Some([0, 1, 2, 3, 4, 5, 6, 7]),
373 rssi: None,
374 }]),
375 }),
376 facade.1,
377 )
378 .await;
379 }
380
381 #[fasync::run_singlethreaded(test)]
382 async fn test_get_neigbor_table() {
383 let facade = MOCK_TESTER.create_facade_and_serve();
384 MockTester::assert_wpan_fn(facade.0.get_neighbor_table(), facade.1).await;
385 }
386}