Fix doc path
[opentx.git] / radio / src / keys.cpp
blob1f9752c3a0bd816bf3261fa7008bc4e652b4e145
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 if (!IS_SHIFT_KEY(key()))
131 putEvent(EVT_KEY_REPT(key()));
133 break;
135 case KSTATE_PAUSE: //pause repeat events
136 if (m_cnt >= KEY_REPEAT_PAUSE_DELAY) {
137 m_state = 8;
138 m_cnt = 0;
140 break;
142 case KSTATE_KILLED: //killed
143 break;
147 void Key::pauseEvents()
149 m_state = KSTATE_PAUSE;
150 m_cnt = 0;
153 void Key::killEvents()
155 // TRACE("key %d killed", key());
156 m_state = KSTATE_KILLED;
160 uint8_t Key::key() const
162 return (this - keys);
165 // Introduce a slight delay in the key repeat sequence
166 void pauseEvents(event_t event)
168 event = EVT_KEY_MASK(event);
169 if (event < (int)DIM(keys)) keys[event].pauseEvents();
172 // Disables any further event generation (BREAK and REPEAT) for this key, until the key is released
173 void killEvents(event_t event)
175 #if defined(ROTARY_ENCODERS)
176 if (event == EVT_ROTARY_LONG) {
177 killEvents(BTN_REa + g_eeGeneral.reNavigation - 1);
178 return;
180 #endif
182 event = EVT_KEY_MASK(event);
183 if (event < (int)DIM(keys)) {
184 keys[event].killEvents();
188 #if defined(CPUARM)
189 bool clearKeyEvents()
191 #if defined(PCBSKY9X)
192 CoTickDelay(100); // 200ms
193 #endif
195 // loop until all keys are up
196 #if !defined(BOOT)
197 tmr10ms_t start = get_tmr10ms();
198 #endif
200 while (keyDown()) {
202 #if defined(SIMU)
203 SIMU_SLEEP_NORET(1/*ms*/);
204 #else
205 wdt_reset();
206 #endif
208 #if !defined(BOOT)
209 if ((get_tmr10ms() - start) >= 300) { // wait no more than 3 seconds
210 //timeout expired, at least one key stuck
211 return false;
213 #endif
216 memclear(keys, sizeof(keys));
217 putEvent(0);
218 return true;
220 #else
221 void clearKeyEvents()
223 // loop until all keys are up
224 while (keyDown()) {
226 #if defined(SIMU)
227 SIMU_SLEEP(1/*ms*/);
228 #else
229 wdt_reset();
230 #endif
232 #if defined(PCBSTD) && defined(ROTARY_ENCODER_NAVIGATION) && !defined(TELEMETREZ)
233 rotencPoll();
234 #endif
237 memclear(keys, sizeof(keys));
238 putEvent(0);
240 #endif // #if defined(CPUARM)