-
Notifications
You must be signed in to change notification settings - Fork 0
/
MinimalButton.h
152 lines (126 loc) · 3.32 KB
/
MinimalButton.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once
#include "Arduino.h"
enum PressLength
{
NO_PRESS,
TINY_PRESS,
SHORT_PRESS,
LONG_PRESS,
SUPER_PRESS,
DOUBLE_PRESS
};
template <uint32_t pin>
class MinimalButton
{
static volatile bool currentState;
static volatile uint32_t changeTime;
typedef void (*CallbackAll)(PressLength);
typedef void (*CallbackSingle)(void);
public:
MinimalButton(bool useInterrupt = true) : _useInterrupt(useInterrupt)
{
}
void begin()
{
init();
}
bool begin(uint16_t newShortDelay, uint16_t newDoubleDelay, uint16_t newLongDelay, uint16_t newSuperDelay)
{
if (newLongDelay > newShortDelay && newSuperDelay > newLongDelay && newShortDelay + newDoubleDelay < newLongDelay)
{
_ShortDelay = newShortDelay;
_DoubleDelay = newDoubleDelay;
_LongDelay = newLongDelay;
_SuperDelay = newSuperDelay;
init();
return true;
}
else
{
return false;
}
}
PressLength process()
{
PressLength returnVal = NO_PRESS;
if (!_useInterrupt)
{
currentState = !digitalRead(pin);
changeTime = millis();
}
if (currentState && !_lastState)
{
_pressTime = changeTime;
_lastState = true;
}
else if (!currentState && _lastState)
{
_releaseTime = changeTime;
_lastState = false;
uint32_t deltaTime = _releaseTime - _pressTime;
if (deltaTime >= _ShortDelay && deltaTime < _LongDelay)
{
if (_pressPending && _releaseTime - _lastShortTime <= _DoubleDelay)
{
returnVal = DOUBLE_PRESS;
_pressPending = false;
}
else
{
_lastShortTime = _releaseTime;
_pressPending = true;
}
}
else if (deltaTime >= _LongDelay && deltaTime < _SuperDelay)
{
returnVal = LONG_PRESS;
}
else if (deltaTime >= _SuperDelay)
{
returnVal = SUPER_PRESS;
}
}
if (_pressPending && millis() - _lastShortTime > _DoubleDelay)
{
returnVal = SHORT_PRESS;
_pressPending = false;
}
return returnVal;
}
bool state()
{
return currentState;
}
private:
static void interruptHandler()
{
currentState = !digitalRead(pin);
changeTime = millis();
}
void init()
{
pinMode(pin, INPUT_PULLUP);
if (_useInterrupt)
{
attachInterrupt(digitalPinToInterrupt(pin), interruptHandler, CHANGE);
}
else
{
}
}
bool _useInterrupt = true;
// bool currentState = false;
bool _lastState = false;
bool _pressPending = false;
uint32_t _pressTime;
uint32_t _releaseTime;
uint32_t _lastShortTime;
uint16_t _ShortDelay = 30;
uint16_t _DoubleDelay = 250;
uint16_t _LongDelay = 500;
uint16_t _SuperDelay = 1500;
};
template <uint32_t pin>
volatile bool MinimalButton<pin>::currentState;
template <uint32_t pin>
volatile uint32_t MinimalButton<pin>::changeTime;