Taranis Q X7 optimized wizard (#5198)
[opentx.git] / radio / src / keys.cpp
blob4c0580b063508901a977e8b4508078cd65e18c4c
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 #define KEY_LONG_DELAY 32 // long key press minimum duration (x10ms), must be less than KEY_REPEAT_DELAY
24 #define KEY_REPEAT_DELAY 40 // press longer than this enables repeat (but does not fire it yet)
25 #define KEY_REPEAT_TRIGGER 48 // repeat trigger, used in combination with m_state to produce decreasing times between repeat events
26 #define KEY_REPEAT_PAUSE_DELAY 64
28 #ifdef SIMU
29 #define FILTERBITS 1 // defines how many bits are used for debounce
30 #else
31 #define FILTERBITS 4 // defines how many bits are used for debounce
32 #endif
34 #define KSTATE_OFF 0
35 #define KSTATE_RPTDELAY 95
36 #define KSTATE_START 97
37 #define KSTATE_PAUSE 98
38 #define KSTATE_KILLED 99
41 event_t s_evt;
42 struct t_inactivity inactivity = {0};
43 Key keys[NUM_KEYS];
45 #if defined(CPUARM)
46 event_t getEvent(bool trim)
48 event_t evt = s_evt;
49 int8_t k = EVT_KEY_MASK(s_evt) - TRM_BASE;
50 bool trim_evt = (k>=0 && k<TRM_LAST-TRM_BASE+1);
52 if (trim == trim_evt) {
53 s_evt = 0;
54 return evt;
56 else {
57 return 0;
60 #else
61 event_t getEvent()
63 event_t evt = s_evt;
64 s_evt = 0;
65 return evt;
67 #endif
69 void Key::input(bool val)
71 // store new value in the bits that hold the key state history (used for debounce)
72 uint8_t t_vals = m_vals ;
73 t_vals <<= 1 ;
74 if (val) t_vals |= 1;
75 m_vals = t_vals ;
77 m_cnt++;
79 if (m_state && m_vals == 0) {
80 // key is released
81 if (m_state != KSTATE_KILLED) {
82 // TRACE("key %d BREAK", key());
83 putEvent(EVT_KEY_BREAK(key()));
85 m_state = KSTATE_OFF;
86 m_cnt = 0;
87 return;
90 switch (m_state) {
91 case KSTATE_OFF:
92 if (m_vals == ((1<<FILTERBITS)-1)) {
93 m_state = KSTATE_START;
94 m_cnt = 0;
96 break;
97 case KSTATE_START:
98 // TRACE("key %d FIRST", key());
99 putEvent(EVT_KEY_FIRST(key()));
100 inactivity.counter = 0;
101 m_state = KSTATE_RPTDELAY;
102 m_cnt = 0;
103 break;
105 case KSTATE_RPTDELAY: // gruvin: delay state before first key repeat
106 if (m_cnt == KEY_LONG_DELAY) {
107 // generate long key press
108 // TRACE("key %d LONG", key());
109 putEvent(EVT_KEY_LONG(key()));
111 if (m_cnt == KEY_REPEAT_DELAY) {
112 m_state = 16;
113 m_cnt = 0;
115 break;
117 case 16:
118 case 8:
119 case 4:
120 case 2:
121 if (m_cnt >= KEY_REPEAT_TRIGGER) { //3 6 12 24 48 pulses in every 480ms
122 m_state >>= 1;
123 m_cnt = 0;
125 // no break
126 case 1:
127 if ((m_cnt & (m_state-1)) == 0) {
128 // this produces repeat events that at first repeat slowly and then increase in speed
129 // TRACE("key %d REPEAT", key());
130 putEvent(EVT_KEY_REPT(key()));
132 break;
134 case KSTATE_PAUSE: //pause repeat events
135 if (m_cnt >= KEY_REPEAT_PAUSE_DELAY) {
136 m_state = 8;
137 m_cnt = 0;
139 break;
141 case KSTATE_KILLED: //killed
142 break;
146 void Key::pauseEvents()
148 m_state = KSTATE_PAUSE;
149 m_cnt = 0;
152 void Key::killEvents()
154 // TRACE("key %d killed", key());
155 m_state = KSTATE_KILLED;
159 uint8_t Key::key() const
161 return (this - keys);
164 // Introduce a slight delay in the key repeat sequence
165 void pauseEvents(event_t event)
167 event = EVT_KEY_MASK(event);
168 if (event < (int)DIM(keys)) keys[event].pauseEvents();
171 // Disables any further event generation (BREAK and REPEAT) for this key, until the key is released
172 void killEvents(event_t event)
174 #if defined(ROTARY_ENCODERS)
175 if (event == EVT_ROTARY_LONG) {
176 killEvents(BTN_REa + g_eeGeneral.reNavigation - 1);
177 return;
179 #endif
181 event = EVT_KEY_MASK(event);
182 if (event < (int)DIM(keys)) {
183 keys[event].killEvents();
187 #if defined(CPUARM)
188 bool clearKeyEvents()
190 #if defined(PCBSKY9X)
191 CoTickDelay(100); // 200ms
192 #endif
194 // loop until all keys are up
195 #if !defined(BOOT)
196 tmr10ms_t start = get_tmr10ms();
197 #endif
199 while (keyDown()) {
201 #if defined(SIMU)
202 SIMU_SLEEP_NORET(1/*ms*/);
203 #else
204 wdt_reset();
205 #endif
207 #if !defined(BOOT)
208 if ((get_tmr10ms() - start) >= 300) { // wait no more than 3 seconds
209 //timeout expired, at least one key stuck
210 return false;
212 #endif
215 memclear(keys, sizeof(keys));
216 putEvent(0);
217 return true;
219 #else
220 void clearKeyEvents()
222 // loop until all keys are up
223 while (keyDown()) {
225 #if defined(SIMU)
226 SIMU_SLEEP(1/*ms*/);
227 #else
228 wdt_reset();
229 #endif
231 #if defined(PCBSTD) && defined(ROTARY_ENCODER_NAVIGATION) && !defined(TELEMETREZ)
232 rotencPoll();
233 #endif
236 memclear(keys, sizeof(keys));
237 putEvent(0);
239 #endif // #if defined(CPUARM)