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
13
14#ifndef _SWITCHINPUT_H
15#define _SWITCHINPUT_H
16
17#include "IoAbstraction.h"
18#include "TaskManager.h"
19#include <BTreeList.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
90
99public:
105 virtual void onPressed(pinid_t pin, bool held) = 0;
111 virtual void onReleased(pinid_t pin, bool held) = 0;
112};
113
120typedef void(*KeyCallbackFn)(pinid_t key, bool heldDown);
121
127typedef void(*EncoderCallbackFn)(int newValue);
128
132class KeyboardItem {
133private:
134 uint8_t stateFlags;
135 KeyPressState previousState;
136 pinid_t pin;
137 uint8_t counter;
138 uint8_t acceleration;
139 uint8_t repeatInterval;
140 union {
141 KeyCallbackFn callback;
142 SwitchListener* listener;
143 } notify;
144 KeyCallbackFn callbackOnRelease;
145public:
146 KeyboardItem();
147 KeyboardItem(pinid_t pin, KeyCallbackFn callback, uint8_t repeatInterval = NO_REPEAT, bool keyLogicIsInverted = false);
148 KeyboardItem(pinid_t pin, SwitchListener* switchListener, uint8_t repeatInterval = NO_REPEAT, bool keyLogicIsInverted = false);
149 KeyboardItem(const KeyboardItem& other);
150 KeyboardItem& operator=(const KeyboardItem& other);
151 void checkAndTrigger(uint8_t pin);
152 void onRelease(KeyCallbackFn callbackOnRelease);
153
154 bool isDebouncing() const { return getState() == DEBOUNCING1 || getState() == DEBOUNCING2; }
155 bool isPressed() const { return getState() == PRESSED || getState() == BUTTON_HELD; }
156 bool isHeld() const { return getState() == BUTTON_HELD; }
157 pinid_t getPin() const { return pin; }
158 pinid_t getKey() const { return pin; }
159
160 void trigger(bool held);
161 void triggerRelease(bool held);
162
163 KeyPressState getState() const { return (KeyPressState)(stateFlags & KEY_PRESS_STATE_MASK); }
164 void setState(KeyPressState state) {
165 stateFlags &= ~KEY_PRESS_STATE_MASK;
166 stateFlags |= (state & KEY_PRESS_STATE_MASK);
167 }
168 bool isUsingListener() { return bitRead(stateFlags, KEY_LISTENER_MODE_BIT); }
169 bool isLogicInverted() { return bitRead(stateFlags, KEY_LOGIC_IS_INVERTED); }
170
171 void changeOnPressed(KeyCallbackFn pFunction);
172 void changeListener(SwitchListener* listener);
173
174 void setRepeatInterval(uint8_t newInterval) { repeatInterval = newInterval;}
175};
176
192
198public:
204 virtual void encoderHasChanged(int newValue)=0;
205};
206
212class RotaryEncoder {
213protected:
214 enum EncoderFlagBits { LAST_SYNC_STATUS=0, WRAP_AROUND_MODE, OO_LISTENER_CALLBACK, LAST_ENCODER_DIRECTION_UP };
215 uint16_t maximumValue;
216 uint16_t currentReading;
217 uint8_t stepSize;
218 union {
219 EncoderCallbackFn callback;
220 EncoderListener* encoderListener;
221 } notify;
222 uint8_t flags;
224public:
225 explicit RotaryEncoder(EncoderCallbackFn callback);
226 explicit RotaryEncoder(EncoderListener* listener);
227 virtual ~RotaryEncoder() {;}
228
236 void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax = false, int step = 1);
237
242 void replaceCallback(EncoderCallbackFn callbackFn);
243
249
253 int getCurrentReading() const { return currentReading; }
254
259 void setCurrentReading(int reading) { currentReading = reading; }
260
265 void increment(int8_t incVal);
266
270 virtual void encoderChanged() {;}
271
277 bool didLastSyncSucceed() { return bitRead(flags, LAST_SYNC_STATUS); }
278
286
287 EncoderUserIntention getUserIntention() { return intent; }
288
289 void runCallback(int newVal) {
290 if(bitRead(flags, OO_LISTENER_CALLBACK)) {
291 notify.encoderListener->encoderHasChanged(newVal);
292 } else {
293 notify.callback(newVal);
294 }
295 }
296
300 bsize_t getMaximumValue() { return maximumValue; }
301};
302
315
328
329class AbstractHwRotaryEncoder : public RotaryEncoder {
330protected:
331 unsigned long lastChange;
332 pinid_t pinA;
333 pinid_t pinB;
334 HWAccelerationMode accelerationMode;
335 EncoderType encoderType;
336
337public:
338 explicit AbstractHwRotaryEncoder(EncoderCallbackFn callback) : RotaryEncoder(callback) {}
339 explicit AbstractHwRotaryEncoder(EncoderListener* listener) : RotaryEncoder(listener) {}
340
345 void setAccelerationMode(HWAccelerationMode mode) { accelerationMode = mode; }
346
351 void setEncoderType(EncoderType et) { encoderType = et; }
352
353protected:
354 void initialiseBase(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType);
355 int amountFromChange(unsigned long change);
356 void handleChangeRaw(bool increase);
357};
358
366class HardwareRotaryEncoder : public AbstractHwRotaryEncoder {
367private:
368 uint8_t state = 0; // Current state of the encoder
369 uint8_t pulseCounter = 0; // Pulse counter for FULL_CYCLE and HALF_CYCLE modes
370public:
379 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
380
390 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
391 void encoderChanged() override;
392private:
393 void initialise(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType et);
394};
395
402class HwStateRotaryEncoder : public AbstractHwRotaryEncoder {
403private:
404 int8_t currentEncoderState = 0;
405public:
414 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
415
425 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
426
427 void encoderChanged() override;
428private:
429 int8_t stateFor(uint8_t bits);
430};
431
432
437class EncoderUpDownButtons : public RotaryEncoder, public SwitchListener {
438private:
439 const pinid_t upPin, downPin, backPin, nextPin;
440 SwitchListener* passThroughListener;
441 const bool canRotate;
442public:
451 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, uint8_t speed = 20);
452
461 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, uint8_t speed = 20);
462
478 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderCallbackFn callback, uint8_t speed = 20);
479
495 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderListener* listener, uint8_t speed = 20);
496
497 void onPressed(pinid_t pin, bool held) override;
498 void onReleased(pinid_t pin, bool held) override;
499
500protected:
501 pinid_t getIncrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? nextPin : upPin; }
502 pinid_t getDecrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? backPin : downPin; }
503 pinid_t getBackPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? upPin : backPin; }
504 pinid_t getNextPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? downPin : nextPin; }
505};
506
507#define SW_FLAG_PULLUP_LOGIC 0
508#define SW_FLAG_INTERRUPT_DRIVEN 1
509#define SW_FLAG_INTERRUPT_DEBOUNCE 2
510#define SW_FLAG_ENCODER_IS_POLLING 3
511
524
525
538private:
539 RotaryEncoder* encoder[MAX_ROTARY_ENCODERS];
540 IoAbstractionRef ioDevice;
541 BtreeList<pinid_t, KeyboardItem> keys;
542 volatile uint8_t swFlags;
543 bool lastSyncStatus;
544public:
549 explicit SwitchInput();
550
558 void initialise(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
559
576 void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp);
577
586 void initialiseInterrupt(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
587
596 bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
597
607 bool addSwitchListener(pinid_t pin, SwitchListener* listener, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
608
614 void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease);
615
621 void replaceOnPressed(pinid_t pin, KeyCallbackFn callbackOnPressed);
622
628 void replaceSwitchListener(pinid_t pin, SwitchListener* newListener);
629
635 void setEncoder(RotaryEncoder* encoder) { this->encoder[0] = encoder; };
636
645 void setEncoder(uint8_t slot, RotaryEncoder* encoder);
646
650 RotaryEncoder* getEncoder() {return encoder[0]; }
651
659 void changeEncoderPrecision(uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(0, precision, currentValue, false, 1); }
660
669 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(slot, precision, currentValue, false, 1); }
670
681 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue, bool rollover, int step=1);
682
689 void pushSwitch(pinid_t pin, bool held);
690
694 bool runLoop();
695
697 IoAbstractionRef getIoAbstraction() { return ioDevice; }
698
704 bool isPullupLogic(bool invertedLogic) {
705 bool pullUp = bitRead(swFlags, SW_FLAG_PULLUP_LOGIC);
706 // check if we need to invert the state, basically when the two states don't match.
707 return (pullUp && !invertedLogic) || (!pullUp && invertedLogic);
708 }
709
711 bool isEncoderPollingEnabled() {return bitRead(swFlags, SW_FLAG_ENCODER_IS_POLLING);}
712
713 bool isInterruptDriven() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DRIVEN);}
714
716 bool isInterruptDebouncing() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE);}
717
722 bool isSwitchPressed(pinid_t pin);
723
728 void setInterruptDebouncing(bool debounce) { bitWrite(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE, debounce);}
729
734 bool didLastSyncSucceed() { return lastSyncStatus; }
735
740 void resetAllSwitches();
741
748 bool removeSwitch(pinid_t pin) {
749 return keys.removeByKey(pin);
750 }
751
758 void setRepeatInterval(pinid_t pin, uint8_t interval);
759 void ensureInitialized();
760
761private:
762 bool internalAddSwitch(pinid_t pin, bool invertLogic);
763
764 friend void onSwitchesInterrupt(pinid_t);
765};
766
770extern SwitchInput switches;
771
789void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
790
808void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
809
823void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed = 20);
824
839void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, int speed = 20);
840
854void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderListener* listener, int speed=20);
855
869 void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderCallbackFn encoderCallbackFn, int speed=20);
870
871#endif
BasicIoAbstraction * IoAbstractionRef
Definition BasicIoAbstraction.h:174
Using basic IoFacilities allows one to abstract away the use of IoExpanders, such that the switching ...
EncoderType
Definition SwitchInput.h:320
@ HALF_CYCLE
Definition SwitchInput.h:324
@ QUARTER_CYCLE
Definition SwitchInput.h:322
@ FULL_CYCLE
Definition SwitchInput.h:326
void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed=20)
Definition SwitchInput.cpp:695
void(* EncoderCallbackFn)(int newValue)
Definition SwitchInput.h:127
void(* KeyCallbackFn)(pinid_t key, bool heldDown)
Definition SwitchInput.h:120
void switchesEnableLegacyStateEncoder()
Definition SwitchInput.cpp:728
void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType encoderType=FULL_CYCLE)
Definition SwitchInput.cpp:732
HWAccelerationMode
Definition SwitchInput.h:307
@ HWACCEL_NONE
Definition SwitchInput.h:309
@ HWACCEL_SLOWER
Definition SwitchInput.h:313
@ HWACCEL_REGULAR
Definition SwitchInput.h:311
SwitchInterruptMode
Definition SwitchInput.h:516
@ SWITCHES_POLL_KEYS_ONLY
Definition SwitchInput.h:520
@ SWITCHES_POLL_EVERYTHING
Definition SwitchInput.h:522
@ SWITCHES_NO_POLLING
Definition SwitchInput.h:518
EncoderUserIntention
Definition SwitchInput.h:182
@ SCROLL_THROUGH_SIDEWAYS
Definition SwitchInput.h:188
@ CHANGE_VALUE
Definition SwitchInput.h:184
@ DIRECTION_ONLY
Definition SwitchInput.h:190
@ SCROLL_THROUGH_ITEMS
Definition SwitchInput.h:186
void setEncoderType(EncoderType et)
Definition SwitchInput.h:351
void setAccelerationMode(HWAccelerationMode mode)
Definition SwitchInput.h:345
Definition SwitchInput.h:197
virtual void encoderHasChanged(int newValue)=0
EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, uint8_t speed=20)
Definition SwitchInput.cpp:547
void onReleased(pinid_t pin, bool held) override
Definition SwitchInput.cpp:596
void onPressed(pinid_t pin, bool held) override
Definition SwitchInput.cpp:581
HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType=FULL_CYCLE)
Definition SwitchInput.cpp:351
void encoderChanged() override
Definition SwitchInput.cpp:440
HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType=FULL_CYCLE)
Definition SwitchInput.cpp:682
void encoderChanged() override
Definition SwitchInput.cpp:639
Definition SwitchInput.h:212
bool didLastSyncSucceed()
Definition SwitchInput.h:277
int getCurrentReading() const
Definition SwitchInput.h:253
virtual void encoderChanged()
Definition SwitchInput.h:270
void replaceCallbackListener(EncoderListener *callbackFn)
Definition SwitchInput.cpp:312
void setUserIntention(EncoderUserIntention intention)
Definition SwitchInput.cpp:317
void replaceCallback(EncoderCallbackFn callbackFn)
Definition SwitchInput.cpp:307
void increment(int8_t incVal)
Definition SwitchInput.cpp:328
void setCurrentReading(int reading)
Definition SwitchInput.h:259
bsize_t getMaximumValue()
Definition SwitchInput.h:300
void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax=false, int step=1)
Definition SwitchInput.cpp:298
Definition SwitchInput.h:537
void changeEncoderPrecision(uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:659
bool removeSwitch(pinid_t pin)
Definition SwitchInput.h:748
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:218
void resetAllSwitches()
Definition SwitchInput.cpp:412
RotaryEncoder * getEncoder()
Definition SwitchInput.h:650
void setRepeatInterval(pinid_t pin, uint8_t interval)
Definition SwitchInput.cpp:178
void setInterruptDebouncing(bool debounce)
Definition SwitchInput.h:728
IoAbstractionRef getIoAbstraction()
Definition SwitchInput.h:697
bool isPullupLogic(bool invertedLogic)
Definition SwitchInput.h:704
bool isInterruptDebouncing()
Definition SwitchInput.h:716
void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease)
Definition SwitchInput.cpp:201
void replaceSwitchListener(pinid_t pin, SwitchListener *newListener)
Definition SwitchInput.cpp:225
bool didLastSyncSucceed()
Definition SwitchInput.h:734
void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:669
void setEncoder(RotaryEncoder *encoder)
Definition SwitchInput.h:635
void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp)
Definition SwitchInput.cpp:139
bool isSwitchPressed(pinid_t pin)
Definition SwitchInput.cpp:232
void pushSwitch(pinid_t pin, bool held)
Definition SwitchInput.cpp:236
bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat=NO_REPEAT, bool invertLogic=false)
Definition SwitchInput.cpp:168
bool isEncoderPollingEnabled()
Definition SwitchInput.h:711
SwitchInput()
Definition SwitchInput.cpp:125
bool runLoop()
Definition SwitchInput.cpp:252
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:98
virtual void onPressed(pinid_t pin, bool held)=0
virtual void onReleased(pinid_t pin, bool held)=0