avr-oxide 0.2.2

An extremely simple Rusty operating system for AVR microcontrollers
/* util.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! General utility types/functions.

pub mod persist;

// Imports ===================================================================
use core::ops::{Deref, DerefMut};
#[cfg(feature="panicout")]
use avr_oxide::hal::generic::serial::SerialNoInterruptTx;

// Declarations ==============================================================
pub enum OwnOrBorrow<'a, T: 'a> {
  Own(T),
  Borrow(&'a T)
}
pub enum OwnOrBorrowMut<'a, T: 'a> {
  Own(T),
  Borrow(&'a mut T)
}

/**
 * Helper newtype to represent a packed bitfield structure.
 */
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct BitField<const BYTES: usize>([u8; BYTES]);

/**
 * Index of a bit in a bitfield structure.
 */
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct BitIndex(usize);


// Code ======================================================================
/// Handy debugging function to print a string to the stdout()
#[cfg(all(feature="panicout",target_arch="avr"))]
pub fn debug_print(string: &str){
  #[cfg(target_arch="avr")]
  avr_oxide::panic_stdout!().blocking_write_slice(string.as_bytes());
}

/// Debugging function to print a u16 to the stdout()
#[cfg(all(feature="panicout",target_arch="avr"))]
pub fn debug_print_u16(val: u16){
  if val > 9 {
    debug_print_u16(val/10);
  }
  avr_oxide::panic_stdout!().blocking_write_u8(((val % 10) + 0x30) as u8);
}

/// Debugging function to print a u16 to the stdout()
#[cfg(all(feature="panicout",target_arch="avr"))]
pub fn debug_print_u32(val: u32){
  if val > 9 {
    debug_print_u32(val/10);
  }
  avr_oxide::panic_stdout!().blocking_write_u8(((val % 10) + 0x30) as u8);
}


macro_rules! common_impl {
  ($name:ident) => {
    impl<T> $name<'_,T>
    where
      T: Clone
    {
      pub fn into_owned(self) -> T {
        match self {
          Self::Own(v) => v,
          Self::Borrow(r) => r.clone()
        }
      }
    }

    impl<T> $name<'_,T> {
      pub fn is_owned(&self) -> bool {
        match self {
          Self::Own(_) => true,
          Self::Borrow(_) => false
        }
      }
    }


    impl<T> Deref for $name<'_,T> {
      type Target = T;

      fn deref(&self) -> &Self::Target {
        match self {
          Self::Own(v) => v,
          Self::Borrow(r) => *r
        }
      }
    }

    impl<T> From<T> for $name<'_,T> {
      fn from(v: T) -> Self {
        Self::Own(v)
      }
    }
  }
}

common_impl!(OwnOrBorrow);
common_impl!(OwnOrBorrowMut);

impl<T> Clone for OwnOrBorrow<'_,T>
where
  T: Clone
{
  fn clone(&self) -> Self {
    match self {
      OwnOrBorrow::Own(v) => Self::Own(v.clone()),
      OwnOrBorrow::Borrow(r) => Self::Borrow(r)
    }
  }
}

impl<'a, T> From<&'a T> for OwnOrBorrow<'a,T> {
  fn from(r: &'a T) -> Self {
    Self::Borrow(r)
  }
}

impl<'a, T> From<&'a mut T> for OwnOrBorrowMut<'a,T> {
  fn from(r: &'a mut T) -> Self {
    Self::Borrow(r)
  }
}

impl<T> DerefMut for OwnOrBorrowMut<'_,T> {
  fn deref_mut(&mut self) -> &mut Self::Target {
    match self {
      Self::Own(v) => v,
      Self::Borrow(r) => r
    }
  }
}


impl BitIndex {
  /// Construct a BitIndex for the given index
  pub const fn bit(b: usize) -> Self {
    Self {
      0: b
    }
  }

  /**
   * Return the index of the byte that will contain this bit.  The size of
   * the overall buffer in bytes is passed as a const parameter.
   */
  #[inline(always)]
  pub fn byte_index<const BYTES: usize>(self) -> usize {
    (BYTES-1) - (self.0 / 8)
  }

  /**
   * Return the index of this bit within its byte within the field.
   */
  #[inline(always)]
  pub fn bit_index_in_byte(self) -> u8 {
    (self.0 % 8) as u8
  }

  /**
   * Return a 'positive' mask (that is, the only bit that is set is the
   * one corresponding to this bit) for this bit in its byte within the field.
   */
  #[inline(always)]
  pub fn positive_byte_mask(self) -> u8 {
    0x01u8 << self.bit_index_in_byte()
  }

  /**
   * Return a 'negative' mask (that is, the only bit that is UNset is the
   * one corresponding to this bit) for this bit in its byte within the field.
   */
  #[inline(always)]
  pub fn negative_byte_mask(self) -> u8 {
    0xffu8 ^ self.positive_byte_mask()
  }
}

