mirror of
https://github.com/opentx/opentx.git
synced 2025-07-24 00:35:18 +03:00
385 lines
9.9 KiB
C++
385 lines
9.9 KiB
C++
/*
|
|
* Copyright (C) OpenTX
|
|
*
|
|
* Based on code named
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "opentx.h"
|
|
|
|
uint8_t currentSpeakerVolume = 255;
|
|
uint8_t requiredSpeakerVolume = 255;
|
|
uint8_t requestScreenshot = false;
|
|
|
|
void handleUsbConnection()
|
|
{
|
|
#if defined(CPUSTM32) && !defined(SIMU)
|
|
static bool usbStarted = false;
|
|
|
|
if (!usbStarted && usbPlugged()) {
|
|
usbStarted = true;
|
|
|
|
/*
|
|
We used to initialize USB peripheral and driver here.
|
|
According to my tests this is way too late. The USB peripheral
|
|
therefore does not have enough information to start responding to
|
|
USB host request, which causes very slow USB device recognition,
|
|
multiple USB device resets, etc...
|
|
|
|
If we want to change the USB profile, the procedure is simple:
|
|
* USB cable must be disconnected
|
|
* call usbDeInit();
|
|
* call usbUnit(); which initializes USB with the new profile.
|
|
Obviously the usbInit() should be modified to have a runtime
|
|
selection of the USB profile.
|
|
*/
|
|
|
|
#if defined(USB_MASS_STORAGE)
|
|
opentxClose();
|
|
usbPluggedIn();
|
|
#endif
|
|
}
|
|
if (usbStarted && !usbPlugged()) {
|
|
usbStarted = false;
|
|
}
|
|
|
|
#if defined(USB_JOYSTICK)
|
|
if (usbStarted ) {
|
|
usbJoystickUpdate();
|
|
}
|
|
#endif
|
|
|
|
#endif // defined(CPUSTM32) && !defined(SIMU)
|
|
}
|
|
|
|
void checkSpeakerVolume()
|
|
{
|
|
if (currentSpeakerVolume != requiredSpeakerVolume) {
|
|
currentSpeakerVolume = requiredSpeakerVolume;
|
|
setScaledVolume(currentSpeakerVolume);
|
|
}
|
|
}
|
|
|
|
#if defined(EEPROM)
|
|
void checkEeprom()
|
|
{
|
|
if (!usbPlugged()) {
|
|
if (eepromIsWriting())
|
|
eepromWriteProcess();
|
|
else if (TIME_TO_WRITE())
|
|
storageCheck(false);
|
|
}
|
|
}
|
|
#else
|
|
void checkEeprom()
|
|
{
|
|
#if defined(RAMBACKUP)
|
|
if (TIME_TO_RAMBACKUP()) {
|
|
rambackupWrite();
|
|
rambackupDirtyMsk = 0;
|
|
}
|
|
#endif
|
|
if (TIME_TO_WRITE()) {
|
|
storageCheck(false);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(GUI) && defined(COLORLCD)
|
|
void guiMain(evt_t evt)
|
|
{
|
|
bool refreshNeeded = false;
|
|
|
|
#if defined(LUA)
|
|
uint32_t t0 = get_tmr10ms();
|
|
static uint32_t lastLuaTime = 0;
|
|
uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
|
|
lastLuaTime = t0;
|
|
if (interval > maxLuaInterval) {
|
|
maxLuaInterval = interval;
|
|
}
|
|
|
|
// run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
|
|
luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
|
|
|
|
// wait for LCD DMA to finish before continuing, because code from this point
|
|
// is allowed to change the contents of LCD buffer
|
|
//
|
|
// WARNING: make sure no code above this line does any change to the LCD display buffer!
|
|
//
|
|
lcdRefreshWait();
|
|
|
|
// draw LCD from menus or from Lua script
|
|
// run Lua scripts that use LCD
|
|
|
|
refreshNeeded = luaTask(evt, RUN_STNDAL_SCRIPT, true);
|
|
if (!refreshNeeded) {
|
|
refreshNeeded = luaTask(evt, RUN_TELEM_FG_SCRIPT, true);
|
|
}
|
|
|
|
t0 = get_tmr10ms() - t0;
|
|
if (t0 > maxLuaDuration) {
|
|
maxLuaDuration = t0;
|
|
}
|
|
#else
|
|
lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
|
|
#endif
|
|
|
|
if (!refreshNeeded) {
|
|
while (1) {
|
|
// normal GUI from menus
|
|
const char * warn = warningText;
|
|
uint8_t menu = popupMenuNoItems;
|
|
|
|
static bool popupDisplayed = false;
|
|
if (warn || menu) {
|
|
if (popupDisplayed == false) {
|
|
menuHandlers[menuLevel](EVT_REFRESH);
|
|
lcdDrawBlackOverlay();
|
|
TIME_MEASURE_START(storebackup);
|
|
lcdStoreBackupBuffer();
|
|
TIME_MEASURE_STOP(storebackup);
|
|
}
|
|
if (popupDisplayed == false || evt) {
|
|
popupDisplayed = lcdRestoreBackupBuffer();
|
|
if (warn) DISPLAY_WARNING(evt);
|
|
if (menu) {
|
|
const char * result = displayPopupMenu(evt);
|
|
if (result) {
|
|
popupMenuHandler(result);
|
|
if (menuEvent == 0) {
|
|
evt = EVT_REFRESH;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
refreshNeeded = true;
|
|
}
|
|
}
|
|
else {
|
|
if (popupDisplayed) {
|
|
if (evt == 0) {
|
|
evt = EVT_REFRESH;
|
|
}
|
|
popupDisplayed = false;
|
|
}
|
|
refreshNeeded = menuHandlers[menuLevel](evt);
|
|
}
|
|
|
|
if (menuEvent == EVT_ENTRY) {
|
|
menuVerticalPosition = -1;
|
|
menuHorizontalPosition = 0;
|
|
evt = menuEvent;
|
|
menuEvent = 0;
|
|
}
|
|
else if (menuEvent == EVT_ENTRY_UP) {
|
|
menuVerticalPosition = menuVerticalPositions[menuLevel];
|
|
menuHorizontalPosition = 0;
|
|
evt = menuEvent;
|
|
menuEvent = 0;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (refreshNeeded) {
|
|
lcdRefresh();
|
|
}
|
|
}
|
|
#elif defined(GUI)
|
|
|
|
void handleGui(uint8_t event) {
|
|
// if Lua standalone, run it and don't clear the screen (Lua will do it)
|
|
// else if Lua telemetry view, run it and don't clear the screen
|
|
// else clear scren and show normal menus
|
|
#if defined(LUA)
|
|
if (luaTask(event, RUN_STNDAL_SCRIPT, true)) {
|
|
// standalone script is active
|
|
}
|
|
else if (luaTask(event, RUN_TELEM_FG_SCRIPT, true)) {
|
|
// the telemetry screen is active
|
|
// prevent events from keys MENU, UP, DOWN, ENT(short) and EXIT(short) from reaching the normal menus,
|
|
// so Lua telemetry script can fully use them
|
|
if (event) {
|
|
uint8_t key = EVT_KEY_MASK(event);
|
|
// no need to filter out MENU and ENT(short), because they are not used by menuTelemetryFrsky()
|
|
if (key == KEY_PLUS || key == KEY_MINUS || (!IS_KEY_LONG(event) && key == KEY_EXIT)) {
|
|
// TRACE("Telemetry script event 0x%02x killed", event);
|
|
event = 0;
|
|
}
|
|
}
|
|
menuHandlers[menuLevel](event);
|
|
// todo drawStatusLine(); here???
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
lcdClear();
|
|
menuHandlers[menuLevel](event);
|
|
drawStatusLine();
|
|
}
|
|
}
|
|
|
|
bool inPopupMenu = false;
|
|
|
|
void guiMain(evt_t evt)
|
|
{
|
|
#if defined(LUA)
|
|
// TODO better lua stopwatch
|
|
uint32_t t0 = get_tmr10ms();
|
|
static uint32_t lastLuaTime = 0;
|
|
uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
|
|
lastLuaTime = t0;
|
|
if (interval > maxLuaInterval) {
|
|
maxLuaInterval = interval;
|
|
}
|
|
|
|
// run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
|
|
luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
|
|
|
|
t0 = get_tmr10ms() - t0;
|
|
if (t0 > maxLuaDuration) {
|
|
maxLuaDuration = t0;
|
|
}
|
|
#endif //#if defined(LUA)
|
|
|
|
// wait for LCD DMA to finish before continuing, because code from this point
|
|
// is allowed to change the contents of LCD buffer
|
|
//
|
|
// WARNING: make sure no code above this line does any change to the LCD display buffer!
|
|
//
|
|
lcdRefreshWait();
|
|
|
|
if (menuEvent) {
|
|
// we have a popupMenuActive entry or exit event
|
|
menuVerticalPosition = (menuEvent == EVT_ENTRY_UP) ? menuVerticalPositions[menuLevel] : 0;
|
|
menuHorizontalPosition = 0;
|
|
evt = menuEvent;
|
|
if (menuEvent == EVT_ENTRY_UP) {
|
|
TRACE("menuEvent EVT_ENTRY_UP");
|
|
}
|
|
// else if (menuEvent == EVT_MENU_UP) {
|
|
// TRACE("menuEvent EVT_MENU_UP");
|
|
// }
|
|
else if (menuEvent == EVT_ENTRY) {
|
|
TRACE("menuEvent EVT_ENTRY");
|
|
}
|
|
else {
|
|
TRACE("menuEvent 0x%02x", menuEvent);
|
|
}
|
|
menuEvent = 0;
|
|
AUDIO_MENUS();
|
|
}
|
|
|
|
if (warningText) {
|
|
// show warning on top of the normal menus
|
|
handleGui(0); // suppress events, they are handled by the warning
|
|
DISPLAY_WARNING(evt);
|
|
}
|
|
else if (popupMenuNoItems > 0) {
|
|
// popup menu is active display it on top of normal menus
|
|
handleGui(0); // suppress events, they are handled by the popup
|
|
if (!inPopupMenu) {
|
|
TRACE("Popup Menu started");
|
|
inPopupMenu = true;
|
|
}
|
|
const char * result = displayPopupMenu(evt);
|
|
if (result) {
|
|
TRACE("popupMenuHandler(%s)", result);
|
|
popupMenuHandler(result);
|
|
}
|
|
}
|
|
else {
|
|
// normal menus
|
|
if (inPopupMenu) {
|
|
TRACE("Popup Menu ended");
|
|
inPopupMenu = false;
|
|
}
|
|
handleGui(evt);
|
|
}
|
|
|
|
lcdRefresh();
|
|
}
|
|
#endif
|
|
|
|
void perMain()
|
|
{
|
|
#if defined(PCBSKY9X) && !defined(REVA)
|
|
calcConsumption();
|
|
#endif
|
|
checkSpeakerVolume();
|
|
checkEeprom();
|
|
sdMountPoll();
|
|
writeLogs();
|
|
handleUsbConnection();
|
|
checkTrainerSettings();
|
|
checkBattery();
|
|
|
|
evt_t evt = getEvent(false);
|
|
if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on
|
|
doLoopCommonActions();
|
|
#if defined(NAVIGATION_STICKS)
|
|
uint8_t sticks_evt = getSticksNavigationEvent();
|
|
if (sticks_evt) evt = sticks_evt;
|
|
#endif
|
|
|
|
#if defined(RAMBACKUP)
|
|
if (unexpectedShutdown) {
|
|
lcd->clear();
|
|
lcdDrawText(LCD_W/2, LCD_H/2-20, "EMERGENCY MODE", DBLSIZE|CENTERED|TEXT_BGCOLOR);
|
|
lcdRefresh();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(USB_MASS_STORAGE)
|
|
if (usbPlugged()) {
|
|
// disable access to menus
|
|
lcdClear();
|
|
menuMainView(0);
|
|
lcdRefresh();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(GUI)
|
|
guiMain(evt);
|
|
#endif
|
|
|
|
#if defined(PCBTARANIS)
|
|
if (requestScreenshot) {
|
|
requestScreenshot = false;
|
|
writeScreenshot();
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCBTARANIS) && defined(REV9E) && !defined(SIMU)
|
|
toplcdRefreshStart();
|
|
setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.toplcdTimer));
|
|
setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer);
|
|
setTopRssi(TELEMETRY_RSSI());
|
|
setTopBatteryValue(g_vbat100mV);
|
|
setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING());
|
|
toplcdRefreshEnd();
|
|
#endif
|
|
|
|
#if defined(PCBTARANIS) && defined(REV9E) && !defined(SIMU)
|
|
bluetoothWakeup();
|
|
#endif
|
|
|
|
}
|