Skip to content

Commit ee3c688

Browse files
committed
Use embedded-storage BlockDevice trait.
This will allow both the SD card driver and the FAT32 implementation to be used with filesystem or block device drivers respectively.
1 parent 52e0e4f commit ee3c688

File tree

11 files changed

+403
-450
lines changed

11 files changed

+403
-450
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ byteorder = {version = "1", default-features = false}
1515
defmt = {version = "0.3", optional = true}
1616
embedded-hal = "1.0.0"
1717
embedded-io = "0.6.1"
18+
embedded-storage = { git = "https://github.com/qwandor/embedded-storage", branch = "block", default-features = false }
1819
heapless = "^0.8"
1920
log = {version = "0.4", default-features = false, optional = true}
2021

@@ -28,5 +29,5 @@ sha2 = "0.10"
2829

2930
[features]
3031
default = ["log"]
31-
defmt-log = ["dep:defmt"]
32+
defmt-log = ["dep:defmt", "embedded-storage/defmt"]
3233
log = ["dep:log"]

examples/linux/mod.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Helpers for using embedded-sdmmc on Linux
22
33
use chrono::Timelike;
4-
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp};
4+
use embedded_sdmmc::{
5+
blockdevice::BLOCK_LEN_U64, Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp,
6+
};
57
use std::cell::RefCell;
68
use std::fs::{File, OpenOptions};
79
use std::io::prelude::*;
@@ -34,35 +36,39 @@ impl LinuxBlockDevice {
3436
impl BlockDevice for LinuxBlockDevice {
3537
type Error = std::io::Error;
3638

37-
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
39+
fn read(
40+
&mut self,
41+
blocks: &mut [Block],
42+
first_block_index: BlockIdx,
43+
) -> Result<(), Self::Error> {
3844
self.file
3945
.borrow_mut()
40-
.seek(SeekFrom::Start(start_block_idx.into_bytes()))?;
46+
.seek(SeekFrom::Start(first_block_index.0 * BLOCK_LEN_U64))?;
4147
for block in blocks.iter_mut() {
42-
self.file.borrow_mut().read_exact(&mut block.contents)?;
48+
self.file.borrow_mut().read_exact(block)?;
4349
if self.print_blocks {
44-
println!("Read block {:?}: {:?}", start_block_idx, &block);
50+
println!("Read block {:?}: {:?}", first_block_index, &block);
4551
}
4652
}
4753
Ok(())
4854
}
4955

50-
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
56+
fn write(&mut self, blocks: &[Block], first_block_index: BlockIdx) -> Result<(), Self::Error> {
5157
self.file
5258
.borrow_mut()
53-
.seek(SeekFrom::Start(start_block_idx.into_bytes()))?;
59+
.seek(SeekFrom::Start(first_block_index.0 * BLOCK_LEN_U64))?;
5460
for block in blocks.iter() {
55-
self.file.borrow_mut().write_all(&block.contents)?;
61+
self.file.borrow_mut().write_all(block)?;
5662
if self.print_blocks {
5763
println!("Wrote: {:?}", &block);
5864
}
5965
}
6066
Ok(())
6167
}
6268

63-
fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
69+
fn block_count(&self) -> Result<BlockCount, Self::Error> {
6470
let num_blocks = self.file.borrow().metadata().unwrap().len() / 512;
65-
Ok(BlockCount(num_blocks as u32))
71+
Ok(BlockCount(num_blocks))
6672
}
6773
}
6874

src/blockdevice.rs

+39-176
Original file line numberDiff line numberDiff line change
@@ -3,88 +3,27 @@
33
//! Generic code for handling block devices, such as types for identifying
44
//! a particular block on a block device by its index.
55
6+
use embedded_storage::block::{BlockCount, BlockDevice, BlockIdx};
7+
68
/// A standard 512 byte block (also known as a sector).
79
///
810
/// IBM PC formatted 5.25" and 3.5" floppy disks, IDE/SATA Hard Drives up to
911
/// about 2 TiB, and almost all SD/MMC cards have 512 byte blocks.
1012
///
1113
/// This library does not support devices with a block size other than 512
1214
/// bytes.
13-
#[derive(Clone)]
14-
pub struct Block {
15-
/// The 512 bytes in this block (or sector).
16-
pub contents: [u8; Block::LEN],
17-
}
18-
19-
impl Block {
20-
/// All our blocks are a fixed length of 512 bytes. We do not support
21-
/// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
22-
/// pre-3.5-inch floppy disk formats.
23-
pub const LEN: usize = 512;
24-
25-
/// Sometimes we want `LEN` as a `u32` and the casts don't look nice.
26-
pub const LEN_U32: u32 = 512;
15+
pub type Block = [u8; BLOCK_LEN];
2716

28-
/// Create a new block full of zeros.
29-
pub fn new() -> Block {
30-
Block {
31-
contents: [0u8; Self::LEN],
32-
}
33-
}
34-
}
17+
/// All our blocks are a fixed length of 512 bytes. We do not support
18+
/// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
19+
/// pre-3.5-inch floppy disk formats.
20+
pub const BLOCK_LEN: usize = 512;
3521

36-
impl core::ops::Deref for Block {
37-
type Target = [u8; 512];
38-
fn deref(&self) -> &[u8; 512] {
39-
&self.contents
40-
}
41-
}
22+
/// Sometimes we want `LEN` as a `u32` and the casts don't look nice.
23+
pub const BLOCK_LEN_U32: u32 = 512;
4224

43-
impl core::ops::DerefMut for Block {
44-
fn deref_mut(&mut self) -> &mut [u8; 512] {
45-
&mut self.contents
46-
}
47-
}
48-
49-
impl core::fmt::Debug for Block {
50-
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
51-
writeln!(fmt, "Block:")?;
52-
for line in self.contents.chunks(32) {
53-
for b in line {
54-
write!(fmt, "{:02x}", b)?;
55-
}
56-
write!(fmt, " ")?;
57-
for &b in line {
58-
if (0x20..=0x7F).contains(&b) {
59-
write!(fmt, "{}", b as char)?;
60-
} else {
61-
write!(fmt, ".")?;
62-
}
63-
}
64-
writeln!(fmt)?;
65-
}
66-
Ok(())
67-
}
68-
}
69-
70-
impl Default for Block {
71-
fn default() -> Self {
72-
Self::new()
73-
}
74-
}
75-
76-
/// A block device - a device which can read and write blocks (or
77-
/// sectors). Only supports devices which are <= 2 TiB in size.
78-
pub trait BlockDevice {
79-
/// The errors that the `BlockDevice` can return. Must be debug formattable.
80-
type Error: core::fmt::Debug;
81-
/// Read one or more blocks, starting at the given block index.
82-
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
83-
/// Write one or more blocks, starting at the given block index.
84-
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
85-
/// Determine how many blocks this device can hold.
86-
fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
87-
}
25+
/// Sometimes we want `LEN` as a `u64` and the casts don't look nice.
26+
pub const BLOCK_LEN_U64: u64 = 512;
8827

8928
/// A caching layer for block devices
9029
///
@@ -104,7 +43,7 @@ where
10443
pub fn new(block_device: D) -> BlockCache<D> {
10544
BlockCache {
10645
block_device,
107-
block: [Block::new()],
46+
block: [[0; BLOCK_LEN]],
10847
block_idx: None,
10948
}
11049
}
@@ -160,112 +99,36 @@ where
16099
}
161100
}
162101

163-
/// The linear numeric address of a block (or sector).
164-
///
165-
/// The first block on a disk gets `BlockIdx(0)` (which usually contains the
166-
/// Master Boot Record).
167-
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
168-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
169-
pub struct BlockIdx(pub u32);
170-
171-
impl BlockIdx {
172-
/// Convert a block index into a 64-bit byte offset from the start of the
173-
/// volume. Useful if your underlying block device actually works in
174-
/// bytes, like `open("/dev/mmcblk0")` does on Linux.
175-
pub fn into_bytes(self) -> u64 {
176-
(u64::from(self.0)) * (Block::LEN as u64)
177-
}
178-
179-
/// Create an iterator from the current `BlockIdx` through the given
180-
/// number of blocks.
181-
pub fn range(self, num: BlockCount) -> BlockIter {
182-
BlockIter::new(self, self + BlockCount(num.0))
183-
}
184-
}
185-
186-
impl core::ops::Add<BlockCount> for BlockIdx {
187-
type Output = BlockIdx;
188-
fn add(self, rhs: BlockCount) -> BlockIdx {
189-
BlockIdx(self.0 + rhs.0)
190-
}
191-
}
192-
193-
impl core::ops::AddAssign<BlockCount> for BlockIdx {
194-
fn add_assign(&mut self, rhs: BlockCount) {
195-
self.0 += rhs.0
196-
}
197-
}
198-
199-
impl core::ops::Sub<BlockCount> for BlockIdx {
200-
type Output = BlockIdx;
201-
fn sub(self, rhs: BlockCount) -> BlockIdx {
202-
BlockIdx(self.0 - rhs.0)
203-
}
102+
/// Convert a block index into a 64-bit byte offset from the start of the
103+
/// volume. Useful if your underlying block device actually works in
104+
/// bytes, like `open("/dev/mmcblk0")` does on Linux.
105+
pub fn block_index_into_bytes(block_index: BlockIdx) -> u64 {
106+
block_index.0 * BLOCK_LEN_U64
204107
}
205108

206-
impl core::ops::SubAssign<BlockCount> for BlockIdx {
207-
fn sub_assign(&mut self, rhs: BlockCount) {
208-
self.0 -= rhs.0
209-
}
210-
}
211-
212-
/// The a number of blocks (or sectors).
109+
/// How many blocks are required to hold this many bytes.
213110
///
214-
/// Add this to a `BlockIdx` to get an actual address on disk.
215-
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
216-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
217-
pub struct BlockCount(pub u32);
218-
219-
impl core::ops::Add<BlockCount> for BlockCount {
220-
type Output = BlockCount;
221-
fn add(self, rhs: BlockCount) -> BlockCount {
222-
BlockCount(self.0 + rhs.0)
223-
}
224-
}
225-
226-
impl core::ops::AddAssign<BlockCount> for BlockCount {
227-
fn add_assign(&mut self, rhs: BlockCount) {
228-
self.0 += rhs.0
229-
}
230-
}
231-
232-
impl core::ops::Sub<BlockCount> for BlockCount {
233-
type Output = BlockCount;
234-
fn sub(self, rhs: BlockCount) -> BlockCount {
235-
BlockCount(self.0 - rhs.0)
236-
}
237-
}
238-
239-
impl core::ops::SubAssign<BlockCount> for BlockCount {
240-
fn sub_assign(&mut self, rhs: BlockCount) {
241-
self.0 -= rhs.0
242-
}
243-
}
244-
245-
impl BlockCount {
246-
/// How many blocks are required to hold this many bytes.
247-
///
248-
/// ```
249-
/// # use embedded_sdmmc::BlockCount;
250-
/// assert_eq!(BlockCount::from_bytes(511), BlockCount(1));
251-
/// assert_eq!(BlockCount::from_bytes(512), BlockCount(1));
252-
/// assert_eq!(BlockCount::from_bytes(513), BlockCount(2));
253-
/// assert_eq!(BlockCount::from_bytes(1024), BlockCount(2));
254-
/// assert_eq!(BlockCount::from_bytes(1025), BlockCount(3));
255-
/// ```
256-
pub const fn from_bytes(byte_count: u32) -> BlockCount {
257-
let mut count = byte_count / Block::LEN_U32;
258-
if (count * Block::LEN_U32) != byte_count {
259-
count += 1;
260-
}
261-
BlockCount(count)
262-
}
263-
264-
/// Take a number of blocks and increment by the integer number of blocks
265-
/// required to get to the block that holds the byte at the given offset.
266-
pub fn offset_bytes(self, offset: u32) -> Self {
267-
BlockCount(self.0 + (offset / Block::LEN_U32))
268-
}
111+
/// ```
112+
/// # use embedded_sdmmc::blockdevice::{block_count_from_bytes};
113+
/// # use embedded_storage::block::BlockCount;
114+
/// assert_eq!(block_count_from_bytes(511), BlockCount(1));
115+
/// assert_eq!(block_count_from_bytes(512), BlockCount(1));
116+
/// assert_eq!(block_count_from_bytes(513), BlockCount(2));
117+
/// assert_eq!(block_count_from_bytes(1024), BlockCount(2));
118+
/// assert_eq!(block_count_from_bytes(1025), BlockCount(3));
119+
/// ```
120+
pub const fn block_count_from_bytes(byte_count: u64) -> BlockCount {
121+
let mut count = byte_count / BLOCK_LEN_U64;
122+
if (count * BLOCK_LEN_U64) != byte_count {
123+
count += 1;
124+
}
125+
BlockCount(count)
126+
}
127+
128+
/// Take a number of blocks and increment by the integer number of blocks
129+
/// required to get to the block that holds the byte at the given offset.
130+
pub fn block_count_offset_bytes(base: BlockCount, offset: u64) -> BlockCount {
131+
BlockCount(base.0 + (offset / BLOCK_LEN_U64))
269132
}
270133

271134
/// An iterator returned from `Block::range`.

src/fat/bpb.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
//! Boot Parameter Block
22
33
use crate::{
4-
blockdevice::BlockCount,
4+
blockdevice::block_count_from_bytes,
55
fat::{FatType, OnDiskDirEntry},
66
};
77
use byteorder::{ByteOrder, LittleEndian};
8+
use embedded_storage::block::BlockCount;
89

910
/// A Boot Parameter Block.
1011
///
@@ -30,8 +31,10 @@ impl<'a> Bpb<'a> {
3031
return Err("Bad BPB footer");
3132
}
3233

33-
let root_dir_blocks =
34-
BlockCount::from_bytes(u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32).0;
34+
let root_dir_blocks = block_count_from_bytes(
35+
u64::from(bpb.root_entries_count()) * u64::from(OnDiskDirEntry::LEN_U32),
36+
)
37+
.0 as u32;
3538
let non_data_blocks = u32::from(bpb.reserved_block_count())
3639
+ (u32::from(bpb.num_fats()) * bpb.fat_size())
3740
+ root_dir_blocks;
@@ -101,7 +104,7 @@ impl<'a> Bpb<'a> {
101104
pub fn fs_info_block(&self) -> Option<BlockCount> {
102105
match self.fat_type {
103106
FatType::Fat16 => None,
104-
FatType::Fat32 => Some(BlockCount(u32::from(self.fs_info()))),
107+
FatType::Fat32 => Some(BlockCount(self.fs_info().into())),
105108
}
106109
}
107110

0 commit comments

Comments
 (0)