Skip to content

Commit 201e1e4

Browse files
committed
add async support using bisync crate
This moves the existing API into a `blocking` module and duplicates the API into a new `asynchronous` module, using `async fn` where applicable. Fixes rust-embedded-community#50
1 parent e7eef2a commit 201e1e4

37 files changed

+889
-807
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic
88

99
### Changed
1010

11+
- __Breaking Change__: Existing API moved into `blocking` module. Adjust your imports from `embedded_sdmmc::` to `embedded_sdmmc::blocking` to keep old code building.
1112
- __Breaking Change__: `VolumeManager` now uses interior-mutability (with a `RefCell`) and so most methods are now `&self`. This also makes it easier to open multiple `File`, `Directory` or `Volume` objects at once.
1213
- __Breaking Change__: The `VolumeManager`, `File`, `Directory` and `Volume` no longer implement `Send` or `Sync.
1314
- `VolumeManager` uses an interior block cache of 512 bytes, increasing its size by about 520 bytes but hugely reducing stack space required at run-time.
@@ -17,6 +18,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic
1718

1819
### Added
1920

21+
- Async API in `asynchronous module`
2022
- `File` now implements the `embedded-io` `Read`, `Write` and `Seek` traits.
2123
- New `iterate_dir_lfn` method on `VolumeManager` and `Directory` - provides decoded Long File Names as `Option<&str>`
2224

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ version = "0.8.0"
1414
rust-version = "1.76"
1515

1616
[dependencies]
17+
bisync = "0.2.3"
1718
byteorder = {version = "1", default-features = false}
1819
defmt = {version = "0.3", optional = true}
1920
embedded-hal = "1.0.0"
21+
embedded-hal-async = "1.0.0"
2022
embedded-io = "0.6.1"
23+
embedded-io-async = "0.6.1"
2124
heapless = "^0.8"
2225
log = {version = "0.4", default-features = false, optional = true}
2326

examples/append_file.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ use linux::*;
2222

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

25-
use embedded_sdmmc::{Error, Mode, VolumeIdx};
25+
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};
2626

27-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
27+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
2828

29-
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
29+
fn main() -> Result<(), Error<std::io::Error>> {
3030
env_logger::init();
3131
let mut args = std::env::args().skip(1);
3232
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());

examples/big_dir.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ extern crate embedded_sdmmc;
33
mod linux;
44
use linux::*;
55

6-
use embedded_sdmmc::Error;
6+
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};
77

8-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
8+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
99

10-
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
10+
fn main() -> Result<(), Error<std::io::Error>> {
1111
env_logger::init();
1212
let mut args = std::env::args().skip(1);
1313
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());
1414
let print_blocks = args.find(|x| x == "-v").map(|_| true).unwrap_or(false);
1515
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
1616
let volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
1717
let volume = volume_mgr
18-
.open_volume(embedded_sdmmc::VolumeIdx(1))
18+
.open_volume(VolumeIdx(1))
1919
.unwrap();
2020
println!("Volume: {:?}", volume);
2121
let root_dir = volume.open_root_dir().unwrap();
@@ -28,7 +28,7 @@ fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
2828
let file = root_dir
2929
.open_file_in_dir(
3030
file_name.as_str(),
31-
embedded_sdmmc::Mode::ReadWriteCreateOrTruncate,
31+
Mode::ReadWriteCreateOrTruncate,
3232
)
3333
.unwrap();
3434
let buf = b"hello world, from rust";

examples/create_file.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ use linux::*;
2222

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

25-
use embedded_sdmmc::{Error, Mode, VolumeIdx};
25+
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};
2626

27-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
27+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
2828

29-
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
29+
fn main() -> Result<(), Error<std::io::Error>> {
3030
env_logger::init();
3131
let mut args = std::env::args().skip(1);
3232
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());

examples/delete_file.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ use linux::*;
2525

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

28-
use embedded_sdmmc::{Error, VolumeIdx};
28+
use embedded_sdmmc::blocking::{Error, VolumeIdx};
2929

30-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
30+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
3131

32-
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
32+
fn main() -> Result<(), Error<std::io::Error>> {
3333
env_logger::init();
3434
let mut args = std::env::args().skip(1);
3535
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());

examples/linux/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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::blocking::{Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp};
55
use std::cell::RefCell;
66
use std::fs::{File, OpenOptions};
77
use std::io::prelude::*;

examples/list_dir.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@
3535
mod linux;
3636
use linux::*;
3737

38-
use embedded_sdmmc::{ShortFileName, VolumeIdx};
38+
use embedded_sdmmc::blocking::{ShortFileName, VolumeIdx};
3939

40-
type Error = embedded_sdmmc::Error<std::io::Error>;
40+
type Error = embedded_sdmmc::blocking::Error<std::io::Error>;
4141

42-
type Directory<'a> = embedded_sdmmc::Directory<'a, LinuxBlockDevice, Clock, 8, 4, 4>;
43-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
42+
type Directory<'a> = embedded_sdmmc::blocking::Directory<'a, LinuxBlockDevice, Clock, 8, 4, 4>;
43+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
4444

4545
fn main() -> Result<(), Error> {
4646
env_logger::init();

examples/read_file.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ use linux::*;
3939

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

42-
use embedded_sdmmc::{Error, Mode, VolumeIdx};
42+
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};
4343

44-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
44+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
4545

46-
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
46+
fn main() -> Result<(), Error<std::io::Error>> {
4747
env_logger::init();
4848
let mut args = std::env::args().skip(1);
4949
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());

examples/readme_test.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ impl embedded_hal::delay::DelayNs for FakeDelayer {
8080

8181
struct FakeTimesource();
8282

83-
impl embedded_sdmmc::TimeSource for FakeTimesource {
84-
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
85-
embedded_sdmmc::Timestamp {
83+
impl embedded_sdmmc::blocking::TimeSource for FakeTimesource {
84+
fn get_timestamp(&self) -> embedded_sdmmc::blocking::Timestamp {
85+
embedded_sdmmc::blocking::Timestamp {
8686
year_since_1970: 0,
8787
zero_indexed_month: 0,
8888
zero_indexed_day: 0,
@@ -95,18 +95,18 @@ impl embedded_sdmmc::TimeSource for FakeTimesource {
9595

9696
#[derive(Debug, Clone)]
9797
enum Error {
98-
Filesystem(embedded_sdmmc::Error<embedded_sdmmc::SdCardError>),
99-
Disk(embedded_sdmmc::SdCardError),
98+
Filesystem(embedded_sdmmc::blocking::Error<embedded_sdmmc::blocking::SdCardError>),
99+
Disk(embedded_sdmmc::blocking::SdCardError),
100100
}
101101

102-
impl From<embedded_sdmmc::Error<embedded_sdmmc::SdCardError>> for Error {
103-
fn from(value: embedded_sdmmc::Error<embedded_sdmmc::SdCardError>) -> Error {
102+
impl From<embedded_sdmmc::blocking::Error<embedded_sdmmc::blocking::SdCardError>> for Error {
103+
fn from(value: embedded_sdmmc::blocking::Error<embedded_sdmmc::blocking::SdCardError>) -> Error {
104104
Error::Filesystem(value)
105105
}
106106
}
107107

108-
impl From<embedded_sdmmc::SdCardError> for Error {
109-
fn from(value: embedded_sdmmc::SdCardError) -> Error {
108+
impl From<embedded_sdmmc::blocking::SdCardError> for Error {
109+
fn from(value: embedded_sdmmc::blocking::SdCardError) -> Error {
110110
Error::Disk(value)
111111
}
112112
}
@@ -120,21 +120,21 @@ fn main() -> Result<(), Error> {
120120
// END Fake stuff that will be replaced with real peripherals
121121

122122
// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
123-
let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, delay);
123+
let sdcard = embedded_sdmmc::blocking::SdCard::new(sdmmc_spi, delay);
124124
// Get the card size (this also triggers card initialisation because it's not been done yet)
125125
println!("Card size is {} bytes", sdcard.num_bytes()?);
126126
// Now let's look for volumes (also known as partitions) on our block device.
127127
// To do this we need a Volume Manager. It will take ownership of the block device.
128-
let volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
128+
let volume_mgr = embedded_sdmmc::blocking::VolumeManager::new(sdcard, time_source);
129129
// Try and access Volume 0 (i.e. the first partition).
130130
// The volume object holds information about the filesystem on that volume.
131-
let volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
131+
let volume0 = volume_mgr.open_volume(embedded_sdmmc::blocking::VolumeIdx(0))?;
132132
println!("Volume 0: {:?}", volume0);
133133
// Open the root directory (mutably borrows from the volume).
134134
let root_dir = volume0.open_root_dir()?;
135135
// Open a file called "MY_FILE.TXT" in the root directory
136136
// This mutably borrows the directory.
137-
let my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)?;
137+
let my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::blocking::Mode::ReadOnly)?;
138138
// Print the contents of the file, assuming it's in ISO-8859-1 encoding
139139
while !my_file.is_eof() {
140140
let mut buffer = [0u8; 32];

examples/shell.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@
7171
7272
use std::{cell::RefCell, io::prelude::*};
7373

74-
use embedded_sdmmc::{
74+
use embedded_sdmmc::blocking::{
7575
Error as EsError, LfnBuffer, RawDirectory, RawVolume, ShortFileName, VolumeIdx,
7676
};
7777

78-
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>;
79-
type Directory<'a> = embedded_sdmmc::Directory<'a, LinuxBlockDevice, Clock, 8, 8, 4>;
78+
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>;
79+
type Directory<'a> = embedded_sdmmc::blocking::Directory<'a, LinuxBlockDevice, Clock, 8, 8, 4>;
8080

8181
use crate::linux::{Clock, LinuxBlockDevice};
8282

@@ -324,7 +324,7 @@ impl Context {
324324
/// print a text file
325325
fn cat(&self, filename: &Path) -> Result<(), Error> {
326326
let (dir, filename) = self.resolve_filename(filename)?;
327-
let f = dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly)?;
327+
let f = dir.open_file_in_dir(filename, embedded_sdmmc::blocking::Mode::ReadOnly)?;
328328
let mut data = Vec::new();
329329
while !f.is_eof() {
330330
let mut buffer = vec![0u8; 65536];
@@ -344,7 +344,7 @@ impl Context {
344344
/// print a binary file
345345
fn hexdump(&self, filename: &Path) -> Result<(), Error> {
346346
let (dir, filename) = self.resolve_filename(filename)?;
347-
let f = dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly)?;
347+
let f = dir.open_file_in_dir(filename, embedded_sdmmc::blocking::Mode::ReadOnly)?;
348348
let mut data = Vec::new();
349349
while !f.is_eof() {
350350
let mut buffer = vec![0u8; 65536];

src/blockdevice.rs renamed to src/inner/blockdevice.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
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 super::super::bisync;
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
@@ -75,15 +77,16 @@ impl Default for Block {
7577

7678
/// A block device - a device which can read and write blocks (or
7779
/// sectors). Only supports devices which are <= 2 TiB in size.
80+
#[bisync]
7881
pub trait BlockDevice {
7982
/// The errors that the `BlockDevice` can return. Must be debug formattable.
8083
type Error: core::fmt::Debug;
8184
/// 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>;
85+
async fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
8386
/// Write one or more blocks, starting at the given block index.
84-
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
87+
async fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
8588
/// Determine how many blocks this device can hold.
86-
fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
89+
async fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
8790
}
8891

8992
/// A caching layer for block devices
@@ -96,6 +99,7 @@ pub struct BlockCache<D> {
9699
block_idx: Option<BlockIdx>,
97100
}
98101

102+
#[bisync]
99103
impl<D> BlockCache<D>
100104
where
101105
D: BlockDevice,
@@ -110,42 +114,42 @@ where
110114
}
111115

112116
/// Read a block, and return a reference to it.
113-
pub fn read(&mut self, block_idx: BlockIdx) -> Result<&Block, D::Error> {
117+
pub async fn read(&mut self, block_idx: BlockIdx) -> Result<&Block, D::Error> {
114118
if self.block_idx != Some(block_idx) {
115119
self.block_idx = None;
116-
self.block_device.read(&mut self.block, block_idx)?;
120+
self.block_device.read(&mut self.block, block_idx).await?;
117121
self.block_idx = Some(block_idx);
118122
}
119123
Ok(&self.block[0])
120124
}
121125

122126
/// Read a block, and return a reference to it.
123-
pub fn read_mut(&mut self, block_idx: BlockIdx) -> Result<&mut Block, D::Error> {
127+
pub async fn read_mut(&mut self, block_idx: BlockIdx) -> Result<&mut Block, D::Error> {
124128
if self.block_idx != Some(block_idx) {
125129
self.block_idx = None;
126-
self.block_device.read(&mut self.block, block_idx)?;
130+
self.block_device.read(&mut self.block, block_idx).await?;
127131
self.block_idx = Some(block_idx);
128132
}
129133
Ok(&mut self.block[0])
130134
}
131135

132136
/// Write back a block you read with [`Self::read_mut`] and then modified.
133-
pub fn write_back(&mut self) -> Result<(), D::Error> {
137+
pub async fn write_back(&mut self) -> Result<(), D::Error> {
134138
self.block_device.write(
135139
&self.block,
136140
self.block_idx.expect("write_back with no read"),
137-
)
141+
).await
138142
}
139143

140144
/// Write back a block you read with [`Self::read_mut`] and then modified, but to two locations.
141145
///
142146
/// This is useful for updating two File Allocation Tables.
143-
pub fn write_back_with_duplicate(&mut self, duplicate: BlockIdx) -> Result<(), D::Error> {
147+
pub async fn write_back_with_duplicate(&mut self, duplicate: BlockIdx) -> Result<(), D::Error> {
144148
self.block_device.write(
145149
&self.block,
146150
self.block_idx.expect("write_back with no read"),
147-
)?;
148-
self.block_device.write(&self.block, duplicate)?;
151+
).await?;
152+
self.block_device.write(&self.block, duplicate).await?;
149153
Ok(())
150154
}
151155

@@ -256,7 +260,7 @@ impl BlockCount {
256260
/// How many blocks are required to hold this many bytes.
257261
///
258262
/// ```
259-
/// # use embedded_sdmmc::BlockCount;
263+
/// # use embedded_sdmmc::blocking::BlockCount;
260264
/// assert_eq!(BlockCount::from_bytes(511), BlockCount(1));
261265
/// assert_eq!(BlockCount::from_bytes(512), BlockCount(1));
262266
/// assert_eq!(BlockCount::from_bytes(513), BlockCount(2));

src/fat/bpb.rs renamed to src/inner/fat/bpb.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Boot Parameter Block
22
3-
use crate::{
3+
use super::super::{
44
blockdevice::BlockCount,
55
fat::{FatType, OnDiskDirEntry},
66
};

src/fat/info.rs renamed to src/inner/fat/info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{BlockCount, BlockIdx, ClusterId};
1+
use super::super::{BlockCount, BlockIdx, ClusterId};
22
use byteorder::{ByteOrder, LittleEndian};
33

44
/// Indentifies the supported types of FAT format

src/fat/mod.rs renamed to src/inner/fat/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ pub use volume::{parse_volume, FatVolume, VolumeName};
3333
#[cfg(test)]
3434
mod test {
3535

36+
use super::super::{Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
3637
use super::*;
37-
use crate::{Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
3838

3939
fn parse(input: &str) -> Vec<u8> {
4040
let mut output = Vec::new();

src/fat/ondiskdirentry.rs renamed to src/inner/fat/ondiskdirentry.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Directory Entry as stored on-disk
22
3-
use crate::{fat::FatType, Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
3+
use super::super::{
4+
fat::FatType, Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp,
5+
};
46
use byteorder::{ByteOrder, LittleEndian};
57

68
/// A 32-byte directory entry as stored on-disk in a directory file.

0 commit comments

Comments
 (0)