#embassy #fatfs #filesystem #no-std #block-devices

sys no-std fatfs-embedded

Rust bindings for the popular embedded FatFs library

1 unstable release

0.1.0 Jan 27, 2024

#27 in #embassy

MIT license

2.5MB
23K SLoC

C 22K SLoC // 0.0% comments Rust 710 SLoC

fatfs-embedded

Rust bindings for the popular embedded FatFs library from elm-chan.org. Full documentation is available on docs.rs.


lib.rs:

FatFs is a generic FAT/exFAT filesystem module designed for small embedded systems. fatfs-embedded is a Rust wrapper of the popular FatFs library from elm-chan.org. It is based on the R0.15 release.

Goals

  • Embedded use - This library is no_std by default, but is std compatible for testing purposes when targeting an OS.
  • Thread safe - The choice was made to have a dependency on the Embassy framework for concurrency support which is suitable for embedded systems. A global file system mutex is implemented in favor of the FF_FS_REENTRANT option, which is more suitable to a Rust implementation.
  • Portable - Implement the FatFsDriver trait to add support for any block device. To support this implementation, alloc support is unfortunately required due to the structure of FatFs. A simulated block storage driver implementation is included for test purposes that may be used for reference.

Drop

The decision was made not to implement the Drop trait for files or directories. This is because doing so would require acquiring a lock on the file system object, which can easily cause a lockup condition. Files and directories must be manually closed. (The file system object itself is implemented as a static singleton and thus is never dropped.)

FatFs Configuration

Most features of FatFs are enabled with a few exceptions:

  • FF_USE_FORWARD is disabled to avoid using additional unsafe code.
  • FF_CODE_PAGE is set to 0 and thus must be set via a call to setcp().
  • FF_VOLUMES is currently set to 1 limiting the number of volumes supported to 1.
  • FF_MULTI_PARTITION is not currently supported.
  • FF_FS_LOCK is configured to support 10 simultaneous open files.
  • An implementation of the f_printf() function is not provided.

Features

  • chrono (default) - Enables time support in the library. Access to an RTC may be provided via an implementation of the FatFsDriver trait.

Examples

A brief example that formats and mounts a simulated drive, writes a string to a file, then reads the data back:

#[path = "../tests/simulated_driver.rs"]
mod simulated_driver;

use fatfs_embedded::fatfs::{self, File, FileOptions, FormatOptions};
use embassy_futures::block_on;

const TEST_STRING: &[u8] = b"Hello world!";

//Install a block device driver that implements `FatFsDriver`
let driver = simulated_driver::RamBlockStorage::new();
block_on(fatfs::diskio::install(driver));

//Acquire a lock on the file system.
let mut locked_fs = block_on(fatfs::FS.lock());

//Format the drive.
locked_fs.mkfs("", FormatOptions::FAT32, 0, 0, 0, 0);

//Mount the drive.
locked_fs.mount();

//Create a new file.
let mut test_file: File = locked_fs.open("test.txt", 
    FileOptions::CreateAlways | 
    FileOptions::Read | 
    FileOptions::Write).unwrap();

//Write a string to the file.
locked_fs.write(&mut test_file, TEST_STRING);

//Seek back to the beginning of the file.
locked_fs.seek(&mut test_file, 0);

//Read the string back from the file.
let mut read_back: [u8; TEST_STRING.len()] = [0; TEST_STRING.len()];
locked_fs.read(&mut test_file, &mut read_back);
assert_eq!(TEST_STRING, read_back);

//Close the file when done.
locked_fs.close(&mut test_file);

Dependencies

~2.3–5MB
~92K SLoC