Phase 3: STM32 Removal: Shared RX/TX parts (#3016)
[ExpressLRS.git] / src / lib / SCREEN / FiveWayButton / FiveWayButton.cpp
blob06f04f677f8950f1a9f3724b2758d9448ea5c7ab
1 #ifdef HAS_FIVE_WAY_BUTTON
2 #include "FiveWayButton.h"
4 uint16_t FiveWayButton::joyAdcValues[] = {0};
6 /**
7 * @brief Calculate fuzz: half the distance to the next nearest neighbor for each joystick position.
9 * The goal is to avoid collisions between joystick positions while still maintaining
10 * the widest tolerance for the analog value.
12 * Example: {10,50,800,1000,300,1600}
13 * If we just choose the minimum difference for this array the value would
14 * be 40/2 = 20.
16 * 20 does not leave enough room for the joystick position using 1600 which
17 * could have a +-100 offset.
19 * Example Fuzz values: {20, 20, 100, 100, 125, 300} now the fuzz for the 1600
20 * position is 300 instead of 20
22 void FiveWayButton::calcFuzzValues()
24 memcpy(FiveWayButton::joyAdcValues, JOY_ADC_VALUES, sizeof(FiveWayButton::joyAdcValues));
25 for (unsigned int i = 0; i < N_JOY_ADC_VALUES; i++)
27 uint16_t closestDist = 0xffff;
28 uint16_t ival = joyAdcValues[i];
29 // Find the closest value to ival
30 for (unsigned int j = 0; j < N_JOY_ADC_VALUES; j++)
32 // Don't compare value with itself
33 if (j == i)
34 continue;
35 uint16_t jval = joyAdcValues[j];
36 if (jval < ival && (ival - jval < closestDist))
37 closestDist = ival - jval;
38 if (jval > ival && (jval - ival < closestDist))
39 closestDist = jval - ival;
40 } // for j
42 // And the fuzz is half the distance to the closest value
43 fuzzValues[i] = closestDist / 2;
44 //DBG("joy%u=%u f=%u, ", i, ival, fuzzValues[i]);
45 } // for i
48 int FiveWayButton::readKey()
50 if (GPIO_PIN_JOYSTICK != UNDEF_PIN)
52 uint16_t value = analogRead(GPIO_PIN_JOYSTICK);
54 constexpr uint8_t IDX_TO_INPUT[N_JOY_ADC_VALUES - 1] =
55 {INPUT_KEY_UP_PRESS, INPUT_KEY_DOWN_PRESS, INPUT_KEY_LEFT_PRESS, INPUT_KEY_RIGHT_PRESS, INPUT_KEY_OK_PRESS};
56 for (unsigned int i=0; i<N_JOY_ADC_VALUES - 1; ++i)
58 if (value < (joyAdcValues[i] + fuzzValues[i]) &&
59 value > (joyAdcValues[i] - fuzzValues[i]))
60 return IDX_TO_INPUT[i];
62 return INPUT_KEY_NO_PRESS;
64 else
66 return digitalRead(GPIO_PIN_FIVE_WAY_INPUT1) << 2 |
67 digitalRead(GPIO_PIN_FIVE_WAY_INPUT2) << 1 |
68 digitalRead(GPIO_PIN_FIVE_WAY_INPUT3);
72 FiveWayButton::FiveWayButton()
74 isLongPressed = false;
75 keyInProcess = INPUT_KEY_NO_PRESS;
76 keyDownStart = 0;
79 void FiveWayButton::init()
81 isLongPressed = false;
82 keyInProcess = INPUT_KEY_NO_PRESS;
83 keyDownStart = 0;
85 if (GPIO_PIN_JOYSTICK != UNDEF_PIN)
87 calcFuzzValues();
89 else
91 pinMode(GPIO_PIN_FIVE_WAY_INPUT1, INPUT_PULLUP);
92 pinMode(GPIO_PIN_FIVE_WAY_INPUT2, INPUT_PULLUP);
93 pinMode(GPIO_PIN_FIVE_WAY_INPUT3, INPUT_PULLUP);
97 void FiveWayButton::update(int *keyValue, bool *keyLongPressed)
99 *keyValue = INPUT_KEY_NO_PRESS;
101 int newKey = readKey();
102 uint32_t now = millis();
103 if (keyInProcess == INPUT_KEY_NO_PRESS)
105 // New key down
106 if (newKey != INPUT_KEY_NO_PRESS)
108 keyDownStart = now;
109 //DBGLN("down=%u", newKey);
112 else
114 // if key released
115 if (newKey == INPUT_KEY_NO_PRESS)
117 //DBGLN("up=%u", keyInProcess);
118 if (!isLongPressed)
120 if ((now - keyDownStart) > KEY_DEBOUNCE_MS)
122 *keyValue = keyInProcess;
123 *keyLongPressed = false;
126 isLongPressed = false;
128 // else if the key has changed while down, reset state for next go-around
129 else if (newKey != keyInProcess)
131 newKey = INPUT_KEY_NO_PRESS;
133 // else still pressing, waiting for long if not already signaled
134 else if (!isLongPressed)
136 if ((now - keyDownStart) > KEY_LONG_PRESS_MS)
138 *keyValue = keyInProcess;
139 *keyLongPressed = true;
140 isLongPressed = true;
143 } // if keyInProcess != INPUT_KEY_NO_PRESS
145 keyInProcess = newKey;
148 #endif