#![allow(rustdoc::broken_intra_doc_links)]
use core::convert::Infallible;
use core::task::Poll;
use embedded_hal::digital::v2::OutputPin;
use crate::gpio::pin::{OptionalPin, SomePin};
use crate::typelevel::NoneT;
use super::spi::{AnySpi, Error, Flags};
#[cfg(feature = "min-samd51g")]
use {
super::spi::{
Capability, Config, DynLength, OpMode, Spi, StaticLength, ValidConfig, ValidPads,
},
typenum::Unsigned,
};
#[cfg(any(feature = "samd11", feature = "samd21"))]
use core::mem::size_of;
#[cfg(any(feature = "samd11", feature = "samd21"))]
type Data = u16;
#[cfg(feature = "min-samd51g")]
type Data = u32;
#[allow(clippy::len_without_is_empty)]
pub trait CheckBufLen: AnySpi {
#[cfg(feature = "min-samd51g")]
const LEN: usize = <Self::Size as Unsigned>::USIZE;
#[cfg(any(feature = "samd11", feature = "samd21"))]
const LEN: usize = size_of::<Self::Word>();
#[inline]
fn len(&self) -> usize {
Self::LEN
}
const STEP: usize = if Self::LEN > 4 { 4 } else { Self::LEN };
#[inline]
fn step(&self) -> usize {
Self::STEP
}
#[inline]
fn check_buf_len(&self, buf: &impl AsRef<[u8]>) {
let buf_len = buf.as_ref().len();
let self_len = self.len();
if (self_len > 4 && buf_len != self_len) || (self_len <= 4 && buf_len % self_len != 0) {
panic!("Invalid SpiFuture buffer length");
}
}
}
#[cfg(any(feature = "samd11", feature = "samd21"))]
impl<S: AnySpi> CheckBufLen for S {}
#[cfg(feature = "min-samd51g")]
impl<P, M, L, A> CheckBufLen for Spi<Config<P, M, L>, A>
where
Config<P, M, L>: ValidConfig,
P: ValidPads,
M: OpMode,
L: StaticLength,
A: Capability,
{
}
#[cfg(feature = "min-samd51g")]
impl<P, M, A> CheckBufLen for Spi<Config<P, M, DynLength>, A>
where
Config<P, M, DynLength>: ValidConfig,
P: ValidPads,
M: OpMode,
A: Capability,
{
#[inline]
fn len(&self) -> usize {
self.get_dyn_length() as usize
}
#[inline]
fn step(&self) -> usize {
let len = self.len();
if len > 4 {
4
} else {
len
}
}
}
pub trait ControlSS: OptionalPin {
fn assert(&mut self);
fn deassert(&mut self);
}
impl<P> ControlSS for P
where
P: SomePin + OutputPin<Error = Infallible>,
{
#[inline]
fn assert(&mut self) {
self.set_low().unwrap();
}
#[inline]
fn deassert(&mut self) {
self.set_high().unwrap();
}
}
impl ControlSS for NoneT {
fn assert(&mut self) {}
fn deassert(&mut self) {}
}
pub struct SpiFuture<S, B, SS = NoneT, W = fn()>
where
S: CheckBufLen,
B: AsRef<[u8]> + AsMut<[u8]> + 'static,
SS: ControlSS,
W: FnOnce() + 'static,
{
spi: S,
buf: B,
sent: usize,
rcvd: usize,
ss: SS,
waker: Option<W>,
}
impl<S, B> SpiFuture<S, B>
where
S: CheckBufLen,
B: AsRef<[u8]> + AsMut<[u8]> + 'static,
{
#[inline]
pub fn new(spi: S, buf: B) -> Self {
spi.check_buf_len(&buf);
SpiFuture {
spi,
buf,
sent: 0,
rcvd: 0,
ss: NoneT,
waker: None,
}
}
}
impl<S, B, W> SpiFuture<S, B, NoneT, W>
where
S: CheckBufLen,
B: AsRef<[u8]> + AsMut<[u8]> + 'static,
W: FnOnce() + 'static,
{
#[inline]
pub fn with_ss<SS>(self, pin: SS) -> SpiFuture<S, B, SS, W>
where
SS: SomePin + OutputPin<Error = Infallible>,
{
SpiFuture {
spi: self.spi,
buf: self.buf,
sent: self.sent,
rcvd: self.rcvd,
ss: pin,
waker: self.waker,
}
}
}
impl<S, B, SS> SpiFuture<S, B, SS>
where
S: CheckBufLen,
B: AsRef<[u8]> + AsMut<[u8]> + 'static,
SS: ControlSS,
{
#[inline]
pub fn with_waker<W>(self, waker: W) -> SpiFuture<S, B, SS, W>
where
W: FnOnce() + 'static,
{
SpiFuture {
spi: self.spi,
buf: self.buf,
sent: self.sent,
rcvd: self.rcvd,
ss: self.ss,
waker: Some(waker),
}
}
}
impl<S, B, SS, W> SpiFuture<S, B, SS, W>
where
S: CheckBufLen,
B: AsRef<[u8]> + AsMut<[u8]> + 'static,
SS: ControlSS,
W: FnOnce() + 'static,
{
#[inline]
pub fn start(&mut self) {
self.ss.assert();
self.spi.as_mut().enable_interrupts(Flags::DRE | Flags::RXC);
}
pub fn send(&mut self) -> Result<(), Error> {
let _ = self.spi.as_ref().read_flags_errors()?;
let buf = self.buf.as_ref();
if let Some(buf) = buf.get(self.sent..) {
let mut data = buf.iter();
let mut bytes = [0; 4];
let mut iter = bytes.iter_mut();
for _ in 0..self.spi.step() {
match (iter.next(), data.next()) {
(Some(b), Some(d)) => *b = *d,
_ => break,
}
}
let word = u32::from_le_bytes(bytes);
unsafe { self.spi.as_mut().write_data(word as Data) };
self.sent += self.spi.step();
}
if self.sent >= buf.len() {
self.spi.as_mut().disable_interrupts(Flags::DRE);
}
Ok(())
}
pub fn recv(&mut self) -> Result<(), Error> {
let _ = self.spi.as_ref().read_flags_errors()?;
let buf = self.buf.as_mut();
if self.rcvd < self.sent {
let buf = unsafe { buf.get_unchecked_mut(self.rcvd..) };
let mut data = buf.iter_mut();
let word = unsafe { self.spi.as_mut().read_data() as u32 };
let bytes = word.to_le_bytes();
let mut iter = bytes.iter();
for _ in 0..self.spi.step() {
match (data.next(), iter.next()) {
(Some(d), Some(b)) => *d = *b,
_ => break,
}
}
self.rcvd += self.spi.step();
}
if self.rcvd >= buf.len() {
self.spi.as_mut().disable_interrupts(Flags::RXC);
self.ss.deassert();
if let Some(waker) = self.waker.take() {
waker();
}
}
Ok(())
}
#[inline]
pub fn poll(&self) -> Poll<&[u8]> {
let buf = self.buf.as_ref();
if self.rcvd >= buf.len() {
Poll::Ready(buf)
} else {
Poll::Pending
}
}
#[inline]
pub fn free(self) -> Result<(S, B, SS), Self> {
if self.rcvd >= self.buf.as_ref().len() {
Ok((self.spi, self.buf, self.ss))
} else {
Err(self)
}
}
#[inline]
pub unsafe fn free_unchecked(self) -> (S, B, SS) {
(self.spi, self.buf, self.ss)
}
}