Taranis Q X7 optimized wizard (#5198)
[opentx.git] / radio / src / main_arm.cpp
blob35a165174c38b38a31a226971ed663acf07384b3
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 uint8_t currentSpeakerVolume = 255;
24 uint8_t requiredSpeakerVolume = 255;
25 uint8_t mainRequestFlags = 0;
27 void handleUsbConnection()
29 #if defined(STM32) && !defined(SIMU)
30 if (!usbStarted() && usbPlugged()) {
31 usbStart();
32 #if defined(USB_MASS_STORAGE)
33 opentxClose(false);
34 usbPluggedIn();
35 #endif
37 if (usbStarted() && !usbPlugged()) {
38 usbStop();
39 #if defined(USB_MASS_STORAGE) && !defined(EEPROM)
40 opentxResume();
41 #endif
43 #endif // defined(STM32) && !defined(SIMU)
46 void checkSpeakerVolume()
48 if (currentSpeakerVolume != requiredSpeakerVolume) {
49 currentSpeakerVolume = requiredSpeakerVolume;
50 #if !defined(SOFTWARE_VOLUME)
51 setScaledVolume(currentSpeakerVolume);
52 #endif
56 #if defined(EEPROM)
57 void checkEeprom()
59 if (!usbPlugged()) {
60 if (eepromIsWriting())
61 eepromWriteProcess();
62 else if (TIME_TO_WRITE())
63 storageCheck(false);
66 #else
67 void checkEeprom()
69 #if defined(RAMBACKUP)
70 if (TIME_TO_RAMBACKUP()) {
71 rambackupWrite();
72 rambackupDirtyMsk = 0;
74 #endif
75 if (TIME_TO_WRITE()) {
76 storageCheck(false);
79 #endif
81 #define BAT_AVG_SAMPLES 8
83 void checkBatteryAlarms()
85 // TRACE("checkBatteryAlarms()");
86 if (IS_TXBATT_WARNING() && g_vbat100mV>50) {
87 AUDIO_TX_BATTERY_LOW();
88 // TRACE("checkBatteryAlarms(): battery low");
90 #if defined(PCBSKY9X)
91 else if (g_eeGeneral.temperatureWarn && getTemperature() >= g_eeGeneral.temperatureWarn) {
92 AUDIO_TX_TEMP_HIGH();
94 else if (g_eeGeneral.mAhWarn && (g_eeGeneral.mAhUsed + Current_used * (488 + g_eeGeneral.txCurrentCalibration)/8192/36) / 500 >= g_eeGeneral.mAhWarn) { // TODO move calculation into board file
95 AUDIO_TX_MAH_HIGH();
97 #endif
100 void checkBattery()
102 static uint32_t batSum;
103 static uint8_t sampleCount;
104 // filter battery voltage by averaging it
105 if (g_vbat100mV == 0) {
106 g_vbat100mV = (getBatteryVoltage() + 5) / 10;
107 batSum = 0;
108 sampleCount = 0;
110 else {
111 batSum += getBatteryVoltage();
112 // TRACE("checkBattery(): sampled = %d", getBatteryVoltage());
113 if (++sampleCount >= BAT_AVG_SAMPLES) {
114 g_vbat100mV = (batSum + BAT_AVG_SAMPLES * 5 ) / (BAT_AVG_SAMPLES * 10);
115 batSum = 0;
116 sampleCount = 0;
117 // TRACE("checkBattery(): g_vbat100mV = %d", g_vbat100mV);
122 void periodicTick_1s()
124 checkBattery();
127 void periodicTick_10s()
129 checkBatteryAlarms();
130 #if defined(LUA)
131 checkLuaMemoryUsage();
132 #endif
135 void periodicTick()
137 static uint8_t count10s;
138 static uint32_t lastTime;
139 if ( (get_tmr10ms() - lastTime) >= 100 ) {
140 lastTime += 100;
141 periodicTick_1s();
142 if (++count10s >= 10) {
143 count10s = 0;
144 periodicTick_10s();
149 #if defined(GUI) && defined(COLORLCD)
150 void guiMain(event_t evt)
152 bool refreshNeeded = false;
154 #if defined(LUA)
155 uint32_t t0 = get_tmr10ms();
156 static uint32_t lastLuaTime = 0;
157 uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
158 lastLuaTime = t0;
159 if (interval > maxLuaInterval) {
160 maxLuaInterval = interval;
163 // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
164 DEBUG_TIMER_START(debugTimerLuaBg);
165 luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
166 DEBUG_TIMER_STOP(debugTimerLuaBg);
167 // wait for LCD DMA to finish before continuing, because code from this point
168 // is allowed to change the contents of LCD buffer
170 // WARNING: make sure no code above this line does any change to the LCD display buffer!
172 DEBUG_TIMER_START(debugTimerLcdRefreshWait);
173 lcdRefreshWait();
174 DEBUG_TIMER_STOP(debugTimerLcdRefreshWait);
176 // draw LCD from menus or from Lua script
177 // run Lua scripts that use LCD
179 DEBUG_TIMER_START(debugTimerLuaFg);
180 refreshNeeded = luaTask(evt, RUN_STNDAL_SCRIPT, true);
181 if (!refreshNeeded) {
182 refreshNeeded = luaTask(evt, RUN_TELEM_FG_SCRIPT, true);
184 DEBUG_TIMER_STOP(debugTimerLuaFg);
186 t0 = get_tmr10ms() - t0;
187 if (t0 > maxLuaDuration) {
188 maxLuaDuration = t0;
190 #else
191 lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
192 #endif
194 if (!refreshNeeded) {
195 DEBUG_TIMER_START(debugTimerMenus);
196 while (1) {
197 // normal GUI from menus
198 const char * warn = warningText;
199 uint8_t menu = popupMenuNoItems;
201 static bool popupDisplayed = false;
202 if (warn || menu) {
203 if (popupDisplayed == false) {
204 menuHandlers[menuLevel](EVT_REFRESH);
205 lcdDrawBlackOverlay();
206 TIME_MEASURE_START(storebackup);
207 lcdStoreBackupBuffer();
208 TIME_MEASURE_STOP(storebackup);
210 if (popupDisplayed == false || evt) {
211 popupDisplayed = lcdRestoreBackupBuffer();
212 if (warn) DISPLAY_WARNING(evt);
213 if (menu) {
214 const char * result = runPopupMenu(evt);
215 if (result) {
216 popupMenuHandler(result);
217 if (menuEvent == 0) {
218 evt = EVT_REFRESH;
219 continue;
223 refreshNeeded = true;
226 else {
227 if (popupDisplayed) {
228 if (evt == 0) {
229 evt = EVT_REFRESH;
231 popupDisplayed = false;
233 DEBUG_TIMER_START(debugTimerMenuHandlers);
234 refreshNeeded = menuHandlers[menuLevel](evt);
235 DEBUG_TIMER_STOP(debugTimerMenuHandlers);
238 if (menuEvent == EVT_ENTRY) {
239 menuVerticalPosition = 0;
240 menuHorizontalPosition = 0;
241 evt = menuEvent;
242 menuEvent = 0;
244 else if (menuEvent == EVT_ENTRY_UP) {
245 menuVerticalPosition = menuVerticalPositions[menuLevel];
246 menuHorizontalPosition = 0;
247 evt = menuEvent;
248 menuEvent = 0;
250 else {
251 break;
254 DEBUG_TIMER_STOP(debugTimerMenus);
257 if (refreshNeeded) {
258 DEBUG_TIMER_START(debugTimerLcdRefresh);
259 lcdRefresh();
260 DEBUG_TIMER_STOP(debugTimerLcdRefresh);
263 #elif defined(GUI)
265 void handleGui(event_t event) {
266 // if Lua standalone, run it and don't clear the screen (Lua will do it)
267 // else if Lua telemetry view, run it and don't clear the screen
268 // else clear scren and show normal menus
269 #if defined(LUA)
270 if (luaTask(event, RUN_STNDAL_SCRIPT, true)) {
271 // standalone script is active
273 else if (luaTask(event, RUN_TELEM_FG_SCRIPT, true)) {
274 // the telemetry screen is active
275 // prevent events from keys MENU, UP, DOWN, ENT(short) and EXIT(short) from reaching the normal menus,
276 // so Lua telemetry script can fully use them
277 if (event) {
278 uint8_t key = EVT_KEY_MASK(event);
279 // no need to filter out MENU and ENT(short), because they are not used by menuViewTelemetryFrsky()
280 if (key == KEY_PLUS || key == KEY_MINUS || (!IS_KEY_LONG(event) && key == KEY_EXIT)) {
281 // TRACE("Telemetry script event 0x%02x killed", event);
282 event = 0;
285 menuHandlers[menuLevel](event);
286 // todo drawStatusLine(); here???
288 else
289 #endif
291 lcdClear();
292 menuHandlers[menuLevel](event);
293 drawStatusLine();
297 bool inPopupMenu = false;
299 void guiMain(event_t evt)
301 #if defined(LUA)
302 // TODO better lua stopwatch
303 uint32_t t0 = get_tmr10ms();
304 static uint32_t lastLuaTime = 0;
305 uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
306 lastLuaTime = t0;
307 if (interval > maxLuaInterval) {
308 maxLuaInterval = interval;
311 // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
312 luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
314 t0 = get_tmr10ms() - t0;
315 if (t0 > maxLuaDuration) {
316 maxLuaDuration = t0;
318 #endif //#if defined(LUA)
320 // wait for LCD DMA to finish before continuing, because code from this point
321 // is allowed to change the contents of LCD buffer
323 // WARNING: make sure no code above this line does any change to the LCD display buffer!
325 lcdRefreshWait();
327 if (menuEvent) {
328 // we have a popupMenuActive entry or exit event
329 menuVerticalPosition = (menuEvent == EVT_ENTRY_UP) ? menuVerticalPositions[menuLevel] : 0;
330 menuHorizontalPosition = 0;
331 evt = menuEvent;
332 menuEvent = 0;
335 if (warningText) {
336 // show warning on top of the normal menus
337 handleGui(0); // suppress events, they are handled by the warning
338 DISPLAY_WARNING(evt);
340 else if (popupMenuNoItems > 0) {
341 // popup menu is active display it on top of normal menus
342 handleGui(0); // suppress events, they are handled by the popup
343 if (!inPopupMenu) {
344 TRACE("Popup Menu started");
345 inPopupMenu = true;
347 const char * result = runPopupMenu(evt);
348 if (result) {
349 TRACE("popupMenuHandler(%s)", result);
350 popupMenuHandler(result);
353 else {
354 // normal menus
355 if (inPopupMenu) {
356 TRACE("Popup Menu ended");
357 inPopupMenu = false;
359 handleGui(evt);
362 lcdRefresh();
364 #endif
366 void perMain()
368 DEBUG_TIMER_START(debugTimerPerMain1);
369 #if defined(PCBSKY9X) && !defined(REVA)
370 calcConsumption();
371 #endif
372 checkSpeakerVolume();
373 checkEeprom();
374 logsWrite();
375 handleUsbConnection();
376 checkTrainerSettings();
377 periodicTick();
378 DEBUG_TIMER_STOP(debugTimerPerMain1);
380 if (mainRequestFlags & (1 << REQUEST_FLIGHT_RESET)) {
381 TRACE("Executing requested Flight Reset");
382 flightReset();
383 mainRequestFlags &= ~(1 << REQUEST_FLIGHT_RESET);
386 event_t evt = getEvent(false);
387 if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) {
388 // on keypress turn the light on
389 backlightOn();
391 doLoopCommonActions();
392 #if defined(NAVIGATION_STICKS)
393 uint8_t sticks_evt = getSticksNavigationEvent();
394 if (sticks_evt) {
395 evt = sticks_evt;
397 #endif
399 #if defined(RAMBACKUP)
400 if (unexpectedShutdown) {
401 drawFatalErrorScreen(STR_EMERGENCY_MODE);
402 return;
404 #endif
406 #if defined(PCBHORUS)
407 // TODO if it is OK on HORUS it could be ported to all other boards
408 // But in this case it's needed to define sdMount for all boards, because sdInit also initializes the SD mutex
409 static uint32_t sdcard_present_before = SD_CARD_PRESENT();
410 uint32_t sdcard_present_now = SD_CARD_PRESENT();
411 if (sdcard_present_now && !sdcard_present_before) {
412 sdMount();
414 sdcard_present_before = sdcard_present_now;
415 #endif
417 #if !defined(EEPROM)
418 // In case the SD card is removed during the session
419 if (!SD_CARD_PRESENT() && !unexpectedShutdown) {
420 drawFatalErrorScreen(STR_NO_SDCARD);
421 return;
423 #endif
425 #if defined(USB_MASS_STORAGE)
426 if (usbPlugged()) {
427 // disable access to menus
428 lcdClear();
429 menuMainView(0);
430 lcdRefresh();
431 return;
433 #endif
435 #if defined(GUI)
436 DEBUG_TIMER_START(debugTimerGuiMain);
437 guiMain(evt);
438 DEBUG_TIMER_STOP(debugTimerGuiMain);
439 #endif
441 #if defined(PCBTARANIS)
442 if (mainRequestFlags & (1 << REQUEST_SCREENSHOT)) {
443 writeScreenshot();
444 mainRequestFlags &= ~(1 << REQUEST_SCREENSHOT);
446 #endif
448 #if defined(PCBX9E) && !defined(SIMU)
449 toplcdRefreshStart();
450 setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.toplcdTimer));
451 setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer);
452 setTopRssi(TELEMETRY_RSSI());
453 setTopBatteryValue(g_vbat100mV);
454 setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING());
455 toplcdRefreshEnd();
456 #endif
458 #if defined(INTERNAL_GPS)
459 gpsWakeup();
460 #endif