Line data Source code
1 : #include "ButtonMatrix.hpp"
2 : #include <AH/Containers/CRTP.hpp>
3 : #include <AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp>
4 : #include <string.h>
5 :
6 : BEGIN_AH_NAMESPACE
7 :
8 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
9 9 : ButtonMatrix<Derived, NumRows, NumCols>::ButtonMatrix(
10 : const PinList<NumRows> &rowPins, const PinList<NumCols> &colPins)
11 9 : : rowPins(rowPins), colPins(colPins) {
12 9 : memset(prevStates, 0xFF, sizeof(prevStates));
13 9 : }
14 :
15 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
16 10 : void ButtonMatrix<Derived, NumRows, NumCols>::update() {
17 10 : unsigned long now = millis();
18 : // only update 25 ms after previous change (crude software debounce).
19 : // Edit this in Settings/Settings.hpp
20 10 : if (now - prevRefresh < debounceTime)
21 0 : return;
22 :
23 40 : for (size_t row = 0; row < NumRows; row++) { // scan through all rows
24 30 : pinMode(rowPins[row], OUTPUT); // make the current row Lo-Z 0V
25 : #if !defined(__AVR__) && defined(ARDUINO)
26 : delayMicroseconds(SELECT_LINE_DELAY);
27 : #endif
28 90 : for (size_t col = 0; col < NumCols; col++) { // scan through all columns
29 60 : bool state = digitalRead(colPins[col]); // read the state
30 60 : if (state != getPrevState(col, row)) {
31 : // if the state changed since last time
32 : // execute the handler
33 10 : CRTP(Derived).onButtonChanged(row, col, state);
34 10 : setPrevState(col, row, state); // remember the state
35 10 : prevRefresh = now;
36 : }
37 : }
38 30 : pinMode(rowPins[row], INPUT); // make the current row Hi-Z again
39 : }
40 : }
41 :
42 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
43 3 : void ButtonMatrix<Derived, NumRows, NumCols>::begin() {
44 : // make all columns input pins and enable
45 : // the internal pull-up resistors
46 9 : for (const pin_t &colPin : colPins)
47 6 : pinMode(colPin, INPUT_PULLUP);
48 : // make all rows Hi-Z
49 12 : for (const pin_t &rowPin : rowPins)
50 9 : pinMode(rowPin, INPUT);
51 3 : }
52 :
53 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
54 : inline uint8_t
55 70 : ButtonMatrix<Derived, NumRows, NumCols>::positionToBits(uint8_t col,
56 : uint8_t row) {
57 : // map from a 2D array of bits to a flat array of bits
58 70 : return col * NumRows + row;
59 : }
60 :
61 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
62 : inline uint8_t
63 70 : ButtonMatrix<Derived, NumRows, NumCols>::bitsToIndex(uint8_t bits) {
64 70 : return bits >> 3; // bits / 8
65 : }
66 :
67 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
68 : inline uint8_t
69 70 : ButtonMatrix<Derived, NumRows, NumCols>::bitsToBitmask(uint8_t bits) {
70 70 : return 1 << (bits & 7); // bits % 8
71 : }
72 :
73 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
74 60 : bool ButtonMatrix<Derived, NumRows, NumCols>::getPrevState(uint8_t col,
75 : uint8_t row) {
76 60 : uint8_t bits = positionToBits(col, row);
77 60 : return !!(prevStates[bitsToIndex(bits)] & bitsToBitmask(bits));
78 : }
79 :
80 : template <class Derived, uint8_t NumRows, uint8_t NumCols>
81 10 : void ButtonMatrix<Derived, NumRows, NumCols>::setPrevState(uint8_t col,
82 : uint8_t row,
83 : bool state) {
84 10 : uint8_t bits = positionToBits(col, row);
85 10 : if (state)
86 5 : prevStates[bitsToIndex(bits)] |= bitsToBitmask(bits);
87 : else
88 5 : prevStates[bitsToIndex(bits)] &= ~bitsToBitmask(bits);
89 10 : }
90 :
91 : END_AH_NAMESPACE
|