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
/* debouncer.rs
*
* Developed by Tim Walls <tim.walls@snowgoons.com>
* Copyright (c) All Rights Reserved, Tim Walls
*/
//! A wrapper around a standard Pin which inverts the sense of the pin.
//! Useful where you have, for example, active-low inputs.
//!
//! # Usage
//! Anywhere you would use a Pin, you can use a Inverter instead. Create
//! the debouncer using one of the methods provided by the [`avr_oxide::devices::UsesPin`] trait,
//! passing the pin you wish to wrap to the constructor.
//!
//! ```rust,no_run
//! # #![no_std]
//! # #![no_main]
//! #
//! # use avr_oxide::alloc::boxed::Box;
//! # use avr_oxide::devices::UsesPin;
//! # use avr_oxide::devices::debouncer::Debouncer;
//! # use avr_oxide::devices::inverter::Inverter;
//! # use avr_oxide::devices::{ OxideButton, button::ButtonState };
//! # use avr_oxide::boards::board;
//! # use avr_oxide::StaticWrap;
//! #
//! # #[avr_oxide::main(chip="atmega4809")]
//! # pub fn main() {
//! let supervisor = avr_oxide::oxide::instance();
//!
//! let mut green_button = StaticWrap::new(OxideButton::using(Inverter::using(Debouncer::with_pin(board::pin_a(2)))));
//! #
//! # // Now enter the event loop
//! # supervisor.run();
//! # }
//! ```
// Imports ===================================================================
use core::any::Any;
use core::cell::Cell;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::hal::generic::callback::IsrCallback;
use avr_oxide::hal::generic::port::{InterruptMode, Pin, PinIsrCallback, PinMode};
use avr_oxide::{isr_cb_invoke, panic_if_none};
use avr_oxide::devices::UsesPin;
use avr_oxide::util::OwnOrBorrow;
// Declarations ==============================================================
pub struct Inverter {
pin: OwnOrBorrow<'static,dyn Pin>,
handler: Cell<PinIsrCallback>
}
// Code ======================================================================
impl Into<OwnOrBorrow<'static, dyn Pin + 'static>> for Inverter {
fn into(self) -> OwnOrBorrow<'static, dyn Pin> {
OwnOrBorrow::Own(Box::new(self))
}
}
impl UsesPin for Inverter {
/**
* Create a Debouncer which will wrap the given underlying Pin instance to
* provide a debounced version of it.
*/
fn using<OP: Into<OwnOrBorrow<'static, dyn Pin>>>(pin: OP) -> Self {
let pin : OwnOrBorrow<dyn Pin> = pin.into();
Inverter {
pin,
handler: Cell::new(IsrCallback::Nop(()))
}
}
}
impl Pin for Inverter {
fn set_mode(&self, mode: PinMode) {
self.pin.set_mode(mode)
}
fn toggle(&self) {
self.pin.toggle()
}
fn set_high(&self) {
self.pin.set_low()
}
fn set_low(&self) {
self.pin.set_high()
}
fn set(&self, high: bool) {
self.pin.set(!high)
}
/**
* Gets the pin state. Reads multiple samples and only returns once the
* pin has reached a steady state.
*/
fn get(&self) -> bool {
!self.pin.get()
}
fn set_interrupt_mode(&self, mode: InterruptMode) {
self.pin.set_interrupt_mode(mode)
}
/**
* Listen for interrupts, calling the given callback once we receive one.
*/
fn listen(&'static self, handler: PinIsrCallback) {
self.handler.replace(handler);
self.pin.listen(IsrCallback::WithData(|isotoken,_source,id,state,udata|{
let myself = unsafe { &*(panic_if_none!(udata, avr_oxide::oserror::OsError::InternalError) as *const Self) };
isr_cb_invoke!(isotoken, myself.handler.get(), myself, id, !state);
}, self as &dyn Any));
}
}
// Tests =====================================================================