1use core::future::Future;
2use core::marker::PhantomData;
3use core::pin::pin;
4
5use embassy_futures::select::{select, select3, select4};
6
7use rs_matter::crypto::{Crypto, RngCore};
8use rs_matter::dm::clusters::gen_comm::CommPolicy;
9use rs_matter::dm::clusters::gen_diag::GenDiag;
10use rs_matter::dm::clusters::gen_diag::NetifDiag;
11use rs_matter::dm::clusters::net_comm::{NetCtl, NetCtlStatus, NetworkType};
12use rs_matter::dm::clusters::sw_diag::SwDiag;
13use rs_matter::dm::clusters::wifi_diag::WifiDiag;
14use rs_matter::dm::endpoints::{wifi_sys_handler, WifiSysHandler, ROOT_ENDPOINT_ID};
15use rs_matter::dm::networks::wireless::{self, NetCtlWithStatusImpl, NoopWirelessNetCtl};
16use rs_matter::dm::networks::NetChangeNotif;
17use rs_matter::dm::{ChainedHandler, DataModel, Endpoint, EpClMatcher};
18use rs_matter::error::Error;
19use rs_matter::persist::KvBlobStoreAccess;
20use rs_matter::root_endpoint;
21use rs_matter::transport::network::NoNetwork;
22use rs_matter::utils::select::Coalesce;
23
24use crate::mdns::Mdns;
25use crate::nal::NetStack;
26use crate::network::Embedding;
27use crate::wireless::{GattPeripheral, MatterStackWirelessTask, WirelessNetCtl};
28use crate::{pin_alloc, UserTask};
29
30use super::{Gatt, GattTask, PreexistingWireless, WirelessMatterStack};
31
32pub type WifiMatterStack<'a, const B: usize, E = ()> =
34 WirelessMatterStack<'a, B, wireless::Wifi, E>;
35
36impl<const B: usize, E> WirelessMatterStack<'_, B, wireless::Wifi, E>
37where
38 E: Embedding,
39{
40 #[allow(clippy::too_many_arguments)]
53 pub async fn run_preex<'t, U, N, Q, D, G, C, H, K, X>(
54 &'t self,
55 net_stack: U,
56 netif: N,
57 net_ctl: Q,
58 mdns: D,
59 gatt: G,
60 crypto: C,
61 handler: H,
62 kv: K,
63 user: X,
64 ) -> impl Future<Output = Result<(), Error>> + 't
65 where
66 U: NetStack + 't,
67 N: NetifDiag + NetChangeNotif + 't,
68 Q: NetCtl + WifiDiag + NetChangeNotif + 't,
69 D: Mdns + 't,
70 G: GattPeripheral + 't,
71 C: Crypto + 't,
72 H: DataModel + 't,
73 K: KvBlobStoreAccess + 't,
74 X: UserTask + 't,
75 {
76 self.run_coex(
77 PreexistingWireless::new(net_stack, netif, net_ctl, mdns, gatt),
78 crypto,
79 handler,
80 kv,
81 user,
82 )
83 }
84
85 pub async fn run_coex<W, C, H, K, U>(
94 &self,
95 mut wifi: W,
96 crypto: C,
97 handler: H,
98 kv: K,
99 user: U,
100 ) -> Result<(), Error>
101 where
102 W: WifiCoex,
103 C: Crypto,
104 H: DataModel,
105 K: KvBlobStoreAccess,
106 U: UserTask,
107 {
108 let _lock = self.run_lock.lock().await;
109
110 info!("Matter Stack memory: {}b", core::mem::size_of_val(self));
111
112 let _defer = scopeguard::guard((), |_| unsafe {
115 self.bump.reset();
116 });
117
118 self.matter().reset_transport()?;
119
120 let net_task = pin_alloc!(
121 self.bump,
122 self.run_wifi_coex(&mut wifi, crypto, handler, kv, user)
123 );
124
125 net_task.await
126 }
127
128 pub async fn run<W, C, H, K, U>(
137 &self,
138 wifi: W,
139 crypto: C,
140 handler: H,
141 kv: K,
142 user: U,
143 ) -> Result<(), Error>
144 where
145 W: Wifi + Gatt,
146 C: Crypto,
147 H: DataModel,
148 K: KvBlobStoreAccess,
149 U: UserTask,
150 {
151 let _lock = self.run_lock.lock().await;
152
153 info!("Matter Stack memory: {}b", core::mem::size_of_val(self));
154
155 let _defer = scopeguard::guard((), |_| unsafe {
158 self.bump.reset();
159 });
160
161 self.matter().reset_transport()?;
162
163 let net_task = pin_alloc!(self.bump, self.run_wifi(wifi, crypto, handler, kv, user));
164
165 net_task.await
166 }
167
168 async fn run_wifi_coex<W, C, H, K, U>(
169 &self,
170 wifi: &mut W,
171 crypto: C,
172 handler: H,
173 kv: K,
174 user: U,
175 ) -> Result<(), Error>
176 where
177 W: WifiCoex,
178 C: Crypto,
179 H: DataModel,
180 K: KvBlobStoreAccess,
181 U: UserTask,
182 {
183 wifi.run(
187 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, NoopWirelessNetCtl> {
188 stack: self,
189 crypto,
190 handler,
191 kv,
192 user_task: user,
193 _net_ctl: PhantomData,
194 },
195 )
196 .await
197 }
198
199 async fn run_wifi<W, C, H, K, U>(
200 &self,
201 mut wifi: W,
202 crypto: C,
203 handler: H,
204 kv: K,
205 mut user: U,
206 ) -> Result<(), Error>
207 where
208 W: Wifi + Gatt,
209 C: Crypto,
210 H: DataModel,
211 K: KvBlobStoreAccess,
212 U: UserTask,
213 {
214 loop {
215 if self
221 .matter()
222 .comm_window_state()
223 .is_open_on_all_transports()
224 {
225 self.reset_net_ctl_state();
226
227 Gatt::run(
228 &mut wifi,
229 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, <W as Wifi>::NetCtl<'_>> {
230 stack: self,
231 crypto: &crypto,
232 handler: &handler,
233 kv: &kv,
234 user_task: &mut user,
235 _net_ctl: PhantomData,
236 },
237 )
238 .await?;
239 }
240
241 Wifi::run(
242 &mut wifi,
243 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, <W as Wifi>::NetCtl<'_>> {
244 stack: self,
245 crypto: &crypto,
246 handler: &handler,
247 kv: &kv,
248 user_task: &mut user,
249 _net_ctl: PhantomData,
250 },
251 )
252 .await?;
253 }
254 }
255
256 pub const fn root_endpoint() -> Endpoint<'static> {
259 const ENDPOINT: Endpoint<'static> = root_endpoint!(wifi);
260
261 ENDPOINT
262 }
263
264 #[allow(clippy::too_many_arguments)]
267 fn root_handler<'a, C>(
268 &'a self,
269 comm_policy: &'a dyn CommPolicy,
270 gen_diag: &'a dyn GenDiag,
271 netif_diag: &'a dyn NetifDiag,
272 net_ctl: &'a C,
273 sw_diag: &'a dyn SwDiag,
274 rand: impl RngCore + Copy,
275 ) -> WifiSysHandler<'a, &'a C>
276 where
277 C: NetCtl + NetCtlStatus + WifiDiag,
278 {
279 wifi_sys_handler(
280 comm_policy,
281 gen_diag,
282 netif_diag,
283 net_ctl,
284 sw_diag,
285 net_ctl,
286 rand,
287 )
288 }
289}
290
291pub trait WifiTask {
294 async fn run<S, N, C, M>(
296 &mut self,
297 net_stack: S,
298 netif: N,
299 net_ctl: C,
300 mdns: M,
301 ) -> Result<(), Error>
302 where
303 S: NetStack,
304 N: NetifDiag + NetChangeNotif,
305 C: NetCtl + WifiDiag + NetChangeNotif,
306 M: Mdns;
307}
308
309impl<T> WifiTask for &mut T
310where
311 T: WifiTask,
312{
313 fn run<S, N, C, M>(
314 &mut self,
315 net_stack: S,
316 netif: N,
317 net_ctl: C,
318 mdns: M,
319 ) -> impl Future<Output = Result<(), Error>>
320 where
321 S: NetStack,
322 N: NetifDiag + NetChangeNotif,
323 C: NetCtl + WifiDiag + NetChangeNotif,
324 M: Mdns,
325 {
326 T::run(*self, net_stack, netif, net_ctl, mdns)
327 }
328}
329
330pub trait Wifi {
332 type NetCtl<'a>: NetCtl + WifiDiag + NetChangeNotif
338 where
339 Self: 'a;
340
341 async fn run<T>(&mut self, task: T) -> Result<(), Error>
344 where
345 T: WifiTask;
346}
347
348impl<T> Wifi for &mut T
349where
350 T: Wifi,
351{
352 type NetCtl<'a>
353 = T::NetCtl<'a>
354 where
355 Self: 'a;
356
357 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
358 where
359 A: WifiTask,
360 {
361 T::run(self, task)
362 }
363}
364
365pub trait WifiCoexTask {
370 async fn run<S, N, C, M, G>(
372 &mut self,
373 net_stack: S,
374 netif: N,
375 net_ctl: C,
376 mdns: M,
377 gatt: G,
378 ) -> Result<(), Error>
379 where
380 S: NetStack,
381 N: NetifDiag + NetChangeNotif,
382 C: NetCtl + WifiDiag + NetChangeNotif,
383 M: Mdns,
384 G: GattPeripheral;
385}
386
387impl<T> WifiCoexTask for &mut T
388where
389 T: WifiCoexTask,
390{
391 fn run<S, N, C, M, G>(
392 &mut self,
393 net_stack: S,
394 netif: N,
395 net_ctl: C,
396 mdns: M,
397 gatt: G,
398 ) -> impl Future<Output = Result<(), Error>>
399 where
400 S: NetStack,
401 N: NetifDiag + NetChangeNotif,
402 C: NetCtl + WifiDiag + NetChangeNotif,
403 M: Mdns,
404 G: GattPeripheral,
405 {
406 T::run(*self, net_stack, netif, net_ctl, mdns, gatt)
407 }
408}
409
410pub trait WifiCoex {
416 async fn run<T>(&mut self, task: T) -> Result<(), Error>
419 where
420 T: WifiCoexTask;
421}
422
423impl<T> WifiCoex for &mut T
424where
425 T: WifiCoex,
426{
427 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
428 where
429 A: WifiCoexTask,
430 {
431 T::run(self, task)
432 }
433}
434
435impl<S, N, C, M, P> Wifi for PreexistingWireless<S, N, C, M, P>
436where
437 S: NetStack,
438 N: NetifDiag + NetChangeNotif,
439 C: NetCtl + WifiDiag + NetChangeNotif,
440 M: Mdns,
441{
442 type NetCtl<'a>
445 = &'a C
446 where
447 Self: 'a;
448
449 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
450 where
451 T: WifiTask,
452 {
453 task.run(&self.net_stack, &self.netif, &self.net_ctl, &mut self.mdns)
454 .await
455 }
456}
457
458impl<S, N, C, M, P> WifiCoex for PreexistingWireless<S, N, C, M, P>
459where
460 S: NetStack,
461 N: NetifDiag + NetChangeNotif,
462 C: NetCtl + WifiDiag + NetChangeNotif,
463 M: Mdns,
464 P: GattPeripheral,
465{
466 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
467 where
468 T: WifiCoexTask,
469 {
470 task.run(
471 &self.net_stack,
472 &self.netif,
473 &self.net_ctl,
474 &mut self.mdns,
475 &mut self.gatt,
476 )
477 .await
478 }
479}
480
481impl<'a, const B: usize, E, C, H, K, U, Q> GattTask
482 for MatterStackWirelessTask<'a, B, wireless::Wifi, E, C, H, K, U, Q>
483where
484 E: Embedding,
485 C: Crypto,
486 H: DataModel,
487 K: KvBlobStoreAccess,
488 Q: NetCtl + WifiDiag + NetChangeNotif,
489{
490 async fn run<P>(&mut self, peripheral: P) -> Result<(), Error>
491 where
492 P: GattPeripheral,
493 {
494 let net_ctl = NetCtlWithStatusImpl::new(
495 &self.stack.network.net_state,
496 WirelessNetCtl::<Q>::Commissioning(NetworkType::Wifi),
497 );
498
499 let sys =
500 self.stack
501 .root_handler(&false, &(), &(), &net_ctl, &(), self.crypto.weak_rand()?);
502 let combined = ChainedHandler::new(
503 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
504 sys,
505 &self.handler,
506 );
507 let im = self
511 .stack
512 .im(&self.crypto, (&self.handler, combined), &self.kv, &net_ctl);
513
514 let mut btp_task = pin!(self.stack.run_btp(&self.crypto, peripheral));
515
516 let mut im_task = pin!(self.stack.run_im(&im));
517
518 select(&mut btp_task, &mut im_task).coalesce().await
519 }
520}
521
522impl<'a, const B: usize, E, C, H, K, X, Z> WifiTask
523 for MatterStackWirelessTask<'a, B, wireless::Wifi, E, C, H, K, X, Z>
524where
525 E: Embedding,
526 C: Crypto,
527 H: DataModel,
528 K: KvBlobStoreAccess,
529 X: UserTask,
530 Z: NetCtl + WifiDiag + NetChangeNotif,
531{
532 async fn run<T, N, Q, D>(
533 &mut self,
534 net_stack: T,
535 netif: N,
536 net_ctl: Q,
537 mut mdns: D,
538 ) -> Result<(), Error>
539 where
540 T: NetStack,
541 N: NetifDiag + NetChangeNotif,
542 Q: NetCtl + WifiDiag + NetChangeNotif,
543 D: Mdns,
544 {
545 info!("Wifi driver started");
546
547 let net_ctl_s = NetCtlWithStatusImpl::new(
548 &self.stack.network.net_state,
549 WirelessNetCtl::Operational(&net_ctl),
550 );
551
552 let sys = self.stack.root_handler(
553 &false,
554 &(),
555 &netif,
556 &net_ctl_s,
557 &(),
558 self.crypto.weak_rand()?,
559 );
560 let combined = ChainedHandler::new(
561 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
562 sys,
563 &self.handler,
564 );
565 let im = self.stack.im(
568 &self.crypto,
569 (&self.handler, combined),
570 &self.kv,
571 &net_ctl_s,
572 );
573
574 let stack = &self.stack;
575
576 let mut net_task = pin!(stack.run_oper_net(
577 &self.crypto,
578 &net_stack,
579 0, core::future::pending(),
581 Option::<(NoNetwork, NoNetwork)>::None
582 ));
583
584 let mut mdns_task =
585 pin!(stack.run_oper_netif_mdns(&self.crypto, &net_stack, &netif, &mut mdns));
586
587 let deferred_connect_id = self.stack.network.net_state.lock(|state| {
595 let state = state.borrow();
596 state.is_prov_ready().then(|| state.network_id.clone())
597 });
598
599 if let Some(network_id) = deferred_connect_id {
600 info!("Non-concurrent commissioning: performing the deferred connect");
601
602 im.connect_once(&network_id).await?;
605 }
606
607 let mut im_task = pin!(self.stack.run_im(&im));
608
609 let mut user_task = pin!(self.user_task.run(&net_stack, &netif));
610
611 let mut oper_task =
612 pin!(select4(&mut net_task, &mut mdns_task, &mut im_task, &mut user_task).coalesce());
613
614 let mut comm_window_task = pin!(async {
620 self.stack.wait_next_comm_window().await;
621
622 info!("Commissioning window opened; handing the radio back to BLE");
623
624 Ok(())
625 });
626
627 select(&mut oper_task, &mut comm_window_task)
628 .coalesce()
629 .await
630 }
631}
632
633impl<'a, const B: usize, E, C, H, K, X, Z> WifiCoexTask
634 for MatterStackWirelessTask<'a, B, wireless::Wifi, E, C, H, K, X, Z>
635where
636 E: Embedding,
637 C: Crypto,
638 H: DataModel,
639 K: KvBlobStoreAccess,
640 X: UserTask,
641 Z: NetCtl + WifiDiag + NetChangeNotif,
642{
643 async fn run<T, N, Q, D, G>(
644 &mut self,
645 net_stack: T,
646 netif: N,
647 net_ctl: Q,
648 mut mdns: D,
649 mut gatt: G,
650 ) -> Result<(), Error>
651 where
652 T: NetStack,
653 N: NetifDiag + NetChangeNotif,
654 Q: NetCtl + WifiDiag + NetChangeNotif,
655 D: Mdns,
656 G: GattPeripheral,
657 {
658 info!("Wifi and BLE drivers started");
659
660 let net_ctl_s = NetCtlWithStatusImpl::new(
661 &self.stack.network.net_state,
662 WirelessNetCtl::Operational(&net_ctl),
663 );
664
665 let sys = self.stack.root_handler(
666 &true,
667 &(),
668 &netif,
669 &net_ctl_s,
670 &(),
671 self.crypto.weak_rand()?,
672 );
673 let combined = ChainedHandler::new(
674 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
675 sys,
676 &self.handler,
677 );
678 let im = self.stack.im(
682 &self.crypto,
683 (&self.handler, combined),
684 &self.kv,
685 &net_ctl_s,
686 );
687
688 let stack = &self.stack;
689 let bump = &stack.bump;
690
691 let mut net_task = pin_alloc!(
692 bump,
693 stack.run_net_coex(&self.crypto, &net_stack, &netif, &mut mdns, &mut gatt)
694 );
695
696 let mut im_task = pin_alloc!(bump, self.stack.run_im_with_bump(&im));
697
698 let mut user_task = pin_alloc!(bump, self.user_task.run(&net_stack, &netif));
699
700 select3(&mut net_task, &mut im_task, &mut user_task)
701 .coalesce()
702 .await
703 }
704}