IoAbstraction
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 
72 enum 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 
92 public:
98  virtual void onPressed(pinid_t pin, bool held) = 0;
104  virtual void onReleased(pinid_t pin, bool held) = 0;
105 };
106 
113 typedef void(*KeyCallbackFn)(pinid_t key, bool heldDown);
114 
120 typedef void(*EncoderCallbackFn)(int newValue);
121 
126 private:
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;
138 public:
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 
173 enum EncoderUserIntention: uint8_t {
182 };
183 
189 public:
195  virtual void encoderHasChanged(int newValue)=0;
196 };
197 
204 protected:
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;
214  EncoderUserIntention intent;
215 public:
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 
239  void replaceCallbackListener(EncoderListener* callbackFn);
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 
276  void setUserIntention(EncoderUserIntention intention);
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 
298 enum HWAccelerationMode : uint8_t {
305 };
306 
311 enum EncoderType : uint8_t {
317  FULL_CYCLE
318 };
319 
321 protected:
322  unsigned long lastChange;
323  pinid_t pinA;
324  pinid_t pinB;
325  HWAccelerationMode accelerationMode;
326  EncoderType encoderType;
327 
328 public:
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 
344 protected:
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 
358 private:
359  uint8_t state = 0; // Current state of the encoder
360  uint8_t pulseCounter = 0; // Pulse counter for FULL_CYCLE and HALF_CYCLE modes
361 public:
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;
383 private:
384  void initialise(pinid_t pinA, pinid_t pinB, HWAccelerationMode accelerationMode, EncoderType et);
385 };
386 
394 private:
395  int8_t currentEncoderState = 0;
396 public:
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;
419 private:
420  int8_t stateFor(uint8_t bits);
421 };
422 
423 
429 private:
430  const pinid_t upPin, downPin, backPin, nextPin;
431  SwitchListener* passThroughListener;
432  const bool canRotate;
433 public:
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 
491 protected:
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 
514 };
515 
516 
528 class SwitchInput {
529 private:
530  RotaryEncoder* encoder[MAX_ROTARY_ENCODERS];
531  IoAbstractionRef ioDevice;
532  BtreeList<pinid_t, KeyboardItem> keys;
533  volatile uint8_t swFlags;
534  bool lastSyncStatus;
535 public:
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 
743 private:
744  bool internalAddSwitch(pinid_t pin, bool invertLogic);
745 
746  friend void onSwitchesInterrupt(pinid_t);
747 };
748 
752 extern SwitchInput switches;
753 
766 void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
767 
785 void setupStateMachineRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
786 
787 
805 void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
806 
824 void setupRotaryEncoderWithInterrupt(pinid_t pinA, pinid_t pinB, EncoderListener* listener, HWAccelerationMode accelerationMode = HWACCEL_REGULAR, EncoderType encoderType = FULL_CYCLE);
825 
839 void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, int speed = 20);
840 
855 void setupUpDownButtonEncoder(pinid_t pinUp, pinid_t pinDown, EncoderListener* listener, int speed = 20);
856 
870 void 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:732
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:690
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:722
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:11
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
EncoderUpDownButtons(pinid_t pinUp, pinid_t pinDown, EncoderCallbackFn callback, uint8_t speed=20)
Definition: SwitchInput.cpp:535
void onReleased(pinid_t pin, bool held) override
Definition: SwitchInput.cpp:584
void onPressed(pinid_t pin, bool held) override
Definition: SwitchInput.cpp:569
Definition: SwitchInput.h:357
HardwareRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType=FULL_CYCLE)
Definition: SwitchInput.cpp:339
void encoderChanged() override
Definition: SwitchInput.cpp:428
Definition: SwitchInput.h:393
HwStateRotaryEncoder(pinid_t pinA, pinid_t pinB, EncoderCallbackFn callback, HWAccelerationMode accelerationMode=HWACCEL_REGULAR, EncoderType=FULL_CYCLE)
Definition: SwitchInput.cpp:677
void encoderChanged() override
Definition: SwitchInput.cpp:627
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:300
void setUserIntention(EncoderUserIntention intention)
Definition: SwitchInput.cpp:305
void replaceCallback(EncoderCallbackFn callbackFn)
Definition: SwitchInput.cpp:295
void increment(int8_t incVal)
Definition: SwitchInput.cpp:316
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:286
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:172
void replaceOnPressed(pinid_t pin, KeyCallbackFn callbackOnPressed)
Definition: SwitchInput.cpp:206
void resetAllSwitches()
Definition: SwitchInput.cpp:400
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:189
void replaceSwitchListener(pinid_t pin, SwitchListener *newListener)
Definition: SwitchInput.cpp:213
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:138
RotaryEncoder * getEncoder()
Definition: SwitchInput.h:641
bool isSwitchPressed(pinid_t pin)
Definition: SwitchInput.cpp:220
void pushSwitch(pinid_t pin, bool held)
Definition: SwitchInput.cpp:224
bool addSwitch(pinid_t pin, KeyCallbackFn callback, uint8_t repeat=NO_REPEAT, bool invertLogic=false)
Definition: SwitchInput.cpp:167
bool isEncoderPollingEnabled()
Definition: SwitchInput.h:702
SwitchInput()
Definition: SwitchInput.cpp:124
bool runLoop()
Definition: SwitchInput.cpp:240
void initialiseInterrupt(IoAbstractionRef ioDevice, bool usePullUpSwitching=false)
Definition: SwitchInput.cpp:130
void initialise(IoAbstractionRef ioDevice, bool usePullUpSwitching=false)
Definition: SwitchInput.cpp:134
Definition: SwitchInput.h:91
virtual void onPressed(pinid_t pin, bool held)=0
virtual void onReleased(pinid_t pin, bool held)=0