PinDetect rework, removed the continuous sampling, using just irq, timers and pin state sequence.
Fork of PinDetect by
Diff: PinDetectMod.h
- Revision:
- 4:3aca44118b7a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PinDetectMod.h Fri Jun 12 01:13:07 2015 +0000 @@ -0,0 +1,497 @@ + /* PinDetectMod + * Copyright (c) 2015 Giuliano Dianda + * Released under the MIT License: http://mbed.org/license/mit + * + * Rework of: PinDetect by Andy Kirkham + */ + +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef PIN_DETECT_MOD_H +#define PIN_DETECT_MOD_H + +#ifndef MBED_H +#include "mbed.h" +#endif + +#ifndef PINDETECT_PINSTATES +#define PINDETECT_PINSTATES + +// pin state bitmask +#define S_IDLE 0 +#define S_RINGING ((uint32_t)1<<0) +#define S_ASSERTED ((uint32_t)1<<1) +#define S_HELD ((uint32_t)1<<2) + +#endif + +/** PinDetectMod is a rework of PinDetect, . + * + * Unlike the original PinDetect which samples pin at specified rate, here is all about interrupts and timers, + * because for some application the continuous sampling of a mostly idle pin is an overhead. + * Pin state is evaluated in sequence deasserted->ringing->asserted->(->held_asserted)->ringing->deasserted + * callback function can be attached to these state changes: + * deasserted->asserted (e.g. as soon as button is pressed) + * asserted->deasserted (e.g quick button pulse) + * asserted->held_asserted (e.g. as soon as the button is evaluated to be held) + * held_asserted->deasserted (e.g. long button pulse) + * + * Only callbacks that have been attached will be called by the library. + * + * Example: + * @code + * #include "mbed.h" + * #include "PinDetectMod.h" + * + * DigitalOut led1( LED1 ); + * PinDetect pin(p30, PullUp, 0); + * + * void keyPressed( void ) { + * backligh_on(); + * } + * + * void keyQuickPulsed( void ) { + * increasevalue(); + * } + * + * void keyPressedHeld( void ) { + * beep(); + * } + * + * void keyLongPulsed( void ) { + * setup_menu(); + * } + * + * int main() { + * + * pin.attach_asserted( &keyPressed ); + * pin.attach_deasserted( &keyQuickPulsed ); + * pin.attach_asserted_held( &keyPressedHeld ); + * pin.attach_deasserted_held( &keyLongPulsed ); + * + * + * while( 1 ) { + * led1 = !led1; + * wait( 0.2 ); + * } + * } + * @endcode + * + */ +class PinDetect { + + + +public: + + /** PinDetect constructor + * + * @see http://mbed.org/handbook/DigitalIn + * @param p PinName is a valid pin that supports DigitalIn + * @param m PinMode (PullUp, PullDown, PullNone....) + * @param assertvalue pin state to be considered as asserted (0 or 1) + * @param debounce_us debounce time in microseconds, default 5000 + * @param held_us time in microseconds for the state to be considered held_asserted, default 2000000 + */ + PinDetect(PinName p, PinMode m, int assertvalue, unsigned int debounce_us=5000, unsigned int held_us=2000000): interr(p), _assertvalue(assertvalue) + { + debouncetime=debounce_us; + heldtime=held_us; + bouncein=0; + bounceout=0; + disable(); + if (_assertvalue) { // pulse up + interr.rise(this, &PinDetect::startpulse); // first rise then fall + interr.fall(this, &PinDetect::endpulse); + + } else { // pulse down + interr.fall(this, &PinDetect::startpulse); // first fall then rise + interr.rise(this, &PinDetect::endpulse); + } + interr.mode(m); + statereset(); // pinstate=S_IDLE; + trig=false; + enable(); + } + + /** PinDetect destructor + */ + ~PinDetect() { + interr.disable_irq(); + timeoutbounce.detach(); + timeoutheld.detach(); + } + /** Disable + */ + void disable() + { + interr.disable_irq(); + statereset(); + } + /** Enable + */ + void enable() + { + interr.enable_irq(); + statereset(); + } + + /** Set debounce time + * + * @param dbtime microseconds + */ + void setDebounceTime(unsigned int dbtime) { debouncetime = dbtime; } + + /** Set time until held assumed. + * + * @param htime microseconds + */ + void setHeldTime(unsigned int htime) { heldtime = htime; } + + + /** Attach a callback function + * + * @code + * + * DigitalOut led1( LED1 ); + * PinDetect pin(p30, PullUp, 0); + * + * void myCallback( void ) { + * led1 = 1; + * }; + * + * main() { + * pin.attach_asserted( &myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is asserted. + * @param function A C function pointer + */ + void attach_asserted(void (*function)(void)) { + callbackAsserted.attach( function ); + } + + /** Attach a callback object/method + * + * @code + * + * class Bar { + * public: + * void myCallback( void ) { led1 = 1; } + * }; + * + * DigitalOut led1( LED1 ); + * PinDetect pin(p30, PullUp, 0); + * Bar bar; + * + * main() { + * pin.attach_asserted( &bar, &Bar::myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is asserted. + * @param object An object that conatins the callback method. + * @param method The method within the object to call. + */ + template<typename T> + void attach_asserted(T *object, void (T::*member)(void)) { + callbackAsserted.attach( object, member ); + } + + /** Attach a callback function + * + * @code + * + * DigitalOut led1( LED1 ); + * PinDetect pin(p30, PullUp, 0); + * + * void myCallback( void ) { + * led1 = 0; + * }; + * + * main() { + * pin.attach_deasserted( &myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is deasserted (short pulse). + * @param function A C function pointer + */ + void attach_deasserted(void (*function)(void)) { + callbackDeasserted.attach( function ); + } + + /** Attach a callback object/method + * + * @code + * + * class Bar { + * public: + * void myCallback( void ) { led1 = 0; } + * }; + * + * DigitalOut led1( LED1 ); + * PinDetect pin(p30, PullUp, 0); + * Bar bar; + * + * main() { + * pin.attach_deasserted( &bar, &Bar::myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is deasserted (short pulse). + * @param object An object that conatins the callback method. + * @param method The method within the object to call. + */ + template<typename T> + void attach_deasserted(T *object, void (T::*member)(void)) { + callbackDeasserted.attach( object, member ); + } + + /** Attach a callback function + * + * @code + * + * DigitalOut led2( LED2 ); + * PinDetect pin(p30, PullUp, 0); + * + * void myCallback( void ) { + * led2 = 1; + * }; + * + * main() { + * pin.attach_asserted_held( &myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is asserted and held. + * @param function A C function pointer + */ + void attach_asserted_held(void (*function)(void)) { + callbackAssertedHeld.attach( function ); + } + + /** Attach a callback object/method + * + * @code + * + * class Bar { + * public: + * void myCallback( void ) { led2 = 0; } + * }; + * + * DigitalOut led2( LED2 ); + * PinDetect pin(p30, PullUp, 0); + * Bar bar; + * + * main() { + * pin.attach_asserted_held( &bar, &Bar::myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is asserted and held. + * @param object An object that conatins the callback method. + * @param method The method within the object to call. + */ + template<typename T> + void attach_asserted_held(T *object, void (T::*member)(void)) { + callbackAssertedHeld.attach( object, member ); + } + + /** Attach a callback function + * + * @code + * + * DigitalOut led3( LED3 ); + * PinDetect pin(p30, PullUp, 0); + * + * void myCallback( void ) { + * led3 = 1; + * }; + * + * main() { + * pin.attach_deasserted_held( &myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is deasserted after being held. + * @param function A C function pointer + */ + void attach_deasserted_held(void (*function)(void)) { + callbackDeassertedHeld.attach( function ); + } + + /** Attach a callback object/method + * + * @code + * + * class Bar { + * public: + * void myCallback( void ) { led3 = 0; } + * }; + * + * DigitalOut led3( LED3 ); + * PinDetect pin(p30, PullUp, 0); + * Bar bar; + * + * main() { + * pin.attach_deasserted_held( &bar, &Bar::myCallback ); + * } + * + * @endcode + * + * Call this function when a pin is deasserted after being held. + * @param object An object that conatins the callback method. + * @param method The method within the object to call. + */ + template<typename T> + void attach_deasserted_held(T *object, void (T::*member)(void)) { + callbackDeassertedHeld.attach( object, member ); + } + + /** operator int() + * + * Read the value of the pin being sampled. + */ + operator int() { return interr.read(); } + + /** Get the current pin state + * + * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE + */ + unsigned int state() + { + return pinstate; + } + + /** Reset pinstate to S_IDLE and reset debounce/held timers + */ + void statereset() + { + pinstate=S_IDLE; + timeoutheld.detach(); + timeoutbounce.detach(); + pinstate=S_IDLE; + } + /** Get the total bounces for deasserted->asserted + * + * @return bounces so far + */ + unsigned int getbouncein() + { + return bouncein; + } + /** Get the total bounces for asserted->deasserted + * + * @return bounces so far + */ + unsigned int getbounceout() + { + return bounceout; + } + +protected: + + void startpulse() + { + pinstate|=S_RINGING; + if((pinstate&S_ASSERTED)==0) timeoutbounce.attach_us(this, &PinDetect::onasserted, debouncetime); + // else if state is asserted and we are here, it means we are debouncing transition to deasserted, timeout is already attached to ondeasserted() + trig=true; // ISR completed + } + + void endpulse() + { + if(!trig) return; // first check if the previous startpulse ISR completed + pinstate|=S_RINGING; + + if((pinstate&S_ASSERTED)!=0) // if was asserted or held asserted, debounce transition to deasserted + { + timeoutheld.detach(); + timeoutbounce.attach_us(this, &PinDetect::ondeasserted, debouncetime); + } + trig=false; + } + + void onasserted() + { + if(interr.read()!=_assertvalue) + { + bouncein++; + return; // was a bounce + } + pinstate|=S_ASSERTED; // set asserted + pinstate&= ~(S_RINGING|S_HELD); // clear ringing and held + timeoutheld.attach_us(this, &PinDetect::onheld, heldtime); + callbackAsserted.call(); // call function for pin state change (deasserted -> asserted) + } + + void onheld() + { + if((pinstate&S_RINGING)!=0 || (pinstate&S_ASSERTED)==0 || (interr.read()!=_assertvalue)) return; // to be valid, needs ringing=false asserted=true pinread=assertvalue + pinstate|=S_HELD; // set held + callbackAssertedHeld.call(); // call function for pin state change (asserted -> held asserted) + } + + void ondeasserted() + { + if((pinstate&(S_ASSERTED))==0) return; // pinstate was reset externally + if(interr.read()==_assertvalue) + { + bounceout++; + return; // was a bounce + } + if((pinstate&S_HELD)==0) callbackDeasserted.call(); // call function for pin state change (asserted -> deasserted)(quick pulse) + else callbackDeassertedHeld.call(); // call function for pin state change (held asserted -> deasserted)(long pulse) + pinstate=S_IDLE; + } + +private: + InterruptIn interr; + Timeout timeoutbounce; + Timeout timeoutheld; + unsigned int debouncetime; + unsigned int heldtime; + int _assertvalue; + FunctionPointer callbackAsserted; + FunctionPointer callbackDeasserted; + FunctionPointer callbackAssertedHeld; + FunctionPointer callbackDeassertedHeld; + volatile unsigned int pinstate; + volatile unsigned int bouncein; + volatile unsigned int bounceout; + + bool trig; + +}; + + +#endif