avr-oxide 0.3.0

An extremely simple Rusty operating system for AVR microcontrollers
/* mod.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Higher-level device abstractions for things like LEDs, system clocks,
//! buttons.
use core::ops::{Deref, DerefMut};
use avr_oxide::alloc::boxed::Box;
use avr_oxide::devices::button::Button;
use avr_oxide::devices::led::Led;
use avr_oxide::devices::masterclock::MasterClock;
use avr_oxide::devices::serialport::SerialPort;
use avr_oxide::devices::wallclock::WallClock;
use avr_oxide::hal::generic::port::Pin;
use avr_oxide::oxide::OxideSupervisor;
use avr_oxide::util::OwnOrBorrow;

pub mod masterclock;
pub mod wallclock;
pub mod led;
pub mod button;
pub mod serialport;
pub mod debouncer;
pub mod inverter;

/// A simple button attached to a hardware pin that generates events with the
/// standard AVRoxide Supervisor implementation.
pub type OxideButton<'a,'b> = Button<'a,OxideSupervisor<'b>>;
/// A simple LED attached to a hardware pin.
pub type OxideLed = Led;
/// A high-frequency, low-accuracy clock event source that works with the
/// standard AVRoxide Supervisor implementation.
pub type OxideMasterClock<'a,'b,T> = MasterClock<'a,T,OxideSupervisor<'b>>;
/// A simple serial port device that works with the standard AVRoxide
/// Supervisor implementation.
pub type OxideSerialPort<'a,'s> = SerialPort<'a,OxideSupervisor<'s>>;
/// A low-frequency, high-accuracy clock event source that works with the
/// standard AVRoxide Supervisor implementation.
pub type OxideWallClock<'a,'b,T> = WallClock<'a,T,OxideSupervisor<'b>>;


/// Convenience trait implemented by any devices that use (and are constructed
/// with) an I/O pin.
pub trait UsesPin {
  /// Create an instance of this device that uses the given instance of
  /// a pin (by ownership or reference.)
  fn using<OP: Into<OwnOrBorrow<'static, dyn Pin>>>(pin: OP) -> Self;

//  /// Convenience method to create an instance of this device with a
//  /// given static reference to a pin (avoids a certain amount of type
//  /// hinting boilerplate for the caller.)
  fn with_pin(pin: &'static dyn Pin) -> Self
  where
    Self: Sized
  {
    Self::using(pin)
  }

  /// Create an instance of this device that uses the given instance of a pin,
  /// and return a static reference good for the lifetime of the program.
  ///
  /// # Note
  /// This method leaks memory, deliberately - the create instance will never
  /// be freed.  In our intended embedded environment, this is entirely
  /// deliberate.
  fn static_using<OP: Into<OwnOrBorrow<'static, dyn Pin>>>(pin: OP) -> &'static mut Self where Self:Sized {
    Box::leak(Box::new(Self::using(pin)))
  }

  /// Create an instance of this device that uses the given reference to a pin,
  /// and return a static reference good for the lifetime of the program.
  ///
  /// # Note
  /// This method leaks memory, deliberately - the create instance will never
  /// be freed.  In our intended embedded environment, this is entirely
  /// deliberate.
  fn static_with_pin(pin: &'static dyn Pin) -> &'static mut Self where Self:Sized {
    Box::leak(Box::new(Self::with_pin(pin)))
  }
}

/// This is a somewhat horrible thing, which allows us to evade Rust's borrow
/// checker.
///
/// Unfortunately, the borrow checker is not yet smart enough to know that
/// our application never terminates after the supervisor starts, and thus
/// that references created in the main() function can be expected to live
/// forever.
///
/// The Handle wrapper allows us to leak these references into a static
/// reference, as well as (by implementing Clone) allowing us to share
/// those references between our various event closures.
///
/// I feel slightly dirty about this, so this wrapper may only be used on
/// internal AVRoxide driver types.
pub struct Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
  device: *mut T
}


/// Marker trait identifying types that can be wrapped in a Handle.
pub(crate) mod internal {
  pub trait StaticShareable {}
}

impl<T> Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
  pub fn new(wrapping: T) -> Self {
    let boxed = Box::new(wrapping);

    Handle {
      device: Box::leak(boxed) as *mut T
    }
  }

  pub(crate) fn static_deref(&self) -> &'static T {
    unsafe {
      &*self.device
    }
  }

  pub(crate) fn static_deref_mut(&self) -> &'static mut T {
    unsafe {
      &mut *self.device
    }
  }
}

impl<T> Deref for Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
  type Target = T;

  fn deref(&self) -> &Self::Target {
    unsafe {
      &*self.device
    }
  }
}

impl<T> DerefMut for Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
  fn deref_mut(&mut self) -> &mut Self::Target {
    unsafe {
      &mut *self.device
    }
  }
}

impl<T> Clone for Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
  fn clone(&self) -> Self {
    Self {
      device: self.device
    }
  }
}

impl<T> Copy for Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable
{
}

unsafe impl<T> Send for Handle<T>
where
  T: avr_oxide::devices::internal::StaticShareable + Send + 'static,
{ }
unsafe impl<T> Sync for Handle<T>
  where
    T: avr_oxide::devices::internal::StaticShareable + Sync + 'static,
{ }