use core::marker::PhantomData;
use embedded_hal::digital::{self as hal_digital};
pub struct Pin<'a, MODE, MUTEX> {
pin_mask: u32,
port_driver: &'a MUTEX,
_m: PhantomData<MODE>,
}
impl<'a, MODE, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
MUTEX: crate::PortMutex<Port = PD>,
{
pub(crate) fn new(pin_number: u8, port_driver: &'a MUTEX) -> Self {
assert!(pin_number < 32);
Self {
pin_mask: 1 << pin_number,
port_driver,
_m: PhantomData,
}
}
pub fn pin_mask(&self) -> u32 {
self.pin_mask
}
pub(crate) fn port_driver(&self) -> &MUTEX {
self.port_driver
}
pub fn access_port_driver<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut PD) -> R,
{
self.port_driver.lock(|pd| f(pd))
}
}
#[derive(Debug)]
pub struct PinError<PDE> {
driver_error: PDE,
}
impl<PDE> PinError<PDE> {
pub fn driver_error(&self) -> &PDE {
&self.driver_error
}
}
impl<PDE> hal_digital::Error for PinError<PDE>
where
PDE: core::fmt::Debug,
{
fn kind(&self) -> hal_digital::ErrorKind {
hal_digital::ErrorKind::Other
}
}
impl<PDE> From<PDE> for PinError<PDE> {
fn from(value: PDE) -> Self {
Self {
driver_error: value,
}
}
}
impl<'a, MODE, MUTEX, PD> hal_digital::ErrorType for Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
PD::Error: core::fmt::Debug,
MUTEX: crate::PortMutex<Port = PD>,
{
type Error = PinError<PD::Error>;
}
impl<'a, MODE, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver + crate::PortDriverTotemPole,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn into_input(self) -> Result<Pin<'a, crate::mode::Input, MUTEX>, PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_direction(self.pin_mask, crate::Direction::Input, false))?;
Ok(Pin {
pin_mask: self.pin_mask,
port_driver: self.port_driver,
_m: PhantomData,
})
}
pub fn into_output(self) -> Result<Pin<'a, crate::mode::Output, MUTEX>, PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_direction(self.pin_mask, crate::Direction::Output, false))?;
Ok(Pin {
pin_mask: self.pin_mask,
port_driver: self.port_driver,
_m: PhantomData,
})
}
pub fn into_output_high(
self,
) -> Result<Pin<'a, crate::mode::Output, MUTEX>, PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_direction(self.pin_mask, crate::Direction::Output, true))?;
Ok(Pin {
pin_mask: self.pin_mask,
port_driver: self.port_driver,
_m: PhantomData,
})
}
}
impl<'a, MODE, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver + crate::PortDriverPolarity,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn into_inverted(self) -> Result<Self, PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_polarity(self.pin_mask, true))?;
Ok(self)
}
pub fn set_inverted(&mut self, inverted: bool) -> Result<(), PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_polarity(self.pin_mask, inverted))?;
Ok(())
}
}
impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn is_high(&self) -> Result<bool, PinError<PD::Error>> {
self.port_driver
.lock(|drv| Ok(drv.get(self.pin_mask, 0)? == self.pin_mask))
}
pub fn is_low(&self) -> Result<bool, PinError<PD::Error>> {
self.port_driver
.lock(|drv| Ok(drv.get(0, self.pin_mask)? == self.pin_mask))
}
}
impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver + crate::PortDriverPullUp,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn enable_pull_up(&mut self, enable: bool) -> Result<(), PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_pull_up(self.pin_mask, enable))?;
Ok(())
}
}
impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver + crate::PortDriverPullDown,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn enable_pull_down(&mut self, enable: bool) -> Result<(), PinError<PD::Error>> {
self.port_driver
.lock(|drv| drv.set_pull_down(self.pin_mask, enable))?;
Ok(())
}
}
impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> hal_digital::InputPin for Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
<PD as crate::PortDriver>::Error: core::fmt::Debug,
MUTEX: crate::PortMutex<Port = PD>,
{
fn is_high(&mut self) -> Result<bool, Self::Error> {
Pin::is_high(self)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Pin::is_low(self)
}
}
impl<'a, MODE: crate::mode::HasOutput, MUTEX, PD> Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
MUTEX: crate::PortMutex<Port = PD>,
{
pub fn set_high(&mut self) -> Result<(), PinError<PD::Error>> {
self.port_driver.lock(|drv| drv.set(self.pin_mask, 0))?;
Ok(())
}
pub fn set_low(&mut self) -> Result<(), PinError<PD::Error>> {
self.port_driver.lock(|drv| drv.set(0, self.pin_mask))?;
Ok(())
}
pub fn is_set_high(&self) -> Result<bool, PinError<PD::Error>> {
self.port_driver
.lock(|drv| Ok(drv.is_set(self.pin_mask, 0)? == self.pin_mask))
}
pub fn is_set_low(&self) -> Result<bool, PinError<PD::Error>> {
self.port_driver
.lock(|drv| Ok(drv.is_set(0, self.pin_mask)? == self.pin_mask))
}
pub fn toggle(&mut self) -> Result<(), PinError<PD::Error>> {
self.port_driver.lock(|drv| drv.toggle(self.pin_mask))?;
Ok(())
}
}
impl<'a, MODE: crate::mode::HasOutput, MUTEX, PD> hal_digital::OutputPin for Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
<PD as crate::PortDriver>::Error: core::fmt::Debug,
MUTEX: crate::PortMutex<Port = PD>,
{
fn set_low(&mut self) -> Result<(), Self::Error> {
Pin::set_low(self)
}
fn set_high(&mut self) -> Result<(), Self::Error> {
Pin::set_high(self)
}
}
impl<'a, MODE: crate::mode::HasOutput, MUTEX, PD> hal_digital::StatefulOutputPin
for Pin<'a, MODE, MUTEX>
where
PD: crate::PortDriver,
<PD as crate::PortDriver>::Error: core::fmt::Debug,
MUTEX: crate::PortMutex<Port = PD>,
{
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Pin::is_set_high(self)
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Pin::is_set_low(self)
}
fn toggle(&mut self) -> Result<(), Self::Error> {
Pin::toggle(self)
}
}