99#include " KeyboardManager.h"
1010#include " IoLogging.h"
1111
12+ MatrixKeyboardManager* MatrixKeyboardManager::INSTANCE = nullptr ;
13+
14+ ISR_ATTR void rawKeyboardInterrupt () {
15+ auto kbMgr = MatrixKeyboardManager::INSTANCE;
16+ if (kbMgr->keyMode == KEYMODE_NOT_PRESSED) {
17+ // we only need to be notified when not pressed. As in other states we are polling
18+ kbMgr->markTriggeredAndNotify ();
19+ }
20+ }
21+
1222MatrixKeyboardManager::MatrixKeyboardManager () {
13- this ->ioRef = NULL ;
14- this ->layout = NULL ;
15- this ->listener = NULL ;
23+ this ->ioRef = nullptr ;
24+ this ->layout = nullptr ;
25+ this ->listener = nullptr ;
26+ currentKey = 0 ;
27+ keyMode = KEYMODE_NOT_PRESSED;
28+ interruptMode = false ;
29+ counter = 0 ;
30+ INSTANCE = this ;
1631}
1732
18- void MatrixKeyboardManager::initialise (IoAbstractionRef ref, KeyboardLayout* layout , KeyboardListener* listener ) {
33+ void MatrixKeyboardManager::initialise (IoAbstractionRef ref, KeyboardLayout* layout_ , KeyboardListener* listener_, bool interruptMode_ ) {
1934 this ->ioRef = ref;
20- this ->layout = layout;
21- this ->listener = listener;
35+ this ->layout = layout_;
36+ this ->listener = listener_;
37+ this ->interruptMode = interruptMode_;
2238
2339 for (int i=0 ; i<layout->numColumns (); i++) {
2440 ioDevicePinMode (ioRef, layout->getColPin (i), OUTPUT);
25- ioDeviceDigitalWrite (ioRef, layout->getColPin (i), HIGH);
41+ ioDeviceDigitalWrite (ioRef, layout->getColPin (i), LOW);
42+ }
43+ for (int i=0 ; i<layout->numRows (); i++) {
44+ ioDevicePinMode (ioRef, layout->getRowPin (i), INPUT_PULLUP);
45+ if (interruptMode && INSTANCE) {
46+ ioRef->attachInterrupt (layout->getRowPin (i), rawKeyboardInterrupt, CHANGE);
47+ }
2648 }
27- for (int i=0 ; i<layout->numRows (); i++) ioDevicePinMode (ioRef, layout->getRowPin (i), INPUT_PULLUP);
2849
2950 ioDeviceSync (ioRef);
3051
3152 currentKey = 0 ;
32- taskManager.scheduleFixedRate (KEYBOARD_TASK_MILLIS, this );
53+ taskManager.registerEvent ( this );
3354}
3455
35- void MatrixKeyboardManager::setToOuput (int col) {
56+ void MatrixKeyboardManager::setToOutput (int col) {
3657 for (int i=0 ; i<layout->numColumns (); i++) {
3758 ioDeviceDigitalWrite (ioRef, layout->getColPin (i), col != i);
3859 }
@@ -43,18 +64,26 @@ void MatrixKeyboardManager::setRepeatKeyMillis(int startAfterMillis, int repeatM
4364 repeatTicks = repeatMillis / KEYBOARD_TASK_MILLIS;
4465}
4566
67+ inline bool isDebouncing (KeyMode keyMode) {
68+ return keyMode == KEYMODE_DEBOUNCE || keyMode == KEYMODE_DEBOUNCE1 || keyMode == KEYMODE_DEBOUNCE2;
69+ }
70+
4671void MatrixKeyboardManager::exec () {
47- if (ioRef == NULL ) return ;
72+ if (ioRef == nullptr ) {
73+ serdebugF (" ioRef null" );
74+ return ;
75+ }
4876
4977 char pressThisTime = 0 ;
5078
79+
5180 // then we read back the right state
5281 for (int c=0 ;c<layout->numColumns ();c++) {
53- setToOuput (c);
82+ setToOutput (c);
5483 ioDeviceSync (ioRef); // first we set the right column low.
5584 taskManager.yieldForMicros (500 ); // let things settle while other tasks run.
5685 ioDeviceSync (ioRef); // then we read the latest row states back
57-
86+
5887 for (int r=0 ; r<layout->numRows (); r++) {
5988 if (!ioDeviceDigitalRead (ioRef, layout->getRowPin (r))) {
6089 pressThisTime = layout->keyFor (r, c);
@@ -63,11 +92,10 @@ void MatrixKeyboardManager::exec() {
6392 }
6493 }
6594
66-
6795 // if the key is the same as last time and not zero
6896 if (pressThisTime == currentKey && pressThisTime) {
6997 // then we either have finished debouncing or are repeating
70- if (keyMode == KEYMODE_DEBOUNCE ) {
98+ if (isDebouncing ( keyMode) ) {
7199 keyMode = KEYMODE_PRESSED;
72100 counter = repeatStartTicks;
73101 listener->keyPressed (currentKey, false );
@@ -79,16 +107,57 @@ void MatrixKeyboardManager::exec() {
79107 }
80108 }
81109 else keyMode = KEYMODE_DEBOUNCE;
82- }
83- else {
84- // otherwise the keys are not the same, we are either in released
85- // state or debouncing.
110+ } else {
111+ // first clear any existing state
86112 if (keyMode == KEYMODE_PRESSED) {
87113 keyMode = KEYMODE_NOT_PRESSED;
88114 counter = 0 ;
89115 listener->keyReleased (currentKey);
116+ currentKey = 0 ;
90117 }
91- if (pressThisTime != 0 ) keyMode = KEYMODE_DEBOUNCE;
92- currentKey = pressThisTime;
118+ doDebounce (pressThisTime);
119+ }
120+
121+ enableAllOutputsForInterrupt ();
122+ }
123+
124+ uint32_t MatrixKeyboardManager::timeOfNextCheck () {
125+
126+ if (interruptMode && (keyMode == KEYMODE_NOT_PRESSED)) {
127+ return secondsToMicros (1 );
128+ } else {
129+ setTriggered (true );
130+ return millisToMicros (KEYBOARD_TASK_MILLIS);
131+ }
132+ }
133+
134+ void MatrixKeyboardManager::enableAllOutputsForInterrupt () {
135+ if (interruptMode && keyMode == KEYMODE_NOT_PRESSED) {
136+ // in interrupt mode we set all output pins low when nothing is pressed so that any change will be detected.
137+ // this effectively means that each column pin is low and will pull down the input line. We don't need to
138+ // know what is pressed, just that something was pressed.
139+ for (int i=0 ; i < layout->numColumns (); i++) {
140+ ioDeviceDigitalWrite (ioRef, layout->getColPin (i), 0 );
141+ }
142+ ioDeviceSync (ioRef);
143+ }
144+ }
145+
146+ void MatrixKeyboardManager::doDebounce (char pressedNow) {
147+ if (isDebouncing (keyMode) && currentKey == pressedNow) {
148+ currentKey = pressedNow;
149+ keyMode = KEYMODE_PRESSED;
150+ return ;
151+ }
152+
153+ if (pressedNow && keyMode == KEYMODE_NOT_PRESSED) {
154+ currentKey = pressedNow;
155+ keyMode = KEYMODE_DEBOUNCE;
156+ } else if (keyMode == KEYMODE_DEBOUNCE) {
157+ keyMode = KEYMODE_DEBOUNCE1;
158+ } else if (keyMode == KEYMODE_DEBOUNCE1) {
159+ keyMode = KEYMODE_DEBOUNCE2;
160+ } else if (keyMode == KEYMODE_DEBOUNCE2) {
161+ keyMode = KEYMODE_NOT_PRESSED;
93162 }
94163}
0 commit comments