Skip to content

Switch from stateless to stateful Clock #27

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

Merged
merged 1 commit into from
Jul 1, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

### Changed

- Add `&mut self` to `Clock` functions (make stateful, or at least allow stateful implementations)
- All time-type inner types from signed to unsigned
- `Instant::duration_since()` return type to `Result`
- Refactor `examples/nrf52_dk`
Expand Down
64 changes: 29 additions & 35 deletions examples/nrf52_dk/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,51 @@

extern crate panic_rtt;

use cortex_m::mutex::CriticalSectionMutex as Mutex;
use cortex_m_rt::entry;
use embedded_time::{self as time, traits::*, Clock, Instant, Period};
use mutex_trait::Mutex as _;
use embedded_time::{self as time, traits::*};

pub mod nrf52 {
pub use nrf52832_hal::{
gpio,
prelude::*,
target::{self as pac, Peripherals},
};
}

pub struct Clock64 {
low: pac::TIMER0,
high: pac::TIMER1,
capture_task: pac::EGU0,
}

impl Clock64 {
pub fn take(low: pac::TIMER0, high: pac::TIMER1, capture_task: pac::EGU0) -> Self {
Self {
low,
high,
capture_task,
}
}
pub struct SysClock {
low: nrf52::pac::TIMER0,
high: nrf52::pac::TIMER1,
capture_task: nrf52::pac::EGU0,
}

pub(crate) fn read(&mut self) -> u64 {
self.capture_task.tasks_trigger[0].write(|write| unsafe { write.bits(1) });
self.low.cc[0].read().bits() as u64 | ((self.high.cc[0].read().bits() as u64) << 32)
impl SysClock {
pub fn take(
low: nrf52::pac::TIMER0,
high: nrf52::pac::TIMER1,
capture_task: nrf52::pac::EGU0,
) -> Self {
Self {
low,
high,
capture_task,
}
}
}

pub struct SysClock;

impl time::Clock for SysClock {
type Rep = u64;
const PERIOD: Period = <Period>::new(1, 16_000_000);
const PERIOD: time::Period = <time::Period>::new(1, 16_000_000);

fn now() -> Instant<Self> {
let ticks = (&CLOCK64).lock(|clock| match clock {
Some(clock) => clock.read(),
None => 0,
});
fn now(&mut self) -> time::Instant<Self> {
self.capture_task.tasks_trigger[0].write(|write| unsafe { write.bits(1) });

Instant::new(ticks as Self::Rep)
let ticks =
self.low.cc[0].read().bits() as u64 | ((self.high.cc[0].read().bits() as u64) << 32);

time::Instant::new(ticks as Self::Rep)
}
}

static CLOCK64: Mutex<Option<nrf52::Clock64>> = Mutex::new(None);

#[entry]
fn main() -> ! {
let device = nrf52::pac::Peripherals::take().unwrap();
Expand Down Expand Up @@ -106,8 +99,7 @@ fn main() -> ! {
// This moves these peripherals to prevent conflicting usage, however not the entire EGU0 is
// used. A ref to EGU0 could be sent instead, although that provides no protection for the
// fields that are being used by Clock64.
let clock64 = nrf52::Clock64::take(device.TIMER0, device.TIMER1, device.EGU0);
(&CLOCK64).lock(|ticks| *ticks = Some(clock64));
let mut clock = SysClock::take(device.TIMER0, device.TIMER1, device.EGU0);

let port0 = nrf52::gpio::p0::Parts::new(device.P0);

Expand Down Expand Up @@ -136,6 +128,7 @@ fn main() -> ! {
&mut led2.degrade(),
&mut led3.degrade(),
&mut led4.degrade(),
&mut clock,
)
.unwrap();

Expand All @@ -147,6 +140,7 @@ fn run<Led>(
led2: &mut Led,
led3: &mut Led,
led4: &mut Led,
clock: &mut SysClock,
) -> Result<(), <Led as nrf52::OutputPin>::Error>
where
Led: nrf52::OutputPin,
Expand All @@ -156,12 +150,12 @@ where
led2.set_high()?;
led3.set_high()?;
led4.set_low()?;
SysClock::delay(250_u32.milliseconds());
clock.delay(250_u32.milliseconds());

led1.set_high()?;
led2.set_low()?;
led3.set_low()?;
led4.set_high()?;
SysClock::delay(250_u32.milliseconds());
clock.delay(250_u32.milliseconds());
}
}
8 changes: 4 additions & 4 deletions src/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ pub trait Clock: Sized {
const PERIOD: Period;

/// Get the current Instant
fn now() -> Instant<Self>;
fn now(&mut self) -> Instant<Self>;

/// Blocking delay
fn delay<Dur: Duration>(dur: Dur)
fn delay<Dur: Duration>(&mut self, dur: Dur)
where
Self::Rep: TryFrom<Dur::Rep>,
{
let start = Self::now();
let start = self.now();
let end = start + dur;
while Self::now() < end {}
while self.now() < end {}
}
}
21 changes: 11 additions & 10 deletions src/instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<Clock: crate::Clock> Instant<Clock> {
/// type Rep = u32;
/// const PERIOD: Period = <Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// assert_eq!(Instant::<Clock>::new(5).duration_since::<Microseconds<u64>>(&Instant::<Clock>::new(3)),
Expand Down Expand Up @@ -74,7 +74,7 @@ impl<Clock: crate::Clock> Instant<Clock> {
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// assert_eq!(Instant::<Clock>::new(5).duration_until::<Microseconds<u64>>(&Instant::<Clock>::new(7)),
Expand All @@ -99,6 +99,7 @@ impl<Clock: crate::Clock> Instant<Clock> {
pub fn duration_since_epoch<Dur: Duration>(&self) -> Result<Dur, ()>
where
Dur::Rep: TryFrom<Clock::Rep>,
Clock::Rep: TryFrom<Dur::Rep>,
{
Self::duration_since::<Dur>(
&self,
Expand Down Expand Up @@ -137,7 +138,7 @@ impl<Clock: crate::Clock> PartialOrd for Instant<Clock> {
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// assert!(Instant::<Clock>::new(5) > Instant::<Clock>::new(3));
Expand Down Expand Up @@ -177,7 +178,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// Instant::<Clock>::new(1) + Seconds(u32::MAX);
Expand All @@ -193,7 +194,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// let _ = Instant::<Clock>::new(0) + Milliseconds(i32::MAX as u32 + 1);
Expand All @@ -210,7 +211,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// assert_eq!(Instant::<Clock>::new(1) + Seconds(3_u32), Instant::<Clock>::new(3_001));
Expand Down Expand Up @@ -250,7 +251,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// Instant::<Clock>::new(1) - Seconds(u32::MAX);
Expand All @@ -266,7 +267,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period = <Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// let _ = Instant::<Clock>::new(u32::MAX) - Milliseconds(i32::MAX as u32 + 1);
Expand All @@ -283,7 +284,7 @@ where
/// type Rep = u32;
/// const PERIOD: Period =<Period>::new(1, 1_000);
/// // ...
/// # fn now() -> Instant<Self> {unimplemented!()}
/// # fn now(&mut self) -> Instant<Self> {unimplemented!()}
/// }
///
/// assert_eq!(Instant::<Clock>::new(800) - Milliseconds(700_u32), Instant::<Clock>::new(100));
Expand Down Expand Up @@ -314,7 +315,7 @@ mod tests {
type Rep = u32;
const PERIOD: Period = <Period>::new(1, 1_000);

fn now() -> Instant<Self> {
fn now(&mut self) -> Instant<Self> {
unimplemented!()
}
}
Expand Down
29 changes: 17 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@
//! type Rep = u64;
//! const PERIOD: Period = <Period>::new(1, 16_000_000);
//!
//! fn now() -> Instant<Self> {
//! fn now(&mut self) -> Instant<Self> {
//! // ...
//! # unimplemented!()
//! }
//! }
//!
//! let instant1 = SomeClock::now();
//! let mut clock = SomeClock;
//! let instant1 = clock.now();
//! // ...
//! let instant2 = SomeClock::now();
//! let instant2 = clock.now();
//! assert!(instant1 < instant2); // instant1 is *before* instant2
//!
//! // duration is the difference between the instances
Expand Down Expand Up @@ -121,7 +122,7 @@ mod tests {
type Rep = u64;
const PERIOD: time::Period = <time::Period>::new(1, 64_000_000);

fn now() -> time::Instant<Self> {
fn now(&mut self) -> time::Instant<Self> {
time::Instant::new(128_000_000)
}
}
Expand All @@ -133,25 +134,29 @@ mod tests {
type Rep = u32;
const PERIOD: time::Period = <time::Period>::new(1, 16_000_000);

fn now() -> time::Instant<Self> {
fn now(&mut self) -> time::Instant<Self> {
time::Instant::new(32_000_000)
}
}

fn get_time<M: time::Clock>()
fn get_time<Clock: time::Clock>(clock: &mut Clock)
where
u32: TryFrom<M::Rep>,
u32: TryFrom<Clock::Rep>,
Clock::Rep: TryFrom<u32>,
{
assert_eq!(M::now().duration_since_epoch(), Ok(Seconds(2_u32)));
assert_eq!(clock.now().duration_since_epoch(), Ok(Seconds(2_u32)));
}

#[test]
fn common_types() {
let then = MockClock32::now();
let now = MockClock32::now();
let then = MockClock32.now();
let now = MockClock32.now();

get_time::<MockClock64>();
get_time::<MockClock32>();
let mut clock64 = MockClock64 {};
let mut clock32 = MockClock32 {};

get_time(&mut clock64);
get_time(&mut clock32);

let then = then - Seconds(1_u32);
assert_ne!(then, now);
Expand Down