use core::sync::atomic::{compiler_fence, Ordering};
use super::{
single_channel::ChannelConfig, single_channel::SingleChannel, EndlessReadTarget,
EndlessWriteTarget, Pace, ReadTarget, WriteTarget,
};
pub struct Config<CH1: SingleChannel, CH2: SingleChannel, FROM: ReadTarget, TO: WriteTarget> {
ch: (CH1, CH2),
from: FROM,
to: TO,
pace: Pace,
}
impl<CH1, CH2, FROM, TO, WORD> Config<CH1, CH2, FROM, TO>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD>,
TO: WriteTarget<TransmittedWord = WORD>,
{
pub fn new(ch: (CH1, CH2), from: FROM, to: TO) -> Config<CH1, CH2, FROM, TO> {
Config {
ch,
from,
to,
pace: Pace::PreferSource,
}
}
pub fn pace(&mut self, pace: Pace) {
self.pace = pace;
}
pub fn start(mut self) -> Transfer<CH1, CH2, FROM, TO, ()> {
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
self.ch
.0
.config(&self.from, &mut self.to, self.pace, None, true);
Transfer {
ch: self.ch,
from: self.from,
to: self.to,
pace: self.pace,
state: (),
second_ch: false,
}
}
}
pub struct ReadNext<BUF: ReadTarget>(BUF);
pub struct WriteNext<BUF: WriteTarget>(BUF);
pub struct Transfer<CH1, CH2, FROM, TO, STATE>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget,
TO: WriteTarget,
{
ch: (CH1, CH2),
from: FROM,
to: TO,
pace: Pace,
state: STATE,
second_ch: bool,
}
impl<CH1, CH2, FROM, TO, WORD, STATE> Transfer<CH1, CH2, FROM, TO, STATE>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD>,
TO: WriteTarget<TransmittedWord = WORD>,
{
pub fn check_irq0(&mut self) -> bool {
if self.second_ch {
self.ch.1.check_irq0()
} else {
self.ch.0.check_irq0()
}
}
pub fn check_irq1(&mut self) -> bool {
if self.second_ch {
self.ch.1.check_irq1()
} else {
self.ch.0.check_irq1()
}
}
pub fn is_done(&self) -> bool {
if self.second_ch {
!self.ch.1.ch().ch_ctrl_trig.read().busy().bit_is_set()
} else {
!self.ch.0.ch().ch_ctrl_trig.read().busy().bit_is_set()
}
}
}
impl<CH1, CH2, FROM, TO, WORD> Transfer<CH1, CH2, FROM, TO, ()>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD>,
TO: WriteTarget<TransmittedWord = WORD> + EndlessWriteTarget,
{
pub fn wait(self) -> (CH1, CH2, FROM, TO) {
while !self.is_done() {}
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
(self.ch.0, self.ch.1, self.from, self.to)
}
}
impl<CH1, CH2, FROM, TO, WORD> Transfer<CH1, CH2, FROM, TO, ()>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD>,
TO: WriteTarget<TransmittedWord = WORD> + EndlessWriteTarget,
{
pub fn read_next<BUF: ReadTarget<ReceivedWord = WORD>>(
mut self,
buf: BUF,
) -> Transfer<CH1, CH2, FROM, TO, ReadNext<BUF>> {
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
if self.second_ch {
self.ch.0.config(&buf, &mut self.to, self.pace, None, false);
} else {
self.ch.1.config(&buf, &mut self.to, self.pace, None, false);
}
if self.second_ch {
self.ch.1.set_chain_to_enabled(&mut self.ch.0);
} else {
self.ch.0.set_chain_to_enabled(&mut self.ch.1);
}
Transfer {
ch: self.ch,
from: self.from,
to: self.to,
pace: self.pace,
state: ReadNext(buf),
second_ch: self.second_ch,
}
}
}
impl<CH1, CH2, FROM, TO, WORD> Transfer<CH1, CH2, FROM, TO, ()>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD> + EndlessReadTarget,
TO: WriteTarget<TransmittedWord = WORD>,
{
pub fn write_next<BUF: WriteTarget<TransmittedWord = WORD>>(
mut self,
mut buf: BUF,
) -> Transfer<CH1, CH2, FROM, TO, WriteNext<BUF>> {
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
if self.second_ch {
self.ch
.0
.config(&self.from, &mut buf, self.pace, None, false);
} else {
self.ch
.1
.config(&self.from, &mut buf, self.pace, None, false);
}
if self.second_ch {
self.ch.1.set_chain_to_enabled(&mut self.ch.0);
} else {
self.ch.0.set_chain_to_enabled(&mut self.ch.1);
}
Transfer {
ch: self.ch,
from: self.from,
to: self.to,
pace: self.pace,
state: WriteNext(buf),
second_ch: self.second_ch,
}
}
}
impl<CH1, CH2, FROM, TO, NEXT, WORD> Transfer<CH1, CH2, FROM, TO, ReadNext<NEXT>>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD>,
TO: WriteTarget<TransmittedWord = WORD> + EndlessWriteTarget,
NEXT: ReadTarget<ReceivedWord = WORD>,
{
pub fn wait(self) -> (FROM, Transfer<CH1, CH2, NEXT, TO, ()>) {
while !self.is_done() {}
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
(
self.from,
Transfer {
ch: self.ch,
from: self.state.0,
to: self.to,
pace: self.pace,
state: (),
second_ch: !self.second_ch,
},
)
}
}
impl<CH1, CH2, FROM, TO, NEXT, WORD> Transfer<CH1, CH2, FROM, TO, WriteNext<NEXT>>
where
CH1: SingleChannel,
CH2: SingleChannel,
FROM: ReadTarget<ReceivedWord = WORD> + EndlessReadTarget,
TO: WriteTarget<TransmittedWord = WORD>,
NEXT: WriteTarget<TransmittedWord = WORD>,
{
pub fn wait(self) -> (TO, Transfer<CH1, CH2, FROM, NEXT, ()>) {
while !self.is_done() {}
cortex_m::asm::dsb();
compiler_fence(Ordering::SeqCst);
(
self.to,
Transfer {
ch: self.ch,
from: self.from,
to: self.state.0,
pace: self.pace,
state: (),
second_ch: !self.second_ch,
},
)
}
}