use crate::{iomuxc, ral};
pub use crate::PinPortIncompatibleError;
type AnyInstance = crate::AnyInstance<ral::rgpio::RegisterBlock>;
pub struct Port {
gpio: AnyInstance,
}
impl Port {
pub fn new<const N: u8>(gpio: ral::rgpio::Instance<N>) -> Self {
let gpio: AnyInstance = crate::into_any(gpio);
Self { gpio }
}
fn instance(&self) -> u8 {
ral::rgpio::number(&*self.gpio).unwrap()
}
fn duplicate_instance(&self) -> AnyInstance {
unsafe { AnyInstance::new(&*self.gpio) }
}
pub fn output<P, const N: u8>(
&mut self,
mut pin: P,
) -> Result<Output, PinPortIncompatibleError<P>>
where
P: iomuxc::gpio::Pin<N>,
{
if N != self.instance() {
return Err(PinPortIncompatibleError(pin));
}
iomuxc::gpio::prepare(&mut pin);
Ok(Output::new(self.duplicate_instance(), P::OFFSET))
}
pub fn input<P, const N: u8>(
&mut self,
mut pin: P,
) -> Result<Input, PinPortIncompatibleError<P>>
where
P: iomuxc::gpio::Pin<N>,
{
if N != self.instance() {
return Err(PinPortIncompatibleError(pin));
}
iomuxc::gpio::prepare(&mut pin);
Ok(Input::new(self.duplicate_instance(), P::OFFSET))
}
}
pub struct Output {
gpio: AnyInstance,
offset: u32,
}
impl Output {
fn new(gpio: AnyInstance, offset: u32) -> Self {
let output = Self { gpio, offset };
ral::modify_reg!(ral::rgpio, output.gpio, PDDR, |gdir| gdir | output.mask());
output
}
const fn mask(&self) -> u32 {
1 << self.offset
}
pub fn set(&self) {
ral::write_reg!(ral::rgpio, self.gpio, PSOR, self.mask());
}
pub fn clear(&self) {
ral::write_reg!(ral::rgpio, self.gpio, PCOR, self.mask());
}
pub fn toggle(&self) {
ral::write_reg!(ral::rgpio, self.gpio, PTOR, self.mask());
}
pub fn is_set(&self) -> bool {
ral::read_reg!(ral::rgpio, self.gpio, PDOR) & self.mask() != 0
}
pub fn is_pad_high(&self) -> bool {
ral::read_reg!(ral::rgpio, self.gpio, PDIR) & self.mask() != 0
}
pub fn without_pin(port: &mut Port, offset: u32) -> Self {
Self::new(port.duplicate_instance(), offset)
}
}
pub struct Input {
gpio: AnyInstance,
offset: u32,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum Trigger {
Low = 0,
High = 1,
RisingEdge = 2,
FallingEdge = 3,
EitherEdge = 4,
}
impl Input {
fn new(gpio: AnyInstance, offset: u32) -> Self {
let input = Self { gpio, offset };
ral::modify_reg!(ral::rgpio, input.gpio, PDDR, |gdir| gdir & !input.mask());
input
}
const fn mask(&self) -> u32 {
1 << self.offset
}
pub fn is_set(&self) -> bool {
ral::read_reg!(ral::rgpio, self.gpio, PDIR) & self.mask() != 0
}
pub fn is_triggered(&self) -> bool {
ral::read_reg!(ral::rgpio, self.gpio, ICR[self.offset as usize], ISF) != 0
}
pub fn clear_triggered(&mut self) {
ral::write_reg!(ral::rgpio, self.gpio, ICR[self.offset as usize], ISF: ISF1);
}
pub fn set_interrupt(&mut self, trigger: Option<Trigger>) {
ral::modify_reg!(ral::rgpio, self.gpio, ICR[self.offset as usize], IRQC:
match trigger {
None => IRQC0,
Some(Trigger::Low) => IRQC8,
Some(Trigger::High) => IRQC12,
Some(Trigger::RisingEdge) => IRQC9,
Some(Trigger::FallingEdge) => IRQC10,
Some(Trigger::EitherEdge) => IRQC11,
}
)
}
pub fn without_pin(port: &mut Port, offset: u32) -> Self {
Self::new(port.duplicate_instance(), offset)
}
}
impl eh02::digital::v2::OutputPin for Output {
type Error = core::convert::Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set();
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.clear();
Ok(())
}
}
impl eh1::digital::ErrorType for Output {
type Error = core::convert::Infallible;
}
impl eh1::digital::OutputPin for Output {
fn set_high(&mut self) -> Result<(), Self::Error> {
Output::set(self);
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Output::clear(self);
Ok(())
}
}
impl eh1::digital::StatefulOutputPin for Output {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(Output::is_set(self))
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!Output::is_set(self))
}
fn toggle(&mut self) -> Result<(), Self::Error> {
Output::toggle(self);
Ok(())
}
}
impl eh1::digital::InputPin for Output {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(Output::is_pad_high(self))
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!Output::is_pad_high(self))
}
}
impl eh1::digital::ErrorType for Input {
type Error = core::convert::Infallible;
}
impl eh1::digital::InputPin for Input {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(Input::is_set(self))
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!Input::is_set(self))
}
}