libDaisy
Hardware Library for Daisy
Loading...
Searching...
No Matches
ButtonMonitor.h
Go to the documentation of this file.
1#pragma once
2#include <stdint.h>
3#include "UiEventQueue.h"
4#include "../sys/system.h"
5
6namespace daisy
7{
35template <typename BackendType, uint32_t numButtons>
37{
38 public:
40 : queue_(nullptr),
41 backend_(nullptr),
42 timeout_(0),
43 doubleClickTimeout_(0),
44 retriggerTimeoutMs_(0),
45 retriggerPeriodMs_(0)
46 {
47 }
48
65 {
66 queue_ = &queueToAddEventsTo;
67 backend_ = &backend;
68 timeout_ = debounceTimeoutMs;
69 doubleClickTimeout_ = doubleClickTimeoutMs;
70 retriggerTimeoutMs_ = retriggerTimeoutMs;
71 retriggerPeriodMs_ = retriggerPeriodMs;
72
73 for(uint32_t i = 0; i < numButtons; i++)
74 {
75 buttonStates_[i] = -timeout_; // starting in "released" state
76 lastClickTimes_[i] = 0;
77 lastRetriggerTimes_[i] = 0;
78 numSuccessiveClicks_[i] = 0;
79 }
80
81 lastCallSysTime_ = System::GetNow();
82 }
83
87 void Process()
88 {
89 const auto now = System::GetNow();
90 const auto timeDiff = now - lastCallSysTime_;
91 lastCallSysTime_ = now;
92
93 for(uint32_t i = 0; i < numButtons; i++)
94 ProcessButton(i, backend_->IsButtonPressed(i), timeDiff, now);
95 }
96
101 {
102 if(buttonId >= numButtons)
103 return false;
104 else
105 return buttonStates_[buttonId] >= timeout_;
106 }
107
109 BackendType& GetBackend() { return backend_; }
110
113
114 private:
115 void ProcessButton(uint16_t id,
116 bool isPressed,
119 {
120 // released or transitioning there...
121 if(buttonStates_[id] < 0)
122 {
123 if(!isPressed)
124 {
125 // transitioning?
126 if(buttonStates_[id] + 1 > -timeout_)
127 {
128 buttonStates_[id] -= timeInMsSinceLastCall;
129 if(buttonStates_[id] + 1 <= -timeout_)
130 queue_->AddButtonReleased(id);
131 }
132 }
133 // start transitioning towards "pressed"
134 else
135 {
136 buttonStates_[id] = 1;
137 // timeout could be set to "0" - no debouncing, send immediately.
138 if(buttonStates_[id] - 1 >= timeout_)
139 PostPhysicalButtonDownEvent(id, currentSystemTime);
140 }
141 }
142 else
143 {
144 if(isPressed)
145 {
146 // transitioning?
147 if(buttonStates_[id] - 1 < timeout_)
148 {
149 buttonStates_[id] += timeInMsSinceLastCall;
150 if(buttonStates_[id] - 1 >= timeout_)
151 PostPhysicalButtonDownEvent(id, currentSystemTime);
152 }
153 // already pressed - check retriggering if enabled
154 else if(retriggerTimeoutMs_ > 0)
155 {
156 const auto timeSincePress
157 = currentSystemTime - lastClickTimes_[id];
158 if(timeSincePress >= retriggerTimeoutMs_)
159 {
160 const auto timeSinceLastRetrigger
161 = currentSystemTime - lastRetriggerTimes_[id];
162 if(timeSinceLastRetrigger > retriggerPeriodMs_)
163 {
164 lastRetriggerTimes_[id] = currentSystemTime;
165 queue_->AddButtonPressed(
166 id, numSuccessiveClicks_[id], true);
167 }
168 }
169 }
170 }
171 // start transitioning towards "released"
172 else
173 {
174 buttonStates_[id] = -1;
175 // timeout could be set to "0" - no debouncing, send immediately.
176 if(buttonStates_[id] + 1 <= -timeout_)
177 queue_->AddButtonReleased(id);
178 }
179 }
180 }
181
182 void PostPhysicalButtonDownEvent(uint16_t id, uint32_t currentSystemTime)
183 {
184 const auto timeDiff = currentSystemTime - lastClickTimes_[id];
185 if(timeDiff <= doubleClickTimeout_)
186 numSuccessiveClicks_[id]++;
187 else
188 numSuccessiveClicks_[id] = 1;
189
190 lastClickTimes_[id] = currentSystemTime;
191 queue_->AddButtonPressed(id, numSuccessiveClicks_[id], false);
192 }
193
194 ButtonMonitor(const ButtonMonitor&) = delete;
195 ButtonMonitor& operator=(const ButtonMonitor&) = delete;
196
197 UiEventQueue* queue_;
198 BackendType* backend_;
199 uint16_t timeout_;
200 uint32_t doubleClickTimeout_;
201 uint32_t retriggerTimeoutMs_;
202 uint32_t retriggerPeriodMs_;
203 int16_t buttonStates_[numButtons]; // <= -timeout --> not pressed,
204 // >= timeout_ --> pressed
205 uint32_t lastClickTimes_[numButtons];
206 uint32_t lastRetriggerTimes_[numButtons];
207 uint8_t numSuccessiveClicks_[numButtons];
208 uint32_t lastCallSysTime_;
209};
210
211} // namespace daisy
A button monitor that generates events in a UiEventQueue.
Definition ButtonMonitor.h:37
bool IsButtonPressed(uint16_t buttonId) const
Definition ButtonMonitor.h:100
BackendType & GetBackend()
Definition ButtonMonitor.h:109
void Init(UiEventQueue &queueToAddEventsTo, BackendType &backend, uint16_t debounceTimeoutMs=50, uint32_t doubleClickTimeoutMs=500, uint32_t retriggerTimeoutMs=2000, uint32_t retriggerPeriodMs=50)
Definition ButtonMonitor.h:59
void Process()
Definition ButtonMonitor.h:87
uint16_t GetNumButtonsMonitored() const
Definition ButtonMonitor.h:112
ButtonMonitor()
Definition ButtonMonitor.h:39
Definition leddriver.h:33
static uint32_t GetNow()
A queue that holds user input events in the UI system.
Definition UiEventQueue.h:18
void AddButtonReleased(uint16_t buttonID)
Definition UiEventQueue.h:131
void AddButtonPressed(uint16_t buttonID, uint16_t numSuccessivePresses, bool isRetriggering=false)
Definition UiEventQueue.h:117
Hardware defines and helpers for daisy field platform.
Definition index.h:2