USB modes cleanup (#5396)
[opentx.git] / radio / src / main_arm.cpp
blob49476aa8205c7b31a69b1ab0890aa65c0c1f4622
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 #if defined(STM32)
28 void onUSBConnectMenu(const char *result)
30 if (result == STR_USB_MASS_STORAGE) {
31 setSelectedUsbMode(USB_MASS_STORAGE_MODE);
33 else if (result == STR_USB_JOYSTICK) {
34 setSelectedUsbMode(USB_JOYSTICK_MODE);
36 else if (result == STR_USB_SERIAL) {
37 setSelectedUsbMode(USB_SERIAL_MODE);
40 #endif
42 void handleUsbConnection()
44 #if defined(STM32) && !defined(SIMU)
45 if (!usbStarted() && usbPlugged() && !(getSelectedUsbMode() == USB_UNSELECTED_MODE)) {
46 usbStart();
47 if (getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
48 opentxClose(false);
49 usbPluggedIn();
52 if (!usbStarted() && usbPlugged() && getSelectedUsbMode() == USB_UNSELECTED_MODE) {
53 if((g_eeGeneral.USBMode == USB_UNSELECTED_MODE) && (popupMenuNoItems == 0)) {
54 POPUP_MENU_ADD_ITEM(STR_USB_JOYSTICK);
55 POPUP_MENU_ADD_ITEM(STR_USB_MASS_STORAGE);
56 #if defined(DEBUG)
57 POPUP_MENU_ADD_ITEM(STR_USB_SERIAL);
58 #endif
59 POPUP_MENU_START(onUSBConnectMenu);
61 if (g_eeGeneral.USBMode != USB_UNSELECTED_MODE) {
62 setSelectedUsbMode(g_eeGeneral.USBMode);
65 if (usbStarted() && !usbPlugged()) {
66 usbStop();
67 if (getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
68 opentxResume();
70 #if !defined(BOOT)
71 setSelectedUsbMode(USB_UNSELECTED_MODE);
72 #endif
74 #endif // defined(STM32) && !defined(SIMU)
77 void checkSpeakerVolume()
79 if (currentSpeakerVolume != requiredSpeakerVolume) {
80 currentSpeakerVolume = requiredSpeakerVolume;
81 #if !defined(SOFTWARE_VOLUME)
82 setScaledVolume(currentSpeakerVolume);
83 #endif
87 #if defined(EEPROM)
88 void checkEeprom()
90 if (!usbPlugged()) {
91 if (eepromIsWriting())
92 eepromWriteProcess();
93 else if (TIME_TO_WRITE())
94 storageCheck(false);
97 #else
98 void checkEeprom()
100 #if defined(RAMBACKUP)
101 if (TIME_TO_RAMBACKUP()) {
102 rambackupWrite();
103 rambackupDirtyMsk = 0;
105 #endif
106 if (TIME_TO_WRITE()) {
107 storageCheck(false);
110 #endif
112 #define BAT_AVG_SAMPLES 8
114 void checkBatteryAlarms()
116 // TRACE("checkBatteryAlarms()");
117 if (IS_TXBATT_WARNING() && g_vbat100mV>50) {
118 AUDIO_TX_BATTERY_LOW();
119 // TRACE("checkBatteryAlarms(): battery low");
121 #if defined(PCBSKY9X)
122 else if (g_eeGeneral.temperatureWarn && getTemperature() >= g_eeGeneral.temperatureWarn) {
123 AUDIO_TX_TEMP_HIGH();
125 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
126 AUDIO_TX_MAH_HIGH();
128 #endif
131 void checkBattery()
133 static uint32_t batSum;
134 static uint8_t sampleCount;
135 // filter battery voltage by averaging it
136 if (g_vbat100mV == 0) {
137 g_vbat100mV = (getBatteryVoltage() + 5) / 10;
138 batSum = 0;
139 sampleCount = 0;
141 else {
142 batSum += getBatteryVoltage();
143 // TRACE("checkBattery(): sampled = %d", getBatteryVoltage());
144 if (++sampleCount >= BAT_AVG_SAMPLES) {
145 g_vbat100mV = (batSum + BAT_AVG_SAMPLES * 5 ) / (BAT_AVG_SAMPLES * 10);
146 batSum = 0;
147 sampleCount = 0;
148 // TRACE("checkBattery(): g_vbat100mV = %d", g_vbat100mV);
153 void periodicTick_1s()
155 checkBattery();
158 void periodicTick_10s()
160 checkBatteryAlarms();
161 #if defined(LUA)
162 checkLuaMemoryUsage();
163 #endif
166 void periodicTick()
168 static uint8_t count10s;
169 static uint32_t lastTime;
170 if ( (get_tmr10ms() - lastTime) >= 100 ) {
171 lastTime += 100;
172 periodicTick_1s();
173 if (++count10s >= 10) {
174 count10s = 0;
175 periodicTick_10s();
180 #if defined(GUI) && defined(COLORLCD)
181 void guiMain(event_t evt)
183 bool refreshNeeded = false;
185 #if defined(LUA)
186 uint32_t t0 = get_tmr10ms();
187 static uint32_t lastLuaTime = 0;
188 uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
189 lastLuaTime = t0;
190 if (interval > maxLuaInterval) {
191 maxLuaInterval = interval;
194 // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
195 DEBUG_TIMER_START(debugTimerLuaBg);
196 luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
197 DEBUG_TIMER_STOP(debugTimerLuaBg);
198 // wait for LCD DMA to finish before continuing, because code from this point
199 // is allowed to change the contents of LCD buffer
201 // WARNING: make sure no code above this line does any change to the LCD display buffer!
203 DEBUG_TIMER_START(debugTimerLcdRefreshWait);
204 lcdRefreshWait();
205 DEBUG_TIMER_STOP(debugTimerLcdRefreshWait);
207 // draw LCD from menus or from Lua script
208 // run Lua scripts that use LCD
210 DEBUG_TIMER_START(debugTimerLuaFg);
211 refreshNeeded = luaTask(evt, RUN_STNDAL_SCRIPT, true);
212 if (!refreshNeeded) {
213 refreshNeeded = luaTask(evt, RUN_TELEM_FG_SCRIPT, true);
215 DEBUG_TIMER_STOP(debugTimerLuaFg);
217 t0 = get_tmr10ms() - t0;
218 if (t0 > maxLuaDuration) {
219 maxLuaDuration = t0;
221 #else
222 lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
223 #endif
225 if (!refreshNeeded) {
226 DEBUG_TIMER_START(debugTimerMenus);
227 while (1) {
228 // normal GUI from menus
229 const char * warn = warningText;
230 uint8_t menu = popupMenuNoItems;
232 static bool popupDisplayed = false;
233 if (warn || menu) {
234 if (popupDisplayed == false) {
235 menuHandlers[menuLevel](EVT_REFRESH);
236 lcdDrawBlackOverlay();
237 TIME_MEASURE_START(storebackup);
238 lcdStoreBackupBuffer();
239 TIME_MEASURE_STOP(storebackup);
241 if (popupDisplayed == false || evt) {
242 popupDisplayed = lcdRestoreBackupBuffer();
243 if (warn) DISPLAY_WARNING(evt);
244 if (menu) {
245 const char * result = runPopupMenu(evt);
246 if (result) {
247 popupMenuHandler(result);
248 if (menuEvent == 0) {
249 evt = EVT_REFRESH;
250 continue;
254 refreshNeeded = true;
257 else {
258 if (popupDisplayed) {
259 if (evt == 0) {
260 evt = EVT_REFRESH;
262 popupDisplayed = false;
264 DEBUG_TIMER_START(debugTimerMenuHandlers);
265 refreshNeeded = menuHandlers[menuLevel](evt);
266 DEBUG_TIMER_STOP(debugTimerMenuHandlers);
269 if (menuEvent == EVT_ENTRY) {
270 menuVerticalPosition = 0;
271 menuHorizontalPosition = 0;
272 evt = menuEvent;
273 menuEvent = 0;
275 else if (menuEvent == EVT_ENTRY_UP) {
276 menuVerticalPosition = menuVerticalPositions[menuLevel];
277 menuHorizontalPosition = 0;
278 evt = menuEvent;
279 menuEvent = 0;
281 else {
282 break;
285 DEBUG_TIMER_STOP(debugTimerMenus);
288 if (refreshNeeded) {
289 DEBUG_TIMER_START(debugTimerLcdRefresh);
290 lcdRefresh();
291 DEBUG_TIMER_STOP(debugTimerLcdRefresh);
294 #elif defined(GUI)
296 void handleGui(event_t event) {
297 // if Lua standalone, run it and don't clear the screen (Lua will do it)
298 // else if Lua telemetry view, run it and don't clear the screen
299 // else clear scren and show normal menus
300 #if defined(LUA)
301 if (luaTask(event, RUN_STNDAL_SCRIPT, true)) {
302 // standalone script is active
304 else if (luaTask(event, RUN_TELEM_FG_SCRIPT, true)) {
305 // the telemetry screen is active
306 // prevent events from keys MENU, UP, DOWN, ENT(short) and EXIT(short) from reaching the normal menus,
307 // so Lua telemetry script can fully use them
308 if (event) {
309 uint8_t key = EVT_KEY_MASK(event);
310 // no need to filter out MENU and ENT(short), because they are not used by menuViewTelemetryFrsky()
311 if (key == KEY_PLUS || key == KEY_MINUS || (!IS_KEY_LONG(event) && key == KEY_EXIT)) {
312 // TRACE("Telemetry script event 0x%02x killed", event);
313 event = 0;
316 menuHandlers[menuLevel](event);
317 // todo drawStatusLine(); here???
319 else
320 #endif
322 lcdClear();
323 menuHandlers[menuLevel](event);
324 drawStatusLine();
328 bool inPopupMenu = false;
330 void guiMain(event_t evt)
332 #if defined(LUA)
333 // TODO better lua stopwatch
334 uint32_t t0 = get_tmr10ms();
335 static uint32_t lastLuaTime = 0;
336 uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
337 lastLuaTime = t0;
338 if (interval > maxLuaInterval) {
339 maxLuaInterval = interval;
342 // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
343 luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
345 t0 = get_tmr10ms() - t0;
346 if (t0 > maxLuaDuration) {
347 maxLuaDuration = t0;
349 #endif //#if defined(LUA)
351 // wait for LCD DMA to finish before continuing, because code from this point
352 // is allowed to change the contents of LCD buffer
354 // WARNING: make sure no code above this line does any change to the LCD display buffer!
356 lcdRefreshWait();
358 if (menuEvent) {
359 // we have a popupMenuActive entry or exit event
360 menuVerticalPosition = (menuEvent == EVT_ENTRY_UP) ? menuVerticalPositions[menuLevel] : 0;
361 menuHorizontalPosition = 0;
362 evt = menuEvent;
363 menuEvent = 0;
366 if (warningText) {
367 // show warning on top of the normal menus
368 handleGui(0); // suppress events, they are handled by the warning
369 DISPLAY_WARNING(evt);
371 else if (popupMenuNoItems > 0) {
372 // popup menu is active display it on top of normal menus
373 handleGui(0); // suppress events, they are handled by the popup
374 if (!inPopupMenu) {
375 TRACE("Popup Menu started");
376 inPopupMenu = true;
378 const char * result = runPopupMenu(evt);
379 if (result) {
380 TRACE("popupMenuHandler(%s)", result);
381 popupMenuHandler(result);
384 else {
385 // normal menus
386 if (inPopupMenu) {
387 TRACE("Popup Menu ended");
388 inPopupMenu = false;
390 handleGui(evt);
393 lcdRefresh();
395 #endif
397 void perMain()
399 DEBUG_TIMER_START(debugTimerPerMain1);
400 #if defined(PCBSKY9X) && !defined(REVA)
401 calcConsumption();
402 #endif
403 checkSpeakerVolume();
404 checkEeprom();
405 logsWrite();
406 handleUsbConnection();
407 checkTrainerSettings();
408 periodicTick();
409 DEBUG_TIMER_STOP(debugTimerPerMain1);
411 if (mainRequestFlags & (1 << REQUEST_FLIGHT_RESET)) {
412 TRACE("Executing requested Flight Reset");
413 flightReset();
414 mainRequestFlags &= ~(1 << REQUEST_FLIGHT_RESET);
417 event_t evt = getEvent(false);
418 if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) {
419 // on keypress turn the light on
420 backlightOn();
422 doLoopCommonActions();
423 #if defined(NAVIGATION_STICKS)
424 uint8_t sticks_evt = getSticksNavigationEvent();
425 if (sticks_evt) {
426 evt = sticks_evt;
428 #endif
430 #if defined(RAMBACKUP)
431 if (unexpectedShutdown) {
432 drawFatalErrorScreen(STR_EMERGENCY_MODE);
433 return;
435 #endif
437 #if defined(STM32)
438 static bool sdcard_present_before = SD_CARD_PRESENT();
439 bool sdcard_present_now = SD_CARD_PRESENT();
440 if (sdcard_present_now && !sdcard_present_before) {
441 sdMount();
443 sdcard_present_before = sdcard_present_now;
444 #endif
446 #if !defined(EEPROM)
447 // In case the SD card is removed during the session
448 if (!SD_CARD_PRESENT() && !unexpectedShutdown) {
449 drawFatalErrorScreen(STR_NO_SDCARD);
450 return;
452 #endif
454 #if defined(STM32)
455 if (usbPlugged() && getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
456 // disable access to menus
457 lcdClear();
458 menuMainView(0);
459 lcdRefresh();
460 return;
462 #endif
464 #if defined(GUI)
465 DEBUG_TIMER_START(debugTimerGuiMain);
466 guiMain(evt);
467 DEBUG_TIMER_STOP(debugTimerGuiMain);
468 #endif
470 #if defined(PCBTARANIS)
471 if (mainRequestFlags & (1 << REQUEST_SCREENSHOT)) {
472 writeScreenshot();
473 mainRequestFlags &= ~(1 << REQUEST_SCREENSHOT);
475 #endif
477 #if defined(PCBX9E) && !defined(SIMU)
478 toplcdRefreshStart();
479 setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.toplcdTimer));
480 setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer);
481 setTopRssi(TELEMETRY_RSSI());
482 setTopBatteryValue(g_vbat100mV);
483 setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING());
484 toplcdRefreshEnd();
485 #endif
487 #if defined(INTERNAL_GPS)
488 gpsWakeup();
489 #endif