-
Notifications
You must be signed in to change notification settings - Fork 229
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 asynchronous versions of most embedded-hal traits using GATs #285
Closed
Closed
Changes from 17 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
e736fb5
First attempt at futures module
lachlansneff ff085fa
Fix some of the docs
lachlansneff 7eb5fd1
Add 'unstable-gats' feature to enable futures module
lachlansneff 3a30a33
Add async i2c module
lachlansneff d9d08fa
Remove futures::spi::FullDuplex
lachlansneff 1928f77
Make futures::spi::{Read, Write, ReadWrite, ReadWriteInPlace} traits
lachlansneff 5cdd987
Rename the futures feature to unstable-features
lachlansneff eecf646
Remove commented-out futures::spi::Transactional trait
lachlansneff 6298952
Remove MaybeUninit from futures::spi::ReadWriteInPlace
lachlansneff bac1603
Remove futures::i2c::Transactional and remove required min_type_alias…
lachlansneff 92aa33b
Remove some unncessary bounds from futures::spi traits
lachlansneff 582ebad
Return initialized buffers from method that read into an uninitialize…
lachlansneff a61008b
Update spi trait names
lachlansneff 306b187
Remove MaybeUninit from futures::spi
lachlansneff 92e0da4
Update changelog
lachlansneff 7ebd9c5
Merge branch 'master' into master
lachlansneff b79bf16
Expand the CHANGELOG.md addition
lachlansneff 4d02ea1
Add futures::Delay trait
lachlansneff 41af589
Add futures::digital::AsyncInputPin trait
lachlansneff 48ab3a8
Switch futures::Delay to take core::time::Duration and add futures::d…
lachlansneff 85accbd
Update changelog
lachlansneff eb2ff8a
Fix some docs in the futures module
lachlansneff d9174d2
Respond to feedback
lachlansneff 941c8bb
Change uart interface to read into a slice
lachlansneff 5617082
Mention what happens when the write and read slices in futures::spi::…
lachlansneff c002a23
Add more futures::digital traits
lachlansneff e686e6e
Change some associated future trait type names
lachlansneff 2e16b79
Formatting
lachlansneff 55cbca1
Remove MaybeUninit from futures::i2c
lachlansneff fee1b99
fix typo
lachlansneff 1df5604
Add error associated types to futures::digital traits
lachlansneff 38ba051
Expand names of generic associated future types
lachlansneff File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//! Async I2C API | ||
//! | ||
//! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` | ||
//! marker type parameter. Two implementation of the `AddressMode` exist: | ||
//! `SevenBitAddress` and `TenBitAddress`. | ||
//! | ||
//! Through this marker types it is possible to implement each address mode for | ||
//! the traits independently in `embedded-hal` implementations and device drivers | ||
//! can depend only on the mode that they support. | ||
//! | ||
//! Additionally, the I2C 10-bit address mode has been developed to be fully | ||
//! backwards compatible with the 7-bit address mode. This allows for a | ||
//! software-emulated 10-bit addressing implementation if the address mode | ||
//! is not supported by the hardware. | ||
//! | ||
//! Since 7-bit addressing is the mode of the majority of I2C devices, | ||
//! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. | ||
|
||
use core::{future::Future, mem::MaybeUninit}; | ||
pub use crate::blocking::i2c::{AddressMode, SevenBitAddress, TenBitAddress}; | ||
|
||
/// Async read | ||
pub trait Read<A: AddressMode = SevenBitAddress> { | ||
/// Error type | ||
type Error; | ||
/// The future associated with the `read` method. | ||
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Reads enough bytes from slave with `address` to fill `buffer` | ||
/// | ||
/// # I2C Events (contract) | ||
/// | ||
/// ``` text | ||
/// Master: ST SAD+R MAK MAK ... NMAK SP | ||
/// Slave: SAK B0 B1 ... BN | ||
/// ``` | ||
/// | ||
/// Where | ||
/// | ||
/// - `ST` = start condition | ||
/// - `SAD+R` = slave address followed by bit 1 to indicate reading | ||
/// - `SAK` = slave acknowledge | ||
/// - `Bi` = ith byte of data | ||
/// - `MAK` = master acknowledge | ||
/// - `NMAK` = master no acknowledge | ||
/// - `SP` = stop condition | ||
fn read<'a>(&'a mut self, address: A, read: &'a mut [MaybeUninit<u8>]) -> Self::ReadFuture<'a>; | ||
} | ||
|
||
/// Async write | ||
pub trait Write<A: AddressMode = SevenBitAddress> { | ||
/// Error type | ||
type Error; | ||
/// The future associated with the `write` method. | ||
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes bytes to slave with address `address` | ||
/// | ||
/// # I2C Events (contract) | ||
/// | ||
/// ``` text | ||
/// Master: ST SAD+W B0 B1 ... BN SP | ||
/// Slave: SAK SAK SAK ... SAK | ||
/// ``` | ||
/// | ||
/// Where | ||
/// | ||
/// - `ST` = start condition | ||
/// - `SAD+W` = slave address followed by bit 0 to indicate writing | ||
/// - `SAK` = slave acknowledge | ||
/// - `Bi` = ith byte of data | ||
/// - `SP` = stop condition | ||
fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a>; | ||
} | ||
|
||
/// Async write + read | ||
pub trait WriteRead<A: AddressMode = SevenBitAddress> { | ||
/// Error type | ||
type Error; | ||
/// The future associated with the `write_read` method. | ||
type WriteReadFuture<'a>: Future<Output = Result<&'a [u8], Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes bytes to slave with address `address` and then reads enough bytes to fill `read` *in a | ||
/// single transaction*. The returned buffer is the initialized `read` buffer. | ||
/// | ||
/// # I2C Events (contract) | ||
/// | ||
/// ``` text | ||
/// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP | ||
/// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN | ||
/// ``` | ||
/// | ||
/// Where | ||
/// | ||
/// - `ST` = start condition | ||
/// - `SAD+W` = slave address followed by bit 0 to indicate writing | ||
/// - `SAK` = slave acknowledge | ||
/// - `Oi` = ith outgoing byte of data | ||
/// - `SR` = repeated start condition | ||
/// - `SAD+R` = slave address followed by bit 1 to indicate reading | ||
/// - `Ii` = ith incoming byte of data | ||
/// - `MAK` = master acknowledge | ||
/// - `NMAK` = master no acknowledge | ||
/// - `SP` = stop condition | ||
fn write_read<'a>( | ||
&'a mut self, | ||
address: A, | ||
write: &'a [u8], | ||
read: &'a mut [MaybeUninit<u8>], | ||
) -> Self::WriteReadFuture<'a>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//! Asynchronous APIs | ||
//! | ||
//! This traits use `core::future::Future` and generic associated types. | ||
|
||
pub mod i2c; | ||
pub mod rng; | ||
pub mod serial; | ||
pub mod spi; | ||
pub mod timer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//! Random Number Generator Interface | ||
|
||
use core::{future::Future, mem::MaybeUninit}; | ||
|
||
/// Nonblocking stream of random bytes. | ||
pub trait Read { | ||
/// An enumeration of RNG errors. | ||
/// | ||
/// For infallible implementations, will be `Infallible` | ||
type Error; | ||
|
||
/// The future associated with the `read` method. | ||
type ReadFuture<'a>: Future<Output=Result<&'a [u8], Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Get a number of bytes from the RNG. The returned buffer is the initialized `buf`. | ||
fn read<'a>(&'a mut self, buf: &'a mut [MaybeUninit<u8>]) -> Self::ReadFuture<'a>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
//! Serial interface | ||
|
||
use core::future::Future; | ||
|
||
/// Read half of a serial interface | ||
/// | ||
/// Some serial interfaces support different data sizes (8 bits, 9 bits, etc.); | ||
/// This can be encoded in this trait via the `Word` type parameter. | ||
pub trait Read<Word> { | ||
/// Read error | ||
type Error; | ||
|
||
/// The future associated with the `read` method. | ||
type ReadFuture<'a>: Future<Output=Result<Word, Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Reads a single word from the serial interface | ||
fn read<'a>(&'a mut self) -> Self::ReadFuture<'a>; | ||
lachlansneff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// Write half of a serial interface | ||
pub trait Write<Word> { | ||
/// Write error | ||
type Error; | ||
|
||
/// The future associated with the `write` method. | ||
type WriteFuture<'a>: Future<Output=Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// The future associated with the `flush` method. | ||
type FlushFuture<'a>: Future<Output=Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes a single word to the serial interface | ||
fn write<'a>(&'a mut self, word: Word) -> Self::WriteFuture<'a>; | ||
|
||
/// Ensures that none of the previously written words are still buffered | ||
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//! Serial Peripheral Interface | ||
|
||
use core::future::Future; | ||
|
||
/// Async transfer | ||
pub trait Transfer<W: 'static> { | ||
/// Error type | ||
type Error; | ||
|
||
/// Associated future for the `transfer` method. | ||
type TransferFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes `words` to the slave from the `write` buffer. Puts the words returned in the `read` buffer. | ||
lachlansneff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// This method uses separate `write` and `read` buffers. | ||
fn transfer<'a>(&'a mut self, write: &'a [W], read: &'a mut [W]) -> Self::TransferFuture<'a>; | ||
} | ||
|
||
/// Async transfer in place. | ||
pub trait TransferInPlace<W: 'static> { | ||
/// Error type | ||
type Error; | ||
|
||
/// Associated future for the `transfer_inplace` method. | ||
type TransferInPlaceFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes `words` to the slave from the `readwrite` buffer and reads words into the same buffer. | ||
/// This method uses a single `readwrite` buffer. | ||
/// | ||
/// The returned buffer is the initialized `readwrite` buffer. | ||
fn transfer_inplace<'a>(&'a mut self, readwrite: &'a mut [W]) -> Self::TransferInPlaceFuture<'a>; | ||
lachlansneff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// Async write | ||
pub trait Write<W> { | ||
/// Error type | ||
type Error; | ||
|
||
/// Associated future for the `write` method. | ||
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Writes `words` to the slave, ignoring all the incoming words | ||
fn write<'a>(&'a mut self, words: &'a [W]) -> Self::WriteFuture<'a>; | ||
} | ||
|
||
/// Async read | ||
pub trait Read<W: 'static> { | ||
/// Error type | ||
type Error; | ||
|
||
/// Associated future for the `read` method. | ||
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Reads words from the slave without specifying any data to write. | ||
/// The SPI hardware will send data, though what data it sends is not defined | ||
/// by this trait. Some hardware can configure what values (e.g. 0x00, 0xFF), some cannot. | ||
/// | ||
/// The returned buffer is the initialized `words` buffer. | ||
fn read<'a>(&'a mut self, words: &'a mut [W]) -> Self::ReadFuture<'a>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
//! Timers | ||
|
||
use core::future::Future; | ||
|
||
/// A count down timer | ||
/// | ||
/// # Contract | ||
/// | ||
/// - `self.start(count); block!(self.wait());` MUST block for AT LEAST the time specified by | ||
lachlansneff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// `count`. | ||
/// | ||
/// *Note* that the implementer doesn't necessarily have to be a *downcounting* timer; it could also | ||
/// be an *upcounting* timer as long as the above contract is upheld. | ||
/// | ||
/// # Examples | ||
/// | ||
/// You can use this timer to create delays | ||
/// | ||
/// ``` | ||
/// extern crate embedded_hal as hal; | ||
/// #[macro_use(block)] | ||
/// extern crate nb; | ||
/// | ||
/// use hal::prelude::*; | ||
/// | ||
/// fn main() { | ||
/// let mut led: Led = { | ||
/// // .. | ||
/// # Led | ||
/// }; | ||
/// let mut timer: Timer6 = { | ||
/// // .. | ||
/// # Timer6 | ||
/// }; | ||
/// | ||
/// Led.on(); | ||
/// timer.start(1.s()).unwrap(); | ||
/// block!(timer.wait()); // blocks for 1 second | ||
/// Led.off(); | ||
/// } | ||
/// | ||
/// # use core::convert::Infallible; | ||
/// # struct Seconds(u32); | ||
/// # trait U32Ext { fn s(self) -> Seconds; } | ||
/// # impl U32Ext for u32 { fn s(self) -> Seconds { Seconds(self) } } | ||
/// # struct Led; | ||
/// # impl Led { | ||
/// # pub fn off(&mut self) {} | ||
/// # pub fn on(&mut self) {} | ||
/// # } | ||
/// # struct Timer6; | ||
/// # impl hal::nb::timer::CountDown for Timer6 { | ||
/// # type Error = Infallible; | ||
/// # type Time = Seconds; | ||
/// # fn start<T>(&mut self, _: T) -> Result<(), Self::Error> where T: Into<Seconds> { Ok(()) } | ||
/// # fn wait(&mut self) -> ::nb::Result<(), Infallible> { Ok(()) } | ||
/// # } | ||
/// ``` | ||
pub trait CountDown { | ||
/// An enumeration of `CountDown` errors. | ||
/// | ||
/// For infallible implementations, will be `Infallible` | ||
type Error; | ||
|
||
/// The unit of time used by this timer | ||
type Time; | ||
|
||
/// The future associated with the `wait` method. | ||
type WaitFuture<'a>: Future<Output=Result<(), Self::Error>> + 'a | ||
where | ||
Self: 'a; | ||
|
||
/// Starts a new count down | ||
fn start<T>(&mut self, count: T) -> Result<(), Self::Error> | ||
where | ||
T: Into<Self::Time>; | ||
|
||
/// Asyncronously waits until the count down finishes. | ||
/// | ||
/// # Contract | ||
/// | ||
/// - If `Self: Periodic`, the timer will start a new count down right after the last one | ||
/// finishes. | ||
/// - Otherwise the behavior of calling `wait` after the last call returned `Ok` is UNSPECIFIED. | ||
/// Implementers are suggested to panic on this scenario to signal a programmer error. | ||
fn wait<'a>(&'a mut self) -> Self::WaitFuture<'a>; | ||
} | ||
|
||
/// Marker trait that indicates that a timer is periodic | ||
pub trait Periodic {} | ||
|
||
/// Trait for cancelable countdowns. | ||
pub trait Cancel: CountDown { | ||
/// Tries to cancel this countdown. | ||
/// | ||
/// # Errors | ||
/// | ||
/// An error will be returned if the countdown has already been canceled or was never started. | ||
/// An error is also returned if the countdown is not `Periodic` and has already expired. | ||
fn cancel(&mut self) -> Result<(), Self::Error>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole
futures
approach should be documented here. Including examples, executors, waking, etc.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with those — that being said I don't think it's quite sorted out how HALs are going to support this. I think they definitely can (and will), but it's going to require some thought as to how HALs should install interrupt handlers and whatnot for async operations to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. There is no "one true answer" as for how all operations should concert in all situations. However, the different alternatives and considerations about how to implement and consume these traits as well as what the expectations are about how the operations will run should be explained here.