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 void setRepeatInterval(uint8_t newInterval) { repeatInterval = newInterval;}
168};
169
185
191public:
197 virtual void encoderHasChanged(int newValue)=0;
198};
199
206protected:
207 enum EncoderFlagBits { LAST_SYNC_STATUS=0, WRAP_AROUND_MODE, OO_LISTENER_CALLBACK, LAST_ENCODER_DIRECTION_UP };
208 uint16_t maximumValue;
209 uint16_t currentReading;
210 uint8_t stepSize;
211 union {
212 EncoderCallbackFn callback;
213 EncoderListener* encoderListener;
214 } notify;
215 uint8_t flags;
217public:
218 explicit RotaryEncoder(EncoderCallbackFn callback);
219 explicit RotaryEncoder(EncoderListener* listener);
220 virtual ~RotaryEncoder() {;}
221
229 void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax = false, int step = 1);
230
235 void replaceCallback(EncoderCallbackFn callbackFn);
236
242
246 int getCurrentReading() const { return currentReading; }
247
252 void setCurrentReading(int reading) { currentReading = reading; }
253
258 void increment(int8_t incVal);
259
263 virtual void encoderChanged() {;}
264
270 bool didLastSyncSucceed() { return bitRead(flags, LAST_SYNC_STATUS); }
271
279
280 EncoderUserIntention getUserIntention() { return intent; }
281
282 void runCallback(int newVal) {
283 if(bitRead(flags, OO_LISTENER_CALLBACK)) {
284 notify.encoderListener->encoderHasChanged(newVal);
285 } else {
286 notify.callback(newVal);
287 }
288 }
289
293 bsize_t getMaximumValue() { return maximumValue; }
294};
295
308
321
323protected:
324 unsigned long lastChange;
325 pinid_t pinA;
326 pinid_t pinB;
327 HWAccelerationMode accelerationMode;
328 EncoderType encoderType;
329
330public:
331 explicit AbstractHwRotaryEncoder(EncoderCallbackFn callback) : RotaryEncoder(callback) {}
332 explicit AbstractHwRotaryEncoder(EncoderListener* listener) : RotaryEncoder(listener) {}
333
338 void setAccelerationMode(HWAccelerationMode mode) { accelerationMode = mode; }
339
344 void setEncoderType(EncoderType et) { encoderType = et; }
345
346protected:
347 void initialiseBase(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType);
348 int amountFromChange(unsigned long change);
349 void handleChangeRaw(bool increase);
350};
351
360private:
361 uint8_t state = 0; // Current state of the encoder
362 uint8_t pulseCounter = 0; // Pulse counter for FULL_CYCLE and HALF_CYCLE modes
363public:
372 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
373
383 HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
384 void encoderChanged() override;
385private:
386 void initialise(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType et);
387};
388
396private:
397 int8_t currentEncoderState = 0;
398public:
407 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
408
418 HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType = FULL_CYCLE);
419
420 void encoderChanged() override;
421private:
422 int8_t stateFor(uint8_t bits);
423};
424
425
431private:
432 const pinid_t upPin, downPin, backPin, nextPin;
433 SwitchListener* passThroughListener;
434 const bool canRotate;
435public:
444 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, uint8_t speed = 20);
445
454 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, uint8_t speed = 20);
455
471 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderCallbackFn callback, uint8_t speed = 20);
472
488 EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, pinid_t pinBack, pinid_t pinNext, SwitchListener* passThrough, EncoderListener* listener, uint8_t speed = 20);
489
490 void onPressed(pinid_t pin, bool held) override;
491 void onReleased(pinid_t pin, bool held) override;
492
493protected:
494 pinid_t getIncrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? nextPin : upPin; }
495 pinid_t getDecrementPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? backPin : downPin; }
496 pinid_t getBackPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? upPin : backPin; }
497 pinid_t getNextPin() { return intent == SCROLL_THROUGH_SIDEWAYS && canRotate ? downPin : nextPin; }
498};
499
500#define SW_FLAG_PULLUP_LOGIC 0
501#define SW_FLAG_INTERRUPT_DRIVEN 1
502#define SW_FLAG_INTERRUPT_DEBOUNCE 2
503#define SW_FLAG_ENCODER_IS_POLLING 3
504
517
518
531private:
532 RotaryEncoder* encoder[MAX_ROTARY_ENCODERS];
533 IoAbstractionRef ioDevice;
534 BtreeList<pinid_t, KeyboardItem> keys;
535 volatile uint8_t swFlags;
536 bool lastSyncStatus;
537public:
542 explicit SwitchInput();
543
551 void initialise(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
552
569 void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp);
570
579 void initialiseInterrupt(IoAbstractionRef ioDevice, bool usePullUpSwitching = false);
580
589 bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
590
600 bool addSwitchListener(pinid_t pin, SwitchListener* listener, uint8_t repeat = NO_REPEAT, bool invertLogic = false);
601
607 void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease);
608
614 void replaceOnPressed(pinid_t pin, KeyCallbackFn callbackOnPressed);
615
621 void replaceSwitchListener(pinid_t pin, SwitchListener* newListener);
622
628 void setEncoder(RotaryEncoder* encoder) { this->encoder[0] = encoder; };
629
638 void setEncoder(uint8_t slot, RotaryEncoder* encoder);
639
643 RotaryEncoder* getEncoder() {return encoder[0]; }
644
652 void changeEncoderPrecision(uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(0, precision, currentValue, false, 1); }
653
662 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue) { changeEncoderPrecision(slot, precision, currentValue, false, 1); }
663
674 void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue, bool rollover, int step=1);
675
682 void pushSwitch(pinid_t pin, bool held);
683
687 bool runLoop();
688
690 IoAbstractionRef getIoAbstraction() { return ioDevice; }
691
697 bool isPullupLogic(bool invertedLogic) {
698 bool pullUp = bitRead(swFlags, SW_FLAG_PULLUP_LOGIC);
699 // check if we need to invert the state, basically when the two states don't match.
700 return (pullUp && !invertedLogic) || (!pullUp && invertedLogic);
701 }
702
704 bool isEncoderPollingEnabled() {return bitRead(swFlags, SW_FLAG_ENCODER_IS_POLLING);}
705
706 bool isInterruptDriven() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DRIVEN);}
707
709 bool isInterruptDebouncing() {return bitRead(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE);}
710
715 bool isSwitchPressed(pinid_t pin);
716
721 void setInterruptDebouncing(bool debounce) { bitWrite(swFlags, SW_FLAG_INTERRUPT_DEBOUNCE, debounce);}
722
727 bool didLastSyncSucceed() { return lastSyncStatus; }
728
733 void resetAllSwitches();
734
741 bool removeSwitch(pinid_t pin) {
742 return keys.removeByKey(pin);
743 }
744
751 void setRepeatInterval(pinid_t pin, uint8_t interval);
752
753private:
754 bool internalAddSwitch(pinid_t pin, bool invertLogic);
755
756 friend void onSwitchesInterrupt(pinid_t);
757};
758
762extern SwitchInput switches;
763
776void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
777
795void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
796
797
815void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
816
834void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
835
849void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed = 20);
850
865void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, int speed = 20);
866
880void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderListener* listener, int speed=20);
881
895 void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, pinid_t pinLeft, pinid_t pinRight, SwitchListener* passThroughListener, EncoderCallbackFn encoderCallbackFn, int speed=20);
896
897#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:740
EncoderType
Definition SwitchInput.h:313
@ HALF_CYCLE
Definition SwitchInput.h:317
@ QUARTER_CYCLE
Definition SwitchInput.h:315
@ FULL_CYCLE
Definition SwitchInput.h:319
void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed=20)
Definition SwitchInput.cpp:698
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:730
HWAccelerationMode
Definition SwitchInput.h:300
@ HWACCEL_NONE
Definition SwitchInput.h:302
@ HWACCEL_SLOWER
Definition SwitchInput.h:306
@ HWACCEL_REGULAR
Definition SwitchInput.h:304
SwitchInterruptMode
Definition SwitchInput.h:509
@ SWITCHES_POLL_KEYS_ONLY
Definition SwitchInput.h:513
@ SWITCHES_POLL_EVERYTHING
Definition SwitchInput.h:515
@ SWITCHES_NO_POLLING
Definition SwitchInput.h:511
SwitchInput switches
Definition SwitchInput.cpp:12
EncoderUserIntention
Definition SwitchInput.h:175
@ SCROLL_THROUGH_SIDEWAYS
Definition SwitchInput.h:181
@ CHANGE_VALUE
Definition SwitchInput.h:177
@ DIRECTION_ONLY
Definition SwitchInput.h:183
@ SCROLL_THROUGH_ITEMS
Definition SwitchInput.h:179
Definition SwitchInput.h:322
void setEncoderType(EncoderType et)
Definition SwitchInput.h:344
void setAccelerationMode(HWAccelerationMode mode)
Definition SwitchInput.h:338
Definition BasicIoAbstraction.h:38
Definition SwitchInput.h:190
virtual void encoderHasChanged(int newValue)=0
Definition SwitchInput.h:430
void onReleased(pinid_t pin, bool held) override
Definition SwitchInput.cpp:592
void onPressed(pinid_t pin, bool held) override
Definition SwitchInput.cpp:577
Definition SwitchInput.h:359
void encoderChanged() override
Definition SwitchInput.cpp:436
Definition SwitchInput.h:395
void encoderChanged() override
Definition SwitchInput.cpp:635
Definition SwitchInput.h:125
Definition SwitchInput.h:205
bool didLastSyncSucceed()
Definition SwitchInput.h:270
int getCurrentReading() const
Definition SwitchInput.h:246
virtual void encoderChanged()
Definition SwitchInput.h:263
void replaceCallbackListener(EncoderListener *callbackFn)
Definition SwitchInput.cpp:308
void setUserIntention(EncoderUserIntention intention)
Definition SwitchInput.cpp:313
void replaceCallback(EncoderCallbackFn callbackFn)
Definition SwitchInput.cpp:303
void increment(int8_t incVal)
Definition SwitchInput.cpp:324
void setCurrentReading(int reading)
Definition SwitchInput.h:252
bsize_t getMaximumValue()
Definition SwitchInput.h:293
void changePrecision(uint16_t maxValue, int currentValue, bool rolloverOnMax=false, int step=1)
Definition SwitchInput.cpp:294
Definition SwitchInput.h:530
void changeEncoderPrecision(uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:652
bool removeSwitch(pinid_t pin)
Definition SwitchInput.h:741
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:214
void resetAllSwitches()
Definition SwitchInput.cpp:408
RotaryEncoder * getEncoder()
Definition SwitchInput.h:643
void setRepeatInterval(pinid_t pin, uint8_t interval)
Definition SwitchInput.cpp:178
void setInterruptDebouncing(bool debounce)
Definition SwitchInput.h:721
IoAbstractionRef getIoAbstraction()
Definition SwitchInput.h:690
bool isPullupLogic(bool invertedLogic)
Definition SwitchInput.h:697
bool isInterruptDebouncing()
Definition SwitchInput.h:709
void onRelease(pinid_t pin, KeyCallbackFn callbackOnRelease)
Definition SwitchInput.cpp:197
void replaceSwitchListener(pinid_t pin, SwitchListener *newListener)
Definition SwitchInput.cpp:221
bool didLastSyncSucceed()
Definition SwitchInput.h:727
void changeEncoderPrecision(uint8_t slot, uint16_t precision, uint16_t currentValue)
Definition SwitchInput.h:662
void setEncoder(RotaryEncoder *encoder)
Definition SwitchInput.h:628
void init(IoAbstractionRef ioDevice, SwitchInterruptMode mode, bool defaultIsPullUp)
Definition SwitchInput.cpp:139
bool isSwitchPressed(pinid_t pin)
Definition SwitchInput.cpp:228
void pushSwitch(pinid_t pin, bool held)
Definition SwitchInput.cpp:232
bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat=NO_REPEAT, bool invertLogic=false)
Definition SwitchInput.cpp:168
bool isEncoderPollingEnabled()
Definition SwitchInput.h:704
SwitchInput()
Definition SwitchInput.cpp:125
bool runLoop()
Definition SwitchInput.cpp:248
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