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::thread_diag::ThreadDiag;
14use rs_matter::dm::clusters::time_sync::TimeSync;
15use rs_matter::dm::endpoints::{thread_sys_handler, ThreadSysHandler, 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, GattTask, MatterStackWirelessTask, WirelessNetCtl};
29use crate::{pin_alloc, UserTask};
30
31use super::{Gatt, PreexistingWireless, WirelessMatterStack};
32
33pub type ThreadMatterStack<'a, const B: usize, E = ()> =
35 WirelessMatterStack<'a, B, wireless::Thread, E>;
36
37impl<const B: usize, E> WirelessMatterStack<'_, B, wireless::Thread, E>
38where
39 E: Embedding,
40{
41 #[allow(clippy::too_many_arguments)]
54 pub 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 + ThreadDiag + 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 thread: W,
97 crypto: C,
98 handler: H,
99 kv: K,
100 user: U,
101 ) -> Result<(), Error>
102 where
103 W: ThreadCoex,
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_thread_coex(&mut thread, 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 thread: W,
140 crypto: C,
141 handler: H,
142 kv: K,
143 user: U,
144 ) -> Result<(), Error>
145 where
146 W: Thread + Gatt,
147 K: KvBlobStoreAccess,
148 C: Crypto,
149 H: DataModel,
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!(
165 self.bump,
166 self.run_thread(thread, crypto, handler, kv, user)
167 );
168
169 net_task.await
170 }
171
172 async fn run_thread_coex<W, C, H, K, U>(
173 &self,
174 thread: &mut W,
175 crypto: C,
176 handler: H,
177 kv: K,
178 user: U,
179 ) -> Result<(), Error>
180 where
181 W: ThreadCoex,
182 C: Crypto,
183 H: DataModel,
184 K: KvBlobStoreAccess,
185 U: UserTask,
186 {
187 thread
191 .run(
192 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, NoopWirelessNetCtl> {
193 stack: self,
194 crypto,
195 handler,
196 kv: &kv,
197 user_task: user,
198 _net_ctl: PhantomData,
199 },
200 )
201 .await
202 }
203
204 async fn run_thread<W, C, H, K, U>(
205 &self,
206 mut thread: W,
207 crypto: C,
208 handler: H,
209 kv: K,
210 mut user: U,
211 ) -> Result<(), Error>
212 where
213 W: Thread + Gatt,
214 C: Crypto,
215 H: DataModel,
216 K: KvBlobStoreAccess,
217 U: UserTask,
218 {
219 loop {
220 let commissioned = self.is_commissioned();
221
222 if !commissioned {
223 Gatt::run(
224 &mut thread,
225 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, <W as Thread>::NetCtl<'_>> {
226 stack: self,
227 crypto: &crypto,
228 handler: &handler,
229 kv: &kv,
230 user_task: &mut user,
231 _net_ctl: PhantomData,
232 },
233 )
234 .await?;
235 }
236
237 if commissioned {
238 let net_ctl = NetCtlWithStatusImpl::new(
239 &self.network.net_state,
240 WirelessNetCtl::<<W as Thread>::NetCtl<'_>>::Commissioning(NetworkType::Thread),
241 );
242
243 let sys =
244 self.root_handler(&false, &(), &(), &net_ctl, &(), &(), crypto.weak_rand()?);
245 let combined = ChainedHandler::new(
246 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
247 sys,
248 &handler,
249 );
250 let im = self.im(&crypto, (&handler, combined), &kv, &net_ctl);
251
252 im.close_comm_window()?;
253 }
254
255 Thread::run(
256 &mut thread,
257 MatterStackWirelessTask::<'_, _, _, _, _, _, _, _, <W as Thread>::NetCtl<'_>> {
258 stack: self,
259 crypto: &crypto,
260 handler: &handler,
261 kv: &kv,
262 user_task: &mut user,
263 _net_ctl: PhantomData,
264 },
265 )
266 .await?;
267 }
268 }
269
270 pub const fn root_endpoint() -> Endpoint<'static> {
273 const ENDPOINT: Endpoint<'static> = root_endpoint!(thread);
274
275 ENDPOINT
276 }
277
278 #[allow(clippy::too_many_arguments)]
281 fn root_handler<'a, N>(
282 &'a self,
283 comm_policy: &'a dyn CommPolicy,
284 gen_diag: &'a dyn GenDiag,
285 netif_diag: &'a dyn NetifDiag,
286 net_ctl: &'a N,
287 time_sync: &'a dyn TimeSync,
288 sw_diag: &'a dyn SwDiag,
289 rand: impl RngCore + Copy,
290 ) -> ThreadSysHandler<'a, &'a N>
291 where
292 N: NetCtl + NetCtlStatus + ThreadDiag,
293 {
294 thread_sys_handler(
295 comm_policy,
296 gen_diag,
297 netif_diag,
298 net_ctl,
299 time_sync,
300 sw_diag,
301 net_ctl,
302 rand,
303 )
304 }
305}
306
307pub trait ThreadTask {
310 async fn run<S, N, C, M>(
312 &mut self,
313 net_stack: S,
314 netif: N,
315 net_ctl: C,
316 mdns: M,
317 ) -> Result<(), Error>
318 where
319 S: NetStack,
320 N: NetifDiag + NetChangeNotif,
321 C: NetCtl + ThreadDiag + NetChangeNotif,
322 M: Mdns;
323}
324
325impl<T> ThreadTask for &mut T
326where
327 T: ThreadTask,
328{
329 fn run<S, N, C, M>(
330 &mut self,
331 net_stack: S,
332 netif: N,
333 net_ctl: C,
334 mdns: M,
335 ) -> impl Future<Output = Result<(), Error>>
336 where
337 S: NetStack,
338 N: NetifDiag + NetChangeNotif,
339 C: NetCtl + ThreadDiag + NetChangeNotif,
340 M: Mdns,
341 {
342 T::run(*self, net_stack, netif, net_ctl, mdns)
343 }
344}
345
346pub trait Thread {
348 type NetCtl<'a>: NetCtl + ThreadDiag + NetChangeNotif
354 where
355 Self: 'a;
356
357 async fn run<T>(&mut self, task: T) -> Result<(), Error>
360 where
361 T: ThreadTask;
362}
363
364impl<T> Thread for &mut T
365where
366 T: Thread,
367{
368 type NetCtl<'a>
369 = T::NetCtl<'a>
370 where
371 Self: 'a;
372
373 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
374 where
375 A: ThreadTask,
376 {
377 T::run(self, task)
378 }
379}
380
381pub trait ThreadCoexTask {
386 async fn run<S, N, C, M, G>(
388 &mut self,
389 net_stack: S,
390 netif: N,
391 net_task: C,
392 mdns: M,
393 gatt: G,
394 ) -> Result<(), Error>
395 where
396 S: NetStack,
397 N: NetifDiag + NetChangeNotif,
398 C: NetCtl + ThreadDiag + NetChangeNotif,
399 M: Mdns,
400 G: GattPeripheral;
401}
402
403impl<T> ThreadCoexTask for &mut T
404where
405 T: ThreadCoexTask,
406{
407 fn run<S, N, C, M, G>(
408 &mut self,
409 net_stack: S,
410 netif: N,
411 net_ctl: C,
412 mdns: M,
413 gatt: G,
414 ) -> impl Future<Output = Result<(), Error>>
415 where
416 S: NetStack,
417 N: NetifDiag + NetChangeNotif,
418 C: NetCtl + ThreadDiag + NetChangeNotif,
419 M: Mdns,
420 G: GattPeripheral,
421 {
422 T::run(*self, net_stack, netif, net_ctl, mdns, gatt)
423 }
424}
425
426pub trait ThreadCoex {
432 async fn run<T>(&mut self, task: T) -> Result<(), Error>
435 where
436 T: ThreadCoexTask;
437}
438
439impl<T> ThreadCoex for &mut T
440where
441 T: ThreadCoex,
442{
443 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
444 where
445 A: ThreadCoexTask,
446 {
447 T::run(self, task)
448 }
449}
450
451impl<S, N, C, M, P> Thread for PreexistingWireless<S, N, C, M, P>
452where
453 S: NetStack,
454 N: NetifDiag + NetChangeNotif,
455 C: NetCtl + ThreadDiag + NetChangeNotif,
456 M: Mdns,
457{
458 type NetCtl<'a>
461 = &'a C
462 where
463 Self: 'a;
464
465 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
466 where
467 T: ThreadTask,
468 {
469 task.run(&self.net_stack, &self.netif, &self.net_ctl, &mut self.mdns)
470 .await
471 }
472}
473
474impl<S, N, C, M, P> ThreadCoex for PreexistingWireless<S, N, C, M, P>
475where
476 S: NetStack,
477 N: NetifDiag + NetChangeNotif,
478 C: NetCtl + ThreadDiag + NetChangeNotif,
479 M: Mdns,
480 P: GattPeripheral,
481{
482 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
483 where
484 T: ThreadCoexTask,
485 {
486 task.run(
487 &self.net_stack,
488 &self.netif,
489 &self.net_ctl,
490 &mut self.mdns,
491 &mut self.gatt,
492 )
493 .await
494 }
495}
496
497impl<'a, const B: usize, E, C, H, K, X, Q> GattTask
498 for MatterStackWirelessTask<'a, B, wireless::Thread, E, C, H, K, X, Q>
499where
500 E: Embedding,
501 C: Crypto,
502 H: DataModel,
503 K: KvBlobStoreAccess,
504 Q: NetCtl + ThreadDiag + NetChangeNotif,
505{
506 async fn run<P>(&mut self, peripheral: P) -> Result<(), Error>
507 where
508 P: GattPeripheral,
509 {
510 let net_ctl = NetCtlWithStatusImpl::new(
511 &self.stack.network.net_state,
512 WirelessNetCtl::<Q>::Commissioning(NetworkType::Thread),
513 );
514
515 let sys = self.stack.root_handler(
516 &false,
517 &(),
518 &(),
519 &net_ctl,
520 &(),
521 &(),
522 self.crypto.weak_rand()?,
523 );
524 let combined = ChainedHandler::new(
525 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
526 sys,
527 &self.handler,
528 );
529 let im = self
533 .stack
534 .im(&self.crypto, (&self.handler, combined), &self.kv, &net_ctl);
535
536 let mut btp_task = pin!(self.stack.run_btp(&self.crypto, peripheral));
537
538 let mut im_task = pin!(self.stack.run_im(&im));
539
540 select(&mut btp_task, &mut im_task).coalesce().await
541 }
542}
543
544impl<'a, const B: usize, E, C, H, K, X, Z> ThreadTask
545 for MatterStackWirelessTask<'a, B, wireless::Thread, E, C, H, K, X, Z>
546where
547 E: Embedding,
548 C: Crypto,
549 H: DataModel,
550 K: KvBlobStoreAccess,
551 X: UserTask,
552 Z: NetCtl + ThreadDiag + NetChangeNotif,
553{
554 async fn run<T, N, Q, D>(
555 &mut self,
556 net_stack: T,
557 netif: N,
558 net_ctl: Q,
559 mut mdns: D,
560 ) -> Result<(), Error>
561 where
562 T: NetStack,
563 N: NetifDiag + NetChangeNotif,
564 Q: NetCtl + ThreadDiag + NetChangeNotif,
565 D: Mdns,
566 {
567 info!("Thread driver started");
568
569 let net_ctl_s = NetCtlWithStatusImpl::new(
570 &self.stack.network.net_state,
571 WirelessNetCtl::Operational(&net_ctl),
572 );
573
574 let sys = self.stack.root_handler(
575 &false,
576 &(),
577 &netif,
578 &net_ctl_s,
579 &(),
580 &(),
581 self.crypto.weak_rand()?,
582 );
583 let combined = ChainedHandler::new(
584 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
585 sys,
586 &self.handler,
587 );
588 let im = self.stack.im(
591 &self.crypto,
592 (&self.handler, combined),
593 &self.kv,
594 &net_ctl_s,
595 );
596
597 let stack = &self.stack;
598
599 let mut net_task = pin!(stack.run_oper_net(
600 &self.crypto,
601 &net_stack,
602 0, core::future::pending(),
604 Option::<(NoNetwork, NoNetwork)>::None
605 ));
606
607 let mut mdns_task =
608 pin!(stack.run_oper_netif_mdns(&self.crypto, &net_stack, &netif, &mut mdns));
609
610 let deferred_connect_id = self.stack.network.net_state.lock(|state| {
627 let state = state.borrow();
628 state.is_prov_ready().then(|| state.network_id.clone())
629 });
630
631 if let Some(network_id) = deferred_connect_id {
632 info!("Non-concurrent commissioning: performing the deferred connect");
633
634 im.connect_once(&network_id).await?;
637 }
638
639 let mut im_task = pin!(self.stack.run_im(&im));
640
641 let mut user_task = pin!(self.user_task.run(&net_stack, &netif));
642
643 select4(&mut net_task, &mut mdns_task, &mut im_task, &mut user_task)
644 .coalesce()
645 .await
646 }
647}
648
649impl<'a, const B: usize, E, C, H, K, X, Z> ThreadCoexTask
650 for MatterStackWirelessTask<'a, B, wireless::Thread, E, C, H, K, X, Z>
651where
652 E: Embedding,
653 C: Crypto,
654 H: DataModel,
655 K: KvBlobStoreAccess,
656 X: UserTask,
657 Z: NetCtl + ThreadDiag + NetChangeNotif,
658{
659 async fn run<T, N, Q, D, G>(
660 &mut self,
661 net_stack: T,
662 netif: N,
663 net_ctl: Q,
664 mut mdns: D,
665 mut gatt: G,
666 ) -> Result<(), Error>
667 where
668 T: NetStack,
669 N: NetifDiag + NetChangeNotif,
670 Q: NetCtl + ThreadDiag + NetChangeNotif,
671 D: Mdns,
672 G: GattPeripheral,
673 {
674 info!("Thread and BLE drivers started");
675
676 let net_ctl_s = NetCtlWithStatusImpl::new(
677 &self.stack.network.net_state,
678 WirelessNetCtl::Operational(&net_ctl),
679 );
680
681 let sys = self.stack.root_handler(
682 &true,
683 &(),
684 &netif,
685 &net_ctl_s,
686 &(),
687 &(),
688 self.crypto.weak_rand()?,
689 );
690 let combined = ChainedHandler::new(
691 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
692 sys,
693 &self.handler,
694 );
695 let im = self.stack.im(
699 &self.crypto,
700 (&self.handler, combined),
701 &self.kv,
702 &net_ctl_s,
703 );
704
705 let stack = &self.stack;
706 let bump = &stack.bump;
707
708 let mut net_task = pin_alloc!(
709 bump,
710 stack.run_net_coex(&self.crypto, &net_stack, &netif, &mut mdns, &mut gatt)
711 );
712
713 let mut im_task = pin_alloc!(bump, self.stack.run_im_with_bump(&im));
714
715 let mut user_task = pin_alloc!(bump, self.user_task.run(&net_stack, &netif));
716
717 select3(&mut net_task, &mut im_task, &mut user_task)
718 .coalesce()
719 .await
720 }
721}