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