use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use std::thread;
use std::time::Duration;
use error::{Error, ErrorKind};
use peripherals::consts::*;
use system::System;
use util::mem::RegisterMap;
static RESERVED: AtomicBool = ATOMIC_BOOL_INIT;
pub use peripherals::consts::GP_PINS as GPIO_PINS;
pub struct Gpio {
registers: RegisterMap,
}
impl Gpio {
pub fn new() -> Result<Gpio, Error> {
if RESERVED.fetch_or(true, Ordering::SeqCst) {
return Err(Error::new(ErrorKind::Reserved));
}
Ok(Gpio {
registers: unsafe { RegisterMap::map(
System::detect()?.peripheral_offset() + GP_PAGE_OFFSET,
PAGE_SIZE,
)}?,
})
}
pub fn is_valid_pin(pin: usize) -> bool {
pin < GPIO_PINS
}
pub fn check_pin(pin: usize) -> Result<(), Error> {
if Gpio::is_valid_pin(pin) {
Ok(())
} else {
Err(Error::new(ErrorKind::OutOfRange))
}
}
pub fn set_function(&mut self, pin: usize, function: PinFunction) {
let mut reg = self.registers.load(GP_FSEL[pin]);
reg &= !GP_FSEL_MASK[pin];
reg |= function.value() << GP_FSEL_SHIFT[pin];
self.registers.store(GP_FSEL[pin], reg);
}
pub fn set_pull(&mut self, pin: usize, pull: Option<PinLevel>) {
let pull_value = match pull {
None => 0b00,
Some(PinLevel::Low) => 0b01,
Some(PinLevel::High) => 0b10,
};
self.registers.store(GP_PUD, pull_value);
thread::sleep(Duration::from_micros(5));
self.registers.store(GP_PUDCLK[pin], GP_PIN[pin]);
thread::sleep(Duration::from_micros(5));
self.registers.store(GP_PUD, 0);
self.registers.store(GP_PUDCLK[pin], GP_PIN[pin]);
}
pub fn get_level(&self, pin: usize) -> PinLevel {
let mut reg = self.registers.load(GP_LEV[pin]);
reg &= GP_PIN[pin];
if reg == 0 {
PinLevel::Low
} else {
PinLevel::High
}
}
pub fn set_level(&mut self, pin: usize, level: PinLevel){
match level {
PinLevel::High => self.set_pin(pin),
PinLevel::Low => self.clear_pin(pin),
};
}
pub fn set_pin(&mut self, pin: usize) {
self.registers.store(GP_SET[pin], GP_PIN[pin]);
}
pub fn clear_pin(&mut self, pin: usize) {
self.registers.store(GP_CLR[pin], GP_PIN[pin]);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PinLevel {
Low,
High,
}
impl From<bool> for PinLevel {
fn from(x: bool) -> PinLevel {
match x {
false => PinLevel::Low,
true => PinLevel::High,
}
}
}
impl From<PinLevel> for bool {
fn from(x: PinLevel) -> bool {
match x {
PinLevel::Low => false,
PinLevel::High => true,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)]
#[allow(missing_docs)] pub enum PinFunction {
In,
Out,
Alt0,
Alt1,
Alt2,
Alt3,
Alt4,
Alt5,
}
impl PinFunction {
fn value(self) -> u32 {
match self {
PinFunction::In => GP_FSEL_IN,
PinFunction::Out => GP_FSEL_OUT,
PinFunction::Alt0 => GP_FSEL_ALT0,
PinFunction::Alt1 => GP_FSEL_ALT1,
PinFunction::Alt2 => GP_FSEL_ALT2,
PinFunction::Alt3 => GP_FSEL_ALT3,
PinFunction::Alt4 => GP_FSEL_ALT4,
PinFunction::Alt5 => GP_FSEL_ALT5,
}
}
}