Skip to content

Commit 3f1b2c5

Browse files
author
Scott Powell
committed
Merge branch 'dev'
2 parents 5be09ff + af0c409 commit 3f1b2c5

File tree

92 files changed

+4084
-1986
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+4084
-1986
lines changed

.clang-format

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# .clang-format
2+
Language: Cpp
3+
AccessModifierOffset: -2
4+
AlignAfterOpenBracket: Align
5+
AlignConsecutiveAssignments: false
6+
AlignConsecutiveDeclarations: false
7+
AlignConsecutiveMacros:
8+
Enabled: true
9+
AcrossEmptyLines: true
10+
AcrossComments: true
11+
AlignOperands: true
12+
AlignTrailingComments: true
13+
AllowAllParametersOfDeclarationOnNextLine: false
14+
AllowShortBlocksOnASingleLine: false
15+
AllowShortCaseLabelsOnASingleLine: false
16+
AllowShortFunctionsOnASingleLine: Inline
17+
AllowShortIfStatementsOnASingleLine: true
18+
AllowShortLoopsOnASingleLine: false
19+
AlwaysBreakAfterDefinitionReturnType: None
20+
AlwaysBreakAfterReturnType: None
21+
AlwaysBreakBeforeMultilineStrings: false
22+
AlwaysBreakTemplateDeclarations: No
23+
BinPackArguments: true
24+
BinPackParameters: true
25+
BraceWrapping:
26+
AfterClass: false
27+
AfterControlStatement: false
28+
AfterEnum: false
29+
AfterFunction: false
30+
AfterNamespace: false
31+
AfterObjCDeclaration: false
32+
AfterStruct: false
33+
AfterUnion: false
34+
BeforeCatch: true
35+
BeforeElse: true
36+
IndentBraces: false
37+
BreakBeforeBinaryOperators: None
38+
BreakBeforeBraces: Attach
39+
BreakBeforeTernaryOperators: true
40+
BreakConstructorInitializersBeforeComma: false
41+
ColumnLimit: 110
42+
CommentPragmas: '^ IWYU pragma:'
43+
CompactNamespaces: false
44+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
45+
Cpp11BracedListStyle: false
46+
DerivePointerAlignment: false
47+
DisableFormat: false
48+
IncludeBlocks: Regroup
49+
IndentCaseLabels: false
50+
IndentPPDirectives: None
51+
IndentWidth: 2
52+
IndentWrappedFunctionNames: false
53+
KeepEmptyLinesAtTheStartOfBlocks: true
54+
MacroBlockBegin: ''
55+
MacroBlockEnd: ''
56+
MaxEmptyLinesToKeep: 1
57+
NamespaceIndentation: None
58+
ObjCBinPackProtocolList: Auto
59+
PenaltyBreakBeforeFirstCallParameter: 19
60+
PenaltyBreakComment: 300
61+
PenaltyBreakFirstLessLess: 120
62+
PenaltyBreakString: 1000
63+
PenaltyExcessCharacter: 100000
64+
PenaltyReturnTypeOnItsOwnLine: 60
65+
PointerAlignment: Right
66+
ReflowComments: true
67+
SortIncludes: true
68+
SpaceAfterCStyleCast: false
69+
SpaceAfterTemplateKeyword: true
70+
SpaceBeforeAssignmentOperators: true
71+
SpaceBeforeCtorInitializerColon: true
72+
SpaceBeforeInheritanceColon: true
73+
SpaceBeforeParens: ControlStatements
74+
SpaceInEmptyParentheses: false
75+
SpacesBeforeTrailingComments: 1
76+
SpacesInAngles: false
77+
SpacesInContainerLiterals: false
78+
SpacesInCStyleCastParentheses: false
79+
SpacesInParentheses: false
80+
SpacesInSquareBrackets: false
81+
Standard: Auto
82+
TabWidth: 2
83+
UseTab: Never
84+
AlignEscapedNewlines: LeftWithLastLine

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ out/
88
.direnv/
99
.DS_Store
1010
.vscode/settings.json
11+
.vscode/extensions.json
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "Button.h"
2+
3+
Button::Button(uint8_t pin, bool activeState)
4+
: _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) {
5+
_currentState = false; // Initialize as not pressed
6+
_lastState = _currentState;
7+
}
8+
9+
Button::Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold)
10+
: _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) {
11+
_currentState = false; // Initialize as not pressed
12+
_lastState = _currentState;
13+
}
14+
15+
void Button::begin() {
16+
_currentState = readButton();
17+
_lastState = _currentState;
18+
}
19+
20+
void Button::update() {
21+
uint32_t now = millis();
22+
23+
// Read button at specified interval
24+
if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) {
25+
return;
26+
}
27+
_lastReadTime = now;
28+
29+
bool newState = readButton();
30+
31+
// Check if state has changed
32+
if (newState != _lastState) {
33+
_stateChangeTime = now;
34+
}
35+
36+
// Debounce check
37+
if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) {
38+
if (newState != _currentState) {
39+
_currentState = newState;
40+
handleStateChange();
41+
}
42+
}
43+
44+
_lastState = newState;
45+
46+
// Handle multi-click timeout
47+
if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) {
48+
// Timeout reached, process the clicks
49+
if (_clickCount == 1) {
50+
triggerEvent(SHORT_PRESS);
51+
} else if (_clickCount == 2) {
52+
triggerEvent(DOUBLE_PRESS);
53+
} else if (_clickCount >= 3) {
54+
triggerEvent(TRIPLE_PRESS);
55+
}
56+
_clickCount = 0;
57+
_state = IDLE;
58+
}
59+
60+
// Handle long press while button is held
61+
if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) {
62+
triggerEvent(LONG_PRESS);
63+
_state = IDLE; // Prevent multiple press events
64+
_clickCount = 0;
65+
}
66+
}
67+
68+
bool Button::readButton() {
69+
if (_isAnalog) {
70+
return (analogRead(_pin) < _analogThreshold);
71+
} else {
72+
return (digitalRead(_pin) == _activeState);
73+
}
74+
}
75+
76+
void Button::handleStateChange() {
77+
uint32_t now = millis();
78+
79+
if (_currentState) {
80+
// Button pressed
81+
_pressTime = now;
82+
_state = PRESSED;
83+
triggerEvent(ANY_PRESS);
84+
} else {
85+
// Button released
86+
if (_state == PRESSED) {
87+
uint32_t pressDuration = now - _pressTime;
88+
89+
if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) {
90+
// Short press detected
91+
_clickCount++;
92+
_releaseTime = now;
93+
_state = WAITING_FOR_MULTI_CLICK;
94+
} else {
95+
// Long press already handled in update()
96+
_state = IDLE;
97+
_clickCount = 0;
98+
}
99+
}
100+
}
101+
}
102+
103+
void Button::triggerEvent(EventType event) {
104+
_lastEvent = event;
105+
106+
switch (event) {
107+
case ANY_PRESS:
108+
if (_onAnyPress) _onAnyPress();
109+
break;
110+
case SHORT_PRESS:
111+
if (_onShortPress) _onShortPress();
112+
break;
113+
case DOUBLE_PRESS:
114+
if (_onDoublePress) _onDoublePress();
115+
break;
116+
case TRIPLE_PRESS:
117+
if (_onTriplePress) _onTriplePress();
118+
break;
119+
case LONG_PRESS:
120+
if (_onLongPress) _onLongPress();
121+
break;
122+
default:
123+
break;
124+
}
125+
}

