PinDetect rework, removed the continuous sampling, using just irq, timers and pin state sequence.

Fork of PinDetect by Andy K

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