embassy_nrf/
gpio.rs

1//! General purpose input/output (GPIO) driver.
2#![macro_use]
3
4use core::convert::Infallible;
5use core::hint::unreachable_unchecked;
6
7use cfg_if::cfg_if;
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9
10use crate::pac;
11use crate::pac::common::{Reg, RW};
12use crate::pac::gpio;
13use crate::pac::gpio::vals;
14#[cfg(not(feature = "_nrf51"))]
15use crate::pac::shared::{regs::Psel, vals::Connect};
16
17/// A GPIO port with up to 32 pins.
18#[derive(Debug, Eq, PartialEq)]
19pub enum Port {
20    /// Port 0, available on nRF9160 and all nRF52 and nRF51 MCUs.
21    Port0,
22
23    /// Port 1, only available on some MCUs.
24    #[cfg(feature = "_gpio-p1")]
25    Port1,
26
27    /// Port 2, only available on some MCUs.
28    #[cfg(feature = "_gpio-p2")]
29    Port2,
30}
31
32/// Pull setting for an input.
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum Pull {
36    /// No pull.
37    None,
38    /// Internal pull-up resistor.
39    Up,
40    /// Internal pull-down resistor.
41    Down,
42}
43
44/// GPIO input driver.
45pub struct Input<'d> {
46    pub(crate) pin: Flex<'d>,
47}
48
49impl<'d> Input<'d> {
50    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
51    #[inline]
52    pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
53        let mut pin = Flex::new(pin);
54        pin.set_as_input(pull);
55
56        Self { pin }
57    }
58
59    /// Get whether the pin input level is high.
60    #[inline]
61    pub fn is_high(&self) -> bool {
62        self.pin.is_high()
63    }
64
65    /// Get whether the pin input level is low.
66    #[inline]
67    pub fn is_low(&self) -> bool {
68        self.pin.is_low()
69    }
70
71    /// Get the pin input level.
72    #[inline]
73    pub fn get_level(&self) -> Level {
74        self.pin.get_level()
75    }
76}
77
78impl Input<'static> {
79    /// Persist the pin's configuration for the rest of the program's lifetime. This method should
80    /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
81    /// reuse of the underlying peripheral.
82    pub fn persist(self) {
83        self.pin.persist()
84    }
85}
86
87/// Digital input or output level.
88#[derive(Clone, Copy, Debug, Eq, PartialEq)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90pub enum Level {
91    /// Logical low.
92    Low,
93    /// Logical high.
94    High,
95}
96
97impl From<bool> for Level {
98    fn from(val: bool) -> Self {
99        match val {
100            true => Self::High,
101            false => Self::Low,
102        }
103    }
104}
105
106impl From<Level> for bool {
107    fn from(level: Level) -> bool {
108        match level {
109            Level::Low => false,
110            Level::High => true,
111        }
112    }
113}
114
115/// Drive strength settings for a given output level.
116// These numbers match vals::Drive exactly so hopefully the compiler will unify them.
117#[cfg(feature = "_nrf54l")]
118#[derive(Clone, Copy, Debug, PartialEq)]
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[repr(u8)]
121pub enum LevelDrive {
122    /// Disconnect (do not drive the output at all)
123    Disconnect = 2,
124    /// Standard
125    Standard = 0,
126    /// High drive
127    High = 1,
128    /// Extra high drive
129    ExtraHigh = 3,
130}
131
132/// Drive strength settings for an output pin.
133///
134/// This is a combination of two drive levels, used when the pin is set
135/// low and high respectively.
136#[cfg(feature = "_nrf54l")]
137#[derive(Clone, Copy, Debug, PartialEq)]
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub struct OutputDrive {
140    low: LevelDrive,
141    high: LevelDrive,
142}
143
144#[cfg(feature = "_nrf54l")]
145#[allow(non_upper_case_globals)]
146impl OutputDrive {
147    /// Standard '0', standard '1'
148    pub const Standard: Self = Self {
149        low: LevelDrive::Standard,
150        high: LevelDrive::Standard,
151    };
152    /// High drive '0', standard '1'
153    pub const HighDrive0Standard1: Self = Self {
154        low: LevelDrive::High,
155        high: LevelDrive::Standard,
156    };
157    /// Standard '0', high drive '1'
158    pub const Standard0HighDrive1: Self = Self {
159        low: LevelDrive::Standard,
160        high: LevelDrive::High,
161    };
162    /// High drive '0', high 'drive '1'
163    pub const HighDrive: Self = Self {
164        low: LevelDrive::High,
165        high: LevelDrive::High,
166    };
167    /// Disconnect '0' standard '1' (normally used for wired-or connections)
168    pub const Disconnect0Standard1: Self = Self {
169        low: LevelDrive::Disconnect,
170        high: LevelDrive::Standard,
171    };
172    /// Disconnect '0', high drive '1' (normally used for wired-or connections)
173    pub const Disconnect0HighDrive1: Self = Self {
174        low: LevelDrive::Disconnect,
175        high: LevelDrive::High,
176    };
177    /// Standard '0'. disconnect '1' (also known as "open drain", normally used for wired-and connections)
178    pub const Standard0Disconnect1: Self = Self {
179        low: LevelDrive::Standard,
180        high: LevelDrive::Disconnect,
181    };
182    /// High drive '0', disconnect '1' (also known as "open drain", normally used for wired-and connections)
183    pub const HighDrive0Disconnect1: Self = Self {
184        low: LevelDrive::High,
185        high: LevelDrive::Disconnect,
186    };
187}
188
189/// Drive strength settings for an output pin.
190// These numbers match vals::Drive exactly so hopefully the compiler will unify them.
191#[cfg(not(feature = "_nrf54l"))]
192#[derive(Clone, Copy, Debug, PartialEq)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194#[repr(u8)]
195pub enum OutputDrive {
196    /// Standard '0', standard '1'
197    Standard = 0,
198    /// High drive '0', standard '1'
199    HighDrive0Standard1 = 1,
200    /// Standard '0', high drive '1'
201    Standard0HighDrive1 = 2,
202    /// High drive '0', high 'drive '1'
203    HighDrive = 3,
204    /// Disconnect '0' standard '1' (normally used for wired-or connections)
205    Disconnect0Standard1 = 4,
206    /// Disconnect '0', high drive '1' (normally used for wired-or connections)
207    Disconnect0HighDrive1 = 5,
208    /// Standard '0'. disconnect '1' (also known as "open drain", normally used for wired-and connections)
209    Standard0Disconnect1 = 6,
210    /// High drive '0', disconnect '1' (also known as "open drain", normally used for wired-and connections)
211    HighDrive0Disconnect1 = 7,
212}
213
214/// GPIO output driver.
215pub struct Output<'d> {
216    pub(crate) pin: Flex<'d>,
217}
218
219impl<'d> Output<'d> {
220    /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDrive] configuration.
221    #[inline]
222    pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self {
223        let mut pin = Flex::new(pin);
224        match initial_output {
225            Level::High => pin.set_high(),
226            Level::Low => pin.set_low(),
227        }
228        pin.set_as_output(drive);
229
230        Self { pin }
231    }
232
233    /// Set the output as high.
234    #[inline]
235    pub fn set_high(&mut self) {
236        self.pin.set_high()
237    }
238
239    /// Set the output as low.
240    #[inline]
241    pub fn set_low(&mut self) {
242        self.pin.set_low()
243    }
244
245    /// Toggle the output level.
246    #[inline]
247    pub fn toggle(&mut self) {
248        self.pin.toggle()
249    }
250
251    /// Set the output level.
252    #[inline]
253    pub fn set_level(&mut self, level: Level) {
254        self.pin.set_level(level)
255    }
256
257    /// Get whether the output level is set to high.
258    #[inline]
259    pub fn is_set_high(&self) -> bool {
260        self.pin.is_set_high()
261    }
262
263    /// Get whether the output level is set to low.
264    #[inline]
265    pub fn is_set_low(&self) -> bool {
266        self.pin.is_set_low()
267    }
268
269    /// Get the current output level.
270    #[inline]
271    pub fn get_output_level(&self) -> Level {
272        self.pin.get_output_level()
273    }
274}
275
276impl Output<'static> {
277    /// Persist the pin's configuration for the rest of the program's lifetime. This method should
278    /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
279    /// reuse of the underlying peripheral.
280    pub fn persist(self) {
281        self.pin.persist()
282    }
283}
284
285pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) {
286    #[cfg(not(feature = "_nrf54l"))]
287    {
288        let drive = match drive {
289            OutputDrive::Standard => vals::Drive::S0S1,
290            OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1,
291            OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1,
292            OutputDrive::HighDrive => vals::Drive::H0H1,
293            OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1,
294            OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1,
295            OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1,
296            OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1,
297        };
298        w.set_drive(drive);
299    }
300
301    #[cfg(feature = "_nrf54l")]
302    {
303        fn convert(d: LevelDrive) -> vals::Drive {
304            match d {
305                LevelDrive::Disconnect => vals::Drive::D,
306                LevelDrive::Standard => vals::Drive::S,
307                LevelDrive::High => vals::Drive::H,
308                LevelDrive::ExtraHigh => vals::Drive::E,
309            }
310        }
311
312        w.set_drive0(convert(drive.low));
313        w.set_drive1(convert(drive.high));
314    }
315}
316
317fn convert_pull(pull: Pull) -> vals::Pull {
318    match pull {
319        Pull::None => vals::Pull::DISABLED,
320        Pull::Up => vals::Pull::PULLUP,
321        Pull::Down => vals::Pull::PULLDOWN,
322    }
323}
324
325/// GPIO flexible pin.
326///
327/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
328/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
329/// mode.
330pub struct Flex<'d> {
331    pub(crate) pin: Peri<'d, AnyPin>,
332}
333
334impl<'d> Flex<'d> {
335    /// Wrap the pin in a `Flex`.
336    ///
337    /// The pin remains disconnected. The initial output level is unspecified, but can be changed
338    /// before the pin is put into output mode.
339    #[inline]
340    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
341        // Pin will be in disconnected state.
342        Self { pin: pin.into() }
343    }
344
345    /// Put the pin into input mode.
346    #[inline]
347    pub fn set_as_input(&mut self, pull: Pull) {
348        self.pin.conf().write(|w| {
349            w.set_dir(vals::Dir::INPUT);
350            w.set_input(vals::Input::CONNECT);
351            w.set_pull(convert_pull(pull));
352            convert_drive(w, OutputDrive::Standard);
353            w.set_sense(vals::Sense::DISABLED);
354        });
355    }
356
357    /// Put the pin into output mode.
358    ///
359    /// The pin level will be whatever was set before (or low by default). If you want it to begin
360    /// at a specific level, call `set_high`/`set_low` on the pin first.
361    #[inline]
362    pub fn set_as_output(&mut self, drive: OutputDrive) {
363        self.pin.conf().write(|w| {
364            w.set_dir(vals::Dir::OUTPUT);
365            w.set_input(vals::Input::DISCONNECT);
366            w.set_pull(vals::Pull::DISABLED);
367            convert_drive(w, drive);
368            w.set_sense(vals::Sense::DISABLED);
369        });
370    }
371
372    /// Put the pin into input + output mode.
373    ///
374    /// This is commonly used for "open drain" mode. If you set `drive = Standard0Disconnect1`,
375    /// the hardware will drive the line low if you set it to low, and will leave it floating if you set
376    /// it to high, in which case you can read the input to figure out whether another device
377    /// is driving the line low.
378    ///
379    /// The pin level will be whatever was set before (or low by default). If you want it to begin
380    /// at a specific level, call `set_high`/`set_low` on the pin first.
381    #[inline]
382    pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) {
383        self.pin.conf().write(|w| {
384            w.set_dir(vals::Dir::OUTPUT);
385            w.set_input(vals::Input::CONNECT);
386            w.set_pull(convert_pull(pull));
387            convert_drive(w, drive);
388            w.set_sense(vals::Sense::DISABLED);
389        });
390    }
391
392    /// Put the pin into disconnected mode.
393    #[inline]
394    pub fn set_as_disconnected(&mut self) {
395        self.pin.conf().write(|w| {
396            w.set_input(vals::Input::DISCONNECT);
397        });
398    }
399
400    /// Get whether the pin input level is high.
401    #[inline]
402    pub fn is_high(&self) -> bool {
403        self.pin.block().in_().read().pin(self.pin.pin() as _)
404    }
405
406    /// Get whether the pin input level is low.
407    #[inline]
408    pub fn is_low(&self) -> bool {
409        !self.is_high()
410    }
411
412    /// Get the pin input level.
413    #[inline]
414    pub fn get_level(&self) -> Level {
415        self.is_high().into()
416    }
417
418    /// Set the output as high.
419    #[inline]
420    pub fn set_high(&mut self) {
421        self.pin.set_high()
422    }
423
424    /// Set the output as low.
425    #[inline]
426    pub fn set_low(&mut self) {
427        self.pin.set_low()
428    }
429
430    /// Toggle the output level.
431    #[inline]
432    pub fn toggle(&mut self) {
433        if self.is_set_low() {
434            self.set_high()
435        } else {
436            self.set_low()
437        }
438    }
439
440    /// Set the output level.
441    #[inline]
442    pub fn set_level(&mut self, level: Level) {
443        match level {
444            Level::Low => self.pin.set_low(),
445            Level::High => self.pin.set_high(),
446        }
447    }
448
449    /// Get whether the output level is set to high.
450    #[inline]
451    pub fn is_set_high(&self) -> bool {
452        self.pin.block().out().read().pin(self.pin.pin() as _)
453    }
454
455    /// Get whether the output level is set to low.
456    #[inline]
457    pub fn is_set_low(&self) -> bool {
458        !self.is_set_high()
459    }
460
461    /// Get the current output level.
462    #[inline]
463    pub fn get_output_level(&self) -> Level {
464        self.is_set_high().into()
465    }
466}
467
468impl Flex<'static> {
469    /// Persist the pin's configuration for the rest of the program's lifetime. This method should
470    /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
471    /// reuse of the underlying peripheral.
472    pub fn persist(self) {
473        core::mem::forget(self);
474    }
475}
476
477impl<'d> Drop for Flex<'d> {
478    fn drop(&mut self) {
479        self.set_as_disconnected();
480    }
481}
482
483pub(crate) trait SealedPin {
484    fn pin_port(&self) -> u8;
485
486    #[inline]
487    fn _pin(&self) -> u8 {
488        cfg_if! {
489            if #[cfg(feature = "_gpio-p1")] {
490                self.pin_port() % 32
491            } else {
492                self.pin_port()
493            }
494        }
495    }
496
497    #[inline]
498    fn block(&self) -> gpio::Gpio {
499        match self.pin_port() / 32 {
500            #[cfg(feature = "_nrf51")]
501            0 => pac::GPIO,
502            #[cfg(not(feature = "_nrf51"))]
503            0 => pac::P0,
504            #[cfg(feature = "_gpio-p1")]
505            1 => pac::P1,
506            #[cfg(feature = "_gpio-p2")]
507            2 => pac::P2,
508            _ => unsafe { unreachable_unchecked() },
509        }
510    }
511
512    #[inline]
513    fn conf(&self) -> Reg<gpio::regs::PinCnf, RW> {
514        self.block().pin_cnf(self._pin() as usize)
515    }
516
517    /// Set the output as high.
518    #[inline]
519    fn set_high(&self) {
520        self.block().outset().write(|w| w.set_pin(self._pin() as _, true))
521    }
522
523    /// Set the output as low.
524    #[inline]
525    fn set_low(&self) {
526        self.block().outclr().write(|w| w.set_pin(self._pin() as _, true))
527    }
528}
529
530/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
531#[allow(private_bounds)]
532pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
533    /// Number of the pin within the port (0..31)
534    #[inline]
535    fn pin(&self) -> u8 {
536        self._pin()
537    }
538
539    /// Port of the pin
540    #[inline]
541    fn port(&self) -> Port {
542        match self.pin_port() / 32 {
543            0 => Port::Port0,
544            #[cfg(feature = "_gpio-p1")]
545            1 => Port::Port1,
546            #[cfg(feature = "_gpio-p2")]
547            2 => Port::Port2,
548            _ => unsafe { unreachable_unchecked() },
549        }
550    }
551
552    /// Peripheral port register value
553    #[inline]
554    #[cfg(not(feature = "_nrf51"))]
555    fn psel_bits(&self) -> pac::shared::regs::Psel {
556        pac::shared::regs::Psel(self.pin_port() as u32)
557    }
558}
559
560/// Type-erased GPIO pin
561pub struct AnyPin {
562    pub(crate) pin_port: u8,
563}
564
565impl AnyPin {
566    /// Create an [AnyPin] for a specific pin.
567    ///
568    /// # Safety
569    /// - `pin_port` should not in use by another driver.
570    #[inline]
571    pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> {
572        Peri::new_unchecked(Self { pin_port })
573    }
574}
575
576impl_peripheral!(AnyPin);
577impl Pin for AnyPin {}
578impl SealedPin for AnyPin {
579    #[inline]
580    fn pin_port(&self) -> u8 {
581        self.pin_port
582    }
583}
584
585// ====================
586
587#[cfg(not(feature = "_nrf51"))]
588#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO
589pub(crate) trait PselBits {
590    fn psel_bits(&self) -> pac::shared::regs::Psel;
591}
592
593#[cfg(not(feature = "_nrf51"))]
594impl<'a, P: Pin> PselBits for Option<Peri<'a, P>> {
595    #[inline]
596    fn psel_bits(&self) -> pac::shared::regs::Psel {
597        match self {
598            Some(pin) => pin.psel_bits(),
599            None => DISCONNECTED,
600        }
601    }
602}
603
604#[cfg(not(feature = "_nrf51"))]
605#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO
606pub(crate) const DISCONNECTED: Psel = Psel(1 << 31);
607
608#[cfg(not(feature = "_nrf51"))]
609#[allow(dead_code)]
610pub(crate) fn deconfigure_pin(psel: Psel) {
611    if psel.connect() == Connect::DISCONNECTED {
612        return;
613    }
614    unsafe { AnyPin::steal(psel.0 as _) }.conf().write(|w| {
615        w.set_input(vals::Input::DISCONNECT);
616    })
617}
618
619// ====================
620
621macro_rules! impl_pin {
622    ($type:ident, $port_num:expr, $pin_num:expr) => {
623        impl crate::gpio::Pin for peripherals::$type {}
624        impl crate::gpio::SealedPin for peripherals::$type {
625            #[inline]
626            fn pin_port(&self) -> u8 {
627                $port_num * 32 + $pin_num
628            }
629        }
630
631        impl From<peripherals::$type> for crate::gpio::AnyPin {
632            fn from(_val: peripherals::$type) -> Self {
633                Self {
634                    pin_port: $port_num * 32 + $pin_num,
635                }
636            }
637        }
638    };
639}
640
641// ====================
642
643mod eh02 {
644    use super::*;
645
646    impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
647        type Error = Infallible;
648
649        fn is_high(&self) -> Result<bool, Self::Error> {
650            Ok(self.is_high())
651        }
652
653        fn is_low(&self) -> Result<bool, Self::Error> {
654            Ok(self.is_low())
655        }
656    }
657
658    impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
659        type Error = Infallible;
660
661        fn set_high(&mut self) -> Result<(), Self::Error> {
662            self.set_high();
663            Ok(())
664        }
665
666        fn set_low(&mut self) -> Result<(), Self::Error> {
667            self.set_low();
668            Ok(())
669        }
670    }
671
672    impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
673        fn is_set_high(&self) -> Result<bool, Self::Error> {
674            Ok(self.is_set_high())
675        }
676
677        fn is_set_low(&self) -> Result<bool, Self::Error> {
678            Ok(self.is_set_low())
679        }
680    }
681
682    impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
683        type Error = Infallible;
684        #[inline]
685        fn toggle(&mut self) -> Result<(), Self::Error> {
686            self.toggle();
687            Ok(())
688        }
689    }
690
691    /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`];
692    ///
693    /// If the pin is not in input mode the result is unspecified.
694    impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
695        type Error = Infallible;
696
697        fn is_high(&self) -> Result<bool, Self::Error> {
698            Ok(self.is_high())
699        }
700
701        fn is_low(&self) -> Result<bool, Self::Error> {
702            Ok(self.is_low())
703        }
704    }
705
706    impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
707        type Error = Infallible;
708
709        fn set_high(&mut self) -> Result<(), Self::Error> {
710            self.set_high();
711            Ok(())
712        }
713
714        fn set_low(&mut self) -> Result<(), Self::Error> {
715            self.set_low();
716            Ok(())
717        }
718    }
719
720    impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
721        fn is_set_high(&self) -> Result<bool, Self::Error> {
722            Ok(self.is_set_high())
723        }
724
725        fn is_set_low(&self) -> Result<bool, Self::Error> {
726            Ok(self.is_set_low())
727        }
728    }
729
730    impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
731        type Error = Infallible;
732        #[inline]
733        fn toggle(&mut self) -> Result<(), Self::Error> {
734            self.toggle();
735            Ok(())
736        }
737    }
738}
739
740impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
741    type Error = Infallible;
742}
743
744impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
745    fn is_high(&mut self) -> Result<bool, Self::Error> {
746        Ok((*self).is_high())
747    }
748
749    fn is_low(&mut self) -> Result<bool, Self::Error> {
750        Ok((*self).is_low())
751    }
752}
753
754impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
755    type Error = Infallible;
756}
757
758impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
759    fn set_high(&mut self) -> Result<(), Self::Error> {
760        self.set_high();
761        Ok(())
762    }
763
764    fn set_low(&mut self) -> Result<(), Self::Error> {
765        self.set_low();
766        Ok(())
767    }
768}
769
770impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
771    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
772        Ok((*self).is_set_high())
773    }
774
775    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
776        Ok((*self).is_set_low())
777    }
778}
779
780impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
781    type Error = Infallible;
782}
783
784/// Implement [embedded_hal_1::digital::InputPin] for [`Flex`];
785///
786/// If the pin is not in input mode the result is unspecified.
787impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
788    fn is_high(&mut self) -> Result<bool, Self::Error> {
789        Ok((*self).is_high())
790    }
791
792    fn is_low(&mut self) -> Result<bool, Self::Error> {
793        Ok((*self).is_low())
794    }
795}
796
797impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
798    fn set_high(&mut self) -> Result<(), Self::Error> {
799        self.set_high();
800        Ok(())
801    }
802
803    fn set_low(&mut self) -> Result<(), Self::Error> {
804        self.set_low();
805        Ok(())
806    }
807}
808
809impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
810    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
811        Ok((*self).is_set_high())
812    }
813
814    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
815        Ok((*self).is_set_low())
816    }
817}