examples/companion_radio/Button.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#pragma once
2+
3+
#include <Arduino.h>
4+
#include <functional>
5+
6+
// Button timing configuration
7+
#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms
8+
#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click
9+
#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds)
10+
#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button
11+
12+
class Button {
13+
public:
14+
enum EventType {
15+
NONE,
16+
SHORT_PRESS,
17+
DOUBLE_PRESS,
18+
TRIPLE_PRESS,
19+
LONG_PRESS,
20+
ANY_PRESS
21+
};
22+
23+
using EventCallback = std::function<void()>;
24+
25+
Button(uint8_t pin, bool activeState = LOW);
26+
Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20);
27+
28+
void begin();
29+
void update();
30+
31+
// Set callbacks for different events
32+
void onShortPress(EventCallback callback) { _onShortPress = callback; }
33+
void onDoublePress(EventCallback callback) { _onDoublePress = callback; }
34+
void onTriplePress(EventCallback callback) { _onTriplePress = callback; }
35+
void onLongPress(EventCallback callback) { _onLongPress = callback; }
36+
void onAnyPress(EventCallback callback) { _onAnyPress = callback; }
37+
38+
// State getters
39+
bool isPressed() const { return _currentState; }
40+
EventType getLastEvent() const { return _lastEvent; }
41+
42+
private:
43+
enum State {
44+
IDLE,
45+
PRESSED,
46+
RELEASED,
47+
WAITING_FOR_MULTI_CLICK
48+
};
49+
50+
uint8_t _pin;
51+
bool _activeState;
52+
bool _isAnalog;
53+
uint16_t _analogThreshold;
54+
55+
State _state = IDLE;
56+
bool _currentState;
57+
bool _lastState;
58+
59+
uint32_t _stateChangeTime = 0;
60+
uint32_t _pressTime = 0;
61+
uint32_t _releaseTime = 0;
62+
uint32_t _lastReadTime = 0;
63+
64+
uint8_t _clickCount = 0;
65+
EventType _lastEvent = NONE;
66+
67+
// Callbacks
68+
EventCallback _onShortPress = nullptr;
69+
EventCallback _onDoublePress = nullptr;
70+
EventCallback _onTriplePress = nullptr;
71+
EventCallback _onLongPress = nullptr;
72+
EventCallback _onAnyPress = nullptr;
73+
74+
bool readButton();
75+
void handleStateChange();
76+
void triggerEvent(EventType event);
77+
};

0 commit comments

Comments
 (0)