#")]
#![cfg_attr(not(feature = "dma"), doc = "`DMA`")]
use super::*;
use crate::ehal_nb;
use nb::Error::WouldBlock;
use num_traits::{AsPrimitive, PrimInt};
impl<P, M, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
where
Config<P, M, C>: ValidConfig,
P: ValidPads,
M: MasterMode,
C: CharSize,
C::Word: PrimInt,
DataWidth: AsPrimitive<C::Word>,
{
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
let in_progress = self.capability.in_progress;
let flags = self.read_flags_errors()?;
if !in_progress && flags.contains(Flags::DRE) {
unsafe { self.write_data(0) };
self.capability.in_progress = true;
Err(WouldBlock)
} else if in_progress && flags.contains(Flags::RXC) {
self.capability.in_progress = false;
unsafe { Ok(self.read_data().as_()) }
} else {
Err(WouldBlock)
}
}
}
impl<P, M, C> serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
where
Config<P, M, C>: ValidConfig,
P: ValidPads,
M: MasterMode,
C: CharSize,
C::Word: PrimInt,
DataWidth: AsPrimitive<C::Word>,
{
type Error = Error;
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
<Self as ehal_nb::serial::Read<C::Word>>::read(self)
}
}
impl<P, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
where
Config<P, Slave, C>: ValidConfig,
P: ValidPads,
C: CharSize,
C::Word: PrimInt,
DataWidth: AsPrimitive<C::Word>,
{
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::RXC) {
unsafe { Ok(self.read_data().as_()) }
} else {
Err(WouldBlock)
}
}
}
impl<P, C> serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
where
Config<P, Slave, C>: ValidConfig,
P: ValidPads,
C: CharSize,
C::Word: PrimInt,
DataWidth: AsPrimitive<C::Word>,
{
type Error = Error;
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
<Self as ehal_nb::serial::Read<C::Word>>::read(self)
}
}
impl<P, M> embedded_io::Read for Spi<Config<P, M, EightBit>, Rx>
where
Config<P, M, EightBit>: ValidConfig,
P: ValidPads,
M: MasterMode,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
for byte in buf.iter_mut() {
let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
*byte = w;
}
Ok(buf.len())
}
}
impl<P> embedded_io::Read for Spi<Config<P, Slave, EightBit>, Rx>
where
Config<P, Slave, EightBit>: ValidConfig,
P: ValidPads,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
};
for byte in buf.iter_mut() {
let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
*byte = w;
}
Ok(buf.len())
}
}
impl<P, M, C> ehal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
where
Config<P, M, C>: ValidConfig,
P: ValidPads,
M: OpMode,
C: CharSize,
C::Word: PrimInt + AsPrimitive<DataWidth>,
{
#[inline]
fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
if self.read_flags().contains(Flags::DRE) {
unsafe { self.write_data(word.as_()) };
Ok(())
} else {
Err(WouldBlock)
}
}
#[inline]
fn flush(&mut self) -> nb::Result<(), Error> {
if self.read_flags().contains(Flags::TXC) {
Ok(())
} else {
Err(WouldBlock)
}
}
}
impl<P, M, C> serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
where
Config<P, M, C>: ValidConfig,
P: ValidPads,
M: OpMode,
C: CharSize,
C::Word: PrimInt + AsPrimitive<DataWidth>,
{
type Error = Error;
#[inline]
fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
<Self as ehal_nb::serial::Write<C::Word>>::write(self, word)
}
#[inline]
fn flush(&mut self) -> nb::Result<(), Error> {
<Self as ehal_nb::serial::Write<C::Word>>::flush(self)
}
}
impl<C> blocking::serial::write::Default<C::Word> for Spi<C, Tx>
where
C: ValidConfig,
Spi<C, Tx>: serial::Write<C::Word>,
{
}
impl<P, M> embedded_io::Write for Spi<Config<P, M, EightBit>, Tx>
where
Config<P, M, EightBit>: ValidConfig,
P: ValidPads,
M: OpMode,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
for byte in buf {
nb::block!(<Self as ehal_nb::serial::Write>::write(self, *byte))?;
}
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(<Self as ehal_nb::serial::Write>::flush(self))
}
}
impl<C> ehal_nb::spi::FullDuplex<C::Word> for Spi<C, Duplex>
where
C: ValidConfig,
C::Word: PrimInt + AsPrimitive<u16>,
u16: AsPrimitive<C::Word>,
{
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::RXC) {
unsafe { Ok(self.read_data().as_()) }
} else {
Err(WouldBlock)
}
}
#[inline]
fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::DRE) {
unsafe { self.write_data(word.as_()) };
Ok(())
} else {
Err(WouldBlock)
}
}
}
impl<C> crate::ehal_02::spi::FullDuplex<C::Word> for Spi<C, Duplex>
where
C: ValidConfig,
C::Word: PrimInt + AsPrimitive<u16>,
u16: AsPrimitive<C::Word>,
{
type Error = Error;
#[inline]
fn read(&mut self) -> nb::Result<C::Word, Error> {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::RXC) {
unsafe { Ok(self.read_data().as_()) }
} else {
Err(WouldBlock)
}
}
#[inline]
fn send(&mut self, word: C::Word) -> nb::Result<(), Error> {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::DRE) {
unsafe { self.write_data(word.as_()) };
Ok(())
} else {
Err(WouldBlock)
}
}
}
macro_rules! impl_blocking_spi_transfer {
( $($CharSize:ident),+ ) => {
$(
impl<P, M, A> blocking::spi::Transfer<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, A>
where
Config<P, M, $CharSize>: ValidConfig,
P: ValidPads,
M: OpMode,
A: Receive,
{
type Error = Error;
#[inline]
fn transfer<'w>(&mut self, words: &'w mut [Word<$CharSize>]) -> Result<&'w [Word<$CharSize>], Error> {
let cells = core::cell::Cell::from_mut(words).as_slice_of_cells();
let mut to_send = cells.iter();
let mut to_recv = cells.iter();
while to_recv.len() > 0 {
let flags = self.read_flags_errors()?;
if to_send.len() > 0 && flags.contains(Flags::DRE) {
let word = match to_send.next() {
Some(cell) => cell.get(),
None => unreachable!(),
};
self.config.as_mut().regs.write_data(word as u16);
}
if to_recv.len() > to_send.len() && flags.contains(Flags::RXC) {
let word = self.config.as_mut().regs.read_data() as Word<$CharSize>;
match to_recv.next() {
Some(cell) => cell.set(word),
None => unreachable!(),
}
}
}
Ok(words)
}
}
)+
}
}
impl_blocking_spi_transfer!(EightBit, NineBit);
macro_rules! impl_blocking_spi_write {
( $($CharSize:ident),+ ) => {
$(
impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
where
Config<P, M, $CharSize>: ValidConfig,
P: ValidPads,
M: OpMode,
{
type Error = Error;
#[inline]
fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
let mut to_send = words.iter();
let mut to_recv = to_send.len();
while to_recv > 0 {
let flags = self.read_flags_errors()?;
if to_send.len() > 0 && flags.contains(Flags::DRE) {
let word = match to_send.next() {
Some(word) => *word,
None => unreachable!(),
};
self.config.as_mut().regs.write_data(word as u16);
}
if to_recv > to_send.len() && flags.contains(Flags::RXC) {
self.config.as_mut().regs.read_data();
to_recv -= 1;
}
}
Ok(())
}
}
impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
where
Config<P, M, $CharSize>: ValidConfig,
P: ValidPads,
M: OpMode,
{
type Error = Error;
#[inline]
fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
for word in words {
loop {
if self.read_status().contains(Status::LENERR) {
return Err(Error::LengthError)
} else if self.read_flags().contains(Flags::DRE) {
self.config.as_mut().regs.write_data(*word as u16);
break
}
}
}
while !self.read_flags().contains(Flags::TXC) {}
Ok(())
}
}
)+
}
}
impl_blocking_spi_write!(EightBit, NineBit);
macro_rules! impl_blocking_spi_write_iter {
( $($CharSize:ident),+ ) => {
$(
impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
where
Config<P, M, $CharSize>: ValidConfig,
P: ValidPads,
M: OpMode,
{
type Error = Error;
#[inline]
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
where
WI: IntoIterator<Item = Word<$CharSize>>,
{
for word in words.into_iter() {
loop {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::DRE) {
unsafe { self.write_data(word as u16) };
break
}
}
loop {
let flags = self.read_flags_errors()?;
if flags.contains(Flags::RXC) {
self.config.as_mut().regs.read_data() as Word<$CharSize>;
break
}
}
}
Ok(())
}
}
impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
where
Config<P, M, $CharSize>: ValidConfig,
P: ValidPads,
M: OpMode,
{
type Error = Error;
#[inline]
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
where
WI: IntoIterator<Item = Word<$CharSize>>,
{
for word in words.into_iter() {
loop {
if self.read_status().contains(Status::LENERR) {
return Err(Error::LengthError)
} else if self.read_flags().contains(Flags::DRE) {
unsafe { self.write_data(word as u16) };
break
}
}
}
while !self.read_flags().contains(Flags::TXC) {}
Ok(())
}
}
)+
};
}
impl_blocking_spi_write_iter!(EightBit, NineBit);