use core::marker::PhantomData;
#[derive(Debug)]
enum State {
High,
Low,
Float,
}
#[derive(Debug)]
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
#[derive(Debug)]
pub struct Floating;
#[derive(Debug)]
pub struct PullUp;
#[derive(Debug)]
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
#[derive(Debug)]
pub struct PushPull;
#[derive(Debug)]
pub struct OpenDrain;
pub trait GpioExt {
type Parts;
fn split() -> Self::Parts;
}
macro_rules! gpio {
($PORT:ident, $port:ident, [$( ($Pin:ident, $pin:ident, $default_mode:ty) ),+ $(,)* ]) => {
pub mod $port {
use super::{State, Input,Output, Floating, PushPull, OpenDrain, GpioExt, PullUp, $PORT};
use core::marker::PhantomData;
use embedded_hal::digital::v2::{InputPin, OutputPin};
#[derive(Debug)]
pub struct Parts {
$(
#[allow(missing_docs)]
pub $pin: $Pin<$default_mode>,
)+
}
impl GpioExt for $PORT {
type Parts = Parts;
fn split() -> Parts {
Self::Parts {
$(
$pin: $Pin::default(),
)+
}
}
}
$(
#[derive(Debug)]
pub struct $Pin<MODE> {
state: State,
_mode: PhantomData<MODE>,
}
impl Default for $Pin<Input<Floating>> {
fn default() -> Self {
Self {
state: State::Float,
_mode: PhantomData,
}
}
}
impl Default for $Pin<Input<PullUp>> {
fn default() -> Self {
Self {
state: State::High,
_mode: PhantomData,
}
}
}
impl Default for $Pin<Output<PushPull>> {
fn default() -> Self {
Self {
state: State::Low,
_mode: PhantomData,
}
}
}
impl Default for $Pin<Output<OpenDrain>> {
fn default() -> Self {
Self {
state: State::Float,
_mode: PhantomData,
}
}
}
impl<MODE> $Pin<MODE> {
pub fn into_push_pull_output(self) -> $Pin<Output<PushPull>> {
$Pin::default()
}
pub fn into_open_drain_output(self) -> $Pin<Output<OpenDrain>> {
$Pin::default()
}
pub fn into_floating_input(self) -> $Pin<Input<Floating>> {
$Pin::default()
}
pub fn into_pull_up_input(self) -> $Pin<Input<PullUp>> {
$Pin::default()
}
}
impl OutputPin for $Pin<Output<PushPull>> {
type Error = core::convert::Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.state = State::High)
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.state = State::Low)
}
}
impl OutputPin for $Pin<Output<OpenDrain>> {
type Error = core::convert::Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.state = State::Float)
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.state = State::Low)
}
}
impl<MODE> InputPin for $Pin<Input<MODE>> {
type Error = core::convert::Infallible;
fn is_high(&self) -> Result<bool,Self::Error> {
Ok(!self.is_low()?)
}
fn is_low(&self) -> Result<bool, Self::Error> {
match self.state {
State::Low => Ok(true),
State::High => Ok(false),
State::Float => {
panic!("Tried to read a floating input, value is non-deterministic!")
}
}
}
}
)+
}
};
}
#[derive(Debug)]
pub struct GPIOA;
gpio!( GPIOA, gpioa, [
(PA0, pa0, Input<Floating>),
(PA1, pa1, Input<Floating>),
(PA2, pa2, Input<Floating>),
(PA3, pa3, Input<Floating>),
(PA4, pa4, Input<Floating>),
(PA5, pa5, Input<Floating>),
(PA6, pa6, Input<Floating>),
(PA7, pa7, Input<Floating>),
(PA8, pa8, Input<Floating>),
(PA9, pa9, Input<Floating>),
(PA10, pa10, Input<Floating>),
(PA11, pa11, Input<Floating>),
(PA12, pa12, Input<Floating>),
(PA13, pa13, Input<Floating>),
(PA14, pa14, Input<Floating>),
(PA15, pa15, Input<Floating>),
]);