|
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