rust-fatfs icon indicating copy to clipboard operation
rust-fatfs copied to clipboard

Examples for no_std usage?

Open Sven65 opened this issue 3 years ago • 9 comments

Are there any plans on adding examples on how to use this with no_std?

Sven65 avatar Dec 28 '21 10:12 Sven65

I think it is a good idea! Probably something basic, not a complete app for a specific microcontroller. I don't really have much experience with no_std in Rust. I think it would be best if someone with such experience contributed it.

rafalh avatar Dec 29 '21 00:12 rafalh

I'm just working on integrating this to my operating system, so I could probably write an example. How concrete are we talking about?

Here is some code (unfinished, untested, uncommented) that might become a part of an example:

#[derive(Debug)]
struct AtaError;

fn ata_read(start_sector: u64, sector_count: u8) -> Result<Vec<u8>, AtaError> {
    todo!("This is platform dependent");
}


#[derive(Debug)]
enum DiskCursorIoError {
    UnexpectedEof,
    WriteZero,
}
impl fatfs::IoError for DiskCursorIoError {
    fn is_interrupted(&self) -> bool {
        false
    }

    fn new_unexpected_eof_error() -> Self {
        Self::UnexpectedEof
    }

    fn new_write_zero_error() -> Self {
        Self::WriteZero
    }
}

struct DiskCursor {
    sector: u64,
    offset: usize,
}

impl DiskCursor {
    fn get_position(&self) -> usize {
        (self.sector * 0x200) as usize + self.offset
    }

    fn set_position(&mut self, position: usize) {
        self.sector = (position / 0x200) as u64;
        self.offset = position % 0x200;
    }

    fn move_cursor(&mut self, amount: usize) {
        self.set_position(self.get_position() + amount)
    }
}

impl fatfs::IoBase for DiskCursor {
    type Error = DiskCursorIoError;
}

impl fatfs::Read for DiskCursor {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, DiskCursorIoError> {
        let mut i = 0;
        while i < buf.len() {
            let data: Vec<u8> =
                ata_read(self.sector, ((buf.len() - i) / 0x200).max(1)).expect("ata error");
            let data = &data[self.offset..];
            if data.len() == 0 {
                break;
            }
            let end = (i + data.len()).min(buf.len());
            let len = end - i;
            buf[i..end].copy_from_slice(&data[..len]);
            i += len;
            self.move_cursor(i);
        }
        Ok(i)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), DiskCursorIoError> {
        let n = self.read(buf)?;
        assert!(n == buf.len(), "TODO: Error");
        Ok(())
    }
}

impl fatfs::Write for DiskCursor {
    fn write(&mut self, buf: &[u8]) -> Result<usize, DiskCursorIoError> {
        todo!("Write");
    }

    fn write_all(&mut self, buf: &[u8]) -> Result<(), DiskCursorIoError> {
        todo!("Write");
    }

    fn flush(&mut self) -> Result<(), DiskCursorIoError> {
        Ok(())
    }
}

impl fatfs::Seek for DiskCursor {
    fn seek(&mut self, pos: fatfs::SeekFrom) -> Result<u64, DiskCursorIoError> {
        match pos {
            fatfs::SeekFrom::Start(i) => {
                self.set_position(i as usize);
                Ok(i)
            }
            fatfs::SeekFrom::End(i) => {
                todo!("Seek from end")
            }
            fatfs::SeekFrom::Current(i) => {
                let new_pos = (self.get_position() as i64) + i;
                self.set_position(new_pos as usize);
                Ok(new_pos as u64)
            }
        }
    }
}

pub fn ls_dir(path: &str) {
    let c = DiskCursor {
        sector: 0,
        offset: 0,
    };

    let fs = fatfs::FileSystem::new(c, fatfs::FsOptions::new()).expect("open fs");
    let mut cursor = fs.root_dir().open_dir(path).expect("move to dir");

    let mut result = Vec::new();
    for entry in cursor.iter() {
        let entry = entry.expect("Entry");
        raw_println!("{}", entry;)
    }
}

Dentosal avatar Jan 09 '22 00:01 Dentosal

Looks good to me :) Write support would be nice, are you planning to add it to? Perhaps there should be some main function so it compiles fine when put into examples folder.

rafalh avatar Feb 01 '22 21:02 rafalh

It doesn't seem like it would be too much to implement Read Write and Seek like fscommon::BufStream but using sdmmc Maybe someone already has?

x37v avatar Apr 25 '22 01:04 x37v

@x37v, I'm currently trying to implement it for the STM32 L4 HAL, but I'm getting a CorruptedFileSystem error from the BootSector::validate function.

reitermarkus avatar May 01 '22 21:05 reitermarkus

@x37v, I'm currently trying to implement it for the STM32 L4 HAL, but I'm getting a CorruptedFileSystem error from the BootSector::validate function.

hey @reitermarkus , cool that you're doing this, I'd love to see your work in progress if you're willing/able to share. I hope to try this out with the stm32h7xx_hal when I get some chance.. I imagine it wouldn't be a whole lot different than what you're doing.

x37v avatar May 02 '22 00:05 x37v

It's here https://github.com/stm32-rs/stm32l4xx-hal/pull/315.

reitermarkus avatar May 02 '22 02:05 reitermarkus

It's here stm32-rs/stm32l4xx-hal#315.

@reitermarkus I added a comment into your PR.. not sure that it will solve things but I'm curious.

x37v avatar May 02 '22 14:05 x37v

Following up on this, @reitermarkus told me that the fatfs support works in this branch: https://github.com/reitermarkus/stm32l4xx-hal/tree/sdmmc

I've addapted that code for stm32h7xx-hal in a branch and have successfully run some example code on the stm32h750.

x37v avatar May 30 '22 14:05 x37v