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

Fork of PinDetect by Andy K

Revision:
3:5ff38909c179
Parent:
2:cb3afc45028b
--- a/PinDetect.h	Thu Jan 13 11:09:22 2011 +0000
+++ b/PinDetect.h	Wed May 06 21:29:16 2015 +0000
@@ -39,12 +39,18 @@
 #define PINDETECT_ASSERT_COUNT  1
 #endif
 
-#ifndef PINDETECT_HOLD_COUNT
-#define PINDETECT_HOLD_COUNT    50
+#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
 
-namespace AjK {
-
 /** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks.
  *
  * This is done by sampling the specified pin at regular intervals and detecting any
@@ -129,47 +135,10 @@
  */
 class PinDetect {
 
-protected:
-    DigitalIn   *_in;
-    Ticker      *_ticker;
-    int         _prevState;
-    int         _currentStateCounter;
-    int         _sampleTime;
-    int         _assertValue;
-    int         _samplesTillAssertReload;
-    int         _samplesTillAssert;
-    int         _samplesTillHeldReload;
-    int         _samplesTillHeld;
-    FunctionPointer _callbackAsserted;
-    FunctionPointer _callbackDeasserted;
-    FunctionPointer _callbackAssertedHeld;
-    FunctionPointer _callbackDeassertedHeld;
-    
-    /** initialise class
-     *
-     * @param PinName p is a valid pin that supports DigitalIn
-     * @param PinMode m The mode the DigitalIn should use.
-     */
-    void init(PinName p, PinMode m) {
-        _sampleTime              = PINDETECT_SAMPLE_PERIOD;
-        _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
-        _samplesTillHeld         = 0;
-        _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
-        _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
-        _assertValue             = PINDETECT_PIN_ASSTERED;
-        
-        _in = new DigitalIn( p );
-        _in->mode( m );        
-        _prevState = _in->read();        
-        _ticker = new Ticker;
-    }
+
     
 public:
 
-    friend class Ticker;
-    
-    PinDetect() { error("You must supply a PinName"); }
-
     /** PinDetect constructor
      *
      * By default the PinMode is set to PullDown.
@@ -177,44 +146,45 @@
      * @see http://mbed.org/handbook/DigitalIn
      * @param p PinName is a valid pin that supports DigitalIn
      */    
-    PinDetect(PinName p) {
-        init( p, PullDown );
-    }
+    PinDetect(PinName p, PinMode m, int assertvalue, unsigned int debounce_us, unsigned int held_us): 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);
 
-    /** PinDetect constructor
-     *
-     * @see http://mbed.org/handbook/DigitalIn
-     * @param PinName p is a valid pin that supports DigitalIn
-     * @param PinMode m The mode the DigitalIn should use.
-     */    
-    PinDetect(PinName p, PinMode m) {
-        init( p, m );
+        } 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() {
-        if ( _ticker )  delete( _ticker );
-        if ( _in )      delete( _in );
+        interr.disable_irq();
+        timeoutbounce.detach();
+        timeoutheld.detach();
     }
     
-    /** Set the sampling time in microseconds.
-     *
-     * @param int The time between pin samples in microseconds.
-     */
-    void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD) { 
-        _sampleTime = i; 
-        _prevState  = _in->read();        
-        _ticker->attach_us( this, &PinDetect::isr, _sampleTime );
+    void disable()
+    {
+        interr.disable_irq();
+        statereset();
     }
-    
-    /** Set the value used as assert.
-     *
-     * Defaults to 1 (ie if pin == 1 then pin asserted).
-     *
-     * @param int New assert value (1 or 0)
-     */
-    void setAssertValue (int i = PINDETECT_PIN_ASSTERED) { _assertValue = i & 1; }
+    void enable()
+    {
+        interr.enable_irq();
+        statereset();
+    }
     
     /** Set the number of continuous samples until assert assumed.
      *
@@ -222,7 +192,7 @@
      *
      * @param int The number of continuous samples until assert assumed.
      */    
-    void setSamplesTillAssert(int i) { _samplesTillAssertReload = i; }
+    void setDebounceTime(int i) { debouncetime = i; }
     
     /** Set the number of continuous samples until held assumed.
      *
@@ -230,14 +200,8 @@
      *
      * @param int The number of continuous samples until held assumed.
      */    
-    void setSamplesTillHeld(int i) { _samplesTillHeldReload = i; }
-    
-    /** Set the pin mode.
-     *
-     * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode
-     * @param PinMode m The mode to pass on to the DigitalIn
-     */
-    void mode(PinMode m) { _in->mode( m ); }
+    void setHeldTime(int i) { heldtime = i; }
+
     
     /** Attach a callback function 
      *
@@ -260,7 +224,7 @@
      * @param function A C function pointer
      */
     void attach_asserted(void (*function)(void)) {
-        _callbackAsserted.attach( function );
+        callbackAsserted.attach( function );
     }
     
     /** Attach a callback object/method 
@@ -288,7 +252,7 @@
      */
     template<typename T>
     void attach_asserted(T *object, void (T::*member)(void)) {
-        _callbackAsserted.attach( object, member );        
+        callbackAsserted.attach( object, member );        
     }
     
     /** Attach a callback function 
@@ -312,7 +276,7 @@
      * @param function A C function pointer
      */
     void attach_deasserted(void (*function)(void)) {
-        _callbackDeasserted.attach( function );
+        callbackDeasserted.attach( function );
     }
     
     /** Attach a callback object/method
@@ -340,7 +304,7 @@
      */
     template<typename T>
     void attach_deasserted(T *object, void (T::*member)(void)) {
-        _callbackDeasserted.attach( object, member );        
+        callbackDeasserted.attach( object, member );        
     }
     
     /** Attach a callback function 
@@ -364,7 +328,7 @@
      * @param function A C function pointer
      */
     void attach_asserted_held(void (*function)(void)) {
-        _callbackAssertedHeld.attach( function );
+        callbackAssertedHeld.attach( function );
     }
     
     /** Attach a callback object/method
@@ -392,7 +356,7 @@
      */
     template<typename T>
     void attach_asserted_held(T *object, void (T::*member)(void)) {
-        _callbackAssertedHeld.attach( object, member );        
+        callbackAssertedHeld.attach( object, member );        
     }
     
     /** Attach a callback function 
@@ -416,7 +380,7 @@
      * @param function A C function pointer
      */
     void attach_deasserted_held(void (*function)(void)) {
-        _callbackDeassertedHeld.attach( function );
+        callbackDeassertedHeld.attach( function );
     }
     
     /** Attach a callback object/method
@@ -444,58 +408,118 @@
      */
     template<typename T>
     void attach_deasserted_held(T *object, void (T::*member)(void)) {
-        _callbackDeassertedHeld.attach( object, member );        
+        callbackDeassertedHeld.attach( object, member );        
     }
     
     /** operator int()
      *
      * Read the value of the pin being sampled.
      */
-    operator int() { return _in->read(); }
-
-protected:    
-    /** The Ticker periodic callback function
+    operator int() { return interr.read(); }
+    
+    /** Get the current pin state
+     *
+     * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE
      */
-    void isr(void) {
-        int currentState = _in->read();
+    unsigned int state()
+    {
+        return pinstate;
+    }
     
-        if ( currentState != _prevState ) {
-            if ( _samplesTillAssert == 0 ) {
-                _prevState = currentState;
-                _samplesTillHeld = _samplesTillHeldReload;
-                if ( currentState == _assertValue ) 
-                    _callbackAsserted.call();
-                else                              
-                    _callbackDeasserted.call();
-            }
-            else {
-                _samplesTillAssert--;
-            }
-        }
-        else {
-            _samplesTillAssert = _samplesTillAssertReload;
+    /** Reset pinstate to S_IDLE and reset debounce/held timers 
+     *
+     * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE
+     */
+    void statereset()
+    {
+        pinstate=S_IDLE;
+        timeoutheld.detach();
+        timeoutbounce.detach();
+        pinstate=S_IDLE;
+    }
+    unsigned int getbouncein()
+    {
+        return bouncein;
+    }
+    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);
         }
-        
-        if ( _samplesTillHeld ) {
-            if ( _prevState == currentState ) {
-                _samplesTillHeld--;
-                if ( _samplesTillHeld == 0 ) {
-                    if ( currentState == _assertValue ) 
-                        _callbackAssertedHeld.call();
-                    else                              
-                        _callbackDeassertedHeld.call();
-                }
-            }
-            else {
-                _samplesTillHeld = 0;
-            }
+        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;
+    
 };
 
-}; // namespace AjK ends.
-
-using namespace AjK;
 
 #endif