use core::marker::PhantomData;
use core::task::Poll;
use crate::iomuxc::{consts, lpspi};
use crate::ral;
type AnyInstance = crate::AnyInstance<ral::lpspi::RegisterBlock>;
pub use eh02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Tx,
Rx,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum BitOrder {
#[default]
Msb,
Lsb,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SamplePoint {
Edge,
DelayedEdge,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LpspiError {
FrameSize,
Fifo(Direction),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u32)]
pub enum Pcs {
#[default]
Pcs0,
Pcs1,
Pcs2,
Pcs3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u32)]
pub enum PcsPolarity {
#[default]
ActiveLow,
ActiveHigh,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct Transaction(u32);
impl Transaction {
#[inline(always)]
pub const fn set_byte_swap(&mut self, swap: bool) -> &mut Self {
self.0 &= !ral::lpspi::TCR::BYSW::mask;
self.0 |= (swap as u32) << ral::lpspi::TCR::BYSW::offset;
self
}
#[inline(always)]
pub const fn set_bit_order(&mut self, bit_order: BitOrder) -> &mut Self {
self.0 &= !ral::lpspi::TCR::LSBF::mask;
self.0 |= (bit_order as u32) << ral::lpspi::TCR::LSBF::offset;
self
}
#[inline(always)]
pub const fn set_receive_data_mask(&mut self, rxmask: bool) -> &mut Self {
self.0 &= !ral::lpspi::TCR::RXMSK::mask;
self.0 |= (rxmask as u32) << ral::lpspi::TCR::RXMSK::offset;
self
}
#[inline(always)]
pub const fn set_transmit_data_mask(&mut self, txmask: bool) -> &mut Self {
self.0 &= !ral::lpspi::TCR::TXMSK::mask;
self.0 |= (txmask as u32) << ral::lpspi::TCR::TXMSK::offset;
self
}
#[inline(always)]
pub const fn set_continuous(&mut self, cont: bool) -> &mut Self {
self.0 &= !ral::lpspi::TCR::CONT::mask;
self.0 |= (cont as u32) << ral::lpspi::TCR::CONT::offset;
self
}
#[inline(always)]
pub const fn set_continuing(&mut self, contc: bool) -> &mut Self {
self.0 &= !ral::lpspi::TCR::CONTC::mask;
self.0 |= (contc as u32) << ral::lpspi::TCR::CONTC::offset;
self
}
#[inline(always)]
pub const fn set_mode(&mut self, mode: Mode) -> &mut Self {
self.0 &= !(ral::lpspi::TCR::CPOL::mask | ral::lpspi::TCR::CPHA::mask);
let cpol = if matches!(mode.polarity, Polarity::IdleHigh) {
ral::lpspi::TCR::CPOL::RW::CPOL_1
} else {
ral::lpspi::TCR::CPOL::RW::CPOL_0
};
let cpha = if matches!(mode.phase, Phase::CaptureOnSecondTransition) {
ral::lpspi::TCR::CPHA::RW::CPHA_1
} else {
ral::lpspi::TCR::CPHA::RW::CPHA_0
};
self.0 |= (cpol << ral::lpspi::TCR::CPOL::offset) | (cpha << ral::lpspi::TCR::CPHA::offset);
self
}
#[inline(always)]
pub const fn set_pcs(&mut self, pcs: Pcs) -> &mut Self {
self.0 &= !ral::lpspi::TCR::PCS::mask;
self.0 |= (pcs as u32) << ral::lpspi::TCR::PCS::offset;
self
}
}
impl Transaction {
pub fn new_u32s(data: &[u32]) -> Result<Self, LpspiError> {
Transaction::new_words(data)
}
fn new_words<W>(data: &[W]) -> Result<Self, LpspiError> {
if let Ok(frame_size) = u16::try_from(8 * core::mem::size_of_val(data)) {
Transaction::new(frame_size)
} else {
Err(LpspiError::FrameSize)
}
}
const fn frame_size_valid(frame_size: u16) -> bool {
const MIN_FRAME_SIZE: u16 = 8;
const MAX_FRAME_SIZE: u16 = 1 << 12;
const WORD_SIZE: u16 = 32;
let last_frame_size = frame_size % WORD_SIZE;
MIN_FRAME_SIZE <= frame_size && frame_size <= MAX_FRAME_SIZE && (1 != last_frame_size)
}
pub const fn new(frame_size: u16) -> Result<Self, LpspiError> {
if Self::frame_size_valid(frame_size) {
Ok(Self(frame_size as u32 - 1))
} else {
Err(LpspiError::FrameSize)
}
}
}
fn compute_spi_clock(source_clock_hz: u32, spi_clock_hz: u32) -> ClockConfigs {
let half_div =
u32::try_from(1 + u64::from(source_clock_hz - 1) / (u64::from(spi_clock_hz) * 2)).unwrap();
let half_div = half_div.clamp(3, 128);
let sckdiv = 2 * (half_div - 1);
ClockConfigs {
dbt: (half_div - 1) as u8,
pcssck: (half_div - 1) as u8,
sckpcs: (half_div - 1) as u8,
sckdiv: sckdiv as u8,
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ClockConfigs {
pub sckpcs: u8,
pub pcssck: u8,
pub dbt: u8,
pub sckdiv: u8,
}
impl ClockConfigs {
const fn as_raw(self) -> u32 {
use ral::lpspi::CCR;
((self.sckpcs as u32) << CCR::SCKPCS::offset)
| ((self.pcssck as u32) << CCR::PCSSCK::offset)
| ((self.dbt as u32) << CCR::DBT::offset)
| ((self.sckdiv as u32) << CCR::SCKDIV::offset)
}
}
struct CcrCache {
dbt: u8,
sckdiv: u8,
}
impl CcrCache {
fn read_ccr(&self, lpspi: &ral::lpspi::RegisterBlock) -> ClockConfigs {
let (sckpcs, pcssck) = ral::read_reg!(ral::lpspi, lpspi, CCR, SCKPCS, PCSSCK);
ClockConfigs {
sckpcs: sckpcs as u8,
pcssck: pcssck as u8,
dbt: self.dbt,
sckdiv: self.sckdiv,
}
}
fn update(&mut self, clock_configs: ClockConfigs) {
self.dbt = clock_configs.dbt;
self.sckdiv = clock_configs.sckdiv;
}
}
pub struct Lpspi {
pub(crate) lpspi: AnyInstance,
bit_order: BitOrder,
mode: Mode,
ccr_cache: CcrCache,
pcs: Pcs,
}
pub struct Pins<SDO, SDI, SCK> {
pub sdo: SDO,
pub sdi: SDI,
pub sck: SCK,
}
impl Lpspi {
pub fn with_pins<SDO, SDI, SCK, const N: u8>(
lpspi: ral::lpspi::Instance<N>,
mut pins: Pins<SDO, SDI, SCK>,
) -> Self
where
SDO: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sdo>,
SDI: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sdi>,
SCK: lpspi::Pin<Module = consts::Const<N>, Signal = lpspi::Sck>,
{
lpspi::prepare(&mut pins.sdo);
lpspi::prepare(&mut pins.sdi);
lpspi::prepare(&mut pins.sck);
Self::init(lpspi)
}
pub fn without_pins<const N: u8>(lpspi: ral::lpspi::Instance<N>) -> Self {
Self::init(lpspi)
}
fn init<const N: u8>(lpspi: ral::lpspi::Instance<N>) -> Self {
let lpspi: AnyInstance = crate::into_any(lpspi);
let spi = Lpspi {
lpspi,
bit_order: BitOrder::default(),
mode: MODE_0,
ccr_cache: CcrCache { dbt: 0, sckdiv: 0 },
pcs: Pcs::default(),
};
ral::modify_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_0, RST: RST_1);
while spi.is_enabled() {}
ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RST: RST_0);
ral::modify_reg!(ral::lpspi, spi.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
ral::write_reg!(
ral::lpspi,
spi.lpspi,
CFGR1,
MASTER: MASTER_1,
SAMPLE: SAMPLE_1
);
let tx_fifo_size = spi.max_watermark(Direction::Tx);
ral::write_reg!(ral::lpspi, spi.lpspi, FCR,
RXWATER: 0, TXWATER: u32::from(tx_fifo_size) / 2 );
ral::write_reg!(ral::lpspi, spi.lpspi, CR, MEN: MEN_1);
spi
}
pub fn is_enabled(&self) -> bool {
ral::read_reg!(ral::lpspi, self.lpspi, CR, MEN == MEN_1)
}
pub fn set_enable(&mut self, enable: bool) {
ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: enable as u32)
}
pub fn reset(&mut self) {
ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_1);
while ral::read_reg!(ral::lpspi, self.lpspi, CR, RST == RST_1) {
ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0);
}
}
pub fn bit_order(&self) -> BitOrder {
self.bit_order
}
pub fn set_bit_order(&mut self, bit_order: BitOrder) {
self.bit_order = bit_order;
}
pub fn disabled<R>(&mut self, func: impl FnOnce(&mut Disabled) -> R) -> R {
let mut disabled = Disabled::new(&mut self.lpspi, &mut self.ccr_cache);
func(&mut disabled)
}
pub fn status(&self) -> Status {
Status::from_bits_truncate(ral::read_reg!(ral::lpspi, self.lpspi, SR))
}
pub fn clear_status(&self, flags: Status) {
let flags = flags & Status::W1C;
ral::write_reg!(ral::lpspi, self.lpspi, SR, flags.bits());
}
pub fn interrupts(&self) -> Interrupts {
Interrupts::from_bits_truncate(ral::read_reg!(ral::lpspi, self.lpspi, IER))
}
pub fn set_interrupts(&self, interrupts: Interrupts) {
ral::write_reg!(ral::lpspi, self.lpspi, IER, interrupts.bits());
}
#[inline]
pub fn clear_fifo(&mut self, direction: Direction) {
match direction {
Direction::Tx => ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1),
Direction::Rx => ral::modify_reg!(ral::lpspi, self.lpspi, CR, RRF: RRF_1),
}
}
pub fn clear_fifos(&mut self) {
ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
}
#[inline]
pub fn watermark(&self, direction: Direction) -> u8 {
(match direction {
Direction::Rx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, RXWATER),
Direction::Tx => ral::read_reg!(ral::lpspi, self.lpspi, FCR, TXWATER),
}) as u8
}
#[inline]
pub fn fifo_status(&self) -> FifoStatus {
let (rxcap, txcap) = ral::read_reg!(ral::lpspi, self.lpspi, PARAM, RXFIFO, TXFIFO);
let (rxcount, txcount) = ral::read_reg!(ral::lpspi, self.lpspi, FSR, RXCOUNT, TXCOUNT);
FifoStatus {
rxcount: rxcount as u16,
txcount: txcount as u16,
rxcap: rxcap as u16,
txcap: txcap as u16,
}
}
fn read_data_unchecked(&self) -> u32 {
ral::read_reg!(ral::lpspi, self.lpspi, RDR)
}
pub fn read_data(&mut self) -> Option<u32> {
if ral::read_reg!(ral::lpspi, self.lpspi, RSR, RXEMPTY == RXEMPTY_0) {
Some(self.read_data_unchecked())
} else {
None
}
}
pub fn enqueue_data(&self, word: u32) {
ral::write_reg!(ral::lpspi, self.lpspi, TDR, word);
}
pub(crate) async fn spin_for_fifo_space(&self) -> Result<(), LpspiError> {
core::future::poll_fn(|_| {
let status = self.status();
if status.intersects(Status::TRANSMIT_ERROR) {
return Poll::Ready(Err(LpspiError::Fifo(Direction::Tx)));
}
let fifo_status = self.fifo_status();
if !fifo_status.is_full(Direction::Tx) {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
})
.await
}
pub(crate) fn wait_for_transmit_fifo_space(&self) -> Result<(), LpspiError> {
crate::spin_on(self.spin_for_fifo_space())
}
async fn spin_for_word(&self) -> Result<u32, LpspiError> {
core::future::poll_fn(|_| {
let status = self.status();
if status.intersects(Status::RECEIVE_ERROR) {
return Poll::Ready(Err(LpspiError::Fifo(Direction::Rx)));
}
let fifo_status = self.fifo_status();
if !fifo_status.is_empty(Direction::Rx) {
let data = self.read_data_unchecked();
Poll::Ready(Ok(data))
} else {
Poll::Pending
}
})
.await
}
async fn spin_transmit(
&self,
mut data: impl TransmitData,
len: usize,
) -> Result<(), LpspiError> {
for _ in 0..len {
self.spin_for_fifo_space().await?;
let word = data.next_word(self.bit_order);
self.enqueue_data(word);
}
Ok(())
}
async fn spin_receive(&self, mut data: impl ReceiveData, len: usize) -> Result<(), LpspiError> {
for _ in 0..len {
let word = self.spin_for_word().await?;
data.next_word(self.bit_order, word);
}
Ok(())
}
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode;
}
pub fn pcs(&self) -> Pcs {
self.pcs
}
pub fn set_pcs(&mut self, pcs: Pcs) {
self.pcs = pcs;
}
#[inline]
pub fn enqueue_transaction(&self, transaction: Transaction) {
ral::write_reg!(ral::lpspi, self.lpspi, TCR, transaction.0);
}
pub fn flush(&mut self) -> Result<(), LpspiError> {
loop {
let status = self.status();
if status.intersects(Status::RECEIVE_ERROR) {
return Err(LpspiError::Fifo(Direction::Rx));
}
if status.intersects(Status::TRANSMIT_ERROR) {
return Err(LpspiError::Fifo(Direction::Tx));
}
if !status.intersects(Status::BUSY) && self.fifo_status().is_empty(Direction::Tx) {
return Ok(());
}
}
}
fn exchange_separate<W: Word>(
&mut self,
read: &mut [W],
write: &[W],
) -> Result<(), LpspiError> {
let larger_buffer: &[W] = if read.len() > write.len() {
read
} else {
write
};
if larger_buffer.is_empty() {
return Ok(());
}
let transaction = self.bus_transaction(larger_buffer)?;
self.wait_for_transmit_fifo_space()?;
self.enqueue_transaction(transaction);
let tx_words = word_count(write);
let rx_words = word_count(read);
let total_words = tx_words.max(rx_words);
let read_len = read.len();
let write_len = write.len();
let total_len = read_len.max(write_len);
let dummies = total_len.saturating_sub(write_len);
let discards = total_len.saturating_sub(read_len);
let tx = self.spin_transmit(TransmitBuffer::with_dummies(write, dummies), total_words);
let rx = self.spin_receive(ReceiveBuffer::with_discards(read, discards), total_words);
crate::spin_on(futures::future::try_join(tx, rx))
.inspect_err(|_| self.recover_from_error())?;
Ok(())
}
fn exchange<W: Word>(&mut self, data: &mut [W]) -> Result<(), LpspiError> {
if data.is_empty() {
return Ok(());
}
let transaction = self.bus_transaction(data)?;
self.wait_for_transmit_fifo_space()?;
self.enqueue_transaction(transaction);
let word_count = word_count(data);
let (tx, rx) = transfer_in_place(data);
crate::spin_on(futures::future::try_join(
self.spin_transmit(tx, word_count),
self.spin_receive(rx, word_count),
))
.inspect_err(|_| self.recover_from_error())?;
Ok(())
}
fn write_no_read<W: Word>(&mut self, data: &[W]) -> Result<(), LpspiError> {
if data.is_empty() {
return Ok(());
}
let mut transaction = self.bus_transaction(data)?;
transaction.set_receive_data_mask(true);
self.wait_for_transmit_fifo_space()?;
self.enqueue_transaction(transaction);
let word_count = word_count(data);
let tx = TransmitBuffer::new(data);
crate::spin_on(self.spin_transmit(tx, word_count)).inspect_err(|_| {
self.recover_from_error();
})?;
Ok(())
}
fn read_no_write<W: Word>(&mut self, data: &mut [W]) -> Result<(), LpspiError> {
if data.is_empty() {
return Ok(());
}
let mut transaction = self.bus_transaction(data)?;
transaction.set_transmit_data_mask(true);
self.wait_for_transmit_fifo_space()?;
self.enqueue_transaction(transaction);
let word_count = word_count(data);
let rx = ReceiveBuffer::new(data);
crate::spin_on(self.spin_receive(rx, word_count)).inspect_err(|_| {
self.recover_from_error();
})?;
Ok(())
}
pub fn enable_dma_receive(&mut self) {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, RXWATER: 0); ral::modify_reg!(ral::lpspi, self.lpspi, DER, RDDE: 1);
}
pub fn disable_dma_receive(&mut self) {
while ral::read_reg!(ral::lpspi, self.lpspi, DER, RDDE == 1) {
ral::modify_reg!(ral::lpspi, self.lpspi, DER, RDDE: 0);
}
}
pub fn enable_dma_transmit(&mut self) {
ral::modify_reg!(ral::lpspi, self.lpspi, FCR, TXWATER: 0); ral::modify_reg!(ral::lpspi, self.lpspi, DER, TDDE: 1);
}
pub fn disable_dma_transmit(&mut self) {
while ral::read_reg!(ral::lpspi, self.lpspi, DER, TDDE == 1) {
ral::modify_reg!(ral::lpspi, self.lpspi, DER, TDDE: 0);
}
}
pub fn rdr(&self) -> *const ral::RORegister<u32> {
core::ptr::addr_of!(self.lpspi.RDR)
}
pub fn tdr(&self) -> *const ral::WORegister<u32> {
core::ptr::addr_of!(self.lpspi.TDR)
}
fn max_watermark(&self, direction: Direction) -> u8 {
(match direction {
Direction::Rx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, RXFIFO),
Direction::Tx => 1 << ral::read_reg!(ral::lpspi, self.lpspi, PARAM, TXFIFO),
}) as u8
}
pub fn soft_reset(&mut self) {
let ier = ral::read_reg!(ral::lpspi, self.lpspi, IER);
let der = ral::read_reg!(ral::lpspi, self.lpspi, DER);
let cfgr0 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR0);
let cfgr1 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR1);
let dmr0 = ral::read_reg!(ral::lpspi, self.lpspi, DMR0);
let dmr1 = ral::read_reg!(ral::lpspi, self.lpspi, DMR1);
let ccr = self.clock_configs().as_raw();
let fcr = ral::read_reg!(ral::lpspi, self.lpspi, FCR);
let enabled = self.is_enabled();
ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: MEN_0, RST: RST_1);
while self.is_enabled() {}
ral::modify_reg!(ral::lpspi, self.lpspi, CR, RST: RST_0);
ral::modify_reg!(ral::lpspi, self.lpspi, CR, RTF: RTF_1, RRF: RRF_1);
ral::write_reg!(ral::lpspi, self.lpspi, IER, ier);
ral::write_reg!(ral::lpspi, self.lpspi, DER, der);
ral::write_reg!(ral::lpspi, self.lpspi, CFGR0, cfgr0);
ral::write_reg!(ral::lpspi, self.lpspi, CFGR1, cfgr1);
ral::write_reg!(ral::lpspi, self.lpspi, DMR0, dmr0);
ral::write_reg!(ral::lpspi, self.lpspi, DMR1, dmr1);
ral::write_reg!(ral::lpspi, self.lpspi, CCR, ccr);
ral::write_reg!(ral::lpspi, self.lpspi, FCR, fcr);
self.set_enable(enabled);
}
#[inline]
pub fn set_watermark(&mut self, direction: Direction, watermark: u8) -> u8 {
set_watermark(&self.lpspi, direction, watermark)
}
fn recover_from_error(&mut self) {
self.soft_reset();
self.clear_status(Status::TRANSMIT_ERROR | Status::RECEIVE_ERROR);
}
pub fn clock_configs(&self) -> ClockConfigs {
self.ccr_cache.read_ccr(&self.lpspi)
}
pub(crate) fn bus_transaction<W>(&self, words: &[W]) -> Result<Transaction, LpspiError> {
let mut transaction = Transaction::new_words(words)?;
transaction.set_bit_order(self.bit_order());
transaction.set_mode(self.mode);
transaction.set_pcs(self.pcs);
Ok(transaction)
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Status : u32 {
const BUSY = 1 << 24;
const DATA_MATCH = 1 << 13;
const RECEIVE_ERROR = 1 << 12;
const TRANSMIT_ERROR = 1 << 11;
const TRANSFER_COMPLETE = 1 << 10;
const FRAME_COMPLETE = 1 << 9;
const WORD_COMPLETE = 1 << 8;
const RECEIVE_DATA = 1 << 1;
const TRANSMIT_DATA = 1 << 0;
}
}
impl Status {
const W1C: Self = Self::from_bits_truncate(
Self::DATA_MATCH.bits()
| Self::RECEIVE_ERROR.bits()
| Self::TRANSMIT_ERROR.bits()
| Self::TRANSFER_COMPLETE.bits()
| Self::FRAME_COMPLETE.bits()
| Self::WORD_COMPLETE.bits(),
);
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct FifoStatus {
pub rxcount: u16,
pub txcount: u16,
pub rxcap: u16,
pub txcap: u16,
}
impl FifoStatus {
#[inline]
pub const fn is_full(self, direction: Direction) -> bool {
match direction {
Direction::Tx => self.txcount >= self.txcap,
Direction::Rx => self.rxcount >= self.rxcap,
}
}
#[inline]
const fn is_empty(self, direction: Direction) -> bool {
0 == match direction {
Direction::Tx => self.txcount,
Direction::Rx => self.rxcount,
}
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Interrupts : u32 {
const DATA_MATCH = 1 << 13;
const RECEIVE_ERROR = 1 << 12;
const TRANSMIT_ERROR = 1 << 11;
const TRANSMIT_COMPLETE = 1 << 10;
const FRAME_COMPLETE = 1 << 9;
const WORD_COMPLETE = 1 << 8;
const RECEIVE_DATA = 1 << 1;
const TRANSMIT_DATA = 1 << 0;
}
}
#[inline]
fn set_watermark(lpspi: &ral::lpspi::RegisterBlock, direction: Direction, watermark: u8) -> u8 {
let max_watermark = match direction {
Direction::Rx => 1 << ral::read_reg!(ral::lpspi, lpspi, PARAM, RXFIFO),
Direction::Tx => 1 << ral::read_reg!(ral::lpspi, lpspi, PARAM, TXFIFO),
};
let watermark = watermark.min(max_watermark - 1);
match direction {
Direction::Rx => {
ral::modify_reg!(ral::lpspi, lpspi, FCR, RXWATER: watermark as u32)
}
Direction::Tx => {
ral::modify_reg!(ral::lpspi, lpspi, FCR, TXWATER: watermark as u32)
}
}
watermark
}
pub struct Disabled<'a> {
lpspi: &'a mut AnyInstance,
men: bool,
ccr_cache: &'a mut CcrCache,
}
impl<'a> Disabled<'a> {
fn new(lpspi: &'a mut AnyInstance, ccr_cache: &'a mut CcrCache) -> Self {
let men = ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1);
ral::modify_reg!(ral::lpspi, lpspi, CR, MEN: MEN_0);
while ral::read_reg!(ral::lpspi, lpspi, CR, MEN == MEN_1) {}
Self {
lpspi,
men,
ccr_cache,
}
}
pub fn set_clock_hz(&mut self, source_clock_hz: u32, clock_hz: u32) {
let clock_configs = compute_spi_clock(source_clock_hz, clock_hz);
self.set_clock_configs(clock_configs);
}
pub fn set_clock_configs(&mut self, timing: ClockConfigs) {
self.ccr_cache.update(timing);
ral::write_reg!(ral::lpspi, self.lpspi, CCR,
SCKPCS: timing.sckpcs as u32,
PCSSCK: timing.pcssck as u32,
DBT: timing.dbt as u32,
SCKDIV: timing.sckdiv as u32,
);
}
#[inline]
pub fn set_sample_point(&mut self, sample_point: SamplePoint) {
match sample_point {
SamplePoint::Edge => ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, SAMPLE: SAMPLE_0),
SamplePoint::DelayedEdge => {
ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, SAMPLE: SAMPLE_1)
}
}
}
#[inline]
pub fn set_peripheral_enable(&mut self, enable: bool) {
ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, MASTER: !enable as u32);
}
#[inline]
pub fn set_chip_select_polarity(&mut self, pcs: Pcs, polarity: PcsPolarity) {
let pcspol = ral::read_reg!(ral::lpspi, self.lpspi, CFGR1, PCSPOL);
let mask = 1 << pcs as u32;
let pcspol = if polarity == PcsPolarity::ActiveHigh {
pcspol | mask
} else {
pcspol & !mask
};
ral::modify_reg!(ral::lpspi, self.lpspi, CFGR1, PCSPOL: pcspol);
}
}
impl Drop for Disabled<'_> {
fn drop(&mut self) {
ral::modify_reg!(ral::lpspi, self.lpspi, CR, MEN: self.men as u32);
}
}
impl eh02::blocking::spi::Transfer<u8> for Lpspi {
type Error = LpspiError;
fn transfer<'a>(&mut self, words: &'a mut [u8]) -> Result<&'a [u8], Self::Error> {
self.exchange(words)?;
self.flush()?;
Ok(words)
}
}
impl eh02::blocking::spi::Transfer<u16> for Lpspi {
type Error = LpspiError;
fn transfer<'a>(&mut self, words: &'a mut [u16]) -> Result<&'a [u16], Self::Error> {
self.exchange(words)?;
self.flush()?;
Ok(words)
}
}
impl eh02::blocking::spi::Transfer<u32> for Lpspi {
type Error = LpspiError;
fn transfer<'a>(&mut self, words: &'a mut [u32]) -> Result<&'a [u32], Self::Error> {
self.exchange(words)?;
self.flush()?;
Ok(words)
}
}
impl eh02::blocking::spi::Write<u8> for Lpspi {
type Error = LpspiError;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.write_no_read(words)?;
self.flush()?;
Ok(())
}
}
impl eh02::blocking::spi::Write<u16> for Lpspi {
type Error = LpspiError;
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
self.write_no_read(words)?;
self.flush()?;
Ok(())
}
}
impl eh02::blocking::spi::Write<u32> for Lpspi {
type Error = LpspiError;
fn write(&mut self, words: &[u32]) -> Result<(), Self::Error> {
self.write_no_read(words)?;
self.flush()?;
Ok(())
}
}
impl eh1::spi::Error for LpspiError {
fn kind(&self) -> eh1::spi::ErrorKind {
match self {
Self::FrameSize => eh1::spi::ErrorKind::Other,
Self::Fifo(Direction::Rx) => eh1::spi::ErrorKind::Overrun,
Self::Fifo(Direction::Tx) => eh1::spi::ErrorKind::Other,
}
}
}
impl eh1::spi::ErrorType for Lpspi {
type Error = LpspiError;
}
macro_rules! spibus {
($ty:ty) => {
impl eh1::spi::SpiBus<$ty> for Lpspi {
fn read(&mut self, words: &mut [$ty]) -> Result<(), Self::Error> {
self.read_no_write(words)?;
Ok(())
}
fn write(&mut self, words: &[$ty]) -> Result<(), Self::Error> {
self.write_no_read(words)?;
Ok(())
}
fn transfer(&mut self, read: &mut [$ty], write: &[$ty]) -> Result<(), Self::Error> {
self.exchange_separate(read, write)?;
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [$ty]) -> Result<(), Self::Error> {
self.exchange(words)?;
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
Lpspi::flush(self)?;
Ok(())
}
}
};
}
spibus!(u8);
spibus!(u16);
spibus!(u32);
trait Word: Copy + Into<u32> + TryFrom<u32> {
const DUMMY: Self;
fn pack_word(bit_order: BitOrder, provider: impl FnMut() -> Option<Self>) -> u32;
fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, sink: impl FnMut(Self));
}
impl Word for u8 {
const DUMMY: u8 = u8::MAX;
fn pack_word(bit_order: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
let mut word = 0;
match bit_order {
BitOrder::Msb => {
for _ in 0..4 {
if let Some(byte) = provider() {
word <<= 8;
word |= u32::from(byte);
}
}
}
BitOrder::Lsb => {
for offset in 0..4 {
if let Some(byte) = provider() {
word |= u32::from(byte) << (8 * offset);
}
}
}
}
word
}
fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, mut sink: impl FnMut(Self)) {
let mut offsets = [0usize, 8, 16, 24];
let valid = &mut offsets[..valid_bytes];
if matches!(bit_order, BitOrder::Msb) {
valid.reverse();
}
for offset in valid {
sink((word >> *offset) as u8);
}
}
}
impl Word for u16 {
const DUMMY: u16 = u16::MAX;
fn pack_word(bit_order: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
let mut word = 0;
match bit_order {
BitOrder::Msb => {
for _ in 0..2 {
if let Some(half) = provider() {
word <<= 16;
word |= u32::from(half);
}
}
}
BitOrder::Lsb => {
for offset in 0..2 {
if let Some(half) = provider() {
word |= u32::from(half) << (16 * offset);
}
}
}
}
word
}
fn unpack_word(word: u32, bit_order: BitOrder, valid_bytes: usize, mut sink: impl FnMut(Self)) {
let mut offsets = [0usize, 16];
let valid = &mut offsets[..valid_bytes / 2];
if matches!(bit_order, BitOrder::Msb) {
valid.reverse();
}
for offset in valid {
sink((word >> *offset) as u16);
}
}
}
impl Word for u32 {
const DUMMY: u32 = u32::MAX;
fn pack_word(_: BitOrder, mut provider: impl FnMut() -> Option<Self>) -> u32 {
provider().unwrap_or(0)
}
fn unpack_word(word: u32, _: BitOrder, _: usize, mut sink: impl FnMut(Self)) {
sink(word)
}
}
trait TransmitData {
fn next_word(&mut self, bit_order: BitOrder) -> u32;
}
trait ReceiveData {
fn next_word(&mut self, bit_order: BitOrder, word: u32);
}
struct TransmitBuffer<'a, W> {
ptr: *const W,
end: *const W,
dummies: usize,
_buffer: PhantomData<&'a [W]>,
}
impl<'a, W> TransmitBuffer<'a, W>
where
W: Word,
{
fn new(buffer: &'a [W]) -> Self {
unsafe { Self::from_raw(buffer.as_ptr(), buffer.len()) }
}
fn with_dummies(buffer: &'a [W], dummies: usize) -> Self {
let mut this = unsafe { Self::from_raw(buffer.as_ptr(), buffer.len()) };
this.dummies = dummies;
this
}
unsafe fn from_raw(ptr: *const W, len: usize) -> Self {
Self {
ptr,
end: unsafe { ptr.add(len) },
dummies: 0,
_buffer: PhantomData,
}
}
fn next_read(&mut self) -> Option<W> {
unsafe {
(!core::ptr::eq(self.ptr, self.end)).then(|| {
let word = self.ptr.read();
self.ptr = self.ptr.add(1);
word
})
}
.or_else(|| {
(self.dummies > 0).then(|| {
self.dummies = self.dummies.saturating_sub(1);
W::DUMMY
})
})
}
}
impl<W> TransmitData for TransmitBuffer<'_, W>
where
W: Word,
{
fn next_word(&mut self, bit_order: BitOrder) -> u32 {
W::pack_word(bit_order, || self.next_read())
}
}
struct ReceiveBuffer<'a, W> {
ptr: *mut W,
end: *const W,
discards: usize,
_buffer: PhantomData<&'a [W]>,
}
impl<W> ReceiveBuffer<'_, W>
where
W: Word,
{
fn new(buffer: &mut [W]) -> Self {
unsafe { Self::from_raw(buffer.as_mut_ptr(), buffer.len()) }
}
fn with_discards(buffer: &mut [W], discards: usize) -> Self {
let mut this = unsafe { Self::from_raw(buffer.as_mut_ptr(), buffer.len()) };
this.discards = discards;
this
}
unsafe fn from_raw(ptr: *mut W, len: usize) -> Self {
Self {
ptr,
end: unsafe { ptr.cast_const().add(len) },
discards: 0,
_buffer: PhantomData,
}
}
fn next_write(&mut self, elem: W) {
unsafe {
if !core::ptr::eq(self.ptr.cast_const(), self.end) {
self.ptr.write(elem);
self.ptr = self.ptr.add(1);
}
}
}
fn array_len(&self) -> usize {
unsafe { self.end.byte_offset_from(self.ptr) as _ }
}
}
impl<W> ReceiveData for ReceiveBuffer<'_, W>
where
W: Word,
{
fn next_word(&mut self, bit_order: BitOrder, word: u32) {
let mut valid_bytes = self.array_len().min(size_of_val(&word));
while valid_bytes < size_of_val(&word) && self.discards != 0 {
valid_bytes = valid_bytes.saturating_add(size_of::<W>());
self.discards = self.discards.saturating_sub(1);
}
W::unpack_word(word, bit_order, valid_bytes, |elem| self.next_write(elem));
}
}
const fn per_word<W: Word>() -> usize {
core::mem::size_of::<u32>() / core::mem::size_of::<W>()
}
const fn word_count<W: Word>(words: &[W]) -> usize {
words.len().div_ceil(per_word::<W>())
}
fn transfer_in_place<W: Word>(buffer: &mut [W]) -> (TransmitBuffer<'_, W>, ReceiveBuffer<'_, W>) {
unsafe {
let len = buffer.len();
let ptr = buffer.as_mut_ptr();
(
TransmitBuffer::from_raw(ptr, len),
ReceiveBuffer::from_raw(ptr, len),
)
}
}
#[cfg(test)]
mod tests {
#[test]
fn transfer_in_place_interleaved_read_write_u32() {
const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
let mut buffer = BUFFER;
let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
for elem in BUFFER {
assert_eq!(elem, tx.next_read().unwrap());
rx.next_write(elem + 1);
}
assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
}
#[test]
fn transfer_in_place_interleaved_write_read_u32() {
const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
let mut buffer = BUFFER;
let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
for elem in BUFFER {
rx.next_write(elem + 1);
assert_eq!(elem + 1, tx.next_read().unwrap());
}
assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
}
#[test]
fn transfer_in_place_bulk_read_write_u32() {
const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
let mut buffer = BUFFER;
let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
for elem in BUFFER {
assert_eq!(elem, tx.next_read().unwrap());
}
for elem in BUFFER {
rx.next_write(elem + 1);
}
assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
}
#[test]
fn transfer_in_place_bulk_write_read_u32() {
const BUFFER: [u32; 9] = [42u32, 43, 44, 45, 46, 47, 48, 49, 50];
let mut buffer = BUFFER;
let (mut tx, mut rx) = super::transfer_in_place(&mut buffer);
for elem in BUFFER {
rx.next_write(elem + 1);
}
for elem in BUFFER {
assert_eq!(elem + 1, tx.next_read().unwrap());
}
assert_eq!(buffer, [43, 44, 45, 46, 47, 48, 49, 50, 51]);
}
#[test]
fn transmit_buffer() {
use super::{BitOrder::*, TransmitBuffer, TransmitData};
let mut tx = TransmitBuffer::new(&[0xDEADBEEFu32, 0xAD1CAC1D]);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0xAD1CAC1D);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADBEEFu32, 0xAD1CAC1D]);
assert_eq!(tx.next_word(Lsb), 0xDEADBEEF);
assert_eq!(tx.next_word(Lsb), 0xAD1CAC1D);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEADBEEFu32, 0xAD1CAC1D], 1);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0xAD1CAC1D);
assert_eq!(tx.next_word(Msb), u32::MAX);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEADBEEFu32, 0xAD1CAC1D], 1);
assert_eq!(tx.next_word(Lsb), 0xDEADBEEF);
assert_eq!(tx.next_word(Lsb), 0xAD1CAC1D);
assert_eq!(tx.next_word(Lsb), u32::MAX);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D]);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0x00A5001D);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D], 1);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0xA5001DFF);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D]);
assert_eq!(tx.next_word(Lsb), 0xEFBEADDE);
assert_eq!(tx.next_word(Lsb), 0x001D00A5);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEu8, 0xAD, 0xBE, 0xEF, 0xA5, 0x00, 0x1D], 1);
assert_eq!(tx.next_word(Lsb), 0xEFBEADDE);
assert_eq!(tx.next_word(Lsb), 0xFF1D00A5);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF]);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE, 0xEF]);
assert_eq!(tx.next_word(Lsb), 0xEFBEADDE);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE]);
assert_eq!(tx.next_word(Msb), 0x00DEADBE);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEu8, 0xAD, 0xBE], 2);
assert_eq!(tx.next_word(Msb), 0xDEADBEFF);
assert_eq!(tx.next_word(Msb), 0xFF);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEu8, 0xAD, 0xBE]);
assert_eq!(tx.next_word(Lsb), 0x00BEADDE);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEu8, 0xAD, 0xBE], 2);
assert_eq!(tx.next_word(Lsb), 0xFFBEADDE);
assert_eq!(tx.next_word(Lsb), 0xFF);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF, 0xA5A5]);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0x0000A5A5);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEADu16, 0xBEEF, 0xA5A5], 3);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0xA5A5FFFF);
assert_eq!(tx.next_word(Msb), u32::MAX);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF, 0xA5A5]);
assert_eq!(tx.next_word(Lsb), 0xBEEFDEAD);
assert_eq!(tx.next_word(Lsb), 0x0000A5A5);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::with_dummies(&[0xDEADu16, 0xBEEF, 0xA5A5], 3);
assert_eq!(tx.next_word(Lsb), 0xBEEFDEAD);
assert_eq!(tx.next_word(Lsb), 0xFFFFA5A5);
assert_eq!(tx.next_word(Lsb), u32::MAX);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF]);
assert_eq!(tx.next_word(Msb), 0xDEADBEEF);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16, 0xBEEF]);
assert_eq!(tx.next_word(Lsb), 0xBEEFDEAD);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16]);
assert_eq!(tx.next_word(Msb), 0x0000DEAD);
assert_eq!(tx.next_word(Msb), 0);
assert_eq!(tx.next_word(Msb), 0);
let mut tx = TransmitBuffer::new(&[0xDEADu16]);
assert_eq!(tx.next_word(Lsb), 0x0000DEAD);
assert_eq!(tx.next_word(Lsb), 0);
assert_eq!(tx.next_word(Lsb), 0);
}
#[test]
fn receive_buffer() {
use super::{BitOrder::*, ReceiveBuffer, ReceiveData};
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x04030201);
rx.next_word(Msb, 0x55555555);
assert_eq!(
buffer,
[0xDE, 0xAD, 0xBE, 0xEF, 0xAD, 0x1C, 0xAC, 0x1D, 0x01]
);
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 1);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x04030201);
rx.next_word(Msb, 0x55555555);
assert_eq!(
buffer,
[0xDE, 0xAD, 0xBE, 0xEF, 0xAD, 0x1C, 0xAC, 0x1D, 0x02]
);
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 2);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x04030201);
rx.next_word(Msb, 0x55555555);
assert_eq!(
buffer,
[0xDE, 0xAD, 0xBE, 0xEF, 0xAD, 0x1C, 0xAC, 0x1D, 0x03]
);
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x04030201);
rx.next_word(Lsb, 0x55555555);
assert_eq!(
buffer,
[0xEF, 0xBE, 0xAD, 0xDE, 0x1D, 0xAC, 0x1C, 0xAD, 0x01]
);
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 1);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x04030201);
rx.next_word(Lsb, 0x55555555);
assert_eq!(
buffer,
[0xEF, 0xBE, 0xAD, 0xDE, 0x1D, 0xAC, 0x1C, 0xAD, 0x01]
);
let mut buffer = [0u8; 9];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 2);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x04030201);
rx.next_word(Lsb, 0x55555555);
assert_eq!(
buffer,
[0xEF, 0xBE, 0xAD, 0xDE, 0x1D, 0xAC, 0x1C, 0xAD, 0x01]
);
let mut buffer = [0u16; 5];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x04030201);
rx.next_word(Msb, 0x55555555);
assert_eq!(buffer, [0xDEAD, 0xBEEF, 0xAD1C, 0xAC1D, 0x0201]);
let mut buffer = [0u16; 5];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 1);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x04030201);
rx.next_word(Msb, 0x55555555);
assert_eq!(buffer, [0xDEAD, 0xBEEF, 0xAD1C, 0xAC1D, 0x0403]);
let mut buffer = [0u16; 5];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x04030201);
rx.next_word(Lsb, 0x55555555);
assert_eq!(buffer, [0xBEEF, 0xDEAD, 0xAC1D, 0xAD1C, 0x0201]);
let mut buffer = [0u16; 5];
let mut rx = ReceiveBuffer::with_discards(&mut buffer, 1);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x04030201);
rx.next_word(Lsb, 0x55555555);
assert_eq!(buffer, [0xBEEF, 0xDEAD, 0xAC1D, 0xAD1C, 0x0201]);
let mut buffer = [0u32; 3];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Msb, 0xDEADBEEF);
rx.next_word(Msb, 0xAD1CAC1D);
rx.next_word(Msb, 0x77777777);
rx.next_word(Msb, 0x55555555);
assert_eq!(buffer, [0xDEADBEEF, 0xAD1CAC1D, 0x77777777]);
let mut buffer = [0u32; 3];
let mut rx = ReceiveBuffer::new(&mut buffer);
rx.next_word(Lsb, 0xDEADBEEF);
rx.next_word(Lsb, 0xAD1CAC1D);
rx.next_word(Lsb, 0x77777777);
rx.next_word(Lsb, 0x55555555);
assert_eq!(buffer, [0xDEADBEEF, 0xAD1CAC1D, 0x77777777]);
}
#[test]
fn transaction_frame_sizes() {
assert!(super::Transaction::new_words(&[1u8]).is_ok());
assert!(super::Transaction::new_words(&[1u8, 2]).is_ok());
assert!(super::Transaction::new_words(&[1u8, 2, 3]).is_ok());
assert!(super::Transaction::new_words(&[1u8, 2, 3, 4]).is_ok());
assert!(super::Transaction::new_words(&[1u8, 2, 3, 4, 5]).is_ok());
assert!(super::Transaction::new_words(&[1u16]).is_ok());
assert!(super::Transaction::new_words(&[1u16, 2]).is_ok());
assert!(super::Transaction::new_words(&[1u16, 2, 3]).is_ok());
assert!(super::Transaction::new_words(&[1u16, 2, 3, 4]).is_ok());
assert!(super::Transaction::new_words(&[1u16, 2, 3, 4, 5]).is_ok());
assert!(super::Transaction::new_words(&[1u32]).is_ok());
assert!(super::Transaction::new_words(&[1u32, 2]).is_ok());
assert!(super::Transaction::new_words(&[1u32, 2, 3]).is_ok());
assert!(super::Transaction::new_words(&[1u32, 2, 3, 4]).is_ok());
assert!(super::Transaction::new_words(&[1u32, 2, 3, 4, 5]).is_ok());
assert!(super::Transaction::new(7).is_err());
assert!(super::Transaction::new(8).is_ok());
assert!(super::Transaction::new(9).is_ok());
assert!(super::Transaction::new(31).is_ok());
assert!(super::Transaction::new(32).is_ok());
assert!(super::Transaction::new(33).is_err());
assert!(super::Transaction::new(34).is_ok());
assert!(super::Transaction::new(95).is_ok());
assert!(super::Transaction::new(96).is_ok());
assert!(super::Transaction::new(97).is_err());
assert!(super::Transaction::new(98).is_ok());
}
}