Skip to content

Commit

Permalink
generic: usart: Introduce a type-parameter for orphan circumvention
Browse files Browse the repository at this point in the history
Because HAL crates neither own the `UsartOps` trait nor the `USARTn`
instance, they are not allowed to implement it for the type.  However,
the orphan rules allow us to deal with this by adding a generic
parameter to `UsartOps` which is local to the HAL crate.

The new `H` parameter serves exactly this purpose and nothing more.
A HAL should define a type and use it for `H` in all HAL
implementations.  Ideally, it should also export type-aliases for all
types from `avr-hal-generic` with the `H` parameter already substituted.
  • Loading branch information
Rahix committed Mar 3, 2021
1 parent 5dfb734 commit 9c33514
Showing 1 changed file with 40 additions and 20 deletions.
60 changes: 40 additions & 20 deletions avr-hal-generic/src/usart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub enum Event {
/// This trait defines the common interface for all USART peripheral variants. It is used as an
/// intermediate abstraction ontop of which the [`Usart`] API is built. **Prefer using the
/// [`Usart`] API instead of this trait.**
pub trait UsartOps<RX, TX> {
pub trait UsartOps<H, RX, TX> {
/// Enable & initialize this USART peripheral to the given baudrate.
///
/// **Warning**: This is a low-level method and should not be called directly from user code.
Expand Down Expand Up @@ -219,14 +219,15 @@ pub trait UsartOps<RX, TX> {
/// ufmt::uwriteln!(&mut serial, "Got {}!\r", b).void_unwrap();
/// }
/// ```
pub struct Usart<USART: UsartOps<RX, TX>, RX, TX, CLOCK> {
pub struct Usart<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
p: USART,
rx: RX,
tx: TX,
_clock: marker::PhantomData<CLOCK>,
_h: marker::PhantomData<H>,
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> Usart<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> Usart<H, USART, RX, TX, CLOCK> {
/// Initialize a USART peripheral on the given pins.
///
/// Note that the RX and TX pins are hardwired for each USART peripheral and you *must* pass
Expand All @@ -237,6 +238,7 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> Usart<USART, RX, TX, CLOCK> {
rx,
tx,
_clock: marker::PhantomData,
_h: marker::PhantomData,
};
usart.p.raw_init(baudrate);
usart
Expand Down Expand Up @@ -284,27 +286,29 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> Usart<USART, RX, TX, CLOCK> {
pub fn split(
self,
) -> (
UsartReader<USART, RX, TX, CLOCK>,
UsartWriter<USART, RX, TX, CLOCK>,
UsartReader<H, USART, RX, TX, CLOCK>,
UsartWriter<H, USART, RX, TX, CLOCK>,
) {
(
UsartReader {
p: unsafe { core::ptr::read(&self.p) },
rx: self.rx,
_tx: marker::PhantomData,
_clock: marker::PhantomData,
_h: marker::PhantomData,
},
UsartWriter {
p: self.p,
tx: self.tx,
_rx: marker::PhantomData,
_clock: marker::PhantomData,
_h: marker::PhantomData,
},
)
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USART, RX, TX, CLOCK> {
type Error = void::Void;

fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
Expand All @@ -315,8 +319,8 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<USART, RX, T
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
for Usart<USART, RX, TX, CLOCK>
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
for Usart<H, USART, RX, TX, CLOCK>
{
type Error = void::Void;

Expand All @@ -329,7 +333,9 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8> for Usart<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
for Usart<H, USART, RX, TX, CLOCK>
{
type Error = void::Void;

fn read(&mut self) -> nb::Result<u8, Self::Error> {
Expand All @@ -344,11 +350,12 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8> for Usart<USA
///
/// The writer half most notably implements [`embedded_hal::serial::Write`] and [`ufmt::uWrite`]
/// for transmitting data.
pub struct UsartWriter<USART: UsartOps<RX, TX>, RX, TX, CLOCK> {
pub struct UsartWriter<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
p: USART,
tx: TX,
_rx: marker::PhantomData<RX>,
_clock: marker::PhantomData<CLOCK>,
_h: marker::PhantomData<H>,
}

/// Reader half of a [`Usart`] peripheral.
Expand All @@ -357,38 +364,49 @@ pub struct UsartWriter<USART: UsartOps<RX, TX>, RX, TX, CLOCK> {
/// concurrently receiving and transmitting data from different contexts.
///
/// The reader half most notably implements [`embedded_hal::serial::Read`] for receiving data.
pub struct UsartReader<USART: UsartOps<RX, TX>, RX, TX, CLOCK> {
pub struct UsartReader<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
p: USART,
rx: RX,
_tx: marker::PhantomData<TX>,
_clock: marker::PhantomData<CLOCK>,
_h: marker::PhantomData<H>,
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> UsartWriter<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartWriter<H, USART, RX, TX, CLOCK> {
/// Merge this `UsartWriter` with a [`UsartReader`] back into a single [`Usart`] peripheral.
pub fn reunite(self, other: UsartReader<USART, RX, TX, CLOCK>) -> Usart<USART, RX, TX, CLOCK> {
pub fn reunite(
self,
other: UsartReader<H, USART, RX, TX, CLOCK>,
) -> Usart<H, USART, RX, TX, CLOCK> {
Usart {
p: self.p,
rx: other.rx,
tx: self.tx,
_clock: marker::PhantomData,
_h: marker::PhantomData,
}
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> UsartReader<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX, CLOCK> {
/// Merge this `UsartReader` with a [`UsartWriter`] back into a single [`Usart`] peripheral.
pub fn reunite(self, other: UsartWriter<USART, RX, TX, CLOCK>) -> Usart<USART, RX, TX, CLOCK> {
pub fn reunite(
self,
other: UsartWriter<H, USART, RX, TX, CLOCK>,
) -> Usart<H, USART, RX, TX, CLOCK> {
Usart {
p: self.p,
rx: self.rx,
tx: other.tx,
_clock: marker::PhantomData,
_h: marker::PhantomData,
}
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> ufmt::uWrite for UsartWriter<USART, RX, TX, CLOCK> {
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
for UsartWriter<H, USART, RX, TX, CLOCK>
{
type Error = void::Void;

fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
Expand All @@ -399,8 +417,8 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> ufmt::uWrite for UsartWriter<USART,
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
for UsartWriter<USART, RX, TX, CLOCK>
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
for UsartWriter<H, USART, RX, TX, CLOCK>
{
type Error = void::Void;

Expand All @@ -413,8 +431,8 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
}
}

impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
for UsartReader<USART, RX, TX, CLOCK>
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
for UsartReader<H, USART, RX, TX, CLOCK>
{
type Error = void::Void;

Expand All @@ -426,13 +444,15 @@ impl<USART: UsartOps<RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
#[macro_export]
macro_rules! impl_usart_traditional {
(
hal: $HAL:ty,
peripheral: $USART:ty,
register_suffix: $n:expr,
rx: $rxpin:ty,
tx: $txpin:ty,
) => {
$crate::paste::paste! {
impl $crate::usart::UsartOps<
$HAL,
$crate::port::Pin<$crate::port::mode::Input<$crate::port::mode::Floating>, $rxpin>,
$crate::port::Pin<$crate::port::mode::Output, $txpin>,
> for $USART {
Expand Down

0 comments on commit 9c33514

Please sign in to comment.