1use core::marker::PhantomData;
2use core::pin::pin;
3
4use embassy_futures::select::select3;
5
6use rs_matter::crypto::Crypto;
7use rs_matter::dm::clusters::gen_diag::NetifDiag;
8use rs_matter::dm::clusters::net_comm::{self, NetCtlError, NetworkType, WirelessCreds};
9use rs_matter::dm::clusters::wifi_diag::WirelessDiag;
10use rs_matter::dm::clusters::{thread_diag, wifi_diag};
11use rs_matter::dm::networks::wireless::{NetCtlState, WirelessNetwork, WirelessNetworks};
12use rs_matter::dm::networks::NetChangeNotif;
13use rs_matter::error::Error;
14use rs_matter::pairing::DiscoveryCapabilities;
15use rs_matter::persist::KvBlobStore;
16use rs_matter::transport::network::btp::{AdvData, Btp};
17use rs_matter::transport::network::NoNetwork;
18use rs_matter::utils::cell::RefCell;
19use rs_matter::utils::init::{init, Init};
20use rs_matter::utils::select::Coalesce;
21use rs_matter::utils::sync::blocking;
22use rs_matter::utils::sync::DynBase;
23
24use crate::ble::GattPeripheral;
25use crate::mdns::Mdns;
26use crate::nal::NetStack;
27use crate::network::{Embedding, Network};
28use crate::private::Sealed;
29use crate::{pin_alloc, DummyAttrNotifier, MatterStack};
30
31pub use gatt::*;
32pub use thread::*;
33pub use wifi::*;
34
35mod gatt;
36mod thread;
37mod wifi;
38
39pub const MAX_WIRELESS_NETWORKS: usize = 2;
40
41pub type WirelessMatterStack<'a, const B: usize, T, E = ()> = MatterStack<'a, B, WirelessBle<T, E>>;
43
44pub struct WirelessBle<T, E = ()>
57where
58 T: WirelessNetwork,
59{
60 btp: Btp,
61 net_state: blocking::Mutex<RefCell<NetCtlState>>,
62 embedding: E,
63 _network: PhantomData<fn() -> T>,
67}
68
69impl<T, E> WirelessBle<T, E>
70where
71 T: WirelessNetwork,
72 E: Embedding,
73{
74 pub const fn new() -> Self {
76 Self {
77 btp: Btp::new(),
78 net_state: NetCtlState::new_with_mutex(),
79 embedding: E::INIT,
80 _network: PhantomData,
81 }
82 }
83
84 pub fn init() -> impl Init<Self> {
86 init!(Self {
87 btp <- Btp::init(),
88 net_state <- NetCtlState::init_with_mutex(),
89 embedding <- E::init(),
90 _network: PhantomData,
91 })
92 }
93}
94
95pub enum WirelessNetCtl<'a, Q> {
117 Commissioning(NetworkType),
119 Operational(&'a Q),
121}
122
123impl<Q> net_comm::NetCtl for WirelessNetCtl<'_, Q>
124where
125 Q: net_comm::NetCtl,
126{
127 fn net_type(&self) -> NetworkType {
128 match self {
129 Self::Commissioning(net_type) => *net_type,
130 Self::Operational(q) => q.net_type(),
131 }
132 }
133
134 fn connect_max_time_seconds(&self) -> u8 {
135 match self {
136 Self::Commissioning(_) => 0,
137 Self::Operational(q) => q.connect_max_time_seconds(),
138 }
139 }
140
141 fn scan_max_time_seconds(&self) -> u8 {
142 match self {
143 Self::Commissioning(_) => 0,
144 Self::Operational(q) => q.scan_max_time_seconds(),
145 }
146 }
147
148 fn supported_wifi_bands<F>(&self, f: F) -> Result<(), Error>
149 where
150 F: FnMut(net_comm::WiFiBandEnum) -> Result<(), Error>,
151 {
152 match self {
153 Self::Commissioning(_) => Ok(()),
154 Self::Operational(q) => q.supported_wifi_bands(f),
155 }
156 }
157
158 fn supported_thread_features(&self) -> net_comm::ThreadCapabilitiesBitmap {
159 match self {
160 Self::Commissioning(_) => net_comm::ThreadCapabilitiesBitmap::empty(),
161 Self::Operational(q) => q.supported_thread_features(),
162 }
163 }
164
165 fn thread_version(&self) -> u16 {
166 match self {
167 Self::Commissioning(_) => 0,
168 Self::Operational(q) => q.thread_version(),
169 }
170 }
171
172 async fn scan<F>(&self, network: Option<&[u8]>, f: F) -> Result<(), NetCtlError>
173 where
174 F: FnMut(&net_comm::NetworkScanInfo) -> Result<(), Error>,
175 {
176 match self {
177 Self::Commissioning(_) => Err(NetCtlError::Other(
179 rs_matter::error::ErrorCode::InvalidAction.into(),
180 )),
181 Self::Operational(q) => q.scan(network, f).await,
182 }
183 }
184
185 async fn connect(&self, creds: &WirelessCreds<'_>) -> Result<(), NetCtlError> {
186 match self {
187 Self::Commissioning(net_type) => Ok(creds.check_match(*net_type)?),
189 Self::Operational(q) => q.connect(creds).await,
190 }
191 }
192}
193
194impl<Q> NetChangeNotif for WirelessNetCtl<'_, Q>
195where
196 Q: NetChangeNotif,
197{
198 async fn wait_changed(&self) {
199 match self {
200 Self::Commissioning(_) => core::future::pending().await,
201 Self::Operational(q) => q.wait_changed().await,
202 }
203 }
204}
205
206#[cfg(feature = "sync-mutex")]
207impl<Q> DynBase for WirelessNetCtl<'_, Q> where Q: Send + Sync {}
208
209#[cfg(not(feature = "sync-mutex"))]
210impl<Q> DynBase for WirelessNetCtl<'_, Q> {}
211
212impl<Q> WirelessDiag for WirelessNetCtl<'_, Q>
213where
214 Q: WirelessDiag,
215{
216 fn connected(&self) -> Result<bool, Error> {
217 match self {
218 Self::Commissioning(_) => Ok(false),
219 Self::Operational(q) => q.connected(),
220 }
221 }
222}
223
224impl<Q> wifi_diag::WifiDiag for WirelessNetCtl<'_, Q>
231where
232 Q: wifi_diag::WifiDiag,
233{
234 fn bssid(&self, f: &mut dyn FnMut(Option<&[u8]>) -> Result<(), Error>) -> Result<(), Error> {
235 match self {
236 Self::Commissioning(_) => f(None),
237 Self::Operational(q) => q.bssid(f),
238 }
239 }
240
241 fn security_type(
242 &self,
243 ) -> Result<rs_matter::tlv::Nullable<wifi_diag::SecurityTypeEnum>, Error> {
244 match self {
245 Self::Commissioning(_) => Ok(rs_matter::tlv::Nullable::none()),
246 Self::Operational(q) => q.security_type(),
247 }
248 }
249
250 fn wi_fi_version(&self) -> Result<rs_matter::tlv::Nullable<wifi_diag::WiFiVersionEnum>, Error> {
251 match self {
252 Self::Commissioning(_) => Ok(rs_matter::tlv::Nullable::none()),
253 Self::Operational(q) => q.wi_fi_version(),
254 }
255 }
256
257 fn channel_number(&self) -> Result<rs_matter::tlv::Nullable<u16>, Error> {
258 match self {
259 Self::Commissioning(_) => Ok(rs_matter::tlv::Nullable::none()),
260 Self::Operational(q) => q.channel_number(),
261 }
262 }
263
264 fn rssi(&self) -> Result<rs_matter::tlv::Nullable<i8>, Error> {
265 match self {
266 Self::Commissioning(_) => Ok(rs_matter::tlv::Nullable::none()),
267 Self::Operational(q) => q.rssi(),
268 }
269 }
270}
271
272impl<Q> thread_diag::ThreadDiag for WirelessNetCtl<'_, Q>
273where
274 Q: thread_diag::ThreadDiag,
275{
276 fn channel(&self) -> Result<Option<u16>, Error> {
277 match self {
278 Self::Commissioning(_) => Ok(None),
279 Self::Operational(q) => q.channel(),
280 }
281 }
282 fn routing_role(&self) -> Result<Option<thread_diag::RoutingRoleEnum>, Error> {
283 match self {
284 Self::Commissioning(_) => Ok(None),
285 Self::Operational(q) => q.routing_role(),
286 }
287 }
288 fn network_name(
289 &self,
290 f: &mut dyn FnMut(Option<&str>) -> Result<(), Error>,
291 ) -> Result<(), Error> {
292 match self {
293 Self::Commissioning(_) => f(None),
294 Self::Operational(q) => q.network_name(f),
295 }
296 }
297 fn pan_id(&self) -> Result<Option<u16>, Error> {
298 match self {
299 Self::Commissioning(_) => Ok(None),
300 Self::Operational(q) => q.pan_id(),
301 }
302 }
303 fn extended_pan_id(&self) -> Result<Option<u64>, Error> {
304 match self {
305 Self::Commissioning(_) => Ok(None),
306 Self::Operational(q) => q.extended_pan_id(),
307 }
308 }
309 fn mesh_local_prefix(
310 &self,
311 f: &mut dyn FnMut(Option<&[u8]>) -> Result<(), Error>,
312 ) -> Result<(), Error> {
313 match self {
314 Self::Commissioning(_) => f(None),
315 Self::Operational(q) => q.mesh_local_prefix(f),
316 }
317 }
318 fn neighbor_table(
319 &self,
320 f: &mut dyn FnMut(&thread_diag::NeighborTable) -> Result<(), Error>,
321 ) -> Result<(), Error> {
322 match self {
323 Self::Commissioning(_) => Ok(()),
324 Self::Operational(q) => q.neighbor_table(f),
325 }
326 }
327 fn route_table(
328 &self,
329 f: &mut dyn FnMut(&thread_diag::RouteTable) -> Result<(), Error>,
330 ) -> Result<(), Error> {
331 match self {
332 Self::Commissioning(_) => Ok(()),
333 Self::Operational(q) => q.route_table(f),
334 }
335 }
336 fn partition_id(&self) -> Result<Option<u32>, Error> {
337 match self {
338 Self::Commissioning(_) => Ok(None),
339 Self::Operational(q) => q.partition_id(),
340 }
341 }
342 fn weighting(&self) -> Result<Option<u16>, Error> {
343 match self {
344 Self::Commissioning(_) => Ok(None),
345 Self::Operational(q) => q.weighting(),
346 }
347 }
348 fn data_version(&self) -> Result<Option<u16>, Error> {
349 match self {
350 Self::Commissioning(_) => Ok(None),
351 Self::Operational(q) => q.data_version(),
352 }
353 }
354 fn stable_data_version(&self) -> Result<Option<u16>, Error> {
355 match self {
356 Self::Commissioning(_) => Ok(None),
357 Self::Operational(q) => q.stable_data_version(),
358 }
359 }
360 fn leader_router_id(&self) -> Result<Option<u8>, Error> {
361 match self {
362 Self::Commissioning(_) => Ok(None),
363 Self::Operational(q) => q.leader_router_id(),
364 }
365 }
366 fn ext_address(&self) -> Result<Option<u64>, Error> {
367 match self {
368 Self::Commissioning(_) => Ok(None),
369 Self::Operational(q) => q.ext_address(),
370 }
371 }
372 fn rloc_16(&self) -> Result<Option<u16>, Error> {
373 match self {
374 Self::Commissioning(_) => Ok(None),
375 Self::Operational(q) => q.rloc_16(),
376 }
377 }
378 fn security_policy(&self) -> Result<Option<thread_diag::SecurityPolicy>, Error> {
379 match self {
380 Self::Commissioning(_) => Ok(None),
381 Self::Operational(q) => q.security_policy(),
382 }
383 }
384 fn channel_page0_mask(
385 &self,
386 f: &mut dyn FnMut(Option<&[u8]>) -> Result<(), Error>,
387 ) -> Result<(), Error> {
388 match self {
389 Self::Commissioning(_) => f(None),
390 Self::Operational(q) => q.channel_page0_mask(f),
391 }
392 }
393 fn operational_dataset_components(
394 &self,
395 f: &mut dyn FnMut(Option<&thread_diag::OperationalDatasetComponents>) -> Result<(), Error>,
396 ) -> Result<(), Error> {
397 match self {
398 Self::Commissioning(_) => f(None),
399 Self::Operational(q) => q.operational_dataset_components(f),
400 }
401 }
402 fn active_network_faults_list(
403 &self,
404 f: &mut dyn FnMut(thread_diag::NetworkFaultEnum) -> Result<(), Error>,
405 ) -> Result<(), Error> {
406 match self {
407 Self::Commissioning(_) => Ok(()),
408 Self::Operational(q) => q.active_network_faults_list(f),
409 }
410 }
411}
412
413impl<T, E> Default for WirelessBle<T, E>
414where
415 T: WirelessNetwork,
416 E: Embedding,
417{
418 fn default() -> Self {
419 Self::new()
420 }
421}
422
423impl<T, E> Sealed for WirelessBle<T, E>
424where
425 T: WirelessNetwork,
426 E: Embedding,
427{
428}
429
430impl<T, E> Network for WirelessBle<T, E>
431where
432 T: WirelessNetwork,
433 E: Embedding,
434{
435 const INIT: Self = Self::new();
436
437 type Embedding<'a>
438 = E
439 where
440 Self: 'a;
441
442 type Networks = WirelessNetworks<MAX_WIRELESS_NETWORKS, T>;
444
445 const NETWORKS: Self::Networks = WirelessNetworks::new();
446
447 fn init() -> impl Init<Self> {
448 WirelessBle::init()
449 }
450
451 fn init_networks() -> impl Init<Self::Networks> {
452 WirelessNetworks::init()
453 }
454
455 fn discovery_capabilities(&self) -> DiscoveryCapabilities {
456 DiscoveryCapabilities::BLE
457 }
458
459 fn embedding(&self) -> &Self::Embedding<'_> {
460 &self.embedding
461 }
462}
463
464impl<const B: usize, T, E> MatterStack<'_, B, WirelessBle<T, E>>
465where
466 T: WirelessNetwork,
467 E: Embedding,
468{
469 pub async fn reset<S>(&mut self, store: S) -> Result<(), Error>
471 where
472 S: KvBlobStore,
473 {
474 let kv = self.matter.kv(store);
475
476 self.matter.reset_persist(&kv).await?;
477
478 self.state.reset_persist(&kv).await?;
483
484 Ok(())
485 }
486
487 pub async fn load<S>(&mut self, store: S) -> Result<(), Error>
489 where
490 S: KvBlobStore,
491 {
492 let kv = self.matter.kv(store);
493
494 self.matter.load_persist(&kv).await?;
495
496 self.state.load_persist(&kv).await?;
500
501 Ok(())
502 }
503
504 pub async fn startup<C, S>(&mut self, crypto: C, kv: S) -> Result<(), Error>
507 where
508 C: Crypto,
509 S: KvBlobStore,
510 {
511 self.load(kv).await?;
512
513 if !self.is_commissioned() {
514 info!("Device is not commissioned yet, opening commissioning window...");
515
516 self.open_basic_comm_window(crypto, &DummyAttrNotifier)?;
517 } else {
518 info!("Device is already commissioned");
519 }
520
521 Ok(())
522 }
523
524 async fn run_net_coex<C, S, N, D, G>(
531 &self,
532 crypto: C,
533 net_stack: S,
534 netif: N,
535 mut mdns: D,
536 mut gatt: G,
537 ) -> Result<(), Error>
538 where
539 C: Crypto,
540 S: NetStack,
541 N: NetifDiag + NetChangeNotif,
542 D: Mdns,
543 G: GattPeripheral,
544 {
545 self.run_btp_coex(&crypto, &net_stack, &netif, &mut mdns, &mut gatt)
546 .await
547 }
548
549 async fn run_btp_coex<C, S, N, D, P>(
550 &self,
551 crypto: C,
552 net_stack: S,
553 netif: N,
554 mut mdns: D,
555 mut peripheral: P,
556 ) -> Result<(), Error>
557 where
558 C: Crypto,
559 S: NetStack,
560 N: NetifDiag + NetChangeNotif,
561 D: Mdns,
562 P: GattPeripheral,
563 {
564 info!("BLE driver started");
565
566 info!("Running in concurrent commissioning mode (BLE and Wireless)");
567
568 let adv_data = AdvData::new(
569 self.matter().dev_det(),
570 self.matter().dev_comm().discriminator,
571 );
572
573 let mut btp_task = pin_alloc!(
574 self.bump,
575 peripheral.run(&self.network.btp, "BT", &adv_data)
576 );
577
578 let mut net_task = pin_alloc!(
579 self.bump,
580 self.run_oper_net(
581 &crypto,
582 &net_stack,
583 0, core::future::pending(),
585 Some((&self.network.btp, &self.network.btp))
586 )
587 );
588
589 let mut mdns_task = pin_alloc!(
590 self.bump,
591 self.run_oper_netif_mdns(&crypto, &net_stack, &netif, &mut mdns)
592 );
593
594 select3(&mut btp_task, &mut net_task, &mut mdns_task)
595 .coalesce()
596 .await
597 }
598
599 async fn run_btp<C, P>(&self, crypto: C, mut peripheral: P) -> Result<(), Error>
600 where
601 C: Crypto,
602 P: GattPeripheral,
603 {
604 info!("BLE driver started");
605
606 info!("Running in non-concurrent commissioning mode (BLE only)");
607
608 let adv_data = AdvData::new(
609 self.matter().dev_det(),
610 self.matter().dev_comm().discriminator,
611 );
612
613 let mut btp_task = pin_alloc!(
614 self.bump,
615 peripheral.run(&self.network.btp, "BT", &adv_data)
616 );
617
618 let mut net_task =
619 pin!(self.run_transport_net(&crypto, &self.network.btp, &self.network.btp, NoNetwork));
620 let mut oper_net_act_task = pin!(async {
621 NetCtlState::wait_prov_ready(&self.network.net_state, &self.network.btp).await;
622
623 embassy_time::Timer::after(embassy_time::Duration::from_secs(2)).await;
628
629 Ok(())
630 });
631
632 select3(&mut btp_task, &mut net_task, &mut oper_net_act_task)
633 .coalesce()
634 .await
635 }
636}
637
638pub struct PreexistingWireless<S, N, C, M, G> {
644 pub(crate) net_stack: S,
645 pub(crate) netif: N,
646 pub(crate) net_ctl: C,
647 pub(crate) mdns: M,
648 pub(crate) gatt: G,
649}
650
651impl<S, N, C, M, G> PreexistingWireless<S, N, C, M, G> {
652 pub const fn new(net_stack: S, netif: N, net_ctl: C, mdns: M, gatt: G) -> Self {
655 Self {
656 net_stack,
657 netif,
658 net_ctl,
659 mdns,
660 gatt,
661 }
662 }
663}
664
665pub(crate) struct MatterStackWirelessTask<'a, const B: usize, T, E, C, H, K, U, Q>
666where
667 T: WirelessNetwork,
668 E: Embedding,
669{
670 stack: &'a MatterStack<'a, B, WirelessBle<T, E>>,
671 crypto: C,
672 handler: H,
673 kv: K,
674 user_task: U,
675 _net_ctl: PhantomData<fn() -> Q>,
676}