avr-oxide 0.1.0

An extremely simple Rusty operating system for AVR microcontrollers
/* wallclock.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! A simple RTC device designed to keep wall-clock time.  It generates
//! events at a fixed frequency of 1Hz, using the a reliable RTC clock
//! generator than the MasterClock device.


// Imports ===================================================================
use core::marker::PhantomData;
use core::cell::RefCell;
use core::ops::DerefMut;
use crate::alloc::boxed::Box;
use crate::event::{EventSink, EventSource, OxideEvent, OxideEventEnvelope};
use crate::hal::generic::timer::{RtcCalibration, RtcPrescaler, RtcSource, RtcTimerCalibration, TimerControl, TimerIsrCallback};
use crate::hal::generic::timer::TimerMode::Periodic;
use crate::panic_if_none;
use crate::util::OwnOrBorrowMut;

use super::masterclock::TickCallback;
use super::masterclock::TickEvents;

// Declarations ==============================================================
pub struct WallClock<'wc,T,S>
where
  T: 'static + TimerControl + RtcTimerCalibration,
  S: EventSink
{
  timer: OwnOrBorrowMut<'static,T>,
  phantom: PhantomData<S>,

  on_tick: RefCell<Option<Box<dyn TickCallback + 'wc>>>
}

// Code ======================================================================
impl<T,S> WallClock<'_,T,S>
where
  T: 'static + TimerControl + RtcTimerCalibration,
  S: EventSink
{
  pub fn using<OT: Into<OwnOrBorrowMut<'static,T>>>(timer: OT) -> Self {
    let mut timer : OwnOrBorrowMut<T> = timer.into();

    // Set up clock to use:
    //   1.024 KHz internal clock
    //   No calibration offset
    //   Prescaler value of 4
    timer.set_clock_calibration(RtcSource::Int1k,
                                RtcCalibration::Fast(0),
                                RtcPrescaler::Div4);

    timer.set_mode(Periodic);
    timer.set_interrupt_period(1024);

    // Note that the prescaler value has no effect on PIT interrupts,
    // so we need a period of 1024 on periodic timer interrupts to generate
    // one interrupt per second.
    Self {
      timer,
      phantom: PhantomData::default(),
      on_tick: RefCell::new(None)
    }
  }

  pub fn with_timer(timer: &'static mut T) -> Self {
    Self::using(timer)
  }
}

impl<'wc, T, S> TickEvents<'wc> for WallClock<'wc, T, S>
  where
    T: 'static + TimerControl + RtcTimerCalibration,
    S: EventSink
{
  fn on_tick(&mut self, bf: Box<dyn TickCallback + 'wc>) {
    self.on_tick.replace(Some(bf));
  }
}

impl<T,S> EventSource for WallClock<'_,T,S>
where
  T: 'static + TimerControl + RtcTimerCalibration,
  S: EventSink
{
  fn listen(&'static self) {
    self.timer.start(TimerIsrCallback::WithData(|source, ticks, udata| {
      S::event(OxideEventEnvelope::to(unsafe { &*(panic_if_none!(udata) as *const WallClock<T,S> as *const dyn EventSource) },
                                      OxideEvent::ClockTick(source,ticks)));
      true
    }, self as *const dyn core::any::Any ));
  }

  fn process_event(&self, evt: OxideEvent) {
    match (self.on_tick.borrow_mut().deref_mut(), evt) {
      (Some(f), OxideEvent::ClockTick(source, ticks)) => {
        (*f)(source,ticks)
      },
      _ => {}
    }
  }
}
// Tests =====================================================================