impl<const BYTES: usize> BitField<BYTES> {
  /// Create a BitField initialised to the given values (big-endian)
  pub const fn with_initial(vals: [u8; BYTES]) -> Self {
    BitField {
      0: vals
    }
  }

  /// Create a BitField where all bits are clear except the ones passed
  /// in the initialisation array.
  pub fn with_bits_set(bits: &[BitIndex]) -> Self {
    let mut new = Self::all_clr();
    for bit in bits {
      new.set(*bit);
    }
    new
  }

  /// An instance of BitField with all bits cleared
  pub const fn all_clr() -> Self {
    BitField {
      0: [0u8; BYTES]
    }
  }

  /// An instance of BitField with all bits set
  pub const fn all_set() -> Self {
    BitField {
      0: [0xffu8; BYTES]
    }
  }

  /// True IFF the bit at the given index is set
  pub fn is_set(&self, bit: BitIndex) -> bool {
    (self.0[bit.byte_index::<BYTES>()] & bit.positive_byte_mask()) > 0
  }

  /// True IFF the bit at the given index is clear
  pub fn is_clr(&self, bit: BitIndex) -> bool {
    !self.is_set(bit)
  }

  /// Set the bit at the given index
  pub fn set(&mut self, bit: BitIndex) {
    self.0[bit.byte_index::<BYTES>()] |= bit.positive_byte_mask();
  }

  /// Clear the bit at the given index
  pub fn clr(&mut self, bit: BitIndex) {
    self.0[bit.byte_index::<BYTES>()] &= bit.negative_byte_mask();
  }

  /// Set or clear the bit at the given index depending on the `set`
  /// parameter (true = set the bit, false = clear it.)
  pub fn set_or_clr(&mut self, bit: BitIndex, set: bool) {
    match set {
      true  => self.set(bit),
      false => self.clr(bit)
    }
  }
}

// Tests =====================================================================
#[cfg(test)]
mod tests {
  use avr_oxide::util::{BitField, BitIndex};

  #[test]
  fn test_bitindex() {
    let bit10 = BitIndex(10);
    assert_eq!(bit10.byte_index::<4>(), 2);
    assert_eq!(bit10.bit_index_in_byte(), 2);
    assert_eq!(bit10.positive_byte_mask(), 0b00000100);
    assert_eq!(bit10.negative_byte_mask(), 0b11111011);

    let bit16 = BitIndex(16);
    assert_eq!(bit16.byte_index::<4>(), 1);
    assert_eq!(bit16.bit_index_in_byte(), 0);
    assert_eq!(bit16.positive_byte_mask(), 0b00000001);
    assert_eq!(bit16.negative_byte_mask(), 0b11111110);

  }

  #[test]
  fn test_bitfield() {
    let mut all_zero : BitField<2> = BitField::all_clr();
    let mut all_one  : BitField<2> = BitField::all_set();

    assert!(all_zero == BitField::<2>::with_initial([ 0b00000000, 0b00000000 ]));
    assert!(all_one  == BitField::<2>::with_initial([ 0b11111111, 0b11111111 ]));

    all_zero.set(BitIndex(3));
    all_one.set(BitIndex(3));

    assert!(all_zero == BitField::<2>::with_initial([ 0b00000000, 0b00001000 ]));
    assert!(all_one  == BitField::<2>::with_initial([ 0b11111111, 0b11111111 ]));

    all_zero.clr(BitIndex(7));
    all_one.clr(BitIndex(7));

    assert!(all_zero == BitField::<2>::with_initial([ 0b00000000, 0b00001000 ]));
    assert!(all_one  == BitField::<2>::with_initial([ 0b11111111, 0b01111111 ]));

    all_zero.set_or_clr(BitIndex(13), true);
    all_one.set_or_clr(BitIndex(15),false);

    assert!(all_zero == BitField::<2>::with_initial([ 0b00100000, 0b00001000 ]));
    assert!(all_one  == BitField::<2>::with_initial([ 0b01111111, 0b01111111 ]));

    assert!(all_zero.is_set(BitIndex(13)));
    assert!(all_zero.is_clr(BitIndex(15)));
    assert!(all_one.is_set(BitIndex(6)));
    assert!(all_one.is_clr(BitIndex(7)));
    assert!(!all_zero.is_set(BitIndex(0)));
    assert!(!all_one.is_clr(BitIndex(1)));
  }

  #[test]
  pub fn test_bitfield_init() {
    let some_set = BitField::<4>::with_bits_set(&[BitIndex(12),BitIndex(5),BitIndex(23),BitIndex(31)]);

    assert!(some_set == BitField::<4>::with_initial([ 0b10000000, 0b10000000, 0b00010000, 0b00100000 ]));
  }
}