Skip to content

implement FAT table write/read and setting the volume dirty status #132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/append_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use linux::*;

const FILE_TO_APPEND: &str = "README.TXT";

use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager};
use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode};

fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
env_logger::init();
Expand All @@ -32,7 +32,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr.open_volume(VolumeIdx(0))?;
let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
let mut root_dir = volume.open_root_dir()?;
println!("\nCreating file {}...", FILE_TO_APPEND);
let mut f = root_dir.open_file_in_dir(FILE_TO_APPEND, Mode::ReadWriteAppend)?;
Expand Down
4 changes: 2 additions & 2 deletions examples/big_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate embedded_sdmmc;
mod linux;
use linux::*;

use embedded_sdmmc::{Error, VolumeManager};
use embedded_sdmmc::{Error, VolumeManager, VolumeOpenMode};

fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
env_logger::init();
Expand All @@ -14,7 +14,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr
.open_volume(embedded_sdmmc::VolumeIdx(1))
.open_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite)
.unwrap();
println!("Volume: {:?}", volume);
let mut root_dir = volume.open_root_dir().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions examples/create_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use linux::*;

const FILE_TO_CREATE: &str = "CREATE.TXT";

use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager};
use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode};

fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
env_logger::init();
Expand All @@ -32,7 +32,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr.open_volume(VolumeIdx(0))?;
let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
let mut root_dir = volume.open_root_dir()?;
println!("\nCreating file {}...", FILE_TO_CREATE);
// This will panic if the file already exists: use ReadWriteCreateOrAppend
Expand Down
4 changes: 2 additions & 2 deletions examples/delete_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use linux::*;

const FILE_TO_DELETE: &str = "README.TXT";

use embedded_sdmmc::{Error, VolumeIdx, VolumeManager};
use embedded_sdmmc::{Error, VolumeIdx, VolumeManager, VolumeOpenMode};

fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
env_logger::init();
Expand All @@ -35,7 +35,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr.open_volume(VolumeIdx(0))?;
let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
let mut root_dir = volume.open_root_dir()?;
println!("Deleting file {}...", FILE_TO_DELETE);
root_dir.delete_file_in_dir(FILE_TO_DELETE)?;
Expand Down
4 changes: 2 additions & 2 deletions examples/list_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extern crate embedded_sdmmc;
mod linux;
use linux::*;

use embedded_sdmmc::{Directory, VolumeIdx, VolumeManager};
use embedded_sdmmc::{Directory, VolumeIdx, VolumeManager, VolumeOpenMode};

type Error = embedded_sdmmc::Error<std::io::Error>;

Expand All @@ -49,7 +49,7 @@ fn main() -> Result<(), Error> {
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr.open_volume(VolumeIdx(0))?;
let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
let root_dir = volume.open_root_dir()?;
list_dir(root_dir, "/")?;
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions examples/read_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use linux::*;

const FILE_TO_READ: &str = "README.TXT";

use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager};
use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode};

fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
env_logger::init();
Expand All @@ -49,7 +49,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
let mut volume = volume_mgr.open_volume(VolumeIdx(0))?;
let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
let mut root_dir = volume.open_root_dir()?;
println!("\nReading file {}...", FILE_TO_READ);
let mut f = root_dir.open_file_in_dir(FILE_TO_READ, Mode::ReadOnly)?;
Expand Down
5 changes: 3 additions & 2 deletions examples/readme_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use core::cell::RefCell;

use embedded_sdmmc::sdcard::DummyCsPin;
use embedded_sdmmc::{sdcard::DummyCsPin, VolumeOpenMode};

struct FakeSpiBus();

Expand Down Expand Up @@ -113,7 +113,8 @@ fn main() -> Result<(), Error> {
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
// Try and access Volume 0 (i.e. the first partition).
// The volume object holds information about the filesystem on that volume.
let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
let mut volume0 =
volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite)?;
println!("Volume 0: {:?}", volume0);
// Open the root directory (mutably borrows from the volume).
let mut root_dir = volume0.open_root_dir()?;
Expand Down
6 changes: 5 additions & 1 deletion examples/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ use std::io::prelude::*;

use embedded_sdmmc::{
Error as EsError, RawDirectory, RawVolume, ShortFileName, VolumeIdx, VolumeManager,
VolumeOpenMode,
};

use crate::linux::{Clock, LinuxBlockDevice};
Expand Down Expand Up @@ -531,7 +532,10 @@ fn main() -> Result<(), Error> {

let mut current_volume = None;
for volume_no in 0..4 {
match ctx.volume_mgr.open_raw_volume(VolumeIdx(volume_no)) {
match ctx
.volume_mgr
.open_raw_volume(VolumeIdx(volume_no), VolumeOpenMode::ReadWrite)
{
Ok(volume) => {
println!("Volume # {}: found", Context::volume_to_letter(volume_no));
match ctx.volume_mgr.open_root_dir(volume) {
Expand Down
62 changes: 62 additions & 0 deletions src/fat/fat_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/// FAT table definition
///
///
use crate::fat::FatType;
use byteorder::{ByteOrder, LittleEndian};

/// Represents a single FAT table. It contains all information about which cluster is occupied
/// from a file
pub struct FatTable<'a> {
fat_type: FatType,
data: &'a mut [u8],
}

impl<'a> FatTable<'a> {
/// Attempt to parse a FAT table from a multiple sectors.
pub fn create_from_bytes(data: &'a mut [u8], fat_type: FatType) -> Result<Self, &'static str> {
Ok(Self { data, fat_type })
}

// FAT16 only
//define_field!(fat_id16, u16, 0);

// FAT32 only
//define_field!(fat_id32, u32, 0);

const FAT16_DIRTY_BIT: u16 = 15;
const FAT32_DIRTY_BIT: u32 = 27;

pub(crate) fn dirty(&self) -> bool {
match self.fat_type {
FatType::Fat16 => {
(LittleEndian::read_u16(&self.data[2..2 + 2]) & (1 << Self::FAT16_DIRTY_BIT)) == 0
}
FatType::Fat32 => {
(LittleEndian::read_u32(&self.data[4..4 + 4]) & (1 << Self::FAT32_DIRTY_BIT)) == 0
}
}
}

pub(crate) fn set_dirty(&mut self, dirty: bool) {
match self.fat_type {
FatType::Fat16 => {
let mut v = LittleEndian::read_u16(&self.data[2..2 + 2]);
if dirty {
v &= !(1 << Self::FAT16_DIRTY_BIT);
} else {
v |= 1 << Self::FAT16_DIRTY_BIT
}
LittleEndian::write_u16(&mut self.data[2..2 + 2], v);
}
FatType::Fat32 => {
let mut v = LittleEndian::read_u32(&self.data[4..4 + 4]);
if dirty {
v &= !(1 << Self::FAT32_DIRTY_BIT);
} else {
v |= 1 << Self::FAT32_DIRTY_BIT
}
LittleEndian::write_u32(&mut self.data[4..4 + 4], v);
}
}
}
}
2 changes: 2 additions & 0 deletions src/fat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ impl BlockCache {
}

mod bpb;
mod fat_table;
mod info;
mod ondiskdirentry;
mod volume;

pub use bpb::Bpb;
pub use fat_table::FatTable;
pub use info::{Fat16Info, Fat32Info, FatSpecificInfo, InfoSector};
pub use ondiskdirentry::OnDiskDirEntry;
pub use volume::{parse_volume, FatVolume, VolumeName};
Expand Down
8 changes: 8 additions & 0 deletions src/fat/volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ pub struct FatVolume {
/// The block the FAT starts in. Relative to start of partition (so add
/// `self.lba_offset` before passing to volume manager)
pub(crate) fat_start: BlockCount,
/// Size of the FAT table in blocks
pub(crate) fat_size: BlockCount,
/// Number of FAT tables (Normaly there are 2 which are always synchronized (backup))
pub(crate) fat_nums: u8,
/// Expected number of free clusters
pub(crate) free_clusters_count: Option<u32>,
/// Number of the next expected free cluster
Expand Down Expand Up @@ -1098,6 +1102,8 @@ where
blocks_per_cluster: bpb.blocks_per_cluster(),
first_data_block: (first_data_block),
fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
fat_size: BlockCount(bpb.fat_size()),
fat_nums: bpb.num_fats(),
free_clusters_count: None,
next_free_cluster: None,
cluster_count: bpb.total_clusters(),
Expand Down Expand Up @@ -1135,6 +1141,8 @@ where
blocks_per_cluster: bpb.blocks_per_cluster(),
first_data_block: BlockCount(first_data_block),
fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
fat_size: BlockCount(bpb.fat_size()),
fat_nums: bpb.num_fats(),
free_clusters_count: info_sector.free_clusters_count(),
next_free_cluster: info_sector.next_free_cluster(),
cluster_count: bpb.total_clusters(),
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! suitable for reading SD and SDHC cards over SPI.
//!
//! ```rust
//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager};
//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager, VolumeOpenMode};
//!
//! fn example<S, CS, D, T>(spi: S, cs: CS, delay: D, ts: T) -> Result<(), Error<SdCardError>>
//! where
Expand All @@ -29,7 +29,7 @@
//! let sdcard = SdCard::new(spi, cs, delay);
//! println!("Card size is {} bytes", sdcard.num_bytes()?);
//! let mut volume_mgr = VolumeManager::new(sdcard, ts);
//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0))?;
//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadOnly)?;
//! println!("Volume 0: {:?}", volume0);
//! let mut root_dir = volume0.open_root_dir()?;
//! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", Mode::ReadOnly)?;
Expand Down Expand Up @@ -75,6 +75,7 @@ pub mod filesystem;
pub mod sdcard;

use filesystem::SearchId;
pub use volume_mgr::VolumeOpenMode;

#[doc(inline)]
pub use crate::blockdevice::{Block, BlockCount, BlockDevice, BlockIdx};
Expand Down Expand Up @@ -175,6 +176,8 @@ where
VolumeStillInUse,
/// You can't open a volume twice
VolumeAlreadyOpen,
/// Volume is opened in read only mode
VolumeReadOnly,
/// We can't do that yet
Unsupported,
/// Tried to read beyond end of file
Expand Down Expand Up @@ -344,6 +347,8 @@ pub(crate) struct VolumeInfo {
idx: VolumeIdx,
/// What kind of volume this is
volume_type: VolumeType,
/// Flag to indicate if the volume was opened as read only. If read only, files cannot be opened in write mode!
open_mode: VolumeOpenMode,
}

/// This enum holds the data for the various different types of filesystems we
Expand Down
Loading