feat: add display UI with splash screen, dashboard, and RSSI sparkline

Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
swaitsandClaude Opus 4.6 committed 2026-03-29 20:42:54 -06:00
1 parent 7064110293
commit 3102fc747a
17624 files changed
+4564928 -38

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
//! Digital I/O
//!
//!
//!
// Deprecated / infallible traits
#[deprecated(
since = "0.2.2",
note = "Deprecated because the methods cannot return errors. \
Users should use the traits in digital::v2."
)]
pub mod v1;
// New / fallible traits
pub mod v2;
// v2 -> v1 compatibility wrappers
// These require explicit casts from v2 -> v1
pub mod v1_compat;
// v1 -> v2 compatibility shims
// These are implicit over v1 implementations
pub mod v2_compat;
// Re-export old traits so this isn't a breaking change
#[allow(deprecated)]
pub use self::v1::*;
+145
View File
@@ -0,0 +1,145 @@
//! Digital I/O
//!
//! The traits in this module are now deprecated. Please use the new versions included
//! in `digital::v2`.
#![allow(deprecated)]
/// Single digital push-pull output pin
///
/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in
/// `digital::v2::OutputPin`*.
pub trait OutputPin {
/// Drives the pin low
///
/// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external
/// electrical sources
fn set_low(&mut self);
/// Drives the pin high
///
/// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external
/// electrical sources
fn set_high(&mut self);
}
/// Push-pull output pin that can read its output state
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in
/// `digital::v2::StatefulOutputPin`*.
#[cfg(feature = "unproven")]
pub trait StatefulOutputPin {
/// Is the pin in drive high mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_high(&self) -> bool;
/// Is the pin in drive low mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_low(&self) -> bool;
}
/// Output pin that can be toggled
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin`
/// trait in `digital::v2::ToggleableOutputPin`*.
///
/// See [toggleable](toggleable) to use a software implementation if
/// both [OutputPin](trait.OutputPin.html) and
/// [StatefulOutputPin](trait.StatefulOutputPin.html) are
/// implemented. Otherwise, implement this using hardware mechanisms.
#[cfg(feature = "unproven")]
pub trait ToggleableOutputPin {
/// Toggle pin output.
fn toggle(&mut self);
}
/// If you can read **and** write the output state, a pin is
/// toggleable by software.
///
/// *This version of the module is now deprecated. Please use the new `toggleable` module in
/// `digital::v2::toggleable`*.
///
/// ```
/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// use embedded_hal::digital::toggleable;
///
/// /// A virtual output pin that exists purely in software
/// struct MyPin {
/// state: bool
/// }
///
/// impl OutputPin for MyPin {
/// fn set_low(&mut self) {
/// self.state = false;
/// }
/// fn set_high(&mut self) {
/// self.state = true;
/// }
/// }
///
/// impl StatefulOutputPin for MyPin {
/// fn is_set_low(&self) -> bool {
/// !self.state
/// }
/// fn is_set_high(&self) -> bool {
/// self.state
/// }
/// }
///
/// /// Opt-in to the software implementation.
/// impl toggleable::Default for MyPin {}
///
/// let mut pin = MyPin { state: false };
/// pin.toggle();
/// assert!(pin.is_set_high());
/// pin.toggle();
/// assert!(pin.is_set_low());
/// ```
#[cfg(feature = "unproven")]
pub mod toggleable {
#[allow(deprecated)]
use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// Software-driven `toggle()` implementation.
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[allow(deprecated)]
pub trait Default: OutputPin + StatefulOutputPin {}
#[allow(deprecated)]
impl<P> ToggleableOutputPin for P
where
P: Default,
{
/// Toggle pin output
fn toggle(&mut self) {
if self.is_set_low() {
self.set_high();
} else {
self.set_low();
}
}
}
}
/// Single digital input pin
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in
/// `digital::v2::InputPin`*.
#[cfg(feature = "unproven")]
pub trait InputPin {
/// Is the input pin high?
fn is_high(&self) -> bool;
/// Is the input pin low?
fn is_low(&self) -> bool;
}
+298
View File
@@ -0,0 +1,298 @@
//! v1 compatibility wrappers
//!
//! This module provides wrappers to support use of v2 implementations with
//! v1 consumers. v2 traits must be explicitly cast to the v1 version using
//! `.into()`, and will panic on internal errors
//!
//! ```
//! extern crate embedded_hal;
//! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin};
//!
//! struct NewOutputPinImpl {}
//!
//! impl v2::OutputPin for NewOutputPinImpl {
//! type Error = ();
//! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) }
//! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) }
//! }
//!
//! struct OldOutputPinConsumer<T: v1::OutputPin> {
//! _pin: T,
//! }
//!
//! impl <T>OldOutputPinConsumer<T>
//! where T: v1::OutputPin {
//! pub fn new(pin: T) -> OldOutputPinConsumer<T> {
//! OldOutputPinConsumer{ _pin: pin }
//! }
//! }
//!
//! fn main() {
//! let pin = NewOutputPinImpl{};
//! let _consumer: OldOutputPinConsumer<OldOutputPin<_>> = OldOutputPinConsumer::new(pin.into());
//! }
//! ```
//!
#[allow(deprecated)]
use super::v1;
use super::v2;
/// Wrapper to allow fallible `v2::OutputPin` traits to be converted to `v1::OutputPin` traits
pub struct OldOutputPin<T> {
pin: T,
}
impl<T, E> OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
E: core::fmt::Debug,
{
/// Create a new OldOutputPin wrapper around a `v2::OutputPin`
pub fn new(pin: T) -> Self {
Self { pin }
}
/// Fetch a reference to the inner `v2::OutputPin` impl
#[cfg(test)]
fn inner(&self) -> &T {
&self.pin
}
}
impl<T, E> From<T> for OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
E: core::fmt::Debug,
{
fn from(pin: T) -> Self {
OldOutputPin { pin }
}
}
/// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins
/// where errors will panic.
#[allow(deprecated)]
impl<T, E> v1::OutputPin for OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
E: core::fmt::Debug,
{
fn set_low(&mut self) {
self.pin.set_low().unwrap()
}
fn set_high(&mut self) {
self.pin.set_high().unwrap()
}
}
/// Implementation of `v1::StatefulOutputPin` trait for `v2::StatefulOutputPin` fallible pins
/// where errors will panic.
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T, E> v1::StatefulOutputPin for OldOutputPin<T>
where
T: v2::StatefulOutputPin<Error = E>,
E: core::fmt::Debug,
{
fn is_set_low(&self) -> bool {
self.pin.is_set_low().unwrap()
}
fn is_set_high(&self) -> bool {
self.pin.is_set_high().unwrap()
}
}
/// Wrapper to allow fallible `v2::InputPin` traits to be converted to `v1::InputPin` traits
/// where errors will panic.
#[cfg(feature = "unproven")]
pub struct OldInputPin<T> {
pin: T,
}
#[cfg(feature = "unproven")]
impl<T, E> OldInputPin<T>
where
T: v2::InputPin<Error = E>,
E: core::fmt::Debug,
{
/// Create an `OldInputPin` wrapper around a `v2::InputPin`.
pub fn new(pin: T) -> Self {
Self { pin }
}
}
#[cfg(feature = "unproven")]
impl<T, E> From<T> for OldInputPin<T>
where
T: v2::InputPin<Error = E>,
E: core::fmt::Debug,
{
fn from(pin: T) -> Self {
OldInputPin { pin }
}
}
/// Implementation of `v1::InputPin` trait for `v2::InputPin` fallible pins
/// where errors will panic.
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T, E> v1::InputPin for OldInputPin<T>
where
T: v2::InputPin<Error = E>,
E: core::fmt::Debug,
{
fn is_low(&self) -> bool {
self.pin.is_low().unwrap()
}
fn is_high(&self) -> bool {
self.pin.is_high().unwrap()
}
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use super::*;
#[allow(deprecated)]
use crate::digital::v1;
use crate::digital::v2;
use crate::digital::v1::OutputPin;
#[derive(Clone)]
struct NewOutputPinImpl {
state: bool,
res: Result<(), ()>,
}
impl v2::OutputPin for NewOutputPinImpl {
type Error = ();
fn set_low(&mut self) -> Result<(), Self::Error> {
self.state = false;
self.res
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self.state = true;
self.res
}
}
#[allow(deprecated)]
struct OldOutputPinConsumer<T: v1::OutputPin> {
_pin: T,
}
#[allow(deprecated)]
impl<T> OldOutputPinConsumer<T>
where
T: v1::OutputPin,
{
pub fn new(pin: T) -> OldOutputPinConsumer<T> {
OldOutputPinConsumer { _pin: pin }
}
}
#[test]
fn v1_v2_output_explicit() {
let i = NewOutputPinImpl {
state: false,
res: Ok(()),
};
let _c: OldOutputPinConsumer<OldOutputPin<_>> = OldOutputPinConsumer::new(i.into());
}
#[test]
fn v1_v2_output_state() {
let mut o: OldOutputPin<_> = NewOutputPinImpl {
state: false,
res: Ok(()),
}
.into();
o.set_high();
assert_eq!(o.inner().state, true);
o.set_low();
assert_eq!(o.inner().state, false);
}
#[test]
#[should_panic]
fn v1_v2_output_panic() {
let mut o: OldOutputPin<_> = NewOutputPinImpl {
state: false,
res: Err(()),
}
.into();
o.set_high();
}
#[cfg(feature = "unproven")]
use crate::digital::v1::InputPin;
#[cfg(feature = "unproven")]
struct NewInputPinImpl {
state: Result<bool, ()>,
}
#[cfg(feature = "unproven")]
impl v2::InputPin for NewInputPinImpl {
type Error = ();
fn is_low(&self) -> Result<bool, Self::Error> {
self.state.map(|v| v == false)
}
fn is_high(&self) -> Result<bool, Self::Error> {
self.state.map(|v| v == true)
}
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
struct OldInputPinConsumer<T: v1::InputPin> {
_pin: T,
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T> OldInputPinConsumer<T>
where
T: v1::InputPin,
{
pub fn new(pin: T) -> OldInputPinConsumer<T> {
OldInputPinConsumer { _pin: pin }
}
}
#[cfg(feature = "unproven")]
#[test]
fn v1_v2_input_explicit() {
let i = NewInputPinImpl { state: Ok(false) };
let _c: OldInputPinConsumer<OldInputPin<_>> = OldInputPinConsumer::new(i.into());
}
#[cfg(feature = "unproven")]
#[test]
fn v1_v2_input_state() {
let i: OldInputPin<_> = NewInputPinImpl { state: Ok(false) }.into();
assert_eq!(i.is_low(), true);
assert_eq!(i.is_high(), false);
}
#[cfg(feature = "unproven")]
#[test]
#[should_panic]
fn v1_v2_input_panic() {
let i: OldInputPin<_> = NewInputPinImpl { state: Err(()) }.into();
i.is_low();
}
}
+216
View File
@@ -0,0 +1,216 @@
//! Digital I/O
//!
//! Version 2 / fallible traits. Infallible implementations should set Error to `!`.
use core::{convert::From, ops::Not};
/// Digital output pin state
///
/// Conversion from `bool` and logical negation are also implemented
/// for this type.
/// ```rust
/// # use embedded_hal::digital::v2::PinState;
/// let state = PinState::from(false);
/// assert_eq!(state, PinState::Low);
/// assert_eq!(!state, PinState::High);
/// ```
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PinState {
/// Low pin state
Low,
/// High pin state
High,
}
impl From<bool> for PinState {
fn from(value: bool) -> Self {
match value {
false => PinState::Low,
true => PinState::High,
}
}
}
impl Not for PinState {
type Output = PinState;
fn not(self) -> Self::Output {
match self {
PinState::High => PinState::Low,
PinState::Low => PinState::High,
}
}
}
/// Single digital push-pull output pin
pub trait OutputPin {
/// Error type
type Error;
/// Drives the pin low
///
/// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external
/// electrical sources
fn set_low(&mut self) -> Result<(), Self::Error>;
/// Drives the pin high
///
/// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external
/// electrical sources
fn set_high(&mut self) -> Result<(), Self::Error>;
/// Drives the pin high or low depending on the provided value
///
/// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external
/// electrical sources
fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> {
match state {
PinState::Low => self.set_low(),
PinState::High => self.set_high(),
}
}
}
/// Push-pull output pin that can read its output state
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[cfg(feature = "unproven")]
pub trait StatefulOutputPin: OutputPin {
/// Is the pin in drive high mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_high(&self) -> Result<bool, Self::Error>;
/// Is the pin in drive low mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_low(&self) -> Result<bool, Self::Error>;
}
/// Output pin that can be toggled
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// See [toggleable](toggleable) to use a software implementation if
/// both [OutputPin](trait.OutputPin.html) and
/// [StatefulOutputPin](trait.StatefulOutputPin.html) are
/// implemented. Otherwise, implement this using hardware mechanisms.
#[cfg(feature = "unproven")]
pub trait ToggleableOutputPin {
/// Error type
type Error;
/// Toggle pin output.
fn toggle(&mut self) -> Result<(), Self::Error>;
}
/// If you can read **and** write the output state, a pin is
/// toggleable by software.
///
/// ```
/// use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// use embedded_hal::digital::v2::toggleable;
///
/// /// A virtual output pin that exists purely in software
/// struct MyPin {
/// state: bool
/// }
///
/// impl OutputPin for MyPin {
/// type Error = void::Void;
///
/// fn set_low(&mut self) -> Result<(), Self::Error> {
/// self.state = false;
/// Ok(())
/// }
/// fn set_high(&mut self) -> Result<(), Self::Error> {
/// self.state = true;
/// Ok(())
/// }
/// }
///
/// impl StatefulOutputPin for MyPin {
/// fn is_set_low(&self) -> Result<bool, Self::Error> {
/// Ok(!self.state)
/// }
/// fn is_set_high(&self) -> Result<bool, Self::Error> {
/// Ok(self.state)
/// }
/// }
///
/// /// Opt-in to the software implementation.
/// impl toggleable::Default for MyPin {}
///
/// let mut pin = MyPin { state: false };
/// pin.toggle().unwrap();
/// assert!(pin.is_set_high().unwrap());
/// pin.toggle().unwrap();
/// assert!(pin.is_set_low().unwrap());
/// ```
#[cfg(feature = "unproven")]
pub mod toggleable {
use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// Software-driven `toggle()` implementation.
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
pub trait Default: OutputPin + StatefulOutputPin {}
impl<P> ToggleableOutputPin for P
where
P: Default,
{
type Error = P::Error;
/// Toggle pin output
fn toggle(&mut self) -> Result<(), Self::Error> {
if self.is_set_low()? {
self.set_high()
} else {
self.set_low()
}
}
}
}
/// Single digital input pin
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[cfg(feature = "unproven")]
pub trait InputPin {
/// Error type
type Error;
/// Is the input pin high?
fn is_high(&self) -> Result<bool, Self::Error>;
/// Is the input pin low?
fn is_low(&self) -> Result<bool, Self::Error>;
}
/// Single pin that can switch from input to output mode, and vice-versa.
///
/// Example use (assumes the `Error` type is the same for the `IoPin`,
/// `InputPin`, and `OutputPin`):
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[cfg(feature = "unproven")]
pub trait IoPin<TInput, TOutput>
where
TInput: InputPin + IoPin<TInput, TOutput>,
TOutput: OutputPin + IoPin<TInput, TOutput>,
{
/// Error type.
type Error;
/// Tries to convert this pin to input mode.
///
/// If the pin is already in input mode, this method should succeed.
fn into_input_pin(self) -> Result<TInput, Self::Error>;
/// Tries to convert this pin to output mode with the given initial state.
///
/// If the pin is already in the requested state, this method should
/// succeed.
fn into_output_pin(self, state: PinState) -> Result<TOutput, Self::Error>;
}
+234
View File
@@ -0,0 +1,234 @@
//! v2 compatibility shims
//!
//! This module adds implicit forward support to v1 digital traits,
//! allowing v1 implementations to be directly used with v2 consumers.
//!
//! ```
//! extern crate embedded_hal;
//! use embedded_hal::digital::{v1, v2};
//!
//! struct OldOutputPinImpl { }
//!
//! impl v1::OutputPin for OldOutputPinImpl {
//! fn set_low(&mut self) { }
//! fn set_high(&mut self) { }
//! }
//!
//! struct NewOutputPinConsumer<T: v2::OutputPin> {
//! _pin: T,
//! }
//!
//! impl <T>NewOutputPinConsumer<T>
//! where T: v2::OutputPin {
//! pub fn new(pin: T) -> NewOutputPinConsumer<T> {
//! NewOutputPinConsumer{ _pin: pin }
//! }
//! }
//!
//! fn main() {
//! let pin = OldOutputPinImpl{};
//! let _consumer = NewOutputPinConsumer::new(pin);
//! }
//! ```
//!
#[allow(deprecated)]
use super::v1;
use super::v2;
/// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits
#[allow(deprecated)]
impl<T> v2::OutputPin for T
where
T: v1::OutputPin,
{
// TODO: update to ! when never_type is stabilized
type Error = ();
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.set_low())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.set_high())
}
}
/// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T> v2::StatefulOutputPin for T
where
T: v1::StatefulOutputPin + v1::OutputPin,
{
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T> v2::toggleable::Default for T where T: v1::toggleable::Default {}
/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T> v2::InputPin for T
where
T: v1::InputPin,
{
// TODO: update to ! when never_type is stabilized
type Error = ();
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
}
#[cfg(test)]
mod tests {
#[allow(deprecated)]
use crate::digital::v1;
use crate::digital::v2;
#[allow(deprecated)]
struct OldOutputPinImpl {
state: bool,
}
#[allow(deprecated)]
impl v1::OutputPin for OldOutputPinImpl {
fn set_low(&mut self) {
self.state = false;
}
fn set_high(&mut self) {
self.state = true;
}
}
#[allow(deprecated)]
#[cfg(feature = "unproven")]
impl v1::StatefulOutputPin for OldOutputPinImpl {
fn is_set_low(&self) -> bool {
self.state == false
}
fn is_set_high(&self) -> bool {
self.state == true
}
}
#[allow(deprecated)]
#[cfg(feature = "unproven")]
impl v1::toggleable::Default for OldOutputPinImpl {}
struct NewOutputPinConsumer<T: v2::OutputPin> {
_pin: T,
}
impl<T> NewOutputPinConsumer<T>
where
T: v2::OutputPin,
{
pub fn new(pin: T) -> NewOutputPinConsumer<T> {
NewOutputPinConsumer { _pin: pin }
}
}
#[cfg(feature = "unproven")]
struct NewToggleablePinConsumer<T: v2::ToggleableOutputPin> {
_pin: T,
}
#[cfg(feature = "unproven")]
impl<T> NewToggleablePinConsumer<T>
where
T: v2::ToggleableOutputPin,
{
pub fn new(pin: T) -> NewToggleablePinConsumer<T> {
NewToggleablePinConsumer { _pin: pin }
}
}
#[test]
#[cfg(feature = "unproven")]
fn v2_v1_toggleable_implicit() {
let i = OldOutputPinImpl { state: false };
let _c = NewToggleablePinConsumer::new(i);
}
#[test]
fn v2_v1_output_implicit() {
let i = OldOutputPinImpl { state: false };
let _c = NewOutputPinConsumer::new(i);
}
#[test]
fn v2_v1_output_state() {
let mut o = OldOutputPinImpl { state: false };
v2::OutputPin::set_high(&mut o).unwrap();
assert_eq!(o.state, true);
v2::OutputPin::set_low(&mut o).unwrap();
assert_eq!(o.state, false);
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
struct OldInputPinImpl {
state: bool,
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl v1::InputPin for OldInputPinImpl {
fn is_low(&self) -> bool {
!self.state
}
fn is_high(&self) -> bool {
self.state
}
}
#[cfg(feature = "unproven")]
struct NewInputPinConsumer<T: v2::InputPin> {
_pin: T,
}
#[cfg(feature = "unproven")]
impl<T> NewInputPinConsumer<T>
where
T: v2::InputPin,
{
pub fn new(pin: T) -> NewInputPinConsumer<T> {
NewInputPinConsumer { _pin: pin }
}
}
#[cfg(feature = "unproven")]
#[test]
#[cfg(feature = "unproven")]
fn v2_v1_input_implicit() {
let i = OldInputPinImpl { state: false };
let _c = NewInputPinConsumer::new(i);
}
#[cfg(feature = "unproven")]
#[test]
fn v2_v1_input_state() {
let mut i = OldInputPinImpl { state: false };
assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false);
assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true);
}
}