use crate::{
digital::{PinMode, Pull},
hw::mcu::sifive::fe310g002::{Gpio, Pin},
sync::Once,
};
pub trait PinOp {
type Arg;
type Result;
fn op<const N: usize, const P: usize>(pin: Pin<'_, N, P>, arg: Self::Arg) -> Self::Result;
#[inline(always)]
fn do_op<const N: usize, const P: usize>(
pin: Option<Pin<'_, N, P>>,
arg: Self::Arg,
) -> Option<Self::Result> {
if let Some(pin) = pin {
Some(Self::op(pin, arg))
} else {
None
}
}
}
pub struct WriteOp;
impl PinOp for WriteOp {
type Arg = bool;
type Result = ();
#[inline(always)]
fn op<const N: usize, const P: usize>(pin: Pin<'_, N, P>, value: bool) {
pin.into_gpio().write(value);
}
}
pub struct ReadOp;
impl PinOp for ReadOp {
type Arg = ();
type Result = bool;
#[inline(always)]
fn op<const N: usize, const P: usize>(pin: Pin<'_, N, P>, _: ()) -> bool {
pin.into_gpio().read()
}
}
pub struct ModeOp;
impl PinOp for ModeOp {
type Arg = PinMode;
type Result = ();
#[inline(always)]
fn op<const N: usize, const P: usize>(pin: Pin<'_, N, P>, mode: PinMode) {
let mut pin = pin.into_gpio();
match mode {
PinMode::Input => {
pin.enable_pullup(false);
pin.set_output(false);
}
PinMode::PulledInput(pull) => {
match pull {
Pull::Up => pin.enable_pullup(true),
_ => {}
}
pin.set_output(false);
}
PinMode::Output => {
pin.set_output(true);
pin.enable_pullup(false);
}
PinMode::OpenDrainOutput => {
pin.set_output(true);
pin.enable_pullup(false);
}
}
}
}
#[inline]
pub fn pin_op<Op: PinOp>(pin: usize, arg: Op::Arg) -> Option<Op::Result> {
match pin {
0 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<16>()), arg),
1 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<17>()), arg),
2 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<18>()), arg),
3 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<19>()), arg),
4 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<20>()), arg),
5 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<21>()), arg),
6 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<22>()), arg),
7 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<23>()), arg),
8 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<0>()), arg),
9 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<1>()), arg),
10 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<2>()), arg),
11 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<3>()), arg),
12 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<4>()), arg),
13 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<5>()), arg),
15 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<9>()), arg),
16 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<10>()), arg),
17 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<11>()), arg),
18 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<12>()), arg),
19 => Op::do_op(gpio().and_then(|gpio| gpio.pin::<13>()), arg),
_ => None,
}
}
#[inline]
pub fn digital_write(pin: usize, value: bool) {
pin_op::<WriteOp>(pin, value);
}
#[inline]
pub fn digital_read(pin: usize) -> bool {
pin_op::<ReadOp>(pin, ()).unwrap_or(false)
}
#[inline]
pub fn pin_mode(pin: usize, mode: PinMode) {
pin_op::<ModeOp>(pin, mode);
}
pub fn gpio() -> Option<&'static Gpio<0>> {
static PORT: Once<Gpio<0>> = Once::new();
PORT.get_or_try_init(|| Gpio::get())
}