device-envoy-rp 0.1.0

Build Pico applications with LED panels, easy Wi-Fi, and composable device abstractions
Documentation
#![allow(missing_docs)]
//! Flash storage example demonstrating type-safe persistent storage.
//!
//! This example demonstrates:
//! - Storing and loading different data types (String and struct) in separate blocks
//! - Type safety: attempting to read the wrong type returns None
//! - Clearing flash blocks

#![no_std]
#![no_main]

use defmt::info;
use defmt_rtt as _;
use embassy_executor::Spawner;
use heapless::String;
use panic_probe as _;
use serde::{Deserialize, Serialize};

use device_envoy_rp::flash_block::{FlashBlock as _, FlashBlockRp};
use device_envoy_rp::{Error, Result};

// ============================================================================
// Test Data Structures
// ============================================================================

/// A simple struct to demonstrate storing custom types in flash
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct SensorConfig {
    name: String<32>,
    sample_rate_hz: u32,
    enabled: bool,
}

#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
    let err = inner_main(_spawner).await.unwrap_err();
    panic!("Example failed: {:?}", err);
}

async fn inner_main(_spawner: Spawner) -> Result<()> {
    info!("Flash Storage Example");

    // Initialize hardware
    let p = embassy_rp::init(Default::default());

    // Initialize Flash device
    let [_, _, _, mut string_block, mut config_block] = FlashBlockRp::new_array::<5>(p.FLASH)?;

    info!("Part 1: Storing data to flash");
    let greeting =
        String::<64>::try_from("Hello, Flash Storage!").map_err(|_| Error::FormatError)?;
    string_block.save(&greeting)?;

    let sensor_name = String::<32>::try_from("Temperature").map_err(|_| Error::FormatError)?;
    config_block.save(&SensorConfig {
        name: sensor_name.clone(),
        sample_rate_hz: 1000,
        enabled: true,
    })?;

    info!("Part 2: Reading data from flash");
    let string: Option<String<64>> = string_block.load()?;
    assert!(string.as_deref() == Some("Hello, Flash Storage!"));
    let config: Option<SensorConfig> = config_block.load()?;
    assert!(
        config
            == Some(SensorConfig {
                name: sensor_name,
                sample_rate_hz: 1000,
                enabled: true,
            })
    );

    info!("Part 3: Reading a different type counts as empty");
    // Try to read the string block as a SensorConfig
    let wrong_type_result: Option<SensorConfig> = string_block.load()?;
    assert!(wrong_type_result.is_none());

    info!("Part 4: Clearing flash blocks");
    string_block.clear()?;
    config_block.clear()?;

    info!("Part 5: Verifying cleared blocks");
    let string: Option<String<64>> = string_block.load()?;
    assert!(string.is_none());
    let config: Option<SensorConfig> = config_block.load()?;
    assert!(config.is_none());

    info!("Flash Storage Example Complete!");
    loop {
        core::future::pending::<()>().await;
    }
}