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