hardware 0.0.9

A no_std bare-metal hardware abstraction layer — all port I/O, memory and swap allocations are guarded at runtime. Do not consider this dependency stable before x.1.x
Documentation
use core::sync::atomic::{AtomicU8, Ordering};

pub const MAX_BUTTONS: usize = 16;

#[derive(Clone, Copy, PartialEq)]
pub enum ButtonState {
    Released,
    Pressed,
}

static BUTTON_STATES: AtomicU16Arr = AtomicU16Arr::new();

struct AtomicU16Arr {
    bits: core::sync::atomic::AtomicU16,
}

impl AtomicU16Arr {
    const fn new() -> Self {
        AtomicU16Arr {
            bits: core::sync::atomic::AtomicU16::new(0),
        }
    }
}

static DEBOUNCE_MS: AtomicU8 = AtomicU8::new(20);

pub fn set_debounce_ms(ms: u8) {
    DEBOUNCE_MS.store(ms, Ordering::Release);
}

pub fn debounce_ms() -> u8 {
    DEBOUNCE_MS.load(Ordering::Acquire)
}

pub fn set_button_state(button: u8, state: ButtonState) {
    if button as usize >= MAX_BUTTONS {
        return;
    }
    let mut bits = BUTTON_STATES.bits.load(Ordering::Acquire);
    match state {
        ButtonState::Pressed => bits |= 1 << button,
        ButtonState::Released => bits &= !(1 << button),
    }
    BUTTON_STATES.bits.store(bits, Ordering::Release);
}

pub fn get_button_state(button: u8) -> ButtonState {
    if button as usize >= MAX_BUTTONS {
        return ButtonState::Released;
    }
    let bits = BUTTON_STATES.bits.load(Ordering::Acquire);
    if bits & (1 << button) != 0 {
        ButtonState::Pressed
    } else {
        ButtonState::Released
    }
}

pub fn any_button_pressed() -> bool {
    BUTTON_STATES.bits.load(Ordering::Acquire) != 0
}

pub fn pressed_mask() -> u16 {
    BUTTON_STATES.bits.load(Ordering::Acquire)
}

pub fn should_accept(last_change_us: u64, now_us: u64) -> bool {
    let threshold = debounce_ms() as u64 * 1000;
    now_us.wrapping_sub(last_change_us) >= threshold
}