Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Revision:
0:b47c2a7920c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debounce.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,490 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_DEBOUNCE__
+#define __ETL_DEBOUNCE__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+
+namespace etl
+{
+  namespace __private_debounce__
+  {
+    class debounce_base
+    {
+    public:
+
+      void add(bool sample)
+      {
+        state &= ~CHANGED;
+
+        // Changed from last time?
+        if (sample != bool((state & LAST) != 0))
+        {
+          count = START_COUNT;
+        }
+      }
+
+      //*************************************************************************
+      /// Gets the current debouncer change state.
+      ///\return 'true' if the debouncer has changed state.
+      //*************************************************************************
+      bool has_changed() const
+      {
+        return (state & CHANGED) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the current debouncer state.
+      ///\return 'true' if the debouncer is in the true state.
+      //*************************************************************************
+      bool is_set() const
+      {
+        return (state & CURRENT) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the debouncer hold state.
+      ///\return 'true' if the debouncer is in the hold state.
+      //*************************************************************************
+      bool is_held() const
+      {
+        return (state & HELD) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the debouncer repeat state.
+      ///\return 'true' if the debouncer is repeating.
+      //*************************************************************************
+      bool is_repeating() const
+      {
+        return (state & REPEATING) != 0;
+      }
+
+    protected:
+
+      //*************************************************************************
+      /// Constructor.
+      ///\param initial_state The initial state. Default = false.
+      //*************************************************************************
+      debounce_base(bool initial_state = false)
+        : state(initial_state ? (CURRENT | LAST) : 0),
+          count(START_COUNT)
+      {
+      }
+
+      enum
+      {
+        START_COUNT = 0
+      };
+
+      enum
+      {
+        CURRENT   = 1,
+        LAST      = 2,
+        HELD      = 4,
+        CHANGED   = 8,
+        REPEATING = 16
+      };
+
+      uint_least8_t state;
+
+      /// The state count.
+      uint16_t count;
+    };
+  }
+
+  //***************************************************************************
+  /// A class to debounce signals.
+  /// The state is decided over N samples, defined by the VALID_COUNT value.
+  /// If the samples are consistent for VALID_COUNT times then the debouncer state is defined.
+  /// If the samples change then the debouncer will change state after VALID_COUNT samples.
+  /// If the samples are true for a count of HOLD_COUNT then the debouncer input is 'held'.
+  /// The debouncer may be constructed in either state.
+  //***************************************************************************
+  template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
+  class debounce : public __private_debounce__::debounce_base
+  {
+  private:
+
+      enum
+      {
+        VALID_THRESHOLD  = VALID_COUNT,
+        HOLD_THRESHOLD   = VALID_THRESHOLD + HOLD_COUNT,
+        REPEAT_THRESHOLD = HOLD_THRESHOLD + REPEAT_COUNT
+      };
+
+      using debounce_base::add;
+
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    /// 4. Key repeats.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < REPEAT_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+          else if (count == HOLD_THRESHOLD)
+          {
+            // Held.
+            state |= CHANGED;
+            state |= HELD;
+          }
+          else if (count == REPEAT_THRESHOLD)
+          {
+            // Repeat.
+            state |= CHANGED;
+            state |= REPEATING;
+            count = HOLD_THRESHOLD;
+          }
+
+          state |= LAST;        
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+  
+  template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
+  class debounce<VALID_COUNT, HOLD_COUNT, 0> : public __private_debounce__::debounce_base
+  {
+  private:
+
+    enum
+    {
+      VALID_THRESHOLD = VALID_COUNT,
+      HOLD_THRESHOLD  = VALID_THRESHOLD + HOLD_COUNT
+    };
+
+    using debounce_base::add;
+
+  public:   
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < HOLD_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+          else if (count == HOLD_THRESHOLD)
+          {
+            // Held.
+            state |= CHANGED;
+            state |= HELD;
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+
+  template <const uint16_t VALID_COUNT>
+  class debounce<VALID_COUNT, 0, 0> : public __private_debounce__::debounce_base
+  {
+  private:
+
+    enum
+    {
+      VALID_THRESHOLD = VALID_COUNT
+    };
+    
+    using debounce_base::add;
+
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < VALID_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+
+  template <>
+  class debounce<0, 0, 0> : public __private_debounce__::debounce_base
+  {
+  public:
+
+    using debounce_base::add;
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce()
+      : debounce_base(false),
+        valid_threshold(1),
+        hold_threshold(0),
+        repeat_threshold(0)
+    {
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state.
+    ///\param valid_count   The count for a valid state. Default = 1.
+    ///\param hold_count    The count after valid_count for a hold state. Default = 0.
+    ///\param repeat_count  The count after hold_count for a key repeat. Default = 0.
+    //*************************************************************************
+    debounce(bool initial_state, uint16_t valid_count = 1, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+      : debounce_base(initial_state)
+    {
+      set(valid_count, hold_count, repeat_count);
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+    {
+      valid_threshold  = valid_count;
+      hold_threshold   = valid_threshold + hold_count;
+      repeat_threshold = hold_threshold + repeat_count;
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    /// 4. Key repeats.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < repeat_threshold)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == valid_threshold)
+          {
+            if (sample)
+            {
+              // Set.
+              state |= CHANGED;
+              state |= CURRENT;
+            }
+          }
+
+          if (hold_threshold != valid_threshold)
+          {
+            if ((count == hold_threshold) && sample)
+            {
+              // Held.
+              state |= CHANGED;
+              state |= HELD;
+            }
+          }
+
+          if (repeat_threshold != hold_threshold)
+          {
+            if ((count == repeat_threshold) && sample)
+            {
+              // Repeat.
+              state |= CHANGED;
+              state |= REPEATING;
+              count = hold_threshold;
+            }
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == valid_threshold)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+
+  private:
+
+    uint16_t valid_threshold;
+    uint16_t hold_threshold;
+    uint16_t repeat_threshold;
+  };
+}
+
+#endif
+