Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add async support using bisync crate #176

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic

### Changed

- __Breaking Change__: Existing API moved into `blocking` module. Adjust your imports from `embedded_sdmmc` to `embedded_sdmmc::blocking` to keep old code building.
- __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.
- __Breaking Change__: The `VolumeManager`, `File`, `Directory` and `Volume` no longer implement `Send` or `Sync.
- `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.
Expand All @@ -17,6 +18,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic

### Added

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

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ version = "0.8.0"
rust-version = "1.76"

[dependencies]
bisync = "0.3.0"
byteorder = {version = "1", default-features = false}
defmt = {version = "0.3", optional = true}
embassy-futures = "0.1.1"
embedded-hal = "1.0.0"
embedded-hal-async = "1.0.0"
embedded-io = "0.6.1"
embedded-io-async = "0.6.1"
heapless = "^0.8"
log = {version = "0.4", default-features = false, optional = true}

Expand Down
4 changes: 2 additions & 2 deletions examples/append_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use linux::*;

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

use embedded_sdmmc::{Error, Mode, VolumeIdx};
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};

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

fn main() -> Result<(), Error<std::io::Error>> {
env_logger::init();
Expand Down
4 changes: 2 additions & 2 deletions examples/big_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
mod linux;
use linux::*;

use embedded_sdmmc::{Error, Mode, VolumeIdx};
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};

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

fn main() -> Result<(), Error<std::io::Error>> {
env_logger::init();
Expand Down
4 changes: 2 additions & 2 deletions examples/create_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use linux::*;

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

use embedded_sdmmc::{Error, Mode, VolumeIdx};
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};

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

fn main() -> Result<(), Error<std::io::Error>> {
env_logger::init();
Expand Down
4 changes: 2 additions & 2 deletions examples/delete_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use linux::*;

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

use embedded_sdmmc::{Error, VolumeIdx};
use embedded_sdmmc::blocking::{Error, VolumeIdx};

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

fn main() -> Result<(), Error<std::io::Error>> {
env_logger::init();
Expand Down
2 changes: 1 addition & 1 deletion examples/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Helpers for using embedded-sdmmc on Linux

use chrono::Timelike;
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp};
use embedded_sdmmc::blocking::{Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp};
use std::cell::RefCell;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
Expand Down
8 changes: 4 additions & 4 deletions examples/list_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@
mod linux;
use linux::*;

use embedded_sdmmc::{ShortFileName, VolumeIdx};
use embedded_sdmmc::blocking::{ShortFileName, VolumeIdx};

type Error = embedded_sdmmc::Error<std::io::Error>;
type Error = embedded_sdmmc::blocking::Error<std::io::Error>;

type Directory<'a> = embedded_sdmmc::Directory<'a, LinuxBlockDevice, Clock, 8, 4, 4>;
type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;
type Directory<'a> = embedded_sdmmc::blocking::Directory<'a, LinuxBlockDevice, Clock, 8, 4, 4>;
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 4, 4>;

fn main() -> Result<(), Error> {
env_logger::init();
Expand Down
4 changes: 2 additions & 2 deletions examples/read_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ use linux::*;

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

use embedded_sdmmc::{Error, Mode, VolumeIdx};
use embedded_sdmmc::blocking::{Error, Mode, VolumeIdx};

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

fn main() -> Result<(), Error<std::io::Error>> {
env_logger::init();
Expand Down
4 changes: 2 additions & 2 deletions examples/readme_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use core::cell::RefCell;

use embedded_sdmmc::{Error, SdCardError, TimeSource, Timestamp};
use embedded_sdmmc::blocking::{Error, SdCardError, TimeSource, Timestamp};

pub struct DummyCsPin;

Expand Down Expand Up @@ -121,7 +121,7 @@ fn main() -> Result<(), MyError> {
let time_source = FakeTimesource();
// END Fake stuff that will be replaced with real peripherals

use embedded_sdmmc::{Mode, SdCard, VolumeIdx, VolumeManager};
use embedded_sdmmc::blocking::{Mode, SdCard, VolumeIdx, VolumeManager};
// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
let sdcard = SdCard::new(sdmmc_spi, delay);
// Get the card size (this also triggers card initialisation because it's not been done yet)
Expand Down
6 changes: 3 additions & 3 deletions examples/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@

use std::{cell::RefCell, io::prelude::*};

use embedded_sdmmc::{
use embedded_sdmmc::blocking::{
Error as EsError, LfnBuffer, Mode, RawDirectory, RawVolume, ShortFileName, VolumeIdx,
};

type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>;
type Directory<'a> = embedded_sdmmc::Directory<'a, LinuxBlockDevice, Clock, 8, 8, 4>;
type VolumeManager = embedded_sdmmc::blocking::VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>;
type Directory<'a> = embedded_sdmmc::blocking::Directory<'a, LinuxBlockDevice, Clock, 8, 8, 4>;

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

Expand Down
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions src/common/filesystem/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub(crate) mod attributes;
pub(crate) mod cluster;
pub(crate) mod timestamp;
File renamed without changes.
4 changes: 4 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Common modules that have no difference between blocking and asynchronous code

pub(crate) mod filesystem;
pub(crate) mod sdcard;
1 change: 1 addition & 0 deletions src/common/sdcard/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod proto;
File renamed without changes.
30 changes: 17 additions & 13 deletions src/blockdevice.rs → src/inner/blockdevice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//! Generic code for handling block devices, such as types for identifying
//! a particular block on a block device by its index.

use super::super::bisync;

/// A standard 512 byte block (also known as a sector).
///
/// IBM PC formatted 5.25" and 3.5" floppy disks, IDE/SATA Hard Drives up to
Expand Down Expand Up @@ -75,15 +77,16 @@ impl Default for Block {

/// A block device - a device which can read and write blocks (or
/// sectors). Only supports devices which are <= 2 TiB in size.
#[bisync]
pub trait BlockDevice {
/// The errors that the `BlockDevice` can return. Must be debug formattable.
type Error: core::fmt::Debug;
/// Read one or more blocks, starting at the given block index.
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
async fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
/// Write one or more blocks, starting at the given block index.
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
async fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
/// Determine how many blocks this device can hold.
fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
async fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
}

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

#[bisync]
impl<D> BlockCache<D>
where
D: BlockDevice,
Expand All @@ -110,42 +114,42 @@ where
}

/// Read a block, and return a reference to it.
pub fn read(&mut self, block_idx: BlockIdx) -> Result<&Block, D::Error> {
pub async fn read(&mut self, block_idx: BlockIdx) -> Result<&Block, D::Error> {
if self.block_idx != Some(block_idx) {
self.block_idx = None;
self.block_device.read(&mut self.block, block_idx)?;
self.block_device.read(&mut self.block, block_idx).await?;
self.block_idx = Some(block_idx);
}
Ok(&self.block[0])
}

/// Read a block, and return a reference to it.
pub fn read_mut(&mut self, block_idx: BlockIdx) -> Result<&mut Block, D::Error> {
pub async fn read_mut(&mut self, block_idx: BlockIdx) -> Result<&mut Block, D::Error> {
if self.block_idx != Some(block_idx) {
self.block_idx = None;
self.block_device.read(&mut self.block, block_idx)?;
self.block_device.read(&mut self.block, block_idx).await?;
self.block_idx = Some(block_idx);
}
Ok(&mut self.block[0])
}

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

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

Expand Down Expand Up @@ -256,7 +260,7 @@ impl BlockCount {
/// How many blocks are required to hold this many bytes.
///
/// ```
/// # use embedded_sdmmc::BlockCount;
/// # use embedded_sdmmc::blocking::BlockCount;
/// assert_eq!(BlockCount::from_bytes(511), BlockCount(1));
/// assert_eq!(BlockCount::from_bytes(512), BlockCount(1));
/// assert_eq!(BlockCount::from_bytes(513), BlockCount(2));
Expand Down
2 changes: 1 addition & 1 deletion src/fat/bpb.rs → src/inner/fat/bpb.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Boot Parameter Block

use crate::{
use super::super::{
blockdevice::BlockCount,
fat::{FatType, OnDiskDirEntry},
};
Expand Down
2 changes: 1 addition & 1 deletion src/fat/info.rs → src/inner/fat/info.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{BlockCount, BlockIdx, ClusterId};
use super::super::{BlockCount, BlockIdx, ClusterId};
use byteorder::{ByteOrder, LittleEndian};

/// Indentifies the supported types of FAT format
Expand Down
2 changes: 1 addition & 1 deletion src/fat/mod.rs → src/inner/fat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ pub use volume::{parse_volume, FatVolume, VolumeName};
#[cfg(test)]
mod test {

use super::super::{Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
use super::*;
use crate::{Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};

fn parse(input: &str) -> Vec<u8> {
let mut output = Vec::new();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Directory Entry as stored on-disk

use crate::{fat::FatType, Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
use super::super::{
fat::FatType, Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp,
};
use byteorder::{ByteOrder, LittleEndian};

/// A 32-byte directory entry as stored on-disk in a directory file.
Expand Down
Loading