avr-oxide 0.0.5

An extremely simple Rusty operating system for AVR microcontrollers
/* watchdog.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Support for the AVR's built-in watchdog timer.


// Imports ===================================================================

// Declarations ==============================================================
pub enum WatchdogPeriod {
  /// Disabled
  Off,
  /// 8 milliseconds
  Millis8,
  Millis16,
  Millis32,
  Millis64,
  Millis128,
  Millis256,
  Millis512,
  Millis1024,
  Millis2048,
  Millis4096,
  Millis8192
}

pub trait WatchdogController {
  /// Disable the watchdog timer
  fn disable(&mut self);

  /// Start the watchdog timer.  Once this method has been called, you must
  /// be sure to call the kick() function at least every `max_gap` ms, but
  /// no quicker than `min_gap` ms, or the watchdog will reset the processor.
  fn enable(&mut self, min_gap: WatchdogPeriod, max_gap: WatchdogPeriod);

  /// Protect the watchdog configuration - you can't change the configuration
  /// once this has been called.
  fn protect(&mut self);

  /// Kick the watchdog - as long as the watchdog is enabled, this must
  /// be called within the configured time limits passed to enable()
  fn kick(&self);
}

// Code ======================================================================
#[cfg(target_arch="avr")]
pub mod base {
  use crate::hal::generic::watchdog::WatchdogPeriod;

  #[repr(C)]
  pub struct AvrWatchdogControlBlock {
    pub(crate) ctrla: u8,
    pub(crate) status: u8
  }

  impl WatchdogPeriod {
    #[inline(always)]
    pub(crate) fn to_bits(&self) -> u8 {
      match self {
        WatchdogPeriod::Off =>        0x00,
        WatchdogPeriod::Millis8 =>    0x01,
        WatchdogPeriod::Millis16 =>   0x02,
        WatchdogPeriod::Millis32 =>   0x03,
        WatchdogPeriod::Millis64 =>   0x04,
        WatchdogPeriod::Millis128 =>  0x05,
        WatchdogPeriod::Millis256 =>  0x06,
        WatchdogPeriod::Millis512 =>  0x07,
        WatchdogPeriod::Millis1024 => 0x08,
        WatchdogPeriod::Millis2048 => 0x09,
        WatchdogPeriod::Millis4096 => 0x0A,
        WatchdogPeriod::Millis8192 => 0x0B
      }
    }
  }

  #[macro_export]
  macro_rules! atmel_watchdog_tpl {
    ($ref:expr, $cpu:expr) => {
      use crate::hal::generic::cpu::{Cpu, ConfigurationChange};
      use crate::hal::generic::watchdog::{WatchdogController,WatchdogPeriod};
      use crate::hal::generic::watchdog::base::AvrWatchdogControlBlock;
      pub type WatchdogImpl = AvrWatchdogControlBlock;

      impl WatchdogController for AvrWatchdogControlBlock {
        fn disable(&mut self) {
          unsafe {
            let locked = core::ptr::read_volatile(&self.status as *const u8) & 0b10000000;

            debug_assert_eq!(locked, 0);

            $cpu.write_protected(ConfigurationChange::ProtectedRegister,
                                 &mut self.ctrla, 0x00);

          }
        }

        fn enable(&mut self, min_gap: WatchdogPeriod, max_gap: WatchdogPeriod) {
          unsafe {
            let locked = core::ptr::read_volatile(&self.status as *const u8) & 0b10000000;

            debug_assert_eq!(locked, 0);

            $cpu.write_protected(ConfigurationChange::ProtectedRegister,
                                 &mut self.ctrla,
                                 min_gap.to_bits() << 4 | max_gap.to_bits());
          }
        }

        fn protect(&mut self) {
          unsafe {
            $cpu.write_protected(ConfigurationChange::ProtectedRegister,
                                 &mut self.status, 0b10000000);
          }
        }

        #[inline(always)]
        fn kick(&self) {
          unsafe {
            llvm_asm!("wdr" :::: "volatile")
          }
        }
      }

      #[inline(always)]
      pub fn instance() -> &'static mut AvrWatchdogControlBlock {
        unsafe {
          core::mem::transmute($ref)
        }
      }
    }
  }
}

#[cfg(not(target_arch="avr"))]
pub mod base {
  #[repr(C)]
  pub struct DummyWatchdogControlBlock {
  }

  #[macro_export]
  macro_rules! atmel_watchdog_tpl {
    ($ref:expr, $cpu:expr) => {
      use crate::hal::generic::watchdog::{WatchdogController,WatchdogPeriod};
      use crate::hal::generic::watchdog::base::DummyWatchdogControlBlock;
      pub type WatchdogImpl = DummyWatchdogControlBlock;

      impl WatchdogController for DummyWatchdogControlBlock {
        fn disable(&mut self) {
          println!("*** WATCHDOG: Disabled");
        }

        fn enable(&mut self, _min_gap: WatchdogPeriod, _max_gap: WatchdogPeriod) {
          println!("*** WATCHDOG: Enabled");
        }

        fn protect(&mut self) {
          println!("*** WATCHDOG: Configuration protected");
        }

        fn kick(&self) {
          println!("*** WATCHDOG: kicked");
        }
      }

      static mut INSTANCE : DummyWatchdogControlBlock = DummyWatchdogControlBlock {
      };

      pub fn instance() -> &'static mut DummyWatchdogControlBlock {
        unsafe {
          &mut INSTANCE
        }
      }
    }
  }
}

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