pub struct PinDriver<'d, MODE> { /* private fields */ }Expand description
A driver for a GPIO pin.
The driver can set the pin as a disconnected/disabled one, input, or output pin, or both or analog. On some chips (i.e. esp32 and esp32s*), the driver can also set the pin in RTC IO mode. Depending on the current operating mode, different sets of functions are available.
The mode-setting depends on the capabilities of the pin as well, i.e. input-only pins cannot be set into output or input-output mode.
Implementations§
Source§impl<'d, MODE> PinDriver<'d, MODE>
impl<'d, MODE> PinDriver<'d, MODE>
Sourcepub fn try_into_disabled(self) -> Result<PinDriver<'d, Disabled>, EspError>
pub fn try_into_disabled(self) -> Result<PinDriver<'d, Disabled>, EspError>
Try to convert the pin driver into a disabled pin driver.
Return an error if the pin cannot be disabled.
Sourcepub fn try_into_input(
self,
pull: Pull,
) -> Result<PinDriver<'d, Input>, EspError>
pub fn try_into_input( self, pull: Pull, ) -> Result<PinDriver<'d, Input>, EspError>
Try to convert the pin driver into an input pin driver.
Return an error if the pin cannot be set as input.
Sourcepub fn try_into_output(self) -> Result<PinDriver<'d, Output>, EspError>
pub fn try_into_output(self) -> Result<PinDriver<'d, Output>, EspError>
Try to convert the pin driver into an output pin driver.
Return an error if the pin cannot be set as output.
Sourcepub fn try_into_input_output(
self,
pull: Pull,
) -> Result<PinDriver<'d, InputOutput>, EspError>
pub fn try_into_input_output( self, pull: Pull, ) -> Result<PinDriver<'d, InputOutput>, EspError>
Try to convert the pin driver into an input-output pin driver.
Return an error if the pin cannot be set as input-output.
Sourcepub fn try_into_output_od(self) -> Result<PinDriver<'d, Output>, EspError>
pub fn try_into_output_od(self) -> Result<PinDriver<'d, Output>, EspError>
Try to convert the pin driver into an output open-drain pin driver.
Return an error if the pin cannot be set as output open-drain.
Sourcepub fn try_into_input_output_od(
self,
pull: Pull,
) -> Result<PinDriver<'d, InputOutput>, EspError>
pub fn try_into_input_output_od( self, pull: Pull, ) -> Result<PinDriver<'d, InputOutput>, EspError>
Try to convert the pin driver into an input-output open-drain pin driver.
Return an error if the pin cannot be set as input-output open-drain.
Source§impl<'d> PinDriver<'d, InputOutput>
impl<'d> PinDriver<'d, InputOutput>
Source§impl<'d, MODE> PinDriver<'d, MODE>
impl<'d, MODE> PinDriver<'d, MODE>
pub fn get_drive_strength(&self) -> Result<DriveStrength, EspError>where
MODE: OutputMode,
pub fn set_drive_strength(
&mut self,
strength: DriveStrength,
) -> Result<(), EspError>where
MODE: OutputMode,
pub fn is_high(&self) -> boolwhere
MODE: InputMode,
pub fn is_low(&self) -> boolwhere
MODE: InputMode,
pub fn get_level(&self) -> Levelwhere
MODE: InputMode,
pub fn is_set_high(&self) -> boolwhere
MODE: OutputMode,
Sourcepub fn is_set_low(&self) -> boolwhere
MODE: OutputMode,
pub fn is_set_low(&self) -> boolwhere
MODE: OutputMode,
Is the output pin set as low?
pub fn set_high(&mut self) -> Result<(), EspError>where
MODE: OutputMode,
Sourcepub fn set_low(&mut self) -> Result<(), EspError>where
MODE: OutputMode,
pub fn set_low(&mut self) -> Result<(), EspError>where
MODE: OutputMode,
Set the output as low.
pub fn set_level(&mut self, level: Level) -> Result<(), EspError>where
MODE: OutputMode,
Sourcepub fn toggle(&mut self) -> Result<(), EspError>where
MODE: OutputMode,
pub fn toggle(&mut self) -> Result<(), EspError>where
MODE: OutputMode,
Toggle pin output
Sourcepub unsafe fn subscribe<F: FnMut() + Send + 'static>(
&mut self,
callback: F,
) -> Result<(), EspError>where
MODE: InputMode,
pub unsafe fn subscribe<F: FnMut() + Send + 'static>(
&mut self,
callback: F,
) -> Result<(), EspError>where
MODE: InputMode,
Subscribes the provided callback for ISR notifications.
As a side effect, interrupts will be disabled, so to receive a notification, one has
to also call PinDriver::enable_interrupt after calling this method.
Note that PinDriver::enable_interrupt should also be called after
each received notification from non-ISR context, because the driver will automatically
disable ISR interrupts on each received ISR notification (so as to avoid IWDT triggers).
§Safety
Care should be taken not to call STD, libc or FreeRTOS APIs (except for a few allowed ones) in the callback passed to this function, as it is executed in an ISR context.
Sourcepub unsafe fn subscribe_nonstatic<F: FnMut() + Send + 'd>(
&mut self,
callback: F,
) -> Result<(), EspError>where
MODE: InputMode,
pub unsafe fn subscribe_nonstatic<F: FnMut() + Send + 'd>(
&mut self,
callback: F,
) -> Result<(), EspError>where
MODE: InputMode,
Subscribes the provided callback for ISR notifications.
As a side effect, interrupts will be disabled, so to receive a notification, one has
to also call PinDriver::enable_interrupt after calling this method.
Note that PinDriver::enable_interrupt should also be called after
each received notification from non-ISR context, because the driver will automatically
disable ISR interrupts on each received ISR notification (so as to avoid IWDT triggers).
§Safety
Care should be taken not to call STD, libc or FreeRTOS APIs (except for a few allowed ones) in the callback passed to this function, as it is executed in an ISR context.
Additionally, this method - in contrast to method subscribe - allows
the passed-in callback/closure to be non-'static. This enables users to borrow
- in the closure - variables that live on the stack - or more generally - in the same scope where the driver is created.
HOWEVER: care should be taken NOT to call core::mem::forget() on the driver,
as that would immediately lead to an UB (crash).
Also note that forgetting the driver might happen with Rc and Arc
when circular references are introduced: https://github.com/rust-lang/rust/issues/24456
The reason is that the closure is actually sent and owned by an ISR routine, which means that if the driver is forgotten, Rust is free to e.g. unwind the stack and the ISR routine will end up with references to variables that no longer exist.
The destructor of the driver takes care - prior to the driver being dropped and e.g. the stack being unwind - to unsubscribe the ISR routine. Unfortunately, when the driver is forgotten, the un-subscription does not happen and invalid references are left dangling.
This “local borrowing” will only be possible to express in a safe way once/if !Leak types
are introduced to Rust (i.e. the impossibility to “forget” a type and thus not call its destructor).
pub fn unsubscribe(&mut self) -> Result<(), EspError>where
MODE: InputMode,
Sourcepub fn enable_interrupt(&mut self) -> Result<(), EspError>where
MODE: InputMode,
pub fn enable_interrupt(&mut self) -> Result<(), EspError>where
MODE: InputMode,
Enables or re-enables the interrupt
Note that the interrupt is automatically disabled each time an interrupt is triggered (or else we risk entering a constant interrupt processing loop while the pin is in low/high state and the interrupt type is set to non-edge)
Therefore - to continue receiving ISR interrupts - user needs to call enable_interrupt
- from a non-ISR context - after each successful interrupt triggering.