Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use method chaining for configuration #12

Merged
merged 1 commit into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,13 @@ impl<I: FilterOwner> MasterFilters<'_, I> {

impl<I: MasterInstance> MasterFilters<'_, I> {
/// Sets the index at which the filter banks owned by the slave peripheral start.
pub fn set_split(&mut self, split_index: u8) {
pub fn set_split(&mut self, split_index: u8) -> &mut Self {
assert!(split_index <= I::NUM_FILTER_BANKS);
self.registers()
.fmr
.modify(|_, w| unsafe { w.can2sb().bits(split_index) });
self.bank_count = split_index;
self
}

/// Accesses the filters assigned to the slave peripheral.
Expand Down
52 changes: 41 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,11 @@ impl PartialOrd for IdReg {
}

/// Configuration proxy to be used with `Can::configure()`.
pub struct CanConfig<I> {
_can: PhantomData<I>,
pub struct CanConfig<'a, I: Instance> {
_can: PhantomData<&'a mut I>,
}

impl<I> CanConfig<I>
where
I: Instance,
{
impl<I: Instance> CanConfig<'_, I> {
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
Expand All @@ -235,25 +232,44 @@ where
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
pub fn set_bit_timing(&mut self, btr: u32) {
pub fn set_bit_timing(&mut self, btr: u32) -> &mut Self {
let can = self.registers();
can.btr.modify(|r, w| unsafe {
let mode_bits = r.bits() & 0xC000_0000;
w.bits(mode_bits | btr)
});
self
}

/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(&mut self, enabled: bool) {
pub fn set_loopback(&mut self, enabled: bool) -> &mut Self {
let can = self.registers();
can.btr.modify(|_, w| w.lbkm().bit(enabled));
self
}

/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(&mut self, enabled: bool) {
pub fn set_silent(&mut self, enabled: bool) -> &mut Self {
let can = self.registers();
can.btr.modify(|_, w| w.silm().bit(enabled));
self
}
}

impl<I: Instance> Drop for CanConfig<'_, I> {
#[inline]
fn drop(&mut self) {
// Leave initialization mode
let can = self.registers();
can.mcr
.modify(|_, w| w.sleep().set_bit().inrq().clear_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_set() && msr.inak().bit_is_clear() {
break;
}
}
}
}

Expand Down Expand Up @@ -307,9 +323,23 @@ where

let mut config = CanConfig { _can: PhantomData };
f(&mut config);
}

/// Configure bit timings and silent/loop-back mode.
pub fn modify_config(&mut self) -> CanConfig<'_, I> {
let can = self.registers();

// Enter init mode.
can.mcr
.modify(|_, w| w.sleep().clear_bit().inrq().set_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_clear() && msr.inak().bit_is_set() {
break;
}
}

// Leave init mode: go back to sleep.
self.sleep();
CanConfig { _can: PhantomData }
}

/// Configures the automatic wake-up feature.
Expand Down
84 changes: 44 additions & 40 deletions testsuite/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ impl State {
let periph = defmt::unwrap!(pac::Peripherals::take());
let (can1, can2) = testsuite::init(periph);
let mut can1 = Can::new(can1);
can1.configure(|c| {
c.set_loopback(true);
c.set_silent(true);
c.set_bit_timing(0x00050000);
});
can1.modify_config()
.set_loopback(true)
.set_silent(true)
.set_bit_timing(0x00050000);
let mut can2 = Can::new(can2);
can2.configure(|c| {
c.set_loopback(true);
c.set_silent(true);
c.set_bit_timing(0x00050000);
});
can2.modify_config()
.set_loopback(true)
.set_silent(true)
.set_bit_timing(0x00050000);

Self { can1, can2 }
}
Expand All @@ -34,21 +32,21 @@ impl State {
///
/// This is useful for testing recovery when the mailboxes are full.
fn go_slow(&mut self) {
self.can1.configure(|c| {
c.set_loopback(true);
c.set_silent(true);
c.set_bit_timing(0x007f_03ff);
});
self.can1
.modify_config()
.set_loopback(true)
.set_silent(true)
.set_bit_timing(0x007f_03ff);
nb::block!(self.can1.enable()).unwrap();
}

/// Configures the default (fast) speed.
fn go_fast(&mut self) {
self.can1.configure(|c| {
c.set_loopback(true);
c.set_silent(true);
c.set_bit_timing(0x00050000);
});
self.can1
.modify_config()
.set_loopback(true)
.set_silent(true)
.set_bit_timing(0x00050000);
nb::block!(self.can1.enable()).unwrap();
}
}
Expand Down Expand Up @@ -384,26 +382,32 @@ mod tests {
/// Requires that both are hooked up to the same CAN bus.
#[test]
fn ext_roundtrip(state: &mut State) {
state.can1.configure(|c| {
c.set_loopback(false);
c.set_silent(false);
c.set_bit_timing(0x00050000);
});
state.can2.configure(|c| {
c.set_loopback(false);
c.set_silent(false);
c.set_bit_timing(0x00050000);
});

let mut filt1 = state.can1.modify_filters();
filt1.set_split(1);
filt1.clear();
filt1.enable_bank(0, Mask32::accept_all());

let mut filt2 = filt1.slave_filters();
filt2.clear();
filt2.enable_bank(1, Mask32::accept_all());
drop(filt1);
state
.can1
.modify_config()
.set_loopback(false)
.set_silent(false)
.set_bit_timing(0x00050000);
state
.can2
.modify_config()
.set_loopback(false)
.set_silent(false)
.set_bit_timing(0x00050000);

state
.can1
.modify_filters()
.set_split(1)
.clear()
.enable_bank(0, Mask32::accept_all());

state
.can1
.modify_filters()
.slave_filters()
.clear()
.enable_bank(1, Mask32::accept_all());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just look at the elegance of this!

block!(state.can1.enable()).unwrap();
block!(state.can2.enable()).unwrap();
Expand Down