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

Update embedded hal to 1.0.0 #106

Merged
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
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ version = "0.6.0"
[dependencies]
byteorder = {version = "1", default-features = false}
defmt = {version = "0.3", optional = true}
embedded-hal = "0.2.3"
embedded-hal = "1.0.0"
heapless = "0.7"
log = {version = "0.4", default-features = false, optional = true}

[dev-dependencies]
env_logger = "0.9"
hex-literal = "0.3"
env_logger = "0.10.0"
hex-literal = "0.4.1"
flate2 = "1.0"
sha2 = "0.10"
chrono = "0.4"
embedded-hal-bus = "0.1.0"

[features]
default = ["log"]
Expand Down
52 changes: 38 additions & 14 deletions examples/readme_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,45 @@
//! We add enough stuff to make it compile, but it won't run because our fake
//! SPI doesn't do any replies.

struct FakeSpi();
use core::cell::RefCell;

impl embedded_hal::blocking::spi::Transfer<u8> for FakeSpi {
use embedded_sdmmc::sdcard::DummyCsPin;

struct FakeSpiBus();

impl embedded_hal::spi::ErrorType for FakeSpiBus {
type Error = core::convert::Infallible;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
Ok(words)
}
}

impl embedded_hal::blocking::spi::Write<u8> for FakeSpi {
type Error = core::convert::Infallible;
fn write(&mut self, _words: &[u8]) -> Result<(), Self::Error> {
impl embedded_hal::spi::SpiBus<u8> for FakeSpiBus {
fn read(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
Ok(())
}

fn write(&mut self, _: &[u8]) -> Result<(), Self::Error> {
Ok(())
}

fn transfer(&mut self, _: &mut [u8], _: &[u8]) -> Result<(), Self::Error> {
Ok(())
}

fn transfer_in_place(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
Ok(())
}

fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}

struct FakeCs();

impl embedded_hal::digital::v2::OutputPin for FakeCs {
impl embedded_hal::digital::ErrorType for FakeCs {
type Error = core::convert::Infallible;
}

impl embedded_hal::digital::OutputPin for FakeCs {
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(())
}
Expand All @@ -32,11 +51,12 @@ impl embedded_hal::digital::v2::OutputPin for FakeCs {
}
}

#[derive(Clone, Copy)]
struct FakeDelayer();

impl embedded_hal::blocking::delay::DelayUs<u8> for FakeDelayer {
fn delay_us(&mut self, us: u8) {
std::thread::sleep(std::time::Duration::from_micros(u64::from(us)));
impl embedded_hal::delay::DelayNs for FakeDelayer {
fn delay_ns(&mut self, ns: u32) {
std::thread::sleep(std::time::Duration::from_nanos(u64::from(ns)));
}
}

Expand Down Expand Up @@ -74,10 +94,14 @@ impl From<embedded_sdmmc::SdCardError> for Error {
}

fn main() -> Result<(), Error> {
let sdmmc_spi = FakeSpi();
let sdmmc_cs = FakeCs();
// BEGIN Fake stuff that will be replaced with real peripherals
let spi_bus = RefCell::new(FakeSpiBus());
jonathanpallant marked this conversation as resolved.
Show resolved Hide resolved
let delay = FakeDelayer();
let sdmmc_spi = embedded_hal_bus::spi::RefCellDevice::new(&spi_bus, DummyCsPin, delay);
let sdmmc_cs = FakeCs();
let time_source = FakeTimesource();
// END Fake stuff that will be replaced with real peripherals

// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delay);
// Get the card size (this also triggers card initialisation because it's not been done yet)
Expand Down
71 changes: 24 additions & 47 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,32 @@
//! couldn't work with a USB Thumb Drive, but we only supply a `BlockDevice`
//! suitable for reading SD and SDHC cards over SPI.
//!
//! ```rust,no_run
//! # struct DummySpi;
//! # struct DummyCsPin;
//! # struct DummyUart;
//! # struct DummyTimeSource;
//! # struct DummyDelayer;
//! # impl embedded_hal::blocking::spi::Transfer<u8> for DummySpi {
//! # type Error = ();
//! # fn transfer<'w>(&mut self, data: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { Ok(&[0]) }
//! # }
//! # impl embedded_hal::blocking::spi::Write<u8> for DummySpi {
//! # type Error = ();
//! # fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> { Ok(()) }
//! # }
//! # impl embedded_hal::digital::v2::OutputPin for DummyCsPin {
//! # type Error = ();
//! # fn set_low(&mut self) -> Result<(), ()> { Ok(()) }
//! # fn set_high(&mut self) -> Result<(), ()> { Ok(()) }
//! # }
//! # impl embedded_sdmmc::TimeSource for DummyTimeSource {
//! # fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { embedded_sdmmc::Timestamp::from_fat(0, 0) }
//! # }
//! # impl embedded_hal::blocking::delay::DelayUs<u8> for DummyDelayer {
//! # fn delay_us(&mut self, us: u8) {}
//! # }
//! # impl std::fmt::Write for DummyUart { fn write_str(&mut self, s: &str) -> std::fmt::Result { Ok(()) } }
//! # use std::fmt::Write;
//! # use embedded_sdmmc::VolumeManager;
//! # fn main() -> Result<(), embedded_sdmmc::Error<embedded_sdmmc::SdCardError>> {
//! # let mut sdmmc_spi = DummySpi;
//! # let mut sdmmc_cs = DummyCsPin;
//! # let time_source = DummyTimeSource;
//! # let delayer = DummyDelayer;
//! let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delayer);
//! println!("Card size is {} bytes", sdcard.num_bytes()?);
//! let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
//! let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
//! println!("Volume 0: {:?}", volume0);
//! let mut root_dir = volume0.open_root_dir()?;
//! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)?;
//! while !my_file.is_eof() {
//! let mut buffer = [0u8; 32];
//! let num_read = my_file.read(&mut buffer)?;
//! for b in &buffer[0..num_read] {
//! print!("{}", *b as char);
//! ```rust
//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager};
//!
//! fn example<S, CS, D, T>(spi: S, cs: CS, delay: D, ts: T) -> Result<(), Error<SdCardError>>
//! where
//! S: embedded_hal::spi::SpiDevice,
//! CS: embedded_hal::digital::OutputPin,
//! D: embedded_hal::delay::DelayNs,
//! T: TimeSource,
//! {
//! let sdcard = SdCard::new(spi, cs, delay);
//! println!("Card size is {} bytes", sdcard.num_bytes()?);
//! let mut volume_mgr = VolumeManager::new(sdcard, ts);
//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0))?;
//! println!("Volume 0: {:?}", volume0);
//! let mut root_dir = volume0.open_root_dir()?;
//! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", Mode::ReadOnly)?;
//! while !my_file.is_eof() {
//! let mut buffer = [0u8; 32];
//! let num_read = my_file.read(&mut buffer)?;
//! for b in &buffer[0..num_read] {
//! print!("{}", *b as char);
//! }
//! }
//! Ok(())
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Features
Expand Down
110 changes: 75 additions & 35 deletions src/sdcard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,74 @@ use crate::{debug, warn};
// Types and Implementations
// ****************************************************************************

/// A dummy "CS pin" that does nothing when set high or low.
///
/// Should be used when constructing an [`SpiDevice`] implementation for use with [`SdCard`].
///
/// Let the [`SpiDevice`] use this dummy CS pin that does not actually do anything, and pass the
/// card's real CS pin to [`SdCard`]'s constructor. This allows the driver to have more
/// fine-grained control of how the CS pin is managed than is allowed by default using the
/// [`SpiDevice`] trait, which is needed to implement the SD/MMC SPI communication spec correctly.
///
/// If you're not sure how to get a [`SpiDevice`], you may use one of the implementations
/// in the [`embedded-hal-bus`] crate, providing a wrapped version of your platform's HAL-provided
/// [`SpiBus`] and [`DelayNs`] as well as our [`DummyCsPin`] in the constructor.
///
/// [`SpiDevice`]: embedded_hal::spi::SpiDevice
/// [`SpiBus`]: embedded_hal::spi::SpiBus
/// [`DelayNs`]: embedded_hal::delay::DelayNs
/// [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus
pub struct DummyCsPin;

impl embedded_hal::digital::ErrorType for DummyCsPin {
type Error = core::convert::Infallible;
}

impl embedded_hal::digital::OutputPin for DummyCsPin {
#[inline(always)]
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(())
}

#[inline(always)]
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}

/// Represents an SD Card on an SPI bus.
///
/// Built from an SPI peripheral and a Chip Select pin. We need Chip Select to
/// be separate so we can clock out some bytes without Chip Select asserted
/// (which "flushes the SD cards registers" according to the spec).
/// Built from an [`SpiDevice`] implementation and a Chip Select pin.
/// Unfortunately, We need control of the chip select pin separately from the [`SpiDevice`]
/// implementation so we can clock out some bytes without Chip Select asserted
/// (which is necessary to make the SD card actually release the Spi bus after performing
/// operations on it, according to the spec). To support this, we provide [`DummyCsPin`]
/// which should be provided to your chosen [`SpiDevice`] implementation rather than the card's
/// actual CS pin. Then provide the actual CS pin to [`SdCard`]'s constructor.
///
/// All the APIs take `&self` - mutability is handled using an inner `RefCell`.
///
/// [`SpiDevice`]: embedded_hal::spi::SpiDevice
pub struct SdCard<SPI, CS, DELAYER>
where
SPI: embedded_hal::blocking::spi::Transfer<u8> + embedded_hal::blocking::spi::Write<u8>,
CS: embedded_hal::digital::v2::OutputPin,
<SPI as embedded_hal::blocking::spi::Transfer<u8>>::Error: core::fmt::Debug,
<SPI as embedded_hal::blocking::spi::Write<u8>>::Error: core::fmt::Debug,
DELAYER: embedded_hal::blocking::delay::DelayUs<u8>,
SPI: embedded_hal::spi::SpiDevice<u8>,
CS: embedded_hal::digital::OutputPin,
DELAYER: embedded_hal::delay::DelayNs,
{
inner: RefCell<SdCardInner<SPI, CS, DELAYER>>,
}

impl<SPI, CS, DELAYER> SdCard<SPI, CS, DELAYER>
where
SPI: embedded_hal::blocking::spi::Transfer<u8> + embedded_hal::blocking::spi::Write<u8>,
CS: embedded_hal::digital::v2::OutputPin,
<SPI as embedded_hal::blocking::spi::Transfer<u8>>::Error: core::fmt::Debug,
<SPI as embedded_hal::blocking::spi::Write<u8>>::Error: core::fmt::Debug,
DELAYER: embedded_hal::blocking::delay::DelayUs<u8>,
SPI: embedded_hal::spi::SpiDevice<u8>,
CS: embedded_hal::digital::OutputPin,
DELAYER: embedded_hal::delay::DelayNs,
{
/// Create a new SD/MMC Card driver using a raw SPI interface.
///
/// See the docs of the [`SdCard`] struct for more information about
/// how to construct the needed `SPI` and `CS` types.
///
/// The card will not be initialised at this time. Initialisation is
/// deferred until a method is called on the object.
///
Expand All @@ -59,6 +99,9 @@ where

/// Construct a new SD/MMC Card driver, using a raw SPI interface and the given options.
///
/// See the docs of the [`SdCard`] struct for more information about
/// how to construct the needed `SPI` and `CS` types.
///
/// The card will not be initialised at this time. Initialisation is
/// deferred until a method is called on the object.
pub fn new_with_options(
Expand Down Expand Up @@ -152,11 +195,9 @@ where

impl<SPI, CS, DELAYER> BlockDevice for SdCard<SPI, CS, DELAYER>
where
SPI: embedded_hal::blocking::spi::Transfer<u8> + embedded_hal::blocking::spi::Write<u8>,
CS: embedded_hal::digital::v2::OutputPin,
<SPI as embedded_hal::blocking::spi::Transfer<u8>>::Error: core::fmt::Debug,
<SPI as embedded_hal::blocking::spi::Write<u8>>::Error: core::fmt::Debug,
DELAYER: embedded_hal::blocking::delay::DelayUs<u8>,
SPI: embedded_hal::spi::SpiDevice<u8>,
CS: embedded_hal::digital::OutputPin,
DELAYER: embedded_hal::delay::DelayNs,
{
type Error = Error;

Expand Down Expand Up @@ -205,11 +246,9 @@ where
/// All the APIs required `&mut self`.
struct SdCardInner<SPI, CS, DELAYER>
where
SPI: embedded_hal::blocking::spi::Transfer<u8> + embedded_hal::blocking::spi::Write<u8>,
CS: embedded_hal::digital::v2::OutputPin,
<SPI as embedded_hal::blocking::spi::Transfer<u8>>::Error: core::fmt::Debug,
<SPI as embedded_hal::blocking::spi::Write<u8>>::Error: core::fmt::Debug,
DELAYER: embedded_hal::blocking::delay::DelayUs<u8>,
SPI: embedded_hal::spi::SpiDevice<u8>,
CS: embedded_hal::digital::OutputPin,
DELAYER: embedded_hal::delay::DelayNs,
{
spi: SPI,
cs: CS,
Expand All @@ -220,11 +259,9 @@ where

impl<SPI, CS, DELAYER> SdCardInner<SPI, CS, DELAYER>
where
SPI: embedded_hal::blocking::spi::Transfer<u8> + embedded_hal::blocking::spi::Write<u8>,
CS: embedded_hal::digital::v2::OutputPin,
<SPI as embedded_hal::blocking::spi::Transfer<u8>>::Error: core::fmt::Debug,
<SPI as embedded_hal::blocking::spi::Write<u8>>::Error: core::fmt::Debug,
DELAYER: embedded_hal::blocking::delay::DelayUs<u8>,
SPI: embedded_hal::spi::SpiDevice<u8>,
CS: embedded_hal::digital::OutputPin,
DELAYER: embedded_hal::delay::DelayNs,
{
/// Read one or more blocks, starting at the given block index.
fn read(&mut self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Error> {
Expand Down Expand Up @@ -583,21 +620,24 @@ where

/// Send one byte and receive one byte over the SPI bus.
fn transfer_byte(&mut self, out: u8) -> Result<u8, Error> {
let mut read_buf = [0u8; 1];
self.spi
.transfer(&mut [out])
.map(|b| b[0])
.map_err(|_e| Error::Transport)
.transfer(&mut read_buf, &[out])
.map_err(|_| Error::Transport)?;
Ok(read_buf[0])
}

/// Send mutiple bytes and ignore what comes back over the SPI bus.
/// Send multiple bytes and ignore what comes back over the SPI bus.
fn write_bytes(&mut self, out: &[u8]) -> Result<(), Error> {
self.spi.write(out).map_err(|_e| Error::Transport)?;
Ok(())
}

/// Send multiple bytes and replace them with what comes back over the SPI bus.
fn transfer_bytes(&mut self, in_out: &mut [u8]) -> Result<(), Error> {
self.spi.transfer(in_out).map_err(|_e| Error::Transport)?;
self.spi
.transfer_in_place(in_out)
.map_err(|_e| Error::Transport)?;
Ok(())
}

Expand Down Expand Up @@ -689,7 +729,7 @@ pub enum CardType {
/// Uses byte-addressing internally, so limited to 2GiB in size.
SD2,
/// An high-capacity 'SDHC' Card.
///
///
/// Uses block-addressing internally to support capacities above 2GiB.
SDHC,
}
Expand Down Expand Up @@ -753,7 +793,7 @@ impl Delay {
/// `Ok(())`.
fn delay<T>(&mut self, delayer: &mut T, err: Error) -> Result<(), Error>
where
T: embedded_hal::blocking::delay::DelayUs<u8>,
T: embedded_hal::delay::DelayNs,
{
if self.retries_left == 0 {
Err(err)
Expand Down