1use core::future::Future;
2
3use embassy_futures::select::select4;
4
5use rs_matter::crypto::{Crypto, RngCore};
6use rs_matter::dm::clusters::gen_comm::CommPolicy;
7use rs_matter::dm::clusters::gen_diag::{GenDiag, NetifDiag};
8use rs_matter::dm::clusters::net_comm::{DummyNetworks, NetworkType};
9use rs_matter::dm::clusters::sw_diag::SwDiag;
10use rs_matter::dm::clusters::time_sync::TimeSync;
11use rs_matter::dm::endpoints::{eth_sys_handler, EthSysHandler, ROOT_ENDPOINT_ID};
12use rs_matter::dm::networks::wireless::NoopWirelessNetCtl;
13use rs_matter::dm::networks::NetChangeNotif;
14use rs_matter::dm::{ChainedHandler, DataModel, Endpoint, EpClMatcher};
15use rs_matter::error::Error;
16use rs_matter::pairing::DiscoveryCapabilities;
17use rs_matter::persist::{KvBlobStore, KvBlobStoreAccess};
18use rs_matter::root_endpoint;
19use rs_matter::transport::network::NoNetwork;
20use rs_matter::utils::init::{init, init_from_closure, Init};
21use rs_matter::utils::select::Coalesce;
22
23use crate::mdns::Mdns;
24use crate::nal::NetStack;
25use crate::network::{Embedding, Network};
26use crate::private::Sealed;
27use crate::{pin_alloc, DummyAttrNotifier, MatterStack, UserTask};
28
29pub struct Eth<E = ()> {
40 embedding: E,
41}
42
43impl<E> Sealed for Eth<E> {}
44
45impl<E> Network for Eth<E>
46where
47 E: Embedding,
48{
49 const INIT: Self = Self { embedding: E::INIT };
50
51 type Embedding<'a>
52 = E
53 where
54 E: 'a;
55
56 type Networks = DummyNetworks;
58
59 const NETWORKS: Self::Networks = DummyNetworks;
60
61 fn init() -> impl Init<Self> {
62 init!(Self {
63 embedding <- E::init(),
64 })
65 }
66
67 fn init_networks() -> impl Init<Self::Networks> {
68 unsafe {
69 init_from_closure(|slot: *mut DummyNetworks| {
70 slot.write(DummyNetworks);
71 Ok(())
72 })
73 }
74 }
75
76 fn discovery_capabilities(&self) -> DiscoveryCapabilities {
77 DiscoveryCapabilities::IP
78 }
79
80 fn embedding(&self) -> &Self::Embedding<'_> {
81 &self.embedding
82 }
83}
84
85pub type EthMatterStack<'a, const B: usize, E = ()> = MatterStack<'a, B, Eth<E>>;
87
88pub trait EthernetTask {
91 async fn run<S, N, M>(&mut self, net_stack: S, netif: N, mdns: M) -> Result<(), Error>
93 where
94 S: NetStack,
95 N: NetifDiag + NetChangeNotif,
96 M: Mdns;
97}
98
99impl<T> EthernetTask for &mut T
100where
101 T: EthernetTask,
102{
103 fn run<S, N, M>(
104 &mut self,
105 net_stack: S,
106 netif: N,
107 mdns: M,
108 ) -> impl Future<Output = Result<(), Error>>
109 where
110 S: NetStack,
111 N: NetifDiag + NetChangeNotif,
112 M: Mdns,
113 {
114 (*self).run(net_stack, netif, mdns)
115 }
116}
117
118pub trait Ethernet {
120 async fn run<T>(&mut self, task: T) -> Result<(), Error>
122 where
123 T: EthernetTask;
124}
125
126impl<T> Ethernet for &mut T
127where
128 T: Ethernet,
129{
130 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
131 where
132 A: EthernetTask,
133 {
134 (*self).run(task)
135 }
136}
137
138pub struct PreexistingEthernet<S, N, M> {
141 stack: S,
142 netif: N,
143 mdns: M,
144}
145
146impl<S, N, M> PreexistingEthernet<S, N, M> {
147 pub const fn new(stack: S, netif: N, mdns: M) -> Self {
149 Self { stack, netif, mdns }
150 }
151}
152
153impl<S, N, M> Ethernet for PreexistingEthernet<S, N, M>
154where
155 S: NetStack,
156 N: NetifDiag + NetChangeNotif,
157 M: Mdns,
158{
159 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
160 where
161 T: EthernetTask,
162 {
163 task.run(&self.stack, &self.netif, &mut self.mdns).await
164 }
165}
166
167impl<const B: usize, E> MatterStack<'_, B, Eth<E>>
169where
170 E: Embedding,
171{
172 pub const fn root_endpoint() -> Endpoint<'static> {
175 const ENDPOINT: Endpoint<'static> = root_endpoint!(eth);
176
177 ENDPOINT
178 }
179
180 fn root_handler<'a>(
183 &self,
184 comm_policy: &'a dyn CommPolicy,
185 gen_diag: &'a dyn GenDiag,
186 netif_diag: &'a dyn NetifDiag,
187 time_sync: &'a dyn TimeSync,
188 sw_diag: &'a dyn SwDiag,
189 rand: impl RngCore + Copy,
190 ) -> EthSysHandler<'a> {
191 eth_sys_handler(comm_policy, gen_diag, netif_diag, time_sync, sw_diag, rand)
192 }
193
194 pub async fn reset<S>(&mut self, store: S) -> Result<(), Error>
196 where
197 S: KvBlobStore,
198 {
199 let kv = self.matter.kv(store);
200
201 self.matter.reset_persist(&kv).await?;
202
203 self.state.reset_persist(&kv).await?;
207
208 Ok(())
209 }
210
211 pub async fn load<S>(&mut self, store: S) -> Result<(), Error>
213 where
214 S: KvBlobStore,
215 {
216 let kv = self.matter.kv(store);
217
218 self.matter.load_persist(&kv).await?;
219
220 self.state.load_persist(&kv).await?;
224
225 Ok(())
226 }
227
228 pub async fn startup<C, S>(&mut self, crypto: C, store: S) -> Result<(), Error>
231 where
232 C: Crypto,
233 S: KvBlobStore,
234 {
235 self.load(store).await?;
236
237 if !self.is_commissioned() {
238 info!("Device is not commissioned yet, opening commissioning window...");
239
240 self.open_basic_comm_window(crypto, &DummyAttrNotifier)?;
241 } else {
242 info!("Device is already commissioned");
243 }
244
245 Ok(())
246 }
247
248 #[allow(clippy::too_many_arguments)]
259 pub fn run_preex<'t, U, N, M, C, H, K, X>(
260 &'t self,
261 net_stack: U,
262 netif: N,
263 mdns: M,
264 crypto: C,
265 handler: H,
266 kv: K,
267 user: X,
268 ) -> impl Future<Output = Result<(), Error>> + 't
269 where
270 U: NetStack + 't,
271 N: NetifDiag + NetChangeNotif + 't,
272 M: Mdns + 't,
273 C: Crypto + 't,
274 H: DataModel + 't,
275 K: KvBlobStoreAccess + 't,
276 X: UserTask + 't,
277 {
278 self.run(
279 PreexistingEthernet::new(net_stack, netif, mdns),
280 crypto,
281 handler,
282 kv,
283 user,
284 )
285 }
286
287 pub async fn run<N, C, H, K, X>(
296 &self,
297 mut ethernet: N,
298 crypto: C,
299 handler: H,
300 kv: K,
301 user: X,
302 ) -> Result<(), Error>
303 where
304 N: Ethernet,
305 C: Crypto,
306 H: DataModel,
307 K: KvBlobStoreAccess,
308 X: UserTask,
309 {
310 let _lock = self.run_lock.lock().await;
311
312 info!("Matter Stack memory: {}b", core::mem::size_of_val(self));
313
314 let _defer = scopeguard::guard((), |_| unsafe {
317 self.bump.reset();
318 });
319
320 self.matter().reset_transport()?;
321
322 let net_task = pin_alloc!(
323 self.bump,
324 self.run_ethernet(&mut ethernet, crypto, handler, &kv, user)
325 );
326
327 net_task.await
328 }
329
330 fn run_ethernet<'t, N, C, H, K, X>(
331 &'t self,
332 ethernet: &'t mut N,
333 crypto: C,
334 handler: H,
335 kv: K,
336 user: X,
337 ) -> impl Future<Output = Result<(), Error>> + 't
338 where
339 N: Ethernet + 't,
340 C: Crypto + 't,
341 H: DataModel + 't,
342 K: KvBlobStoreAccess + 't,
343 X: UserTask + 't,
344 {
345 Ethernet::run(
346 ethernet,
347 MatterStackEthernetTask {
348 stack: self,
349 crypto,
350 handler,
351 kv,
352 user_task: user,
353 },
354 )
355 }
356}
357
358struct MatterStackEthernetTask<'a, const B: usize, E, C, H, K, X>
359where
360 E: Embedding,
361 C: Crypto,
362 H: DataModel,
363 K: KvBlobStoreAccess,
364 X: UserTask,
365{
366 stack: &'a MatterStack<'a, B, Eth<E>>,
367 crypto: C,
368 handler: H,
369 kv: K,
370 user_task: X,
371}
372
373impl<const B: usize, E, C, H, K, X> EthernetTask for MatterStackEthernetTask<'_, B, E, C, H, K, X>
374where
375 E: Embedding,
376 C: Crypto,
377 H: DataModel,
378 K: KvBlobStoreAccess,
379 X: UserTask,
380{
381 async fn run<N, I, M>(&mut self, net_stack: N, netif: I, mut mdns: M) -> Result<(), Error>
382 where
383 N: NetStack,
384 I: NetifDiag + NetChangeNotif,
385 M: Mdns,
386 {
387 info!("Ethernet driver started");
388
389 let sys = self
395 .stack
396 .root_handler(&false, &(), &netif, &(), &(), self.crypto.weak_rand()?);
397 let combined = ChainedHandler::new(
398 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
399 sys,
400 &self.handler,
401 );
402 let im = self.stack.im(
405 &self.crypto,
406 (&self.handler, combined),
407 &self.kv,
408 NoopWirelessNetCtl::new(NetworkType::Ethernet),
409 );
410
411 let mut net_task = pin_alloc!(
412 self.stack.bump,
413 self.stack.run_oper_net(
414 &self.crypto,
415 &net_stack,
416 0, core::future::pending(),
418 Option::<(NoNetwork, NoNetwork)>::None,
419 )
420 );
421
422 let mut mdns_task = pin_alloc!(
423 self.stack.bump,
424 self.stack
425 .run_oper_netif_mdns(&self.crypto, &net_stack, &netif, &mut mdns)
426 );
427
428 let mut im_task = pin_alloc!(self.stack.bump, self.stack.run_im_with_bump(&im));
429
430 let mut user_task = pin_alloc!(self.stack.bump, self.user_task.run(&net_stack, &netif));
431
432 select4(&mut net_task, &mut mdns_task, &mut im_task, &mut user_task)
433 .coalesce()
434 .await
435 }
436}