1- //! An example utilizing the `EmbassyWifiMatterStack` struct.
1+ //! An example utilizing the `EmbassyWifiMatterStack` struct
2+ //! and additionally persisting the `rs-matter` state to the NOR Flash.
23//!
34//! As the name suggests, this Matter stack assembly uses Wifi as the main transport,
45//! and thus BLE for commissioning.
@@ -20,17 +21,19 @@ use core::pin::pin;
2021use embassy_embedded_hal:: adapter:: BlockingAsync ;
2122use embassy_executor:: Spawner ;
2223
24+ use embassy_futures:: select:: { select, Either } ;
2325use esp_alloc:: heap_allocator;
2426use esp_backtrace as _;
2527use esp_bootloader_esp_idf:: partitions:: {
2628 read_partition_table, DataPartitionSubType , PartitionType , PARTITION_TABLE_MAX_LEN ,
2729} ;
30+ use esp_hal:: gpio:: { Input , InputConfig , Pull } ;
2831use esp_hal:: ram;
2932use esp_hal:: timer:: timg:: TimerGroup ;
3033use esp_metadata_generated:: memory_range;
31-
3234use esp_storage:: FlashStorage ;
33- use log:: info;
35+
36+ use log:: { info, warn} ;
3437
3538use rs_matter_embassy:: epoch:: epoch;
3639use rs_matter_embassy:: matter:: crypto:: { default_crypto, Crypto } ;
@@ -42,8 +45,10 @@ use rs_matter_embassy::matter::dm::devices::test::{
4245} ;
4346use rs_matter_embassy:: matter:: dm:: devices:: DEV_TYPE_ON_OFF_LIGHT ;
4447use rs_matter_embassy:: matter:: dm:: { Async , Dataver , EmptyHandler , Endpoint , EpClMatcher , Node } ;
48+ use rs_matter_embassy:: matter:: error:: Error ;
4549use rs_matter_embassy:: matter:: persist:: KvBlobStore ;
4650use rs_matter_embassy:: matter:: utils:: init:: InitMaybeUninit ;
51+ use rs_matter_embassy:: matter:: utils:: select:: Coalesce ;
4752use rs_matter_embassy:: matter:: { clusters, devices} ;
4853use rs_matter_embassy:: persist:: SeqMapKvBlobStore ;
4954use rs_matter_embassy:: stack:: rand:: reseeding_csprng;
@@ -86,6 +91,8 @@ const HEAP_SIZE: usize = 140 * 1024;
8691const RECLAIMED_RAM : usize =
8792 memory_range ! ( "DRAM2_UNINIT" ) . end - memory_range ! ( "DRAM2_UNINIT" ) . start ;
8893
94+ const RESET_SECS : u64 = 3 ;
95+
8996esp_bootloader_esp_idf:: esp_app_desc!( ) ;
9097
9198#[ esp_rtos:: main]
@@ -154,33 +161,60 @@ async fn main(_s: Spawner) {
154161 let mut kv = get_persistent_store ( peripherals. FLASH , stack. kv_store_buf ( ) . unwrap ( ) ) ;
155162 stack. startup ( & crypto, & mut kv) . await . unwrap ( ) ;
156163
157- // Wrap the KV BLOB store as a shared reference, so that it can be used both by `rs-matter` and the user
158- let kv = stack. create_shared_kv ( kv) . unwrap ( ) ;
159-
160- // Run the Matter stack with our handler
161- // Using `pin!` is completely optional, but reduces the size of the final future
162- //
163- // This step can be repeated in that the stack can be stopped and started multiple times, as needed.
164- let matter = pin ! ( stack. run_coex(
165- // The Matter stack needs to instantiate an `embassy-net` `Driver` and `Controller`
166- EmbassyWifi :: new(
167- EspWifiDriver :: new( peripherals. WIFI , peripherals. BT ) ,
168- weak_rand,
169- true , // Use a random BLE address
170- stack,
171- ) ,
172- // The crypto provider
173- & crypto,
174- // Our `AsyncHandler` + `AsyncMetadata` impl
175- ( NODE , handler) ,
176- // The Matter stack needs a blob store to store its state
177- & kv,
178- // No user future to run
179- ( ) ,
180- ) ) ;
181-
182- // Run Matter
183- matter. await . unwrap ( ) ;
164+ if stack. is_commissioned ( ) {
165+ info ! (
166+ "To reset, press and hold the Boot Mode pin (GPIO9) for {} or more seconds" ,
167+ RESET_SECS
168+ ) ;
169+ }
170+
171+ {
172+ // Wrap the KV BLOB store as a shared reference, so that it can be used both by `rs-matter` and the user
173+ let kv = stack. create_shared_kv ( & mut kv) . unwrap ( ) ;
174+
175+ // Run the Matter stack with our handler
176+ // Using `pin!` is completely optional, but reduces the size of the final future
177+ //
178+ // This step can be repeated in that the stack can be stopped and started multiple times, as needed.
179+ let mut matter = pin ! ( stack. run_coex(
180+ // The Matter stack needs to instantiate an `embassy-net` `Driver` and `Controller`
181+ EmbassyWifi :: new(
182+ EspWifiDriver :: new( peripherals. WIFI , peripherals. BT ) ,
183+ weak_rand,
184+ true , // Use a random BLE address
185+ stack,
186+ ) ,
187+ // The crypto provider
188+ & crypto,
189+ // Our `AsyncHandler` + `AsyncMetadata` impl
190+ ( NODE , handler) ,
191+ // The Matter stack needs a blob store to store its state
192+ & kv,
193+ // No user future to run
194+ ( ) ,
195+ ) ) ;
196+
197+ // Run Matter and also wait for a reset signal
198+ let mut wait_reset = pin ! ( wait_pin_low( Input :: new(
199+ peripherals. GPIO9 ,
200+ InputConfig :: default ( ) . with_pull( Pull :: Down )
201+ ) ) ) ;
202+
203+ select ( & mut matter, & mut wait_reset)
204+ . coalesce ( )
205+ . await
206+ . unwrap ( ) ;
207+ }
208+
209+ // If we get here, with no errors, this means the user is willing to reset the storage
210+ // by holding the BOOT pin low 3 or more seconds
211+ warn ! ( "Resetting storage" ) ;
212+
213+ stack. reset ( kv) . await . unwrap ( ) ;
214+
215+ warn ! ( "Rebooting..." ) ;
216+
217+ esp_hal:: system:: software_reset ( )
184218}
185219
186220/// Endpoint 0 (the root endpoint) always runs
@@ -230,3 +264,31 @@ fn get_persistent_store<'d>(
230264
231265 SeqMapKvBlobStore :: new ( BlockingAsync :: new ( flash) , start..end)
232266}
267+
268+ async fn wait_pin_low ( mut pin : Input < ' _ > ) -> Result < ( ) , Error > {
269+ loop {
270+ pin. wait_for_low ( ) . await ;
271+
272+ // Debounce
273+ embassy_time:: Timer :: after_millis ( 50 ) . await ;
274+
275+ if pin. is_low ( ) {
276+ warn ! (
277+ "Detected Boot Mode pin low, keep it low for {} more seconds to reset the storage" ,
278+ RESET_SECS
279+ ) ;
280+
281+ let result = select (
282+ pin. wait_for_high ( ) ,
283+ embassy_time:: Timer :: after_secs ( RESET_SECS ) ,
284+ )
285+ . await ;
286+
287+ if matches ! ( result, Either :: Second ( ( ) ) ) {
288+ break ;
289+ }
290+ }
291+ }
292+
293+ Ok ( ( ) )
294+ }
0 commit comments