3template <uint8_t menuCount>
4bool MenuHandler<menuCount>::previousState;
6template <uint8_t menuCount>
7long MenuHandler<menuCount>::previousMillis;
9template <uint8_t menuCount>
10uint8_t MenuHandler<menuCount>::inputCount;
12template <uint8_t menuCount>
13uint8_t MenuHandler<menuCount>::currentMenu;
15template <uint8_t menuCount>
16uint16_t MenuHandler<menuCount>::inputStream[4];
18template <uint8_t menuCount>
19uint8_t MenuHandler<menuCount>::currentValue[menuCount];
21template <uint8_t menuCount>
22uint8_t MenuHandler<menuCount>::maxValue[menuCount];
24template <uint8_t menuCount>
25uint8_t MenuHandler<menuCount>::pin;
27template <uint8_t menuCount>
28void MenuHandler<menuCount>::Begin() {
29 previousMillis = millis();
30 previousState = false;
33template <uint8_t menuCount>
34void MenuHandler<menuCount>::Update() {
35 bool pinState = !digitalRead(pin);
36 long timeOn = millis() - previousMillis;
38 if (timeOn < 40) return;
40 if (!pinState && inputCount > 0 && timeOn > 500) {
42 if (inputStream[0] > 0) mask |= (inputStream[0] < 150 ? 1 : 2) << 0; // 1 2
43 if (inputStream[1] > 0) mask |= (inputStream[1] < 150 ? 1 : 2) << 2; // 4 8
44 if (inputStream[2] > 0) mask |= (inputStream[2] < 150 ? 1 : 2) << 4; // 16 32
45 if (inputStream[3] > 0) mask |= (inputStream[3] < 150 ? 1 : 2) << 6; // 64 128
49 case 9: val = 1; break; // A: .-
50 case 86: val = 2; break; // B: -...
51 case 102: val = 3; break; // C: -.-.
52 case 22: val = 4; break; // D: -..
53 case 1: val = 5; break; // E: .
54 case 101: val = 6; break; // F: ..-.
55 case 26: val = 7; break; // G: --.
56 case 85: val = 8; break; // H: ....
57 case 5: val = 9; break; // I: ..
58 case 169: val = 10; break; // J: .---
59 case 38: val = 11; break; // K: -.-
60 case 89: val = 12; break; // L: .-..
61 case 10: val = 13; break; // M: --
62 case 6: val = 14; break; // N: -.
63 case 42: val = 15; break; // O: ---
64 case 105: val = 16; break; // P: .--.
65 case 154: val = 17; break; // Q: --.-
66 case 25: val = 18; break; // R: .-.
67 case 21: val = 19; break; // S: ...
68 case 2: val = 20; break; // T: -
69 case 37: val = 21; break; // U: ..-
70 case 149: val = 22; break; // V: ...-
71 case 41: val = 23; break; // W: .--
72 case 150: val = 24; break; // X: -..-
73 case 166: val = 25; break; // Y: -.--
74 case 90: val = 26; break; // Z: --..
75 default: val = 0; break;
79 // T (long press) is used to advance menu, to keep it similar to default menu navigation
80 WriteEEPROM(currentMenu, currentValue[currentMenu]);
81 currentMenu = (currentMenu + 1) % menuCount;
82 } else if (currentMenu > 0) {
86 // E (short press) is used to advance selection in non-face menu, to keep it similar to default menu navigation
87 currentValue[currentMenu] = (currentValue[currentMenu] + 1) % maxValue[currentMenu];
90 // I (2 short presses) is used to go back a selection in non-face menu
91 val = currentValue[currentMenu];
92 if (val == 0) val += maxValue[currentMenu];
93 currentValue[currentMenu] = val - 1;
96 // M (2 long presses) is used to go back a menu
97 WriteEEPROM(currentMenu, currentValue[currentMenu]);
98 currentMenu = (currentMenu - 1) % menuCount;
101 // O (3 long presses) is used to exit the menu
102 WriteEEPROM(currentMenu, currentValue[currentMenu]);
107 if (maxValue[currentMenu] > 0) val = val % maxValue[currentMenu]; // If max is set, wrap value
108 currentValue[currentMenu] = val;
111 std::fill_n(inputStream, inputCount, 0);
113 previousState = false;
117 if (pinState == previousState) return;
119 if (!pinState && inputCount < 4) {
120 inputStream[inputCount] = timeOn;
124 previousMillis = millis();
125 previousState = pinState;
128template <uint8_t menuCount>
129uint8_t MenuHandler<menuCount>::ReadEEPROM(uint16_t index) {
130 return EEPROM.read(index);
133template <uint8_t menuCount>
134void MenuHandler<menuCount>::WriteEEPROM(uint16_t index, uint8_t value) {
135 EEPROM.write(index, value);
138template <uint8_t menuCount>
139bool MenuHandler<menuCount>::Initialize(uint8_t pin, uint16_t _holdingTime) {
140 MenuHandler::pin = pin;
141 MenuHandler::previousState = false;
143 pinMode(pin, INPUT_PULLUP);
145 for (uint8_t i = 0; i < menuCount; i++) {
146 currentValue[i] = ReadEEPROM(i);
149 return ReadEEPROM(menuCount + 1) != 255;
152template <uint8_t menuCount>
153void MenuHandler<menuCount>::SetDefaultValue(uint16_t menu, uint8_t value) {
154 if (menu >= menuCount) return;
156 currentValue[menu] = value;
158 WriteEEPROM(menu, value);
161template <uint8_t menuCount>
162void MenuHandler<menuCount>::SetInitialized() {
163 WriteEEPROM(menuCount + 1, 0);
166template <uint8_t menuCount>
167void MenuHandler<menuCount>::SetMenuMax(uint8_t menu, uint8_t maxValue) {
168 if (menu >= menuCount) return;
170 MenuHandler::maxValue[menu] = maxValue;
173template <uint8_t menuCount>
174uint8_t MenuHandler<menuCount>::GetMenuValue(uint8_t menu) {
175 return currentValue[menu];
178template <uint8_t menuCount>
179uint8_t MenuHandler<menuCount>::GetCurrentMenu() {