Ryo Od / ExioBufferdController
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ExioBufferedPinDetect.h Source File

ExioBufferedPinDetect.h

00001 /*
00002     Copyright (c) 2010 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021 */
00022 
00023  /*
00024  * 2016.11.5 Customized for MCP23S17 Buffered Input by ryood
00025  */
00026 
00027 #ifndef AJK_PIN_DETECT_H
00028 #define AJK_PIN_DETECT_H
00029  
00030 #ifndef MBED_H
00031 #include "mbed.h"
00032 #endif
00033 
00034 #include "ExioBufferedIn.h" 
00035  
00036 #ifndef PINDETECT_PIN_ASSTERED
00037 #define PINDETECT_PIN_ASSTERED   1
00038 #endif
00039  
00040 #ifndef PINDETECT_SAMPLE_PERIOD
00041 #define PINDETECT_SAMPLE_PERIOD 20000
00042 #endif
00043  
00044 #ifndef PINDETECT_ASSERT_COUNT  
00045 #define PINDETECT_ASSERT_COUNT  1
00046 #endif
00047  
00048 #ifndef PINDETECT_HOLD_COUNT
00049 #define PINDETECT_HOLD_COUNT    50
00050 #endif
00051  
00052 namespace AjK {
00053  
00054 /** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks.
00055  *
00056  * This is done by sampling the specified pin at regular intervals and detecting any
00057  * change of state ( 0 -> 1 or 1 -> 0 ). When a state change is detected the attached
00058  * callback handler is called. Additionally, if the pin stays in the same state after
00059  * a state change for a defined period of time, an extra callback is made allowing a
00060  * program to detect when a "key is pressed and held down" rather than a momentary
00061  * key/switch press.
00062  *
00063  * All parameters are customisable which include:-
00064  *  <ul>
00065  *  <li> The sampling frequency. </li>
00066  *  <li> The number of continuous samples until a state change is detected. </li> 
00067  *  <li> The number of continuous samples until a key is assumed held after a state change. </li>
00068  *  <li> The logic level which is assumed to be asserted (0volts or +volts). </li>
00069  *  </ul>
00070  *
00071  * Only callbacks that have been attached will be called by the library.
00072  *
00073  * Example:
00074  * @code
00075  * #include "mbed.h"
00076  * #include "PinDetect.h"
00077  *
00078  * PinDetect  pin( p30 );
00079  * DigitialOut led1( LED1 );
00080  * DigitialOut led2( LED2 );
00081  * DigitialOut led3( LED3 );
00082  * DigitialOut led4( LED4 );
00083  *
00084  * void keyPressed( void ) {
00085  *     led2 = 1;
00086  *     led3 = 0;
00087  *     led4 = 0;
00088  * }
00089  *
00090  * void keyReleased( void ) {
00091  *     led2 = 0;
00092  *     led3 = 0;
00093  *     led4 = 0;
00094  * }
00095  *
00096  * void keyPressedHeld( void ) {
00097  *     led3 = 1;
00098  * }
00099  *
00100  * void keyReleasedHeld( void ) {
00101  *     led4 = 1;
00102  * }
00103  *
00104  * int main() {
00105  *
00106  *     pin.mode( PullDown );
00107  *     pin.attach_asserted( &keyPressed );
00108  *     pin.attach_deasserted( &keyReleased );
00109  *     pin.attach_asserted_held( &keyPressedHeld );
00110  *     pin.attach_deasserted_held( &keyReleasedHeld );
00111  *
00112  *     // Sampling does not begin until you set a frequency.
00113  *     // The default is 20ms. If you want a different frequency
00114  *     // then pass the period in microseconds for example, for 10ms :-
00115  *     //     pin.setSampleFrequency( 10000 );
00116  *     //
00117  *     pin.setSampleFrequency(); // Defaults to 20ms.
00118  *
00119  *     while( 1 ) {
00120  *         led1 = !led1;
00121  *         wait( 0.2 );
00122  *     }
00123  * }
00124  * @endcode
00125  *
00126  * This example will flash led1 in a similar to a standard starting program.
00127  *
00128  * Applying a "1" (switch on) to pin 30 will switch on led2, removing the "1" to "0"
00129  * (switch off) led2 goes out. Holding the "switch" at one for one second will switch
00130  * on led3. An unasserted P30 (switched off) will, after one second illuminate led4
00131  * when the deasserted calledback is called.
00132  *
00133  * The above is a very basic introduction. For more details:-
00134  * @see example.h
00135  */
00136 class ExioBufferedPinDetect {
00137  
00138 protected:
00139     //DigitalIn   *_in;
00140     ExioBufferedIn   *_in;
00141     Ticker      *_ticker;
00142     int         _prevState;
00143     int         _currentStateCounter;
00144     int         _sampleTime;
00145     int         _assertValue;
00146     int         _samplesTillAssertReload;
00147     int         _samplesTillAssert;
00148     int         _samplesTillHeldReload;
00149     int         _samplesTillHeld;
00150     FunctionPointer _callbackAsserted;
00151     FunctionPointer _callbackDeasserted;
00152     FunctionPointer _callbackAssertedHeld;
00153     FunctionPointer _callbackDeassertedHeld;
00154     
00155     /** initialise class
00156      *
00157      * @param PinName p is a valid pin that supports DigitalIn
00158      * @param PinMode m The mode the DigitalIn should use.
00159      */
00160      /*
00161     void init(PinName p, PinMode m) {
00162         _sampleTime              = PINDETECT_SAMPLE_PERIOD;
00163         _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
00164         _samplesTillHeld         = 0;
00165         _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
00166         _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
00167         _assertValue             = PINDETECT_PIN_ASSTERED;
00168         
00169         _in = new DigitalIn( p );
00170         _in->mode( m );        
00171         _prevState = _in->read();        
00172         _ticker = new Ticker;
00173     }
00174     */
00175     void init(ExioInBuffer* buffer, int pin, PinMode m) {
00176         _sampleTime              = PINDETECT_SAMPLE_PERIOD;
00177         _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
00178         _samplesTillHeld         = 0;
00179         _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
00180         _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
00181         _assertValue             = PINDETECT_PIN_ASSTERED;
00182         
00183         _in = new ExioBufferedIn( buffer, pin );
00184         _in->mode( m );        
00185         _prevState = _in->read();        
00186         _ticker = new Ticker;
00187     }
00188     
00189 public:
00190  
00191     friend class Ticker;
00192     
00193     ExioBufferedPinDetect() { error("You must construct ExioBufferedDetect with params"); }
00194  
00195     /** PinDetect constructor
00196      *
00197      * By default the PinMode is set to PullDown.
00198      *
00199      * @see http://mbed.org/handbook/DigitalIn
00200      * @param p PinName is a valid pin that supports DigitalIn
00201      */
00202     /* 
00203     PinDetect(PinName p) {
00204         init( p, PullDown );
00205     }
00206     */
00207     ExioBufferedPinDetect(ExioInBuffer* buffer, int pin) {
00208         init( buffer, pin, PullUp );
00209     }
00210  
00211     /** PinDetect constructor
00212      *
00213      * @see http://mbed.org/handbook/DigitalIn
00214      * @param PinName p is a valid pin that supports DigitalIn
00215      * @param PinMode m The mode the DigitalIn should use.
00216      */
00217      /*
00218     PinDetect(PinName p, PinMode m) {
00219         init( p, m );
00220     }
00221     */
00222     ExioBufferedPinDetect(ExioInBuffer* buffer, int pin, PinMode m) {
00223         init( buffer, pin, m );
00224     }
00225     
00226     /** PinDetect destructor
00227      */    
00228     ~ExioBufferedPinDetect() {
00229         if ( _ticker )  delete( _ticker );
00230         if ( _in )      delete( _in );
00231     }
00232     
00233     /** Set the sampling time in microseconds.
00234      *
00235      * @param int The time between pin samples in microseconds.
00236      */
00237     void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD) { 
00238         _sampleTime = i; 
00239         _prevState  = _in->read();        
00240         _ticker->attach_us( this, &ExioBufferedPinDetect::isr, _sampleTime );
00241     }
00242     
00243     /** Set the value used as assert.
00244      *
00245      * Defaults to 1 (ie if pin == 1 then pin asserted).
00246      *
00247      * @param int New assert value (1 or 0)
00248      */
00249     void setAssertValue (int i = PINDETECT_PIN_ASSTERED) { _assertValue = i & 1; }
00250     
00251     /** Set the number of continuous samples until assert assumed.
00252      *
00253      * Defaults to 1 (1 * sample frequency).
00254      *
00255      * @param int The number of continuous samples until assert assumed.
00256      */    
00257     void setSamplesTillAssert(int i) { _samplesTillAssertReload = i; }
00258     
00259     /** Set the number of continuous samples until held assumed.
00260      *
00261      * Defaults to 50 * sample frequency.
00262      *
00263      * @param int The number of continuous samples until held assumed.
00264      */    
00265     void setSamplesTillHeld(int i) { _samplesTillHeldReload = i; }
00266     
00267     /** Set the pin mode.
00268      *
00269      * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode
00270      * @param PinMode m The mode to pass on to the DigitalIn
00271      */
00272     void mode(PinMode m) { _in->mode( m ); }
00273     
00274     /** Attach a callback function 
00275      *
00276      * @code
00277      *
00278      * DigitalOut led1( LED1 );
00279      * PinDetect pin( p30 );
00280      *
00281      * void myCallback( void ) {
00282      *   led1 = 1;
00283      * };
00284      * 
00285      * main() {
00286      *     pin.attach_asserted( &myCallback );
00287      * }
00288      *
00289      * @endcode
00290      *
00291      * Call this function when a pin is asserted.
00292      * @param function A C function pointer
00293      */
00294     void attach_asserted(void (*function)(void)) {
00295         _callbackAsserted.attach( function );
00296     }
00297     
00298     /** Attach a callback object/method 
00299      *
00300      * @code
00301      *
00302      * class Bar {
00303      *   public:
00304      *     void myCallback( void ) { led1 = 1; }
00305      * };
00306      *
00307      * DigitalOut led1( LED1 );
00308      * PinDetect pin( p30 );
00309      * Bar bar;
00310      *
00311      * main() {
00312      *     pin.attach_asserted( &bar, &Bar::myCallback );
00313      * }
00314      *
00315      * @endcode
00316      *
00317      * Call this function when a pin is asserted.
00318      * @param object An object that conatins the callback method.
00319      * @param method The method within the object to call.
00320      */
00321     template<typename T>
00322     void attach_asserted(T *object, void (T::*member)(void)) {
00323         _callbackAsserted.attach( object, member );        
00324     }
00325     
00326     /** Attach a callback function 
00327      *
00328      * @code
00329      *
00330      * DigitalOut led1( LED1 );
00331      * PinDetect pin( p30 );
00332      *
00333      * void myCallback( void ) {
00334      *   led1 = 0;
00335      * };
00336      *
00337      * main() {
00338      *     pin.attach_deasserted( &myCallback );
00339      * }
00340      *
00341      * @endcode
00342      *
00343      * Call this function when a pin is deasserted.
00344      * @param function A C function pointer
00345      */
00346     void attach_deasserted(void (*function)(void)) {
00347         _callbackDeasserted.attach( function );
00348     }
00349     
00350     /** Attach a callback object/method
00351      *
00352      * @code
00353      *
00354      * class Bar {
00355      *   public:
00356      *     void myCallback( void ) { led1 = 0; }
00357      * };
00358      *
00359      * DigitalOut led1( LED1 );
00360      * PinDetect pin( p30 );
00361      * Bar bar;
00362      * 
00363      * main() {
00364      *     pin.attach_deasserted( &bar, &Bar::myCallback );
00365      * }
00366      *
00367      * @endcode
00368      *
00369      * Call this function when a pin is deasserted.
00370      * @param object An object that conatins the callback method.
00371      * @param method The method within the object to call.
00372      */
00373     template<typename T>
00374     void attach_deasserted(T *object, void (T::*member)(void)) {
00375         _callbackDeasserted.attach( object, member );        
00376     }
00377     
00378     /** Attach a callback function 
00379      *
00380      * @code
00381      *
00382      * DigitalOut led2( LED2 );
00383      * PinDetect pin( p30 );
00384      *
00385      * void myCallback( void ) {
00386      *   led2 = 1;
00387      * };
00388      *
00389      * main() {
00390      *     pin.attach_asserted_held( &myCallback );
00391      * }
00392      *
00393      * @endcode
00394      *
00395      * Call this function when a pin is asserted and held.
00396      * @param function A C function pointer
00397      */
00398     void attach_asserted_held(void (*function)(void)) {
00399         _callbackAssertedHeld.attach( function );
00400     }
00401     
00402     /** Attach a callback object/method
00403      *
00404      * @code
00405      *
00406      * class Bar {
00407      *   public:
00408      *     void myCallback( void ) { led2 = 0; }
00409      * };
00410      *
00411      * DigitalOut led2( LED2 );
00412      * PinDetect pin( p30 );
00413      * Bar bar;
00414      * 
00415      * main() {
00416      *     pin.attach_asserted_held( &bar, &Bar::myCallback );
00417      * }
00418      *
00419      * @endcode
00420      *
00421      * Call this function when a pin is asserted and held.
00422      * @param object An object that conatins the callback method.
00423      * @param method The method within the object to call.
00424      */
00425     template<typename T>
00426     void attach_asserted_held(T *object, void (T::*member)(void)) {
00427         _callbackAssertedHeld.attach( object, member );        
00428     }
00429     
00430     /** Attach a callback function 
00431      *
00432      * @code
00433      *
00434      * DigitalOut led3( LED3 );
00435      * PinDetect pin( p30 );
00436      *
00437      * void myCallback( void ) {
00438      *   led3 = 1;
00439      * };
00440      *
00441      * main() {
00442      *     pin.attach_deasserted_held( &myCallback );
00443      * }
00444      *
00445      * @endcode
00446      *
00447      * Call this function when a pin is deasserted and held.
00448      * @param function A C function pointer
00449      */
00450     void attach_deasserted_held(void (*function)(void)) {
00451         _callbackDeassertedHeld.attach( function );
00452     }
00453     
00454     /** Attach a callback object/method
00455      *
00456      * @code
00457      *
00458      * class Bar {
00459      *   public:
00460      *     void myCallback( void ) { led3 = 0; }
00461      * };
00462      *
00463      * DigitalOut led3( LED3 );
00464      * PinDetect pin( p30 );
00465      * Bar bar;
00466      * 
00467      * main() {
00468      *     pin.attach_deasserted_held( &bar, &Bar::myCallback );
00469      * }
00470      *
00471      * @endcode
00472      *
00473      * Call this function when a pin is deasserted and held.
00474      * @param object An object that conatins the callback method.
00475      * @param method The method within the object to call.
00476      */
00477     template<typename T>
00478     void attach_deasserted_held(T *object, void (T::*member)(void)) {
00479         _callbackDeassertedHeld.attach( object, member );        
00480     }
00481     
00482     /** operator int()
00483      *
00484      * Read the value of the pin being sampled.
00485      */
00486     operator int() { return _in->read(); }
00487  
00488 protected:    
00489     /** The Ticker periodic callback function
00490      */
00491     void isr(void) {
00492         int currentState = _in->read();
00493     
00494         if ( currentState != _prevState ) {
00495             if ( _samplesTillAssert == 0 ) {
00496                 _prevState = currentState;
00497                 _samplesTillHeld = _samplesTillHeldReload;
00498                 if ( currentState == _assertValue ) 
00499                     _callbackAsserted.call();
00500                 else                              
00501                     _callbackDeasserted.call();
00502             }
00503             else {
00504                 _samplesTillAssert--;
00505             }
00506         }
00507         else {
00508             _samplesTillAssert = _samplesTillAssertReload;
00509         }
00510         
00511         if ( _samplesTillHeld ) {
00512             if ( _prevState == currentState ) {
00513                 _samplesTillHeld--;
00514                 if ( _samplesTillHeld == 0 ) {
00515                     if ( currentState == _assertValue ) 
00516                         _callbackAssertedHeld.call();
00517                     else                              
00518                         _callbackDeassertedHeld.call();
00519                 }
00520             }
00521             else {
00522                 _samplesTillHeld = 0;
00523             }
00524         }
00525     }
00526     
00527 };
00528  
00529 }; // namespace AjK ends.
00530  
00531 using namespace AjK;
00532  
00533 #endif
00534