mod consts;
pub mod clock;
pub mod gpio;
pub mod pwm;
use std::cell::RefCell;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use error::{Error, ErrorKind};
use util::reservation::{Reservations, Reservation};
use self::clock::{ClockManager, Clock, ClockSource};
use self::gpio::{Gpio, PinFunction, PinLevel, GPIO_PINS};
use self::pwm::{Pwm, PWM_CHANNELS};
const PWM_PINS: [Option<(usize, PinFunction)>; GPIO_PINS] = [
None, None, None, None, None, None, None, None,
None, None, None, None,
Some((0, PinFunction::Alt0)), Some((1, PinFunction::Alt0)),
None, None, None, None,
Some((0, PinFunction::Alt5)), Some((1, PinFunction::Alt5)),
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None,
Some((0, PinFunction::Alt0)), Some((1, PinFunction::Alt0)),
None, None,
None, Some((1, PinFunction::Alt0)),
None, None, None, None, None, None, None, None,
];
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum Peripheral {
Clock(Clock),
GpioPin(usize),
PwmChannel(usize),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PwmMode {
Balanced,
MarkSpace,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct PwmConfig {
pub mode: PwmMode,
pub silence_bit: PinLevel,
pub invert_polarity: bool,
}
impl Default for PwmConfig {
fn default() -> PwmConfig {
PwmConfig {
mode: PwmMode::Balanced,
silence_bit: PinLevel::Low,
invert_polarity: false,
}
}
}
pub struct Peripherals {
_pwm_clock: Reservation<Peripheral>,
reservations: Reservations<Peripheral>,
cm: Rc<RefCell<ClockManager>>,
gpio: Rc<RefCell<Gpio>>,
pwm: Rc<RefCell<Pwm>>,
}
impl Peripherals {
pub fn new() -> Result<Peripherals, Error> {
let reservations = Reservations::new();
let pwm_clock = reservations.try_reserve(
Peripheral::Clock(Clock::Pwm)
).unwrap();
let mut peripherals = Peripherals {
_pwm_clock: pwm_clock,
reservations,
cm: Rc::new(RefCell::new(ClockManager::new()?)),
gpio: Rc::new(RefCell::new(Gpio::new()?)),
pwm: Rc::new(RefCell::new(Pwm::new()?)),
};
peripherals.set_pwm_clock(32, 0).unwrap();
Ok(peripherals)
}
pub fn get_digital_input(&self, pin: usize)
-> Result<DigitalInput, Error>
{
let reservation = self.try_reserve_gpio(pin)?;
let mut gpio = self.gpio.borrow_mut();
gpio.set_pull(pin, None);
gpio.set_function(pin, PinFunction::In);
Ok(DigitalInput {
_reservation: reservation,
pin,
gpio: Rc::clone(&self.gpio),
})
}
pub fn get_digital_output(&self, pin: usize)
-> Result<DigitalOutput, Error>
{
let reservation = self.try_reserve_gpio(pin)?;
let mut gpio = self.gpio.borrow_mut();
gpio.clear_pin(pin);
gpio.set_function(pin, PinFunction::Out);
Ok(DigitalOutput {
_reservation: reservation,
pin,
gpio: Rc::clone(&self.gpio),
})
}
pub fn get_pwm_output(&self, pin: usize, config: PwmConfig)
-> Result<PwmOutput, Error>
{
let gpio_reservation = self.try_reserve_gpio(pin)?;
let (channel, func) = PWM_PINS[pin]
.ok_or(Error::new(ErrorKind::OutOfRange))?;
let pwm_reservation = self.try_reserve_pwm(channel)?;
let mut gpio = self.gpio.borrow_mut();
let mut pwm = self.pwm.borrow_mut();
gpio.set_function(pin, func);
thread::sleep(Duration::from_micros(110));
match config.mode {
PwmMode::MarkSpace => pwm.enable_mark_space(channel),
PwmMode::Balanced => pwm.disable_mark_space(channel),
}
match config.silence_bit {
PinLevel::Low => pwm.set_sbit_low(channel),
PinLevel::High => pwm.set_sbit_high(channel),
}
match config.invert_polarity {
false => pwm.set_polarity_normal(channel),
true => pwm.set_polarity_inverse(channel),
}
pwm.set_data(channel, 0);
pwm.set_range(channel, 1024);
pwm.enable(channel);
Ok(PwmOutput {
_gpio_reservation: gpio_reservation,
_pwm_reservation: pwm_reservation,
channel,
pwm: Rc::clone(&self.pwm),
})
}
pub fn set_pwm_clock(&mut self, int: u32, frac: u32) -> Result<(), Error> {
if (0..PWM_CHANNELS)
.any(|x| self.reservations.is_reserved(&Peripheral::PwmChannel(x)))
{
return Err(Error::new(ErrorKind::Reserved));
}
let mut cm = self.cm.borrow_mut();
cm.disable(Clock::Pwm);
cm.set_source(Clock::Pwm, ClockSource::Oscillator);
cm.set_divider(Clock::Pwm, int, frac);
cm.enable(Clock::Pwm);
Ok(())
}
fn try_reserve_gpio(&self, pin: usize)
-> Result<Reservation<Peripheral>, Error>
{
Gpio::check_pin(pin)?;
self.reservations.try_reserve(Peripheral::GpioPin(pin))
}
fn try_reserve_pwm(&self, channel: usize)
-> Result<Reservation<Peripheral>, Error>
{
Pwm::check_channel(channel)?;
self.reservations.try_reserve(Peripheral::PwmChannel(channel))
}
}
pub struct DigitalInput {
_reservation: Reservation<Peripheral>,
pin: usize,
gpio: Rc<RefCell<Gpio>>,
}
impl DigitalInput {
pub fn set_pull(&mut self, pull: Option<PinLevel>) {
let mut gpio = self.gpio.borrow_mut();
gpio.set_pull(self.pin, pull);
}
pub fn get_level(&self) -> PinLevel {
let gpio = self.gpio.borrow();
gpio.get_level(self.pin)
}
}
pub struct DigitalOutput {
_reservation: Reservation<Peripheral>,
pin: usize,
gpio: Rc<RefCell<Gpio>>,
}
impl DigitalOutput {
pub fn set(&mut self) {
let mut gpio = self.gpio.borrow_mut();
gpio.set_pin(self.pin);
}
pub fn clear(&mut self) {
let mut gpio = self.gpio.borrow_mut();
gpio.clear_pin(self.pin);
}
pub fn set_level(&mut self, level: PinLevel) {
let mut gpio = self.gpio.borrow_mut();
gpio.set_level(self.pin, level);
}
}
pub struct PwmOutput {
_gpio_reservation: Reservation<Peripheral>,
_pwm_reservation: Reservation<Peripheral>,
channel: usize,
pwm: Rc<RefCell<Pwm>>,
}
impl PwmOutput {
pub fn set_value(&mut self, value: u32) {
let mut pwm = self.pwm.borrow_mut();
pwm.set_data(self.channel, value);
}
pub fn set_range(&mut self, range: u32) {
let mut pwm = self.pwm.borrow_mut();
pwm.set_range(self.channel, range);
}
}