Add state machines for recognizing different button presses
For now single, double and long presses are supported.
This commit is contained in:
		
							
								
								
									
										81
									
								
								code/button.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								code/button.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| #include "debounce.h" | ||||
|  | ||||
| template<uint16_t SLEEP_TIMEOUT, uint16_t LONGPRESS_TIMEOUT, uint16_t DOUBLEPRESS_TIMEOUT> | ||||
| class Button { | ||||
|  | ||||
|     using DResult = Debounce<0>::Result; | ||||
|  | ||||
|     public: | ||||
|         enum class State : uint8_t { | ||||
|             Sleep, | ||||
|             Idle, | ||||
|             Pressed, | ||||
|             LongPressed, | ||||
|             Released, | ||||
|             DoublePressed, | ||||
|         }; | ||||
|  | ||||
|         enum class Result : uint8_t { | ||||
|             NoEvent, | ||||
|             Press, | ||||
|             LongPress, | ||||
|             DoublePress, | ||||
|         }; | ||||
|  | ||||
|         Result event(DResult result) { | ||||
|             switch(state) { | ||||
|                 case State::Sleep : | ||||
|                     state = State::Idle; | ||||
|                     counter = millis(); | ||||
|                     break; | ||||
|                 case State::Idle : | ||||
|                     if(result == DResult::Pressed) { | ||||
|                         state = State::Pressed; | ||||
|                         counter = millis(); | ||||
|                     } else if(millis() - counter >= SLEEP_TIMEOUT) { | ||||
|                         state = State::Sleep; | ||||
|                         // Activate Hardware sleep | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::Pressed : | ||||
|                     if(result == DResult::Released) { | ||||
|                         state = State::Released; | ||||
|                         counter = millis(); | ||||
|                     } else if(millis() - counter >= LONGPRESS_TIMEOUT) { | ||||
|                         state = State::LongPressed; | ||||
|                         return Result::LongPress; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::Released : | ||||
|                     if(result == DResult::Pressed) { | ||||
|                         state = State::DoublePressed; | ||||
|                     } else if(millis() - counter >= DOUBLEPRESS_TIMEOUT) { | ||||
|                         state = State::Idle; | ||||
|                         counter = millis(); | ||||
|                         return Result::Press; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::LongPressed : | ||||
|                     if(result == DResult::Released) { | ||||
|                         state = State::Idle; | ||||
|                         counter = millis(); | ||||
|                     } else { | ||||
|                         return Result::LongPress; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::DoublePressed : | ||||
|                     if(result == DResult::Released) { | ||||
|                         state = State::Idle; | ||||
|                         counter = millis(); | ||||
|                         return Result::DoublePress; | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
|             return Result::NoEvent; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         State state = State::Idle; | ||||
|         uint16_t counter = 0; | ||||
| }; | ||||
| @@ -2,6 +2,7 @@ | ||||
| #undef min | ||||
| #undef max | ||||
|  | ||||
| #include "button.h" | ||||
| #include "debounce.h" | ||||
| #include "lcg_rng.h" | ||||
| #include "segment.h" | ||||
|   | ||||
| @@ -1,12 +1,57 @@ | ||||
| enum class State : uint8_t { | ||||
|     Unpressed, | ||||
|     UnpressedDebounced, | ||||
|     Pressed, | ||||
|     PressedDebounced, | ||||
| }; | ||||
| #ifndef _DEBOUNCE_H_ | ||||
| #define _DEBOUNCE_H_ | ||||
|  | ||||
| template<uint8_t DEBOUNCE_PRESSED, uint8_t DEBOUNCE_UNPRESSED = DEBOUNCE_PRESSED> | ||||
| class Debounce { | ||||
|  | ||||
|     public: | ||||
|         enum class State : uint8_t { | ||||
|             Unpressed, | ||||
|             UnpressedDebounced, | ||||
|             Pressed, | ||||
|             PressedDebounced, | ||||
|         }; | ||||
|  | ||||
|         enum class Result : uint8_t { | ||||
|             NoEvent, | ||||
|             Pressed, | ||||
|             Released, | ||||
|         }; | ||||
|  | ||||
|         Result event(bool pressed) { | ||||
|             switch(state) { | ||||
|                 case State::Unpressed : | ||||
|                     if(pressed) { | ||||
|                         state = State::PressedDebounced; | ||||
|                         counter = millis(); | ||||
|                         return Result::Pressed; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::PressedDebounced : | ||||
|                     if(millis() - counter > DEBOUNCE_PRESSED) { | ||||
|                         state = State::Pressed; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::Pressed : | ||||
|                     if(!pressed) { | ||||
|                         state = State::UnpressedDebounced; | ||||
|                         counter = millis(); | ||||
|                         return Result::Released; | ||||
|                     } | ||||
|                     break; | ||||
|                 case State::UnpressedDebounced : | ||||
|                     if(millis() - counter > DEBOUNCE_UNPRESSED) { | ||||
|                         state = State::Unpressed; | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
|             return Result::NoEvent; | ||||
|         } | ||||
|      | ||||
|     private: | ||||
|         State state = State::Unpressed; | ||||
|         uint8_t counter = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user