IoAbstraction
Loading...
Searching...
No Matches
SwitchInput.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 https://www.thecoderscorner.com (Dave Cherry).
3 * This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
4 */
5
14#ifndef _SWITCHINPUT_H
15#define _SWITCHINPUT_H
16
17#include "IoAbstraction.h"
18#include "TaskManager.h"
19#include <SimpleCollections.h>
20
21// START user adjustable section
22
23// The threshold for an item becoming held down or for it to repeat, this is about half a second by default
24#ifndef HOLD_THRESHOLD
25#define HOLD_THRESHOLD 20
26#endif //HOLD_THRESHOLD
27
28// The rate a which switches will speed up under acceleration, 0 = extremely fast (untested!), 1 = fast, 2 = regular, 3 = slower
29#ifndef SWITCHES_ACCELERATION_DIVISOR
30#define SWITCHES_ACCELERATION_DIVISOR 2
31#endif //SWITCHES_ACCELERATION_DIVISOR
32
33/*
34 * If you want more buttons, the library will reallocate as needed, however this is not efficient and in production
35 * probably better to set this value to about the number of switches needed. Each button adds about 10 bytes of RAM,
36 * so on a tiny you could adjust downwards for example.
37 */
38#ifndef MAX_KEYS
39#define MAX_KEYS DEFAULT_LIST_SIZE
40#endif // MAX_KEYS defined
41
46#ifndef MAX_ROTARY_ENCODERS
47#define MAX_ROTARY_ENCODERS 4
48#endif // MAX_ROTARY_ENCODERS
49
50/*
51 * This parameter defines the interval between polling on switches. It defaults to 20 millis per poll.
52 */
53#ifndef SWITCH_POLL_INTERVAL
54#define SWITCH_POLL_INTERVAL 20
55#endif // SWITCH_POLL_INTERVAL
56
57/*
58 * This parameter defines the time threshold for which the rotary encoder should reject a direction change as
59 * part of the debouncing. IE if there is a spike that would represent a "valid" direction change this would prevent
60 * that direction change if within 100 milliseconds of a turn in the other direction. A user would have to be pretty
61 * quick to change direction in 1/10th of a second, but it is configurable in case.
62 */
63#ifndef REJECT_DIRECTION_CHANGE_THRESHOLD
64#define REJECT_DIRECTION_CHANGE_THRESHOLD 10000
65#endif //REJECT_DIRECTION_CHANGE_THRESHOLD
66
67// END user adjustable section
68
70#define NO_REPEAT 0xff
71
72enum KeyPressState : uint8_t {
73 NOT_PRESSED,
74 DEBOUNCING1,
75 DEBOUNCING2,
76 PRESSED,
77 BUTTON_HELD
78};
79
80#define KEY_PRESS_STATE_MASK 0x0f
81#define KEY_LISTENER_MODE_BIT 7
82#define KEY_LOGIC_IS_INVERTED 6
83
92public:
98 virtual void onPressed(pinid_t pin, bool held) = 0;
104 virtual void onReleased(pinid_t pin, bool held) = 0;
105};
106
113typedef void(*KeyCallbackFn)(pinid_t key, bool heldDown);
114
120typedef void(*EncoderCallbackFn)(int newValue);
121
126private:
127 uint8_t stateFlags;
128 KeyPressState previousState;
129 pinid_t pin;
130 uint8_t counter;
131 uint8_t acceleration;
132 uint8_t repeatInterval;
133 union {
134 KeyCallbackFn callback;
135 SwitchListener* listener;
136 } notify;
137 KeyCallbackFn callbackOnRelease;
138public:
139 KeyboardItem();
140 KeyboardItem(pinid_t pin, KeyCallbackFn callback, uint8_t repeatInterval = NO_REPEAT, bool keyLogicIsInverted = false);
141 KeyboardItem(pinid_t pin, SwitchListener* switchListener, uint8_t repeatInterval = NO_REPEAT, bool keyLogicIsInverted = false);
142 KeyboardItem(const KeyboardItem& other);
143 KeyboardItem& operator=(const KeyboardItem& other);
144 void checkAndTrigger(uint8_t pin);
145 void onRelease(KeyCallbackFn callbackOnRelease);
146
147 bool isDebouncing() const { return getState() == DEBOUNCING1 || getState() == DEBOUNCING2; }
148 bool isPressed() const { return getState() == PRESSED || getState() == BUTTON_HELD; }
149 bool isHeld() const { return getState() == BUTTON_HELD; }
150 pinid_t getPin() const { return pin; }
151 pinid_t getKey() const { return pin; }
152
153 void trigger(bool held);
154 void triggerRelease(bool held);
155
156 KeyPressState getState() const { return (KeyPressState)(stateFlags & KEY_PRESS_STATE_MASK); }
157 void setState(KeyPressState state) {
158 stateFlags &= ~KEY_PRESS_STATE_MASK;
159 stateFlags |= (state & KEY_PRESS_STATE_MASK);
160 }
161 bool isUsingListener() { return bitRead(stateFlags, KEY_LISTENER_MODE_BIT); }
162 bool isLogicInverted() { return bitRead(stateFlags, KEY_LOGIC_IS_INVERTED); }
163
164 void changeOnPressed(KeyCallbackFn pFunction);
165 void changeListener(SwitchListener* listener);
166};
167
183
189public:
195 virtual void encoderHasChanged(int newValue)=0;
196};
197
204protected:
205 enum EncoderFlagBits { LAST_SYNC_STATUS=0, WRAP_AROUND_MODE, OO_LISTENER_CALLBACK, LAST_ENCODER_DIRECTION_UP };
206 uint16_t maximumValue;
207 uint16_t currentReading;
208 uint8_t stepSize;
209 union {
210 EncoderCallbackFn callback;
211 EncoderListener* encoderListener;
212 } notify;
213 uint8_t flags;
215public:
216 explicit RotaryEncoder(EncoderCallbackFn callback);
217 explicit RotaryEncoder(EncoderListener* listener);
218 virtual ~RotaryEncoder() {;}
219
227 void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax = false, int step = 1);
228
233 void replaceCallback(EncoderCallbackFn callbackFn);
234
240
244 int getCurrentReading() const { return currentReading; }
245
250 void setCurrentReading(int reading) { currentReading = reading; }
251
256 void increment(int8_t incVal);
257
261 virtual void encoderChanged() {;}
262
268 bool didLastSyncSucceed() { return bitRead(flags, LAST_SYNC_STATUS); }
269
277
278 EncoderUserIntention getUserIntention() { return intent; }
279
280 void runCallback(int newVal) {
281 if(bitRead(flags, OO_LISTENER_CALLBACK)) {
282 notify.encoderListener->encoderHasChanged(newVal);
283 } else {
284 notify.callback(newVal);
285 }
286 }
287
291 bsize_t getMaximumValue() { return maximumValue; }
292};
293
306
319
321protected:
322 unsigned long lastChange;
323 pinid_t pinA;
324 pinid_t pinB;
325 HWAccelerationMode accelerationMode;
326 EncoderType encoderType;
327
328public:
329 explicit AbstractHwRotaryEncoder(EncoderCallbackFn callback) : RotaryEncoder(callback) {}
330 explicit AbstractHwRotaryEncoder(EncoderListener* listener) : RotaryEncoder(listener) {}
331
336 void setAccelerationMode(HWAccelerationMode mode) { accelerationMode = mode; }
337
342 void setEncoderType(EncoderType et) { encoderType = et; }
343
344protected:
345 void initialiseBase(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType);
346 int amountFromChange(unsigned long change);
347 void handleChangeRaw(bool increase);
348};
349
358private:
359 uint8_t state = 0; // Current state of the encoder
360 uint8_t pulseCounter = 0; // Pulse counter for FULL_CYCLE and HALF_CYCLE modes
361public:
370 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
371
381 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
382 void encoderChanged() override;
383private:
384 void initialise(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType et);
385};
386
394private:
395 int8_t currentEncoderState = 0;
396public:
405 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
406
416 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
417
418 void encoderChanged() override;
419private:
420 int8_t stateFor(uint8_t bits);
421};
422
423
429private:
430 const pinid_t upPin, downPin, backPin, nextPin;
431 SwitchListener* passThroughListener;
432 const bool canRotate;
433public:
442 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, uint8_t speed = 20);
443
452 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, uint8_t speed = 20);
453
469 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderCallbackFn callback, uint8_t speed = 20);
470
486 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderListener* listener, uint8_t speed = 20);
487
488 void onPressed(pinid_t pin, bool held) override;
489 void onReleased(pinid_t pin, bool held) override;
490
491protected:
492 pinid_t getIncrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? nextPin : upPin; }
493 pinid_t getDecrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? backPin : downPin; }
494 pinid_t getBackPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? upPin : backPin; }
495 pinid_t getNextPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? downPin : nextPin; }
496};
497
498#define SW_FLAG_PULLUP_LOGIC 0
499#define SW_FLAG_INTERRUPT_DRIVEN 1
500#define SW_FLAG_INTERRUPT_DEBOUNCE 2
501#define SW_FLAG_ENCODER_IS_POLLING 3
502
515
516
529private:
530 RotaryEncoder* encoder[MAX_ROTARY_ENCODERS];
531 IoAbstractionRef ioDevice;
532 BtreeList<pinid_t, KeyboardItem> keys;
533 volatile uint8_t swFlags;
534 bool lastSyncStatus;
535public:
540 explicit SwitchInput();
541
549 void initialise(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
550
567 void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp);
568
577 void initialiseInterrupt(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
578
587 bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
588
598 bool addSwitchListener(pinid_t pin, SwitchListener* listener, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
599
605 void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease);
606
612 void replaceOnPressed(pinid_t pin, KeyCallbackFn callbackOnPressed);
613
619 void replaceSwitchListener(pinid_t pin, SwitchListener* newListener);
620
626 void setEncoder(RotaryEncoder* encoder) { this->encoder[0] = encoder; };
627
636 void setEncoder(uint8_t slot, RotaryEncoder* encoder);
637
641 RotaryEncoder* getEncoder() {return encoder[0]; }
642
650 void changeEncoderPrecision(uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(0, precision, currentValue, false, 1); }
651
660 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(slot, precision, currentValue, false, 1); }
661
672 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue, bool rollover, int step=1);
673
680 void pushSwitch(pinid_t pin, bool held);
681
685 bool runLoop();
686
688 IoAbstractionRef getIoAbstraction() { return ioDevice; }
689
695 bool isPullupLogic(bool invertedLogic) {
696 bool pullUp = bitRead(swFlags, SW_FLAG_PULLUP_LOGIC);
697 // check if we need to invert the state, basically when the two states don't match.
698 return (pullUp && !invertedLogic) || (!pullUp && invertedLogic);
699 }
700
702 bool isEncoderPollingEnabled() {return bitRead(swFlags, SW_FLAG_ENCODER_IS_POLLING);}
703
704 bool isInterruptDriven() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DRIVEN);}
705
707 bool isInterruptDebouncing() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE);}
708
713 bool isSwitchPressed(pinid_t pin);
714
719 void setInterruptDebouncing(bool debounce) { bitWrite(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE, debounce);}
720
725 bool didLastSyncSucceed() { return lastSyncStatus; }
726
731 void resetAllSwitches();
732
739 bool removeSwitch(pinid_t pin) {
740 return keys.removeByKey(pin);
741 }
742
743private:
744 bool internalAddSwitch(pinid_t pin, bool invertLogic);
745
746 friend void onSwitchesInterrupt(pinid_t);
747};
748
752extern SwitchInput switches;
753
766void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
767
785void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
786
787
805void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
806
824void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
825
839void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed = 20);
840
855void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, int speed = 20);
856
870void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderListener* listener, int speed=20);
871
885 void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderCallbackFn encoderCallbackFn, int speed=20);
886
887#endif
Using basic IoFacilities allows one to abstract away the use of IoExpanders, such that the switching ...
void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType encoderType=FULL_CYCLE)
Definition SwitchInput.cpp:733
EncoderType
Definition SwitchInput.h:311
@ HALF_CYCLE
Definition SwitchInput.h:315
@ QUARTER_CYCLE
Definition SwitchInput.h:313
@ FULL_CYCLE
Definition SwitchInput.h:317
void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed=20)
Definition SwitchInput.cpp:691
void(* EncoderCallbackFn)(int newValue)
Definition SwitchInput.h:120
void(* KeyCallbackFn)(pinid_t key, bool heldDown)
Definition SwitchInput.h:113
void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType encoderType=FULL_CYCLE)
Definition SwitchInput.cpp:723
HWAccelerationMode
Definition SwitchInput.h:298
@ HWACCEL_NONE
Definition SwitchInput.h:300
@ HWACCEL_SLOWER
Definition SwitchInput.h:304
@ HWACCEL_REGULAR
Definition SwitchInput.h:302
SwitchInterruptMode
Definition SwitchInput.h:507
@ SWITCHES_POLL_KEYS_ONLY
Definition SwitchInput.h:511
@ SWITCHES_POLL_EVERYTHING
Definition SwitchInput.h:513
@ SWITCHES_NO_POLLING
Definition SwitchInput.h:509
SwitchInput switches
Definition SwitchInput.cpp:12
EncoderUserIntention
Definition SwitchInput.h:173
@ SCROLL_THROUGH_SIDEWAYS
Definition SwitchInput.h:179
@ CHANGE_VALUE
Definition SwitchInput.h:175
@ DIRECTION_ONLY
Definition SwitchInput.h:181
@ SCROLL_THROUGH_ITEMS
Definition SwitchInput.h:177
Definition SwitchInput.h:320
void setEncoderType(EncoderType et)
Definition SwitchInput.h:342
void setAccelerationMode(HWAccelerationMode mode)
Definition SwitchInput.h:336
Definition BasicIoAbstraction.h:38
Definition SwitchInput.h:188
virtual void encoderHasChanged(int newValue)=0
Definition SwitchInput.h:428
void onReleased(pinid_t pin, bool held) override
Definition SwitchInput.cpp:585
void onPressed(pinid_t pin, bool held) override
Definition SwitchInput.cpp:570
Definition SwitchInput.h:357
void encoderChanged() override
Definition SwitchInput.cpp:429
Definition SwitchInput.h:393
void encoderChanged() override
Definition SwitchInput.cpp:628
Definition SwitchInput.h:125
Definition SwitchInput.h:203
bool didLastSyncSucceed()
Definition SwitchInput.h:268
int getCurrentReading() const
Definition SwitchInput.h:244
virtual void encoderChanged()
Definition SwitchInput.h:261
void replaceCallbackListener(EncoderListener *callbackFn)
Definition SwitchInput.cpp:301
void setUserIntention(EncoderUserIntention intention)
Definition SwitchInput.cpp:306
void replaceCallback(EncoderCallbackFn callbackFn)
Definition SwitchInput.cpp:296
void increment(int8_t incVal)
Definition SwitchInput.cpp:317
void setCurrentReading(int reading)
Definition SwitchInput.h:250
bsize_t getMaximumValue()
Definition SwitchInput.h:291
void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax=false, int step=1)
Definition SwitchInput.cpp:287
Definition SwitchInput.h:528
void changeEncoderPrecision(uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:650
bool removeSwitch(pinid_t pin)
Definition SwitchInput.h:739
bool addSwitchListener(pinid_t pin, SwitchListener *listener, uint8_t repeat=NO_REPEAT, bool invertLogic=false)
Definition SwitchInput.cpp:173
void replaceOnPressed(pinid_t pin, KeyCallbackFn callbackOnPressed)
Definition SwitchInput.cpp:207
void resetAllSwitches()
Definition SwitchInput.cpp:401
RotaryEncoder * getEncoder()
Definition SwitchInput.h:641
void setInterruptDebouncing(bool debounce)
Definition SwitchInput.h:719
IoAbstractionRef getIoAbstraction()
Definition SwitchInput.h:688
bool isPullupLogic(bool invertedLogic)
Definition SwitchInput.h:695
bool isInterruptDebouncing()
Definition SwitchInput.h:707
void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease)
Definition SwitchInput.cpp:190
void replaceSwitchListener(pinid_t pin, SwitchListener *newListener)
Definition SwitchInput.cpp:214
bool didLastSyncSucceed()
Definition SwitchInput.h:725
void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:660
void setEncoder(RotaryEncoder *encoder)
Definition SwitchInput.h:626
void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp)
Definition SwitchInput.cpp:139
bool isSwitchPressed(pinid_t pin)
Definition SwitchInput.cpp:221
void pushSwitch(pinid_t pin, bool held)
Definition SwitchInput.cpp:225
bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat=NO_REPEAT, bool invertLogic=false)
Definition SwitchInput.cpp:168
bool isEncoderPollingEnabled()
Definition SwitchInput.h:702
SwitchInput()
Definition SwitchInput.cpp:125
bool runLoop()
Definition SwitchInput.cpp:241
void initialiseInterrupt(IoAbstractionRef ioDevice, bool usePullUpSwitching=false)
Definition SwitchInput.cpp:131
void initialise(IoAbstractionRef ioDevice, bool usePullUpSwitching=false)
Definition SwitchInput.cpp:135
Definition SwitchInput.h:91
virtual void onPressed(pinid_t pin, bool held)=0
virtual void onReleased(pinid_t pin, bool held)=0