Stefan Scholz / ETL
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers debounce.h Source File

debounce.h

Go to the documentation of this file.
00001 ///\file
00002 
00003 /******************************************************************************
00004 The MIT License(MIT)
00005 
00006 Embedded Template Library.
00007 https://github.com/ETLCPP/etl
00008 http://www.etlcpp.com
00009 
00010 Copyright(c) 2016 jwellbelove
00011 
00012 Permission is hereby granted, free of charge, to any person obtaining a copy
00013 of this software and associated documentation files(the "Software"), to deal
00014 in the Software without restriction, including without limitation the rights
00015 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
00016 copies of the Software, and to permit persons to whom the Software is
00017 furnished to do so, subject to the following conditions :
00018 
00019 The above copyright notice and this permission notice shall be included in all
00020 copies or substantial portions of the Software.
00021 
00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
00025 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00028 SOFTWARE.
00029 ******************************************************************************/
00030 
00031 #ifndef __ETL_DEBOUNCE__
00032 #define __ETL_DEBOUNCE__
00033 
00034 #include <stdint.h>
00035 
00036 #include "platform.h "
00037 #include "static_assert.h"
00038 
00039 namespace etl
00040 {
00041   namespace __private_debounce__
00042   {
00043     class debounce_base
00044     {
00045     public:
00046 
00047       void add(bool sample)
00048       {
00049         state &= ~CHANGED;
00050 
00051         // Changed from last time?
00052         if (sample != bool((state & LAST) != 0))
00053         {
00054           count = START_COUNT;
00055         }
00056       }
00057 
00058       //*************************************************************************
00059       /// Gets the current debouncer change state.
00060       ///\return 'true' if the debouncer has changed state.
00061       //*************************************************************************
00062       bool has_changed() const
00063       {
00064         return (state & CHANGED) != 0;
00065       }
00066 
00067       //*************************************************************************
00068       /// Gets the current debouncer state.
00069       ///\return 'true' if the debouncer is in the true state.
00070       //*************************************************************************
00071       bool is_set() const
00072       {
00073         return (state & CURRENT) != 0;
00074       }
00075 
00076       //*************************************************************************
00077       /// Gets the debouncer hold state.
00078       ///\return 'true' if the debouncer is in the hold state.
00079       //*************************************************************************
00080       bool is_held() const
00081       {
00082         return (state & HELD) != 0;
00083       }
00084 
00085       //*************************************************************************
00086       /// Gets the debouncer repeat state.
00087       ///\return 'true' if the debouncer is repeating.
00088       //*************************************************************************
00089       bool is_repeating() const
00090       {
00091         return (state & REPEATING) != 0;
00092       }
00093 
00094     protected:
00095 
00096       //*************************************************************************
00097       /// Constructor.
00098       ///\param initial_state The initial state. Default = false.
00099       //*************************************************************************
00100       debounce_base(bool initial_state = false)
00101         : state(initial_state ? (CURRENT | LAST) : 0),
00102           count(START_COUNT)
00103       {
00104       }
00105 
00106       enum
00107       {
00108         START_COUNT = 0
00109       };
00110 
00111       enum
00112       {
00113         CURRENT   = 1,
00114         LAST      = 2,
00115         HELD      = 4,
00116         CHANGED   = 8,
00117         REPEATING = 16
00118       };
00119 
00120       uint_least8_t state;
00121 
00122       /// The state count.
00123       uint16_t count;
00124     };
00125   }
00126 
00127   //***************************************************************************
00128   /// A class to debounce signals.
00129   /// The state is decided over N samples, defined by the VALID_COUNT value.
00130   /// If the samples are consistent for VALID_COUNT times then the debouncer state is defined.
00131   /// If the samples change then the debouncer will change state after VALID_COUNT samples.
00132   /// If the samples are true for a count of HOLD_COUNT then the debouncer input is 'held'.
00133   /// The debouncer may be constructed in either state.
00134   //***************************************************************************
00135   template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
00136   class debounce : public __private_debounce__::debounce_base
00137   {
00138   private:
00139 
00140       enum
00141       {
00142         VALID_THRESHOLD  = VALID_COUNT,
00143         HOLD_THRESHOLD   = VALID_THRESHOLD + HOLD_COUNT,
00144         REPEAT_THRESHOLD = HOLD_THRESHOLD + REPEAT_COUNT
00145       };
00146 
00147       using debounce_base::add;
00148 
00149   public:
00150 
00151     //*************************************************************************
00152     /// Constructor.
00153     ///\param initial_state The initial state. Default = false.
00154     //*************************************************************************
00155     debounce(bool initial_state = false)
00156       : debounce_base(initial_state)
00157     {
00158     }
00159 
00160     //*************************************************************************
00161     /// Adds a new sample.
00162     /// Returns 'true' if the debouncer changes state from...
00163     /// 1. Clear to Set.
00164     /// 2. Set to Clear.
00165     /// 3. Not Held to Held.
00166     /// 4. Key repeats.
00167     ///\param sample The new sample.
00168     ///\return 'true' if the debouncer changed state.
00169     //*************************************************************************
00170     bool add(bool sample)
00171     {
00172       debounce_base::add(sample);
00173 
00174       if (count < REPEAT_THRESHOLD)
00175       {
00176         ++count;
00177 
00178         if (sample)
00179         {
00180           if (count == VALID_THRESHOLD)
00181           {
00182             // Set.
00183             state |= CHANGED;
00184             state |= CURRENT;
00185           }
00186           else if (count == HOLD_THRESHOLD)
00187           {
00188             // Held.
00189             state |= CHANGED;
00190             state |= HELD;
00191           }
00192           else if (count == REPEAT_THRESHOLD)
00193           {
00194             // Repeat.
00195             state |= CHANGED;
00196             state |= REPEATING;
00197             count = HOLD_THRESHOLD;
00198           }
00199 
00200           state |= LAST;        
00201         }
00202         else
00203         {
00204           if (count == VALID_THRESHOLD)
00205           {
00206             // Clear.
00207             state |= CHANGED;
00208             state &= ~CURRENT;
00209             state &= ~HELD;
00210             state &= ~REPEATING;
00211           }
00212 
00213           state &= ~LAST;
00214         }
00215       }
00216 
00217       return (state & CHANGED) != 0;
00218     }
00219   };
00220   
00221   template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
00222   class debounce<VALID_COUNT, HOLD_COUNT, 0> : public __private_debounce__::debounce_base
00223   {
00224   private:
00225 
00226     enum
00227     {
00228       VALID_THRESHOLD = VALID_COUNT,
00229       HOLD_THRESHOLD  = VALID_THRESHOLD + HOLD_COUNT
00230     };
00231 
00232     using debounce_base::add;
00233 
00234   public:   
00235 
00236     //*************************************************************************
00237     /// Constructor.
00238     ///\param initial_state The initial state. Default = false.
00239     //*************************************************************************
00240     debounce(bool initial_state = false)
00241       : debounce_base(initial_state)
00242     {
00243     }
00244 
00245     //*************************************************************************
00246     /// Adds a new sample.
00247     /// Returns 'true' if the debouncer changes state from...
00248     /// 1. Clear to Set.
00249     /// 2. Set to Clear.
00250     /// 3. Not Held to Held.
00251     ///\param sample The new sample.
00252     ///\return 'true' if the debouncer changed state.
00253     //*************************************************************************
00254     bool add(bool sample)
00255     {
00256       debounce_base::add(sample);
00257 
00258       if (count < HOLD_THRESHOLD)
00259       {
00260         ++count;
00261 
00262         if (sample)
00263         {
00264           if (count == VALID_THRESHOLD)
00265           {
00266             // Set.
00267             state |= CHANGED;
00268             state |= CURRENT;
00269           }
00270           else if (count == HOLD_THRESHOLD)
00271           {
00272             // Held.
00273             state |= CHANGED;
00274             state |= HELD;
00275           }
00276 
00277           state |= LAST;
00278         }
00279         else
00280         {
00281           if (count == VALID_THRESHOLD)
00282           {
00283             // Clear.
00284             state |= CHANGED;
00285             state &= ~CURRENT;
00286             state &= ~HELD;
00287             state &= ~REPEATING;
00288           }
00289 
00290           state &= ~LAST;
00291         }
00292       }
00293 
00294       return (state & CHANGED) != 0;
00295     }
00296   };
00297 
00298   template <const uint16_t VALID_COUNT>
00299   class debounce<VALID_COUNT, 0, 0> : public __private_debounce__::debounce_base
00300   {
00301   private:
00302 
00303     enum
00304     {
00305       VALID_THRESHOLD = VALID_COUNT
00306     };
00307     
00308     using debounce_base::add;
00309 
00310   public:
00311 
00312     //*************************************************************************
00313     /// Constructor.
00314     ///\param initial_state The initial state. Default = false.
00315     //*************************************************************************
00316     debounce(bool initial_state = false)
00317       : debounce_base(initial_state)
00318     {
00319     }
00320 
00321     //*************************************************************************
00322     /// Adds a new sample.
00323     /// Returns 'true' if the debouncer changes state from...
00324     /// 1. Clear to Set.
00325     /// 2. Set to Clear.
00326     ///\param sample The new sample.
00327     ///\return 'true' if the debouncer changed state.
00328     //*************************************************************************
00329     bool add(bool sample)
00330     {
00331       debounce_base::add(sample);
00332 
00333       if (count < VALID_THRESHOLD)
00334       {
00335         ++count;
00336 
00337         if (sample)
00338         {
00339           if (count == VALID_THRESHOLD)
00340           {
00341             // Set.
00342             state |= CHANGED;
00343             state |= CURRENT;
00344           }
00345 
00346           state |= LAST;
00347         }
00348         else
00349         {
00350           if (count == VALID_THRESHOLD)
00351           {
00352             // Clear.
00353             state |= CHANGED;
00354             state &= ~CURRENT;
00355             state &= ~HELD;
00356             state &= ~REPEATING;
00357           }
00358 
00359           state &= ~LAST;
00360         }
00361       }
00362 
00363       return (state & CHANGED) != 0;
00364     }
00365   };
00366 
00367   template <>
00368   class debounce<0, 0, 0> : public __private_debounce__::debounce_base
00369   {
00370   public:
00371 
00372     using debounce_base::add;
00373 
00374     //*************************************************************************
00375     /// Constructor.
00376     ///\param initial_state The initial state. Default = false.
00377     //*************************************************************************
00378     debounce()
00379       : debounce_base(false),
00380         valid_threshold(1),
00381         hold_threshold(0),
00382         repeat_threshold(0)
00383     {
00384     }
00385 
00386     //*************************************************************************
00387     /// Constructor.
00388     ///\param initial_state The initial state.
00389     ///\param valid_count   The count for a valid state. Default = 1.
00390     ///\param hold_count    The count after valid_count for a hold state. Default = 0.
00391     ///\param repeat_count  The count after hold_count for a key repeat. Default = 0.
00392     //*************************************************************************
00393     debounce(bool initial_state, uint16_t valid_count = 1, uint16_t hold_count = 0, uint16_t repeat_count = 0)
00394       : debounce_base(initial_state)
00395     {
00396       set(valid_count, hold_count, repeat_count);
00397     }
00398 
00399     //*************************************************************************
00400     /// Constructor.
00401     ///\param initial_state The initial state. Default = false.
00402     //*************************************************************************
00403     void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0)
00404     {
00405       valid_threshold  = valid_count;
00406       hold_threshold   = valid_threshold + hold_count;
00407       repeat_threshold = hold_threshold + repeat_count;
00408     }
00409 
00410     //*************************************************************************
00411     /// Adds a new sample.
00412     /// Returns 'true' if the debouncer changes state from...
00413     /// 1. Clear to Set.
00414     /// 2. Set to Clear.
00415     /// 3. Not Held to Held.
00416     /// 4. Key repeats.
00417     ///\param sample The new sample.
00418     ///\return 'true' if the debouncer changed state.
00419     //*************************************************************************
00420     bool add(bool sample)
00421     {
00422       debounce_base::add(sample);
00423 
00424       if (count < repeat_threshold)
00425       {
00426         ++count;
00427 
00428         if (sample)
00429         {
00430           if (count == valid_threshold)
00431           {
00432             if (sample)
00433             {
00434               // Set.
00435               state |= CHANGED;
00436               state |= CURRENT;
00437             }
00438           }
00439 
00440           if (hold_threshold != valid_threshold)
00441           {
00442             if ((count == hold_threshold) && sample)
00443             {
00444               // Held.
00445               state |= CHANGED;
00446               state |= HELD;
00447             }
00448           }
00449 
00450           if (repeat_threshold != hold_threshold)
00451           {
00452             if ((count == repeat_threshold) && sample)
00453             {
00454               // Repeat.
00455               state |= CHANGED;
00456               state |= REPEATING;
00457               count = hold_threshold;
00458             }
00459           }
00460 
00461           state |= LAST;
00462         }
00463         else
00464         {
00465           if (count == valid_threshold)
00466           {
00467             // Clear.
00468             state |= CHANGED;
00469             state &= ~CURRENT;
00470             state &= ~HELD;
00471             state &= ~REPEATING;
00472           }
00473 
00474           state &= ~LAST;
00475         }
00476       }
00477 
00478       return (state & CHANGED) != 0;
00479     }
00480 
00481   private:
00482 
00483     uint16_t valid_threshold;
00484     uint16_t hold_threshold;
00485     uint16_t repeat_threshold;
00486   };
00487 }
00488 
00489 #endif
00490