norfs 0.0.0

Wear-leveling filesystem for embedded systems
Documentation
use crate::{drivers::aligned::AlignedStorage, medium::WriteGranularity, StorageError};

#[cfg_attr(feature = "esp32s3", path = "esp32s3.rs")]
pub mod implem;

#[cfg(feature = "critical-section")]
#[inline(always)]
#[link_section = ".rwtext"]
fn maybe_with_critical_section<R>(f: impl FnOnce() -> R) -> R {
    return critical_section::with(|_| f());

    #[cfg(not(feature = "critical-section"))]
    f()
}

#[cfg(not(feature = "critical-section"))]
#[inline(always)]
#[allow(unused)]
fn maybe_with_critical_section<R>(f: impl FnOnce() -> R) -> R {
    f()
}

pub trait InternalPartition {
    const OFFSET: usize;
    const SIZE: usize;
}

pub struct InternalDriver<P: InternalPartition> {
    unlocked: bool,
    _partition: P,
}

impl<P: InternalPartition> InternalDriver<P> {
    pub fn new(partition: P) -> Self {
        Self {
            unlocked: false,
            _partition: partition,
        }
    }

    fn unlock(&mut self) -> Result<(), StorageError> {
        if !self.unlocked {
            if implem::esp_rom_spiflash_unlock() != 0 {
                return Err(StorageError::Io);
            }
            self.unlocked = true;
        }

        Ok(())
    }

    async fn wait_idle(&mut self) -> Result<(), StorageError> {
        const SR_WIP: u32 = 1 << 0;

        let mut status = 0x00;
        loop {
            if implem::esp_rom_spiflash_read_user_cmd(&mut status, 0x05) != 0 {
                return Err(StorageError::Io);
            }
            if status & SR_WIP == 0 {
                return Ok(());
            }
            embassy_futures::yield_now().await;
        }
    }
}

impl<P: InternalPartition> AlignedStorage for InternalDriver<P> {
    const BLOCK_COUNT: usize = P::SIZE / implem::BLOCK_SIZE;
    const BLOCK_SIZE: usize = implem::BLOCK_SIZE;
    const PAGE_SIZE: usize = implem::PAGE_SIZE;
    const WRITE_GRANULARITY: WriteGranularity = implem::WRITE_GRANULARITY;

    async fn erase(&mut self, block: usize) -> Result<(), StorageError> {
        self.unlock()?;

        let offset = P::OFFSET / Self::BLOCK_SIZE;
        let block = offset + block;

        if implem::esp_rom_spiflash_erase_block(block as u32) == 0 {
            self.wait_idle().await
        } else {
            Err(StorageError::Io)
        }
    }

    async fn read_aligned(
        &mut self,
        block: usize,
        offset: usize,
        data: &mut [u8],
    ) -> Result<(), StorageError> {
        let len = data.len() as u32;
        let ptr = data.as_mut_ptr().cast();

        let offset = P::OFFSET + block * Self::BLOCK_SIZE + offset;

        if implem::esp_rom_spiflash_read(offset as u32, ptr, len) == 0 {
            Ok(())
        } else {
            Err(StorageError::Io)
        }
    }

    async fn write_aligned(
        &mut self,
        block: usize,
        offset: usize,
        data: &[u8],
    ) -> Result<(), StorageError> {
        let len = data.len() as u32;
        let ptr = data.as_ptr().cast();

        let offset = P::OFFSET + block * Self::BLOCK_SIZE + offset;

        if implem::esp_rom_spiflash_write(offset as u32, ptr, len) == 0 {
            self.wait_idle().await
        } else {
            Err(StorageError::Io)
        }
    }
}