Skip to main content

flash/
flash.rs

1#![allow(missing_docs)]
2//! Flash storage example demonstrating type-safe persistent storage.
3//!
4//! This example demonstrates:
5//! - Storing and loading different data types (String and struct) in separate blocks
6//! - Type safety: attempting to read the wrong type returns None
7//! - Clearing flash blocks
8
9#![no_std]
10#![no_main]
11
12use defmt::info;
13use defmt_rtt as _;
14use embassy_executor::Spawner;
15use heapless::String;
16use panic_probe as _;
17use serde::{Deserialize, Serialize};
18
19use device_envoy::Result;
20use device_envoy::flash_array::FlashArray;
21
22// ============================================================================
23// Test Data Structures
24// ============================================================================
25
26/// A simple struct to demonstrate storing custom types in flash
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28struct SensorConfig {
29    name: String<32>,
30    sample_rate_hz: u32,
31    enabled: bool,
32}
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) -> ! {
36    let err = inner_main(_spawner).await.unwrap_err();
37    panic!("Example failed: {:?}", err);
38}
39
40async fn inner_main(_spawner: Spawner) -> Result<()> {
41    info!("Flash Storage Example");
42
43    // Initialize hardware
44    let p = embassy_rp::init(Default::default());
45
46    // Initialize Flash device
47    let [_, _, _, mut string_block, mut config_block] = FlashArray::<5>::new(p.FLASH)?;
48
49    info!("Part 1: Storing data to flash");
50    string_block.save(&String::<64>::try_from("Hello, Flash Storage!")?)?;
51    config_block.save(&SensorConfig {
52        name: String::<32>::try_from("Temperature")?,
53        sample_rate_hz: 1000,
54        enabled: true,
55    })?;
56
57    info!("Part 2: Reading data from flash");
58    let string: Option<String<64>> = string_block.load()?;
59    assert!(string.as_deref() == Some("Hello, Flash Storage!"));
60    let config: Option<SensorConfig> = config_block.load()?;
61    assert!(
62        config
63            == Some(SensorConfig {
64                name: String::<32>::try_from("Temperature")?,
65                sample_rate_hz: 1000,
66                enabled: true,
67            })
68    );
69
70    info!("Part 3: Reading a different type counts as empty");
71    // Try to read the string block as a SensorConfig
72    let wrong_type_result: Option<SensorConfig> = string_block.load()?;
73    assert!(wrong_type_result.is_none());
74
75    info!("Part 4: Clearing flash blocks");
76    string_block.clear()?;
77    config_block.clear()?;
78
79    info!("Part 5: Verifying cleared blocks");
80    let string: Option<String<64>> = string_block.load()?;
81    assert!(string.is_none());
82    let config: Option<SensorConfig> = config_block.load()?;
83    assert!(config.is_none());
84
85    info!("Flash Storage Example Complete!");
86    loop {
87        embassy_time::Timer::after_secs(1).await;
88    }
89}