embedded_sdmmc/
blockdevice.rs

1//! embedded-sdmmc-rs - Block Device support
2//!
3//! Generic code for handling block devices.
4
5/// Represents a standard 512 byte block (also known as a sector). IBM PC
6/// formatted 5.25" and 3.5" floppy disks, SD/MMC cards up to 1 GiB in size
7/// and IDE/SATA Hard Drives up to about 2 TiB all have 512 byte blocks.
8///
9/// This library does not support devices with a block size other than 512
10/// bytes.
11#[derive(Clone)]
12pub struct Block {
13    /// The 512 bytes in this block (or sector).
14    pub contents: [u8; Block::LEN],
15}
16
17/// Represents the linear numeric address of a block (or sector). The first
18/// block on a disk gets `BlockIdx(0)` (which usually contains the Master Boot
19/// Record).
20#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
21pub struct BlockIdx(pub u32);
22
23/// Represents the a number of blocks (or sectors). Add this to a `BlockIdx`
24/// to get an actual address on disk.
25#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
26pub struct BlockCount(pub u32);
27
28/// An iterator returned from `Block::range`.
29pub struct BlockIter {
30    inclusive_end: BlockIdx,
31    current: BlockIdx,
32}
33
34/// Represents a block device - a device which can read and write blocks (or
35/// sectors). Only supports devices which are <= 2 TiB in size.
36pub trait BlockDevice {
37    /// The errors that the `BlockDevice` can return. Must be debug formattable.
38    type Error: core::fmt::Debug;
39    /// Read one or more blocks, starting at the given block index.
40    fn read(
41        &self,
42        blocks: &mut [Block],
43        start_block_idx: BlockIdx,
44        reason: &str,
45    ) -> Result<(), Self::Error>;
46    /// Write one or more blocks, starting at the given block index.
47    fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
48    /// Determine how many blocks this device can hold.
49    fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
50}
51
52impl Block {
53    /// All our blocks are a fixed length of 512 bytes. We do not support
54    /// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
55    /// pre-3.5-inch floppy disk formats.
56    pub const LEN: usize = 512;
57
58    /// Sometimes we want `LEN` as a `u32` and the casts don't look nice.
59    pub const LEN_U32: u32 = 512;
60
61    /// Create a new block full of zeros.
62    pub fn new() -> Block {
63        Block {
64            contents: [0u8; Self::LEN],
65        }
66    }
67}
68
69impl Default for Block {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75impl core::ops::Add<BlockCount> for BlockIdx {
76    type Output = BlockIdx;
77    fn add(self, rhs: BlockCount) -> BlockIdx {
78        BlockIdx(self.0 + rhs.0)
79    }
80}
81
82impl core::ops::AddAssign<BlockCount> for BlockIdx {
83    fn add_assign(&mut self, rhs: BlockCount) {
84        self.0 += rhs.0
85    }
86}
87
88impl core::ops::Add<BlockCount> for BlockCount {
89    type Output = BlockCount;
90    fn add(self, rhs: BlockCount) -> BlockCount {
91        BlockCount(self.0 + rhs.0)
92    }
93}
94
95impl core::ops::AddAssign<BlockCount> for BlockCount {
96    fn add_assign(&mut self, rhs: BlockCount) {
97        self.0 += rhs.0
98    }
99}
100
101impl core::ops::Sub<BlockCount> for BlockIdx {
102    type Output = BlockIdx;
103    fn sub(self, rhs: BlockCount) -> BlockIdx {
104        BlockIdx(self.0 - rhs.0)
105    }
106}
107
108impl core::ops::SubAssign<BlockCount> for BlockIdx {
109    fn sub_assign(&mut self, rhs: BlockCount) {
110        self.0 -= rhs.0
111    }
112}
113
114impl core::ops::Sub<BlockCount> for BlockCount {
115    type Output = BlockCount;
116    fn sub(self, rhs: BlockCount) -> BlockCount {
117        BlockCount(self.0 - rhs.0)
118    }
119}
120
121impl core::ops::SubAssign<BlockCount> for BlockCount {
122    fn sub_assign(&mut self, rhs: BlockCount) {
123        self.0 -= rhs.0
124    }
125}
126
127impl core::ops::Deref for Block {
128    type Target = [u8; 512];
129    fn deref(&self) -> &[u8; 512] {
130        &self.contents
131    }
132}
133
134impl core::ops::DerefMut for Block {
135    fn deref_mut(&mut self) -> &mut [u8; 512] {
136        &mut self.contents
137    }
138}
139
140impl core::fmt::Debug for Block {
141    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
142        writeln!(fmt, "Block:")?;
143        for line in self.contents.chunks(32) {
144            for b in line {
145                write!(fmt, "{:02x}", b)?;
146            }
147            write!(fmt, " ")?;
148            for &b in line {
149                if b >= 0x20 && b <= 0x7F {
150                    write!(fmt, "{}", b as char)?;
151                } else {
152                    write!(fmt, ".")?;
153                }
154            }
155            writeln!(fmt)?;
156        }
157        Ok(())
158    }
159}
160
161impl BlockIdx {
162    /// Convert a block index into a 64-bit byte offset from the start of the
163    /// volume. Useful if your underlying block device actually works in
164    /// bytes, like `open("/dev/mmcblk0")` does on Linux.
165    pub fn into_bytes(self) -> u64 {
166        (u64::from(self.0)) * (Block::LEN as u64)
167    }
168
169    /// Create an iterator from the current `BlockIdx` through the given
170    /// number of blocks.
171    pub fn range(self, num: BlockCount) -> BlockIter {
172        BlockIter::new(self, self + BlockCount(num.0))
173    }
174}
175
176impl BlockCount {
177    /// Take a number of blocks and increment by the integer number of blocks
178    /// required to get to the block that holds the byte at the given offset.
179    pub fn offset_bytes(self, offset: u32) -> Self {
180        BlockCount(self.0 + (offset / Block::LEN_U32))
181    }
182}
183
184impl BlockIter {
185    /// Create a new `BlockIter`, from the given start block, through (and
186    /// including) the given end block.
187    pub fn new(start: BlockIdx, inclusive_end: BlockIdx) -> BlockIter {
188        BlockIter {
189            inclusive_end,
190            current: start,
191        }
192    }
193}
194
195impl core::iter::Iterator for BlockIter {
196    type Item = BlockIdx;
197    fn next(&mut self) -> Option<Self::Item> {
198        if self.current.0 >= self.inclusive_end.0 {
199            None
200        } else {
201            let this = self.current;
202            self.current += BlockCount(1);
203            Some(this)
204        }
205    }
206}
207
208// ****************************************************************************
209//
210// End Of File
211//
212// ****************************************************************************