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.
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()) {
32 #if defined(USB_MASS_STORAGE)
37 if (usbStarted() && !usbPlugged()) {
39 #if defined(USB_MASS_STORAGE) && !defined(EEPROM)
43 #endif // defined(STM32) && !defined(SIMU)
46 void checkSpeakerVolume()
48 if (currentSpeakerVolume
!= requiredSpeakerVolume
) {
49 currentSpeakerVolume
= requiredSpeakerVolume
;
50 #if !defined(SOFTWARE_VOLUME)
51 setScaledVolume(currentSpeakerVolume
);
60 if (eepromIsWriting())
62 else if (TIME_TO_WRITE())
69 #if defined(RAMBACKUP)
70 if (TIME_TO_RAMBACKUP()) {
72 rambackupDirtyMsk
= 0;
75 if (TIME_TO_WRITE()) {
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");
91 else if (g_eeGeneral
.temperatureWarn
&& getTemperature() >= g_eeGeneral
.temperatureWarn
) {
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
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;
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);
117 // TRACE("checkBattery(): g_vbat100mV = %d", g_vbat100mV);
122 void periodicTick_1s()
127 void periodicTick_10s()
129 checkBatteryAlarms();
131 checkLuaMemoryUsage();
137 static uint8_t count10s
;
138 static uint32_t lastTime
;
139 if ( (get_tmr10ms() - lastTime
) >= 100 ) {
142 if (++count10s
>= 10) {
149 #if defined(GUI) && defined(COLORLCD)
150 void guiMain(event_t evt
)
152 bool refreshNeeded
= false;
155 uint32_t t0
= get_tmr10ms();
156 static uint32_t lastLuaTime
= 0;
157 uint16_t interval
= (lastLuaTime
== 0 ? 0 : (t0
- lastLuaTime
));
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
);
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
) {
191 lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
194 if (!refreshNeeded
) {
195 DEBUG_TIMER_START(debugTimerMenus
);
197 // normal GUI from menus
198 const char * warn
= warningText
;
199 uint8_t menu
= popupMenuNoItems
;
201 static bool popupDisplayed
= false;
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
);
214 const char * result
= runPopupMenu(evt
);
216 popupMenuHandler(result
);
217 if (menuEvent
== 0) {
223 refreshNeeded
= true;
227 if (popupDisplayed
) {
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;
244 else if (menuEvent
== EVT_ENTRY_UP
) {
245 menuVerticalPosition
= menuVerticalPositions
[menuLevel
];
246 menuHorizontalPosition
= 0;
254 DEBUG_TIMER_STOP(debugTimerMenus
);
258 DEBUG_TIMER_START(debugTimerLcdRefresh
);
260 DEBUG_TIMER_STOP(debugTimerLcdRefresh
);
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
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
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);
285 menuHandlers
[menuLevel
](event
);
286 // todo drawStatusLine(); here???
292 menuHandlers
[menuLevel
](event
);
297 bool inPopupMenu
= false;
299 void guiMain(event_t evt
)
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
));
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
) {
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!
328 // we have a popupMenuActive entry or exit event
329 menuVerticalPosition
= (menuEvent
== EVT_ENTRY_UP
) ? menuVerticalPositions
[menuLevel
] : 0;
330 menuHorizontalPosition
= 0;
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
344 TRACE("Popup Menu started");
347 const char * result
= runPopupMenu(evt
);
349 TRACE("popupMenuHandler(%s)", result
);
350 popupMenuHandler(result
);
356 TRACE("Popup Menu ended");
368 DEBUG_TIMER_START(debugTimerPerMain1
);
369 #if defined(PCBSKY9X) && !defined(REVA)
372 checkSpeakerVolume();
375 handleUsbConnection();
376 checkTrainerSettings();
378 DEBUG_TIMER_STOP(debugTimerPerMain1
);
380 if (mainRequestFlags
& (1 << REQUEST_FLIGHT_RESET
)) {
381 TRACE("Executing requested Flight Reset");
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
391 doLoopCommonActions();
392 #if defined(NAVIGATION_STICKS)
393 uint8_t sticks_evt
= getSticksNavigationEvent();
399 #if defined(RAMBACKUP)
400 if (unexpectedShutdown
) {
401 drawFatalErrorScreen(STR_EMERGENCY_MODE
);
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
) {
414 sdcard_present_before
= sdcard_present_now
;
418 // In case the SD card is removed during the session
419 if (!SD_CARD_PRESENT() && !unexpectedShutdown
) {
420 drawFatalErrorScreen(STR_NO_SDCARD
);
425 #if defined(USB_MASS_STORAGE)
427 // disable access to menus
436 DEBUG_TIMER_START(debugTimerGuiMain
);
438 DEBUG_TIMER_STOP(debugTimerGuiMain
);
441 #if defined(PCBTARANIS)
442 if (mainRequestFlags
& (1 << REQUEST_SCREENSHOT
)) {
444 mainRequestFlags
&= ~(1 << REQUEST_SCREENSHOT
);
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());
458 #if defined(INTERNAL_GPS)