#![doc = include_str!("../doc/mock_example.md")]
#![no_std]
mod low;
use core::{marker::PhantomData, ops::Not};
pub use low::{Bank, io::Gpio, register::GpioRegisters};
mod private {
use crate::OutputMode;
pub trait Sealed {}
impl Sealed for super::Input {}
impl<Mode: OutputMode> Sealed for super::Output<Mode> {}
impl Sealed for super::PushPull {}
impl Sealed for super::OpenDrain {}
}
use self::private::Sealed;
#[doc(hidden)]
pub trait Direction: Sealed {
fn init<R>(gpio: &mut Gpio<R>, pin: u32)
where
R: GpioRegisters;
}
pub enum Interrupt {
Off,
RisingEdge,
FallingEgdge,
BothEdges,
}
#[derive(Copy, Clone, Debug)]
pub enum Level {
Low,
High,
}
impl Not for Level {
type Output = Level;
fn not(self) -> Self::Output {
match self {
Level::Low => Level::High,
Level::High => Level::Low,
}
}
}
pub enum IoDir {
In,
Out,
}
pub struct Io<B, const N: u32, R, D>
where
B: Bank<R>,
R: GpioRegisters,
{
dir: PhantomData<fn() -> D>,
bank: PhantomData<fn() -> B>,
register: PhantomData<fn() -> R>,
}
#[doc(hidden)]
pub trait OutputMode: Sealed {
fn active_state() -> Level;
}
pub struct Input;
pub struct PushPull;
impl OutputMode for PushPull {
fn active_state() -> Level {
Level::High
}
}
pub struct OpenDrain;
impl OutputMode for OpenDrain {
fn active_state() -> Level {
Level::Low
}
}
pub struct Output<Mode: OutputMode> {
default: PhantomData<fn() -> Mode>,
}
impl Direction for Input {
fn init<R>(gpio: &mut Gpio<R>, pin: u32)
where
R: GpioRegisters,
{
gpio.set_dir(pin, IoDir::In);
gpio.set_interrupt(pin, Interrupt::Off);
}
}
impl<Mode: OutputMode> Direction for Output<Mode> {
fn init<R>(gpio: &mut Gpio<R>, pin: u32)
where
R: GpioRegisters,
{
let active_state = Mode::active_state();
gpio.set_dir(pin, IoDir::Out);
gpio.set_active_state(pin, active_state);
gpio.write(pin, Level::Low);
}
}
impl<B, const N: u32, R, D> Io<B, N, R, D>
where
B: Bank<R>,
R: GpioRegisters,
D: Direction,
{
pub fn init() -> Self {
let mut bank = <B as Bank<R>>::get_handle();
D::init(&mut bank, N);
Self {
dir: PhantomData,
bank: PhantomData,
register: PhantomData,
}
}
}
impl<B, const N: u32, R> Io<B, N, R, Input>
where
B: Bank<R>,
R: GpioRegisters,
{
pub fn set_interrupt(&mut self, interrupt: Interrupt) {
let mut bank = <B as Bank<R>>::get_handle();
bank.set_interrupt(N, interrupt);
}
pub fn read(&self) -> Level {
let bank = <B as Bank<R>>::get_handle();
bank.read(N)
}
pub fn interrupt_pending(&self) -> bool {
let mut bank = <B as Bank<R>>::get_handle();
bank.interrupt_pending(N)
}
}
impl<B, const N: u32, R, Mode: OutputMode> Io<B, N, R, Output<Mode>>
where
B: Bank<R>,
R: GpioRegisters,
{
fn write(&mut self, level: Level) {
let mut bank = <B as Bank<R>>::get_handle();
bank.write(N, level);
}
#[inline]
pub fn activate(&mut self) {
self.write(Mode::active_state());
}
#[inline]
pub fn deactivate(&mut self) {
self.write(!Mode::active_state());
}
}