1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use super::{mode, Pin, PinMode};
use core::marker::PhantomData;

macro_rules! pin {
    ($name:ident, $assign_v:expr) => {
        pub struct $name<MODE: PinMode>(PhantomData<MODE>);

        impl<MODE: super::PinMode> $name<MODE> {
            pub(crate) fn new() -> Self {
                Self(PhantomData)
            }

            /// Obtain the input portion of the pin.
            ///
            /// Input functions can coexist on the same pin, so the input
            /// portion can be freely copied and shared even though the other
            /// portions are subject to ownership and move semantics.
            ///
            /// The result of this method implements the embedded-hal digital
            /// v2 `InputPin` trait.
            pub fn digital_input(&self) -> $name<mode::DigitalInput> {
                $name::<mode::DigitalInput>(PhantomData)
            }
        }

        impl<MODE: super::PinMode> !Sync for $name<MODE> {}

        impl $name<mode::Unassigned> {
            /// Configure the pin's output portion for general-purpose digital
            /// output.
            ///
            /// The result of this method implements the embedded-hal digital
            /// v2 `OutputPin` trait.
            ///
            /// If `high` is set then the output will be driving the line high
            /// once activated. Otherwise, it will be driving the line low.
            /// Use the `OutputPin` trait methods to change the pin state after
            /// initial configuration.
            pub fn to_digital_output(self, high: bool) -> $name<mode::DigitalOutput> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();

                // Set output state first, so that we won't be briefly in the
                // wrong state when we activate the output.
                if high {
                    unsafe { (*gpio).set0.write(|w| w.bits(Self::REG_MASK)) }
                } else {
                    unsafe { (*gpio).clr0.write(|w| w.bits(Self::REG_MASK)) }
                }
                // Now put the pin in output mode. If the pin was already
                // configured to be a GPIO then we'll start driving the pin
                // after this step.
                unsafe {
                    (*gpio)
                        .dir0
                        .modify(|r, w| w.bits(r.bits() | Self::REG_MASK));
                }

                $name(PhantomData)
            }
        }

        unsafe impl<MODE: super::PinMode> Pin for $name<MODE> {
            const NUMBER: u8 = $assign_v;
        }

        unsafe impl super::UnassignedPin for $name<mode::Unassigned> {}
        unsafe impl super::InputPin for $name<mode::DigitalInput> {}
        unsafe impl super::InputPin for $name<mode::Unassigned> {}

        impl embedded_hal::digital::v2::InputPin for $name<mode::DigitalInput> {
            type Error = !;

            fn is_high(&self) -> Result<bool, !> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();
                Ok(unsafe { (*gpio).b[Self::NUMBER as usize].read().bits() != 0 })
            }

            fn is_low(&self) -> Result<bool, !> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();
                Ok(unsafe { (*gpio).b[Self::NUMBER as usize].read().bits() == 0 })
            }
        }

        impl embedded_hal::digital::v2::OutputPin for $name<mode::DigitalOutput> {
            type Error = !;

            fn set_high(&mut self) -> Result<(), !> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();
                unsafe { (*gpio).set0.write(|w| w.bits(Self::REG_MASK)) };
                Ok(())
            }

            fn set_low(&mut self) -> Result<(), !> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();
                unsafe { (*gpio).clr0.write(|w| w.bits(Self::REG_MASK)) };
                Ok(())
            }
        }

        impl embedded_hal::digital::v2::ToggleableOutputPin for $name<mode::DigitalOutput> {
            type Error = !;

            fn toggle(&mut self) -> Result<(), !> {
                let gpio = lpc81x_pac::GPIO_PORT::ptr();
                unsafe { (*gpio).not0.write(|w| w.bits(Self::REG_MASK)) };
                Ok(())
            }
        }

        /// The input portion of a pin can be freely copied, because multiple
        /// input functions can coexist on the same pin.
        impl core::marker::Copy for $name<mode::DigitalInput> {}
        impl core::clone::Clone for $name<mode::DigitalInput> {
            fn clone(&self) -> Self {
                Self(PhantomData)
            }
        }
    };
}

pin!(Pin0, 0);
pin!(Pin1, 1);
pin!(Pin2, 2);
pin!(Pin3, 3);
pin!(Pin4, 4);
pin!(Pin5, 5);
pin!(Pin6, 6);
pin!(Pin7, 7);
pin!(Pin8, 8);
pin!(Pin9, 9);
pin!(Pin10, 10);
pin!(Pin11, 11);
pin!(Pin12, 12);
pin!(Pin13, 13);
pin!(Pin14, 14);
pin!(Pin15, 15);
pin!(Pin16, 16);
pin!(Pin17, 17);