first version, first embedded lib, please help.
This commit is contained in:
commit
ce75a8f890
1013
Cargo.lock
generated
Normal file
1013
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
Cargo.toml
Normal file
30
Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "led-button"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 's' # default is opt-level = '0', but that makes very verbose machine code
|
||||
codegen-units = 1 # trade compile speed for slightly better optimisations
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
opt-level = 's' # default is opt-level = '3', but that makes quite verbose machine code
|
||||
codegen-units = 1 # trade compile speed for slightly better optimisations
|
||||
lto = 'fat' # Use Link Time Optimisations to further inline things across crates
|
||||
debug = 2 # Leave the debug symbols in (default is no debug info)
|
||||
strip = true # strip stupid stuff.
|
||||
|
||||
[dependencies]
|
||||
cortex-m = { version = "0.7.7" }
|
||||
cortex-m-rt = "0.7.5"
|
||||
critical-section = { version = "1.2.0", features = ["restore-state-u8"] }
|
||||
embedded-hal = "1.0.0"
|
||||
rp235x-hal = { version = "0.4.0", features = ["rt", "critical-section-impl"] }
|
||||
semihosting = "0.1.25"
|
||||
|
||||
[[bin]]
|
||||
name = "led-button-example"
|
||||
path = "src/example/led_button.rs"
|
||||
test = false
|
||||
bench = false
|
||||
27
build.rs
Normal file
27
build.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//! Set up linker scripts for the rp235x-hal examples
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// The file `memory.x` is loaded by cortex-m-rt's `link.x` script, which
|
||||
// is what we specify in `.cargo/config.toml` for Arm builds
|
||||
let memory_x = include_bytes!("memory.x");
|
||||
let mut f = File::create(out.join("memory.x")).unwrap();
|
||||
f.write_all(memory_x).unwrap();
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
|
||||
// The file `rp235x_riscv.x` is what we specify in `.cargo/config.toml` for
|
||||
// RISC-V builds
|
||||
let rp235x_riscv_x = include_bytes!("rp235x_riscv.x");
|
||||
let mut f = File::create(out.join("rp235x_riscv.x")).unwrap();
|
||||
f.write_all(rp235x_riscv_x).unwrap();
|
||||
println!("cargo:rerun-if-changed=rp235x_riscv.x");
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
25
src/button_config.rs
Normal file
25
src/button_config.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//! Button config
|
||||
|
||||
use super::PullConfig;
|
||||
|
||||
/// The configuration of a simple button.
|
||||
pub struct ButtonConfig {
|
||||
/// fn_refresh * pressing_time = how many loops to trigger ButtonState::Pressed
|
||||
pub pressing_time : f32,
|
||||
/// fn_refresh * longpressing_time = how many loops to trigger ButtonState::LongPress
|
||||
pub longpressing_time : f32,
|
||||
/// if the button is in pull-up/down configuration.
|
||||
pub pull_configuration : PullConfig
|
||||
}
|
||||
|
||||
impl Default for ButtonConfig {
|
||||
|
||||
/// some random default values.
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pressing_time : 0.25,
|
||||
longpressing_time : 1.77,
|
||||
pull_configuration : PullConfig::PullUp,
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/button_state.rs
Normal file
13
src/button_state.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//! contains the enum ButtonState.
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ButtonState {
|
||||
NotPressed,
|
||||
Released,
|
||||
LongReleased,
|
||||
Flank,
|
||||
LongFlank,
|
||||
Pressing,
|
||||
Pressed,
|
||||
LongPress,
|
||||
}
|
||||
141
src/button_stateful.rs
Normal file
141
src/button_stateful.rs
Normal file
@ -0,0 +1,141 @@
|
||||
//! # A stateful button
|
||||
//! -------------------
|
||||
//! has counter and poll that can be used to avoid contact bounce.
|
||||
//! very very nice, much wow.
|
||||
|
||||
use embedded_hal::digital::InputPin;
|
||||
use super::button_state::ButtonState;
|
||||
use super::button_config::ButtonConfig;
|
||||
use super::PullConfig;
|
||||
|
||||
/// A stateful input pin represented as a button.
|
||||
pub struct StatefulButton<IP> {
|
||||
/// The pin from hal denoted as IP for Input Pin.
|
||||
pub pin : IP,
|
||||
|
||||
/// ButtonConfig struct with a few options like pull-configuration.
|
||||
pub config : ButtonConfig,
|
||||
|
||||
/// Current state of the button
|
||||
state : ButtonState,
|
||||
|
||||
/// The previous state of the button
|
||||
last_state : ButtonState,
|
||||
|
||||
/// counter for how many loops the button have been pressed.
|
||||
pub counter : u32,
|
||||
|
||||
/// Threshold for triggering long pressed.
|
||||
long_press_th : u32,
|
||||
|
||||
/// Threshold for triggering pressed.
|
||||
pressing_th : u32
|
||||
}
|
||||
|
||||
impl<IP: InputPin> StatefulButton<IP> {
|
||||
|
||||
/// Creates a stateful button.
|
||||
///
|
||||
/// ## Parameters:
|
||||
/// - button_pin : IP
|
||||
/// - An input pin from embedded-hal crate.
|
||||
/// - config : ButtonConfig
|
||||
/// - a config from this crate (see led_button::button_config::ButtonConfig)
|
||||
/// - fn_refresh : f32
|
||||
/// - function refresh, lets say your program runs the function 10.000.000 times a seconds then thats a good value to use here.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use led_button::button_stateful::StatefulButton;
|
||||
/// use led_button::button_config::ButtonConfig;
|
||||
///
|
||||
/// // remember to always do a weird dance..
|
||||
///
|
||||
/// let button = StatefulButton::create(
|
||||
/// pins.gpio21.into_pull_up_input(),
|
||||
/// ButtonConfig::default(),
|
||||
/// 274000.1
|
||||
/// );
|
||||
/// ```
|
||||
pub fn create(button_pin: IP, config: ButtonConfig, fn_refresh: f32) -> Self {
|
||||
let lpt = config.longpressing_time;
|
||||
let pt = config.pressing_time;
|
||||
Self {
|
||||
pin : button_pin,
|
||||
config : config,
|
||||
long_press_th : (fn_refresh * lpt) as u32,
|
||||
pressing_th : (fn_refresh * pt) as u32,
|
||||
state : ButtonState::NotPressed,
|
||||
last_state : ButtonState::NotPressed,
|
||||
counter : 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// checks if button is in active state.
|
||||
pub fn is_pressed(&mut self) -> u8 {
|
||||
match (&self.config.pull_configuration, self.pin.is_low()) {
|
||||
(PullConfig::PullUp, Ok(true)) => 1,
|
||||
(PullConfig::PullDown, Ok(false)) => 1,
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
/// trigger a state, in case you want to.
|
||||
pub fn trigger_state(&mut self, state: ButtonState) {
|
||||
self.last_state = self.state;
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
/// polling logic will increase self.counter by one each time you call this function and the button is pressed.
|
||||
/// if the button is released and poll is called the counter is reset.
|
||||
/// will also set internal state of the button for a press, long press, not pressed and pressing.
|
||||
pub fn poll(&mut self) {
|
||||
self.last_state = self.state;
|
||||
if self.is_pressed() > 0 {
|
||||
self.counter = self.counter.wrapping_add(1);
|
||||
if self.counter >= self.long_press_th {
|
||||
self.state = ButtonState::LongPress;
|
||||
}
|
||||
else if self.counter >= self.pressing_th {
|
||||
self.state = ButtonState::Pressed;
|
||||
}
|
||||
else {
|
||||
self.state = ButtonState::Pressing;
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// read the current state and previous state and return one of the following states.
|
||||
/// - NotPressed
|
||||
/// - Released
|
||||
/// - LongReleased
|
||||
/// - Pressing
|
||||
/// - Flank
|
||||
/// - Pressed
|
||||
/// - LongFlank
|
||||
/// - LongPress
|
||||
pub fn read(&mut self) -> ButtonState {
|
||||
match (self.state, self.last_state) {
|
||||
(ButtonState::NotPressed, ButtonState::NotPressed) => ButtonState::NotPressed,
|
||||
(ButtonState::NotPressed, ButtonState::Pressed) => ButtonState::Released,
|
||||
(ButtonState::NotPressed, ButtonState::Pressing) => ButtonState::Released,
|
||||
(ButtonState::NotPressed, ButtonState::LongPress) => ButtonState::LongReleased,
|
||||
(ButtonState::Pressing, _) => ButtonState::Pressing,
|
||||
(ButtonState::Pressed, ButtonState::Pressing) => ButtonState::Flank,
|
||||
(ButtonState::Pressed, ButtonState::Pressed) => ButtonState::Pressed,
|
||||
(ButtonState::LongPress, ButtonState::Pressed) => ButtonState::LongFlank,
|
||||
(ButtonState::LongPress, ButtonState::LongPress) => ButtonState::LongPress,
|
||||
_ => ButtonState::NotPressed
|
||||
}
|
||||
}
|
||||
|
||||
/// resets the counter and set state and previous state to NotPressed.
|
||||
pub fn reset(&mut self) {
|
||||
self.state = ButtonState::NotPressed;
|
||||
self.last_state = ButtonState::NotPressed;
|
||||
self.counter = 0;
|
||||
}
|
||||
}
|
||||
73
src/errors.rs
Normal file
73
src/errors.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use core::{
|
||||
fmt,
|
||||
//convert::{Infallible},
|
||||
};
|
||||
|
||||
//#[cfg(feature = "defmt-03")]
|
||||
//use crate::defmt;
|
||||
/*
|
||||
pub trait Error: fmt::Debug {
|
||||
/// Convert error to a generic error kind
|
||||
///
|
||||
/// By using this method, errors freely defined by HAL implementations
|
||||
/// can be converted to a set of generic errors upon which generic
|
||||
/// code can act.
|
||||
fn kind(&self) -> ErrorKind;
|
||||
}
|
||||
|
||||
impl Error for Infallible {
|
||||
fn kind(&self) -> ErrorKind {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/// Error kind.
|
||||
///
|
||||
/// This represents a common set of operation errors. HAL implementations are
|
||||
/// free to define more specific or additional error types. However, by providing
|
||||
/// a mapping to these common errors, generic code can still react to them.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
//#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub enum ErrorKind {
|
||||
LedCouldNotTurnPinLow,
|
||||
LedCouldNotTurnPinHigh,
|
||||
ButtonSomething
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorKind {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::LedCouldNotTurnPinLow => write!(
|
||||
f,
|
||||
"[puckoprutt error] <- could not turn on led."
|
||||
),
|
||||
Self::LedCouldNotTurnPinHigh => write!(
|
||||
f,
|
||||
"[puckoprutt error] <- could not turn off led."
|
||||
),
|
||||
Self::ButtonSomething => write!(
|
||||
f,
|
||||
"[placeholder]"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// Error type trait.
|
||||
///
|
||||
/// This just defines the error type, to be used by the other traits.
|
||||
pub trait ErrorType {
|
||||
type Error: Error;
|
||||
}
|
||||
|
||||
impl<T: ErrorType + ?Sized> ErrorType for &T {
|
||||
type Error = T::Error;
|
||||
}
|
||||
|
||||
impl<T: ErrorType + ?Sized> ErrorType for &mut T {
|
||||
type Error = T::Error;
|
||||
}
|
||||
*/
|
||||
126
src/example/led_button.rs
Normal file
126
src/example/led_button.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::cell::RefCell;
|
||||
use core::panic::PanicInfo;
|
||||
use critical_section::Mutex;
|
||||
use cortex_m::asm;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use cortex_m_rt::entry;
|
||||
use led_button::{LedButton, PullConfig};
|
||||
use led_button::led_state::LedState;
|
||||
use led_button::button_config::ButtonConfig;
|
||||
use rp235x_hal::{
|
||||
self as hal,
|
||||
block::ImageDef,
|
||||
pac::{Peripherals, interrupt},
|
||||
gpio::{
|
||||
Interrupt,
|
||||
Pin, FunctionSio,
|
||||
PullDown, PullUp,
|
||||
SioInput, SioOutput
|
||||
}
|
||||
};
|
||||
|
||||
type LedPin1 = Pin<hal::gpio::bank0::Gpio15, FunctionSio<SioOutput>, PullDown>;
|
||||
type ButtonPin1 = Pin<hal::gpio::bank0::Gpio16, FunctionSio<SioInput>, PullUp>;
|
||||
type LedPin2 = Pin<hal::gpio::bank0::Gpio13, FunctionSio<SioOutput>, PullDown>;
|
||||
type ButtonPin2 = Pin<hal::gpio::bank0::Gpio21, FunctionSio<SioInput>, PullUp>;
|
||||
|
||||
static GLOBAL_LED_BTN_1 : Mutex<RefCell<Option<LedButton<LedPin1, ButtonPin1>>>> = Mutex::new(RefCell::new(None));
|
||||
static GLOBAL_LED_BTN_2 : Mutex<RefCell<Option<LedButton<LedPin2, ButtonPin2>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
pub const XOSC_CRYSTAL_FREQ : u32 = 12000000;
|
||||
|
||||
#[interrupt]
|
||||
#[allow(non_snake_case)]
|
||||
fn IO_IRQ_BANK0() {
|
||||
critical_section::with(|cs| {
|
||||
let mut button1_ref = GLOBAL_LED_BTN_1.borrow(cs).borrow_mut();
|
||||
let mut button2_ref = GLOBAL_LED_BTN_2.borrow(cs).borrow_mut();
|
||||
|
||||
if let (Some(button1), Some(button2)) = (button1_ref.as_mut(), button2_ref.as_mut()) {
|
||||
if button1.button.pin.interrupt_status(Interrupt::EdgeLow) {
|
||||
let _ = button2.toggle();
|
||||
button1.button.pin.clear_interrupt(Interrupt::EdgeLow);
|
||||
}
|
||||
if button2.button.pin.interrupt_status(Interrupt::EdgeLow) {
|
||||
let _ = button1.toggle();
|
||||
button2.button.pin.clear_interrupt(Interrupt::EdgeLow);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let mut pac = Peripherals::take().unwrap();
|
||||
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
// clock and timers
|
||||
let _clocks = hal::clocks::init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
pac.PLL_USB,
|
||||
&mut pac.RESETS,
|
||||
&mut watchdog
|
||||
).ok().unwrap();
|
||||
|
||||
// init gpio
|
||||
let sio = hal::Sio::new(pac.SIO);
|
||||
let pins = hal::gpio::Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS
|
||||
);
|
||||
|
||||
let led1_pin = pins.gpio15.into_push_pull_output();
|
||||
let button1_pin = pins.gpio16.into_pull_up_input();
|
||||
let led2_pin = pins.gpio13.into_push_pull_output();
|
||||
let button2_pin = pins.gpio21.into_pull_up_input();
|
||||
button1_pin.set_interrupt_enabled(Interrupt::EdgeLow, true);
|
||||
button2_pin.set_interrupt_enabled(Interrupt::EdgeLow, true);
|
||||
|
||||
let button1 = LedButton::create(
|
||||
led1_pin, LedState::Off, PullConfig::PullDown, button1_pin, ButtonConfig::default(), 274000.0
|
||||
);
|
||||
let button2 = LedButton::create(
|
||||
led2_pin, LedState::Off, PullConfig::PullDown, button2_pin, ButtonConfig::default(), 274000.0
|
||||
);
|
||||
|
||||
critical_section::with(|cs| {
|
||||
GLOBAL_LED_BTN_1.borrow(cs).replace(Some(button1));
|
||||
GLOBAL_LED_BTN_2.borrow(cs).replace(Some(button2));
|
||||
});
|
||||
|
||||
unsafe {
|
||||
NVIC::unmask(hal::pac::Interrupt::IO_IRQ_BANK0);
|
||||
}
|
||||
|
||||
loop {
|
||||
asm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(link_section = ".start_block")]
|
||||
#[used]
|
||||
pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
loop { asm::udf() }
|
||||
}
|
||||
|
||||
pub fn exit() -> ! {
|
||||
semihosting::process::exit(0);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[cortex_m_rt::exception]
|
||||
unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
|
||||
semihosting::process::exit(1);
|
||||
}
|
||||
55
src/led_state.rs
Normal file
55
src/led_state.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! LedState is pretty much a bool.
|
||||
|
||||
use core::ops::Not;
|
||||
|
||||
/// Digital output led state.
|
||||
///
|
||||
/// Conversion from `bool` and logical negation are also implemented
|
||||
/// for this type.
|
||||
/// ```rust
|
||||
/// # use led_button::let_state::LedState;
|
||||
/// let state = LedState::from(false);
|
||||
/// assert_eq!(state, LedState::Low);
|
||||
/// assert_eq!(!state, LedState::High);
|
||||
///
|
||||
/// let state = LedState::from(LedState::On);
|
||||
/// assert_eq!(state, false);
|
||||
/// assert_eq!(!state, true);
|
||||
/// ```
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LedState {
|
||||
On,
|
||||
Off
|
||||
}
|
||||
|
||||
impl From<bool> for LedState {
|
||||
#[inline]
|
||||
fn from(on: bool) -> Self {
|
||||
match on {
|
||||
true => LedState::On,
|
||||
false => LedState::Off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LedState> for bool {
|
||||
#[inline]
|
||||
fn from(value: LedState) -> bool {
|
||||
match value {
|
||||
LedState::Off => false,
|
||||
LedState::On => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for LedState {
|
||||
type Output = LedState;
|
||||
|
||||
#[inline]
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
LedState::Off => LedState::On,
|
||||
LedState::On => LedState::Off
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/led_stateful.rs
Normal file
111
src/led_stateful.rs
Normal file
@ -0,0 +1,111 @@
|
||||
//! # Stateful LED
|
||||
//! --------------
|
||||
//! cool stuff.
|
||||
//! very much wow factor.
|
||||
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use super::PullConfig;
|
||||
use super::led_state::LedState;
|
||||
use super::errors::ErrorKind;
|
||||
|
||||
/// A stateful output pin representing a LED.
|
||||
pub struct StatefulLed<OP> {
|
||||
/// The pin from hal denoted as OP for Output Pin.
|
||||
pub pin : OP,
|
||||
|
||||
/// The current state of the led, can be On or Off.
|
||||
pub current_state : LedState,
|
||||
|
||||
/// Resistor pull-up/down configuration. is the led "on" by a low or high signal.
|
||||
pull_configuration : PullConfig,
|
||||
}
|
||||
|
||||
impl<OP: OutputPin> StatefulLed<OP> {
|
||||
/// Creates a StatefulLed
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use led_button::led_stateful::StatefulLed;
|
||||
/// use led_button::led_state::LedState;
|
||||
/// use led_button::button_config::Buttonconfig;
|
||||
/// use led_button::PullConfig;
|
||||
///
|
||||
/// // ... init your hal and do a weird a dance..
|
||||
///
|
||||
/// let led1_pin = pins.gpio15.into_push_pull_output();
|
||||
/// let button1_pin = pins.gpio16.into_pull_up_input();
|
||||
///
|
||||
/// let button1 = LedButton::create(
|
||||
/// led1_pin,
|
||||
/// LedState::Off,
|
||||
/// PullConfig::PullDown,
|
||||
/// button1_pin,
|
||||
/// ButtonConfig::default(),
|
||||
/// 274000.0
|
||||
/// );
|
||||
///
|
||||
/// // ... continue doing a weird a dance.
|
||||
/// ```
|
||||
///
|
||||
pub fn create(led_pin: OP, pull_config: PullConfig, start_state: LedState) -> Self {
|
||||
Self {
|
||||
pin : led_pin,
|
||||
pull_configuration : pull_config,
|
||||
current_state : start_state,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_low(&mut self) -> Result<(), ErrorKind>{
|
||||
match self.pin.set_low() {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_e) => Err(ErrorKind::LedCouldNotTurnPinLow)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), ErrorKind>{
|
||||
match self.pin.set_high() {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_e) => Err(ErrorKind::LedCouldNotTurnPinHigh)
|
||||
}
|
||||
}
|
||||
|
||||
/// will trigger 'on' state depending on your pull configuration.
|
||||
pub fn on(&mut self) -> Result<(), ErrorKind> {
|
||||
match self.set_state(LedState::On) {
|
||||
Ok(()) => {
|
||||
self.current_state = LedState::On;
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// will trigger 'off' state depending on your pull configuration.
|
||||
pub fn off(&mut self) -> Result<(), ErrorKind>{
|
||||
match self.set_state(LedState::Off) {
|
||||
Ok(()) => {
|
||||
self.current_state = LedState::Off;
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// will trigger the 'on/off' state thats not in use.
|
||||
pub fn toggle(&mut self) -> Result<(), ErrorKind>{
|
||||
match self.current_state {
|
||||
LedState::On => self.off(),
|
||||
LedState::Off => self.on(),
|
||||
}
|
||||
}
|
||||
|
||||
/// set the state that was given in the 'state' argument.
|
||||
pub fn set_state(&mut self, state: LedState) -> Result<(), ErrorKind> {
|
||||
match (state, self.pull_configuration) {
|
||||
(LedState::Off, PullConfig::PullDown) => { self.set_low() }
|
||||
(LedState::On, PullConfig::PullDown) => { self.set_high() }
|
||||
(LedState::Off, PullConfig::PullUp) => { self.set_high() }
|
||||
(LedState::On, PullConfig::PullUp) => { self.set_low() }
|
||||
}
|
||||
}
|
||||
}
|
||||
126
src/lib.rs
Normal file
126
src/lib.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Hej och välkommen till denna skit.
|
||||
|
||||
#![no_std]
|
||||
|
||||
mod errors;
|
||||
pub mod button_state;
|
||||
pub mod button_config;
|
||||
pub mod button_stateful;
|
||||
pub mod led_state;
|
||||
pub mod led_stateful;
|
||||
|
||||
use embedded_hal::digital::{InputPin, OutputPin};
|
||||
use led_state::LedState;
|
||||
use led_stateful::StatefulLed;
|
||||
use button_stateful::StatefulButton;
|
||||
use button_config::ButtonConfig;
|
||||
use crate::button_state::ButtonState;
|
||||
|
||||
/// Pull configuration, used by both StatefulButton and StatefulLed.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PullConfig {
|
||||
PullUp,
|
||||
PullDown
|
||||
}
|
||||
|
||||
/// Represents a button with built in led.
|
||||
pub struct LedButton<OP, IP> {
|
||||
/// the pin from mcu to LED
|
||||
pub led : StatefulLed<OP>,
|
||||
|
||||
/// the pin from mcu to button
|
||||
pub button : StatefulButton<IP>,
|
||||
|
||||
/// the state of the button, always initialised to NotPressed.
|
||||
pub state : ButtonState
|
||||
}
|
||||
|
||||
impl<OP: OutputPin, IP: InputPin> LedButton<OP, IP> {
|
||||
/// Creates a StatefulLed
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use led_button::led_stateful::StatefulLed;
|
||||
/// use led_button::led_state::LedState;
|
||||
/// use led_button::button_config::Buttonconfig;
|
||||
/// use led_button::PullConfig;
|
||||
///
|
||||
/// // ... init your hal and do a weird a dance..
|
||||
///
|
||||
/// let led1_pin = pins.gpio15.into_push_pull_output();
|
||||
/// let button1_pin = pins.gpio16.into_pull_up_input();
|
||||
///
|
||||
/// let button1 = LedButton::create(
|
||||
/// led1_pin,
|
||||
/// LedState::Off,
|
||||
/// PullConfig::PullDown,
|
||||
/// button1_pin,
|
||||
/// ButtonConfig::default(),
|
||||
/// 274000.0
|
||||
/// );
|
||||
///
|
||||
/// // ... continue doing a weird a dance.
|
||||
/// ```
|
||||
///
|
||||
pub fn create(led_pin: OP, led_state: LedState, led_pullconf: PullConfig, button_pin: IP, button_config: ButtonConfig, fn_refresh: f32 ) -> Self {
|
||||
Self {
|
||||
led : StatefulLed::create(led_pin, led_pullconf, led_state),
|
||||
button : StatefulButton::create(button_pin, button_config, fn_refresh),
|
||||
state : ButtonState::NotPressed
|
||||
}
|
||||
}
|
||||
|
||||
/// get the current state of the LED.
|
||||
pub fn led_state(self) -> LedState {
|
||||
self.led.current_state
|
||||
}
|
||||
|
||||
/// set the LED to "On"-state.
|
||||
pub fn on(&mut self) {
|
||||
let _ = self.led.on();
|
||||
}
|
||||
|
||||
/// set the LED to "Off"-state.
|
||||
pub fn off(&mut self) {
|
||||
let _ = self.led.off();
|
||||
}
|
||||
|
||||
/// toggle the LED.
|
||||
pub fn toggle(&mut self) {
|
||||
let _ = self.led.toggle();
|
||||
}
|
||||
|
||||
/// the current counter value of the button.
|
||||
pub fn counter(self) -> u32 {
|
||||
self.button.counter
|
||||
}
|
||||
|
||||
/// polls the button and read the current state
|
||||
pub fn poll_and_read(&mut self, led_while_pressed: bool) -> ButtonState {
|
||||
self.button.poll();
|
||||
if led_while_pressed { let _ = self.led.on(); }
|
||||
match self.button.read() {
|
||||
ButtonState::Released => {
|
||||
if led_while_pressed { let _ = self.led.off(); }
|
||||
self.state = ButtonState::NotPressed;
|
||||
ButtonState::Released
|
||||
}
|
||||
ButtonState::LongReleased => {
|
||||
if led_while_pressed { let _ = self.led.off(); }
|
||||
self.state = ButtonState::NotPressed;
|
||||
ButtonState::LongReleased
|
||||
}
|
||||
ButtonState::Flank => {
|
||||
self.state = ButtonState::Pressed;
|
||||
ButtonState::Flank
|
||||
}
|
||||
ButtonState::LongFlank => {
|
||||
self.state = ButtonState::LongPress;
|
||||
ButtonState::LongFlank
|
||||
}
|
||||
n => {
|
||||
n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user