avr-oxide 0.1.0

An extremely simple Rusty operating system for AVR microcontrollers
/* oxide.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! A very basic "operating system" (ha!) for our embedded devices, that
//! essentially comprises an event loop that executes a provided closure
//! whenever something happens.  "Something happens" is indicated by
//! sending events to the supervisor.

// Imports ===================================================================
use crate::alloc::boxed::Box;
use crate::private::ringq::RingQ;
use crate::event::{OxideEvent, EventSink, EventSource, OxideEventEnvelope};
use crate::hal::concurrency::interrupt;

// Declarations ==============================================================

pub struct OxideSupervisor<'e>
{
  event_q: RingQ<OxideEventEnvelope<'e>, 16>,
}

static mut GLOBAL_INSTANCE : Option<&mut OxideSupervisor> = None;

// Code ======================================================================
pub(crate) fn create_supervisor<'a>() -> OxideSupervisor<'a> {
  OxideSupervisor {
    event_q: RingQ::new_with(OxideEventEnvelope::anon(OxideEvent::Initialise)),
  }
}

pub(crate) unsafe fn set_global_supervisor(global: &mut OxideSupervisor) {
  GLOBAL_INSTANCE.replace(core::mem::transmute(global));
}

pub fn instance() -> &'static mut OxideSupervisor<'static> {
  unsafe {
    match &mut GLOBAL_INSTANCE {
      Some(instance) => {
        *instance
      },
      None => panic!()
    }
  }
}

impl OxideSupervisor<'_> {
  /**
   * Called to have the supervisor listen for events from this device.
   */
  #[cfg(feature="alloc_ftr")]
  pub fn listen<EP: 'static + EventSource>(&mut self, source: Box<EP>) {
    let source : &'static mut EP = Box::leak(source);
    source.listen();
  }

  /**
   * Called to have the supervisor listen for events from this device.
   */
  pub fn listen_byref<EP: 'static + EventSource>(&mut self, source: &'static EP) {
    source.listen();
  }


  /**
   * Enter the event loop - and never return (*evil cackle*).  A pre-handler
   * closure is provided that will be called with the event before the
   * default handling method (a callback to the originator) is executed.  If
   * this prehandler returns `false`, then the standard event handling will
   * not be executed for this event and it will be discarded immediately
   * after the prehandler.
   */
  pub fn run_with_prehandler<F: FnMut(OxideEvent) -> bool>(&mut self, mut pre_handler: F) -> ! {
    loop {
      interrupt::wait();

      // We use the no-locking event Q.  This is safe as long as I am
      // the only consumer, and any producers are running in an interrupt-secure
      // context.
      while let Some(event) = self.event_q.consume_nolock() {
        if pre_handler(event.unwrap()) {
          event.invoke_recipient();
        }
      }
    }
  }

  /**
   * Enter the event loop and never return.
   */
  pub fn run(&mut self) -> ! {
    self.run_with_prehandler(|_|{true});
  }
}

impl EventSink for OxideSupervisor<'_> {
  fn event(event: OxideEventEnvelope) {
    unsafe {
      match &mut GLOBAL_INSTANCE {
        None => {}
        Some(supervisor) => {
          let _ = (*supervisor).event_q.append_nolock(core::mem::transmute(event));
        }
      }
    }
  }
}


// Tests =====================================================================