|
3 | 3 | //! Generic code for handling block devices, such as types for identifying
|
4 | 4 | //! a particular block on a block device by its index.
|
5 | 5 |
|
| 6 | +use embedded_storage::block::{BlockCount, BlockDevice, BlockIdx}; |
| 7 | + |
6 | 8 | /// A standard 512 byte block (also known as a sector).
|
7 | 9 | ///
|
8 | 10 | /// IBM PC formatted 5.25" and 3.5" floppy disks, IDE/SATA Hard Drives up to
|
9 | 11 | /// about 2 TiB, and almost all SD/MMC cards have 512 byte blocks.
|
10 | 12 | ///
|
11 | 13 | /// This library does not support devices with a block size other than 512
|
12 | 14 | /// 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]; |
27 | 16 |
|
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; |
35 | 21 |
|
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; |
42 | 24 |
|
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; |
88 | 27 |
|
89 | 28 | /// A caching layer for block devices
|
90 | 29 | ///
|
|
104 | 43 | pub fn new(block_device: D) -> BlockCache<D> {
|
105 | 44 | BlockCache {
|
106 | 45 | block_device,
|
107 |
| - block: [Block::new()], |
| 46 | + block: [[0; BLOCK_LEN]], |
108 | 47 | block_idx: None,
|
109 | 48 | }
|
110 | 49 | }
|
@@ -160,112 +99,36 @@ where
|
160 | 99 | }
|
161 | 100 | }
|
162 | 101 |
|
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 |
204 | 107 | }
|
205 | 108 |
|
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. |
213 | 110 | ///
|
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)) |
269 | 132 | }
|
270 | 133 |
|
271 | 134 | /// An iterator returned from `Block::range`.
|
|
0 commit comments