use core::convert::TryFrom;
use hal::digital::v2::OutputPin;
#[cfg(feature = "unproven")]
use hal::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin};
use super::pin::*;
pub enum Error {
InvalidPinType,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynDisabled {
Floating,
PullDown,
PullUp,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynInput {
Floating,
PullDown,
PullUp,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynOutput {
PushPull,
Readable,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynAlternate {
A,
B,
C,
D,
E,
F,
G,
#[cfg(any(feature = "samd21", feature = "min-samd51g"))]
H,
#[cfg(feature = "min-samd51g")]
I,
#[cfg(feature = "min-samd51g")]
J,
#[cfg(feature = "min-samd51g")]
K,
#[cfg(feature = "min-samd51g")]
L,
#[cfg(feature = "min-samd51g")]
M,
#[cfg(feature = "min-samd51g")]
N,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DynPinMode {
Disabled(DynDisabled),
Input(DynInput),
Output(DynOutput),
Alternate(DynAlternate),
}
pub const DYN_FLOATING_DISABLED: DynPinMode = DynPinMode::Disabled(DynDisabled::Floating);
pub const DYN_PULL_DOWN_DISABLED: DynPinMode = DynPinMode::Disabled(DynDisabled::PullDown);
pub const DYN_PULL_UP_DISABLED: DynPinMode = DynPinMode::Disabled(DynDisabled::PullUp);
pub const DYN_FLOATING_INPUT: DynPinMode = DynPinMode::Input(DynInput::Floating);
pub const DYN_PULL_DOWN_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullDown);
pub const DYN_PULL_UP_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullUp);
pub const DYN_PUSH_PULL_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::PushPull);
pub const DYN_READABLE_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::Readable);
pub const DYN_ALTERNATE_A: DynPinMode = DynPinMode::Alternate(DynAlternate::A);
pub const DYN_ALTERNATE_B: DynPinMode = DynPinMode::Alternate(DynAlternate::B);
pub const DYN_ALTERNATE_C: DynPinMode = DynPinMode::Alternate(DynAlternate::C);
pub const DYN_ALTERNATE_D: DynPinMode = DynPinMode::Alternate(DynAlternate::D);
pub const DYN_ALTERNATE_E: DynPinMode = DynPinMode::Alternate(DynAlternate::E);
pub const DYN_ALTERNATE_F: DynPinMode = DynPinMode::Alternate(DynAlternate::F);
pub const DYN_ALTERNATE_G: DynPinMode = DynPinMode::Alternate(DynAlternate::G);
#[cfg(any(feature = "samd21", feature = "min-samd51g"))]
pub const DYN_ALTERNATE_H: DynPinMode = DynPinMode::Alternate(DynAlternate::H);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_I: DynPinMode = DynPinMode::Alternate(DynAlternate::I);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_J: DynPinMode = DynPinMode::Alternate(DynAlternate::J);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_K: DynPinMode = DynPinMode::Alternate(DynAlternate::K);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_L: DynPinMode = DynPinMode::Alternate(DynAlternate::L);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_M: DynPinMode = DynPinMode::Alternate(DynAlternate::M);
#[cfg(feature = "min-samd51g")]
pub const DYN_ALTERNATE_N: DynPinMode = DynPinMode::Alternate(DynAlternate::N);
#[derive(PartialEq, Clone, Copy)]
pub enum DynGroup {
A,
#[cfg(any(feature = "samd21", feature = "min-samd51g"))]
B,
#[cfg(feature = "min-samd51n")]
C,
#[cfg(feature = "min-samd51p")]
D,
}
#[derive(PartialEq, Clone, Copy)]
pub struct DynPinId {
pub group: DynGroup,
pub num: u8,
}
pub struct DynPin {
id: DynPinId,
mode: DynPinMode,
}
impl DynPin {
#[inline]
pub fn id(&self) -> DynPinId {
self.id
}
#[inline]
pub fn mode(&self) -> DynPinMode {
self.mode
}
#[inline]
fn group(&self) -> *const GROUP {
match self.id.group {
DynGroup::A => GroupA::group(),
#[cfg(any(feature = "samd21", feature = "min-samd51g"))]
DynGroup::B => GroupB::group(),
#[cfg(feature = "min-samd51n")]
DynGroup::C => GroupC::group(),
#[cfg(feature = "min-samd51p")]
DynGroup::D => GroupD::group(),
}
}
#[inline]
pub fn into_mode(&mut self, mode: DynPinMode) {
let group = self.group();
let num = self.id.num;
use self::DynPinMode::*;
match mode {
Disabled(config) => {
use self::DynDisabled::*;
match config {
Floating => FloatingDisabled::convert(group, num),
PullDown => PullDownDisabled::convert(group, num),
PullUp => PullUpDisabled::convert(group, num),
}
}
Input(config) => {
use self::DynInput::*;
match config {
Floating => FloatingInput::convert(group, num),
PullDown => PullDownInput::convert(group, num),
PullUp => PullUpInput::convert(group, num),
}
}
Output(config) => {
use self::DynOutput::*;
match config {
PushPull => PushPullOutput::convert(group, num),
Readable => ReadableOutput::convert(group, num),
}
}
Alternate(config) => {
use self::DynAlternate::*;
match config {
A => AlternateA::convert(group, num),
B => AlternateB::convert(group, num),
C => AlternateC::convert(group, num),
D => AlternateD::convert(group, num),
E => AlternateE::convert(group, num),
F => AlternateF::convert(group, num),
G => AlternateG::convert(group, num),
#[cfg(any(feature = "samd21", feature = "min-samd51g"))]
H => AlternateH::convert(group, num),
#[cfg(feature = "min-samd51g")]
I => AlternateI::convert(group, num),
#[cfg(feature = "min-samd51g")]
J => AlternateJ::convert(group, num),
#[cfg(feature = "min-samd51g")]
K => AlternateK::convert(group, num),
#[cfg(feature = "min-samd51g")]
L => AlternateL::convert(group, num),
#[cfg(feature = "min-samd51g")]
M => AlternateM::convert(group, num),
#[cfg(feature = "min-samd51g")]
N => AlternateN::convert(group, num),
}
}
}
}
#[inline]
pub fn into_floating_disabled(&mut self) {
self.into_mode(DYN_FLOATING_DISABLED);
}
#[inline]
pub fn into_pull_down_disabled(&mut self) {
self.into_mode(DYN_PULL_DOWN_DISABLED);
}
#[inline]
pub fn into_pull_up_disabled(&mut self) {
self.into_mode(DYN_PULL_UP_DISABLED);
}
#[inline]
pub fn into_floating_input(&mut self) {
self.into_mode(DYN_FLOATING_INPUT);
}
#[inline]
pub fn into_pull_down_input(&mut self) {
self.into_mode(DYN_PULL_DOWN_INPUT);
}
#[inline]
pub fn into_pull_up_input(&mut self) {
self.into_mode(DYN_PULL_UP_INPUT);
}
#[inline]
pub fn into_push_pull_output(&mut self) {
self.into_mode(DYN_PUSH_PULL_OUTPUT);
}
#[inline]
pub fn into_readable_output(&mut self) {
self.into_mode(DYN_READABLE_OUTPUT);
}
#[inline]
pub fn into_alternate(&mut self, config: DynAlternate) {
self.into_mode(DynPinMode::Alternate(config));
}
#[inline]
pub fn get_drive_strength(&self) {
read_drive_strength(self.group(), self.id.num);
}
#[inline]
pub fn set_drive_strength(&mut self, stronger: bool) {
write_drive_strength(self.group(), self.id.num, stronger);
}
#[inline]
fn _read(&self) -> Result<bool, Error> {
match self.mode {
DynPinMode::Input(_) | DYN_READABLE_OUTPUT => Ok(read_pin(self.group(), self.id.num)),
_ => Err(Error::InvalidPinType),
}
}
#[inline]
fn _write(&mut self, bit: bool) -> Result<(), Error> {
match self.mode {
DynPinMode::Output(_) => Ok(write_pin(self.group(), self.id.num, bit)),
_ => Err(Error::InvalidPinType),
}
}
#[inline]
fn _toggle(&mut self) -> Result<(), Error> {
match self.mode {
DynPinMode::Output(_) => Ok(toggle_pin(self.group(), self.id.num)),
_ => Err(Error::InvalidPinType),
}
}
#[inline]
fn _read_out(&self) -> Result<bool, Error> {
match self.mode {
DYN_READABLE_OUTPUT => Ok(read_out_pin(self.group(), self.id.num)),
_ => Err(Error::InvalidPinType),
}
}
#[inline]
fn _is_low(&self) -> Result<bool, Error> {
Ok(self._read()? == false)
}
#[inline]
fn _is_high(&self) -> Result<bool, Error> {
Ok(self._read()? == true)
}
#[inline]
fn _set_low(&mut self) -> Result<(), Error> {
self._write(false)
}
#[inline]
fn _set_high(&mut self) -> Result<(), Error> {
self._write(true)
}
#[inline]
fn _is_set_low(&self) -> Result<bool, Error> {
Ok(self._read_out()? == false)
}
#[inline]
fn _is_set_high(&self) -> Result<bool, Error> {
Ok(self._read_out()? == true)
}
}
impl<I, M> From<Pin<I, M>> for DynPin
where
I: PinId,
M: PinMode,
{
#[inline]
fn from(_pin: Pin<I, M>) -> Self {
DynPin {
id: I::DYN,
mode: M::DYN,
}
}
}
impl<I, M> TryFrom<DynPin> for Pin<I, M>
where
I: PinId,
M: PinMode,
{
type Error = Error;
#[inline]
fn try_from(pin: DynPin) -> Result<Self, Error> {
if pin.id == I::DYN && pin.mode == M::DYN {
Ok(Self::new())
} else {
Err(Error::InvalidPinType)
}
}
}
impl OutputPin for DynPin {
type Error = Error;
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high()
}
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low()
}
}
#[cfg(feature = "unproven")]
impl InputPin for DynPin {
type Error = Error;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
self._is_high()
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
self._is_low()
}
}
#[cfg(feature = "unproven")]
impl ToggleableOutputPin for DynPin {
type Error = Error;
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle()
}
}
#[cfg(feature = "unproven")]
impl StatefulOutputPin for DynPin {
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
self._is_set_high()
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
self._is_set_low()
}
}