1 #ifdef HAS_FIVE_WAY_BUTTON
2 #include "FiveWayButton.h"
4 uint16_t FiveWayButton::joyAdcValues
[] = {0};
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
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
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
;
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]);
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
;
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
;
79 void FiveWayButton::init()
81 isLongPressed
= false;
82 keyInProcess
= INPUT_KEY_NO_PRESS
;
85 if (GPIO_PIN_JOYSTICK
!= UNDEF_PIN
)
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
)
106 if (newKey
!= INPUT_KEY_NO_PRESS
)
109 //DBGLN("down=%u", newKey);
115 if (newKey
== INPUT_KEY_NO_PRESS
)
117 //DBGLN("up=%u", keyInProcess);
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
;