1
0
forked from me/IronOS
Files
IronOS/source/Core/Threads/GUIThread.cpp
Ben V. Brown baf2f26e59 Big overhaul of the UI framework (#1749)
* Starting GUI render refactor to be more immediate mode

Update TemperatureAdjust.cpp

.

Cleanup Soldering

Sleep

SolderingProfiles

Soldering Rework

Rough pass GUI

Temp Adjust

Cleanup old OperatingMode

Debug Menu

* Update TemperatureAdjust.cpp

* Roughing some transition work

* Fixup! Hook in the init starter helper

* Better home screen button handler

* FIXUP! Fix typo's

.

* Update SettingsMenu.cpp

* More settings rework

* More settings rendering

* Fixup

* Transitions

Update SolderingProfile.cpp

Hook in transistions

* Update TemperatureAdjust.cpp

* Update push.yml

* Add auto-repeat to settings menu

* Miniware: Use IT for I2C writes

* Update USBPDDebug_HUSB238.cpp

* Force write screen on side animation cancel

.

* Refactor moving down the settings list

* Update settingsGUI.cpp

* Update I2C_Wrapper.cpp

* Update OLED.cpp

* Rework button handling

* Fix PD debug at boot

* Fixup not showing right menu options

* silence some warnings

* Style cleanup

* Fkit use bit-bang I2C for Miniware

* Update GUIRendering.md

* Fixup transition on enter soldering mode

* Save Settings

* Fixes for some animations not running

Dont bail on animations if keypress is still held

* Fixup settings acceleration

* OLED Up animation

* Link up/down on debug meny

* Make all accelerometers I2C bus aware

Update accelerometers_common.h

* Make I2C mag optional

* Miniware -> Only Bit-Bang I2C

* Fixup for scrollbar

FIXUP! Debug menu returns to home screen

FIXUP! Up oled animation

Fix temp exit

* Settings menu -> Both buttons return a menu layer

* Merge fixup

* Update BMA223.cpp

* Re-Enable OLED sleep

* Save Setting on temp adjust exit

* WiP on startup mode

* Some autostart working

* Add hibernation mode & more autostart fixes

* If cant CJC; go to startup

* Hibernate in sleep

* Cleanup scroll indicator

* FIXUP! Ensure startup warnings are linked in

* FIXUP! Ensure we render out temp change before timing out

* Ensure 100ms delay between CJC samples

* Fix not re-calculating menu length on entering menu

* Implement NegotiationinProgress for USB-PD

* Mask heating until PD finishes negotiation

* Fixup staying in hibernate correctly

* Warning timeout

* Show reset settings warning

* Correctly compensate help text start time

* Update GUIThread.cpp

* Update USBPD.cpp

* .

* Fixup sleep time

* Update printSleepCountdown.cpp

* replacing countdown with big plus while in boost mode

* bringing back the + 1 since it was missing when not in boost mode

* Bail on USB-PD check after 3 seconds incase of DC source

* Fix hibernate

* Update PIDThread.cpp

* did center plus symbol (boost mode)

* Big refactor to not make settings increment handler handle the "is last item" return

* Fixup boot logo

* Fix flashing

* Fixup recalculate the menu length on long hold

* Fixup missing menu entries

* Fix junk left on screen after user confirmation

* Re-order button handler to use custom, then default order to allow setting associated setting

* Attach setting for settings using custom handler

* Fix swap +/- keys

* Fix boost temp

* Implement last menu option for Language selector

* Wait for init before CJC runs

* Check last setting via increment value

* Update BSP.cpp

* removed = from >=

Otherwise incrementing would stop and the scroll bar would already flash at the second to last value.

* (Hacky) Fix for Settings reset

---------

Co-authored-by: discip <53649486+discip@users.noreply.github.com>
2024-02-18 09:42:08 +11:00

240 lines
8.0 KiB
C++

/*
* GUIThread.cpp
*
* Created on: 19 Aug 2019
* Author: ralim
*/
extern "C" {
#include "FreeRTOSConfig.h"
}
#include "BootLogo.h"
#include "Buttons.hpp"
#include "I2CBB2.hpp"
#include "LIS2DH12.hpp"
#include "MMA8652FC.hpp"
#include "OLED.hpp"
#include "OperatingModeUtilities.h"
#include "OperatingModes.h"
#include "Settings.h"
#include "TipThermoModel.h"
#include "Translation.h"
#include "cmsis_os.h"
#include "configuration.h"
#include "history.hpp"
#include "main.hpp"
#include "power.hpp"
#include "settingsGUI.hpp"
#include "stdlib.h"
#include "string.h"
#ifdef POW_PD
#include "USBPD.h"
#include "pd.h"
#endif
// File local variables
#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
ButtonState buttonsAtDeviceBoot; // We record button state at startup, incase of jumping to debug modes
OperatingMode currentOperatingMode = OperatingMode::InitialisationDone; // Current mode we are rendering
guiContext context; // Context passed to functions to aid in state during render passes
OperatingMode handle_post_init_state();
OperatingMode guiHandleDraw(void) {
OLED::clearScreen(); // Clear ready for render pass
// Read button state
ButtonState buttons = getButtonState();
// Enforce screen on if buttons pressed, movement, hot tip etc
if (buttons != BUTTON_NONE) {
OLED::setDisplayState(OLED::DisplayState::ON);
} else {
// Buttons are none; check if we can sleep display
uint32_t tipTemp = TipThermoModel::getTipInC();
if ((tipTemp < 50) && getSettingValue(SettingsOptions::Sensitivity) &&
(((xTaskGetTickCount() - lastMovementTime) > MOVEMENT_INACTIVITY_TIME) && ((xTaskGetTickCount() - lastButtonTime) > BUTTON_INACTIVITY_TIME))) {
OLED::setDisplayState(OLED::DisplayState::OFF);
setStatusLED(LED_OFF);
} else {
OLED::setDisplayState(OLED::DisplayState::ON);
if (tipTemp > 55) {
setStatusLED(LED_COOLING_STILL_HOT);
} else {
setStatusLED(LED_STANDBY);
}
}
}
// Dispatch button state to gui mode
OperatingMode newMode = currentOperatingMode;
switch (currentOperatingMode) {
case OperatingMode::StartupWarnings:
newMode = showWarnings(buttons, &context);
break;
case OperatingMode::UsbPDDebug:
#ifdef HAS_POWER_DEBUG_MENU
newMode = showPDDebug(buttons, &context);
break;
#else
newMode = OperatingMode::InitialisationDone;
#endif
case OperatingMode::StartupLogo:
showBootLogo();
if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::SLEEP) {
lastMovementTime = lastButtonTime = 0; // We mask the values so that sleep goes until user moves again or presses a button
newMode = OperatingMode::Sleeping;
} else if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::SOLDER) {
lastMovementTime = lastButtonTime = xTaskGetTickCount(); // Move forward so we dont go to sleep
newMode = OperatingMode::Soldering;
} else if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::ZERO) {
lastMovementTime = lastButtonTime = 0; // We mask the values so that sleep goes until user moves again or presses a button
newMode = OperatingMode::Hibernating;
} else {
newMode = OperatingMode::HomeScreen;
}
break;
default:
/* Fallthrough */
case OperatingMode::HomeScreen:
newMode = drawHomeScreen(buttons, &context);
break;
case OperatingMode::Soldering:
context.scratch_state.state4 = 0;
newMode = gui_solderingMode(buttons, &context);
break;
case OperatingMode::SolderingProfile:
newMode = gui_solderingProfileMode(buttons, &context);
break;
case OperatingMode::Sleeping:
newMode = gui_SolderingSleepingMode(buttons, &context);
break;
case OperatingMode::TemperatureAdjust:
newMode = gui_solderingTempAdjust(buttons, &context);
break;
case OperatingMode::DebugMenuReadout:
newMode = showDebugMenu(buttons, &context);
break;
case OperatingMode::CJCCalibration:
newMode = performCJCC(buttons, &context);
break;
case OperatingMode::SettingsMenu:
newMode = gui_SettingsMenu(buttons, &context);
break;
case OperatingMode::InitialisationDone:
newMode = handle_post_init_state();
break;
case OperatingMode::Hibernating:
context.scratch_state.state4 = 1;
gui_SolderingSleepingMode(buttons, &context);
if (lastButtonTime > 0 || lastMovementTime > 0) {
newMode = OperatingMode::Soldering;
}
break;
case OperatingMode::ThermalRunaway:
/*TODO*/
newMode = OperatingMode::HomeScreen;
break;
};
return newMode;
}
void guiRenderLoop(void) {
OperatingMode newMode = guiHandleDraw(); // This does the screen drawing
// Post draw we handle any state transitions
if (newMode != currentOperatingMode) {
context.viewEnterTime = xTaskGetTickCount();
context.previousMode = currentOperatingMode;
// If the previous mode is the startup logo; we dont want to return to it, but instead dispatch out to either home or soldering
if (currentOperatingMode == OperatingMode::StartupLogo) {
if (getSettingValue(SettingsOptions::AutoStartMode)) {
context.previousMode = OperatingMode::Soldering;
} else {
newMode = OperatingMode::HomeScreen;
}
}
memset(&context.scratch_state, 0, sizeof(context.scratch_state));
currentOperatingMode = newMode;
}
// If the transition marker is set, we need to make the next draw occur to the secondary buffer so we have something to transition to
if (context.transitionMode != TransitionAnimation::None) {
OLED::useSecondaryFramebuffer(true);
// Now we need to fill the secondary buffer with the _next_ frame to transistion to
guiHandleDraw();
OLED::useSecondaryFramebuffer(false);
// Now dispatch the transition
switch (context.transitionMode) {
case TransitionAnimation::Down:
OLED::transitionScrollDown(context.viewEnterTime);
break;
case TransitionAnimation::Left:
OLED::transitionSecondaryFramebuffer(false, context.viewEnterTime);
break;
case TransitionAnimation::Right:
OLED::transitionSecondaryFramebuffer(true, context.viewEnterTime);
break;
case TransitionAnimation::Up:
OLED::transitionScrollUp(context.viewEnterTime);
case TransitionAnimation::None:
default:
break; // Do nothing on unknown
}
context.transitionMode = TransitionAnimation::None; // Clear transition flag
}
// Render done, draw it out
OLED::refresh();
}
OperatingMode handle_post_init_state() {
#ifdef HAS_POWER_DEBUG_MENU
#ifdef DEBUG_POWER_MENU_BUTTON_B
if (buttonsAtDeviceBoot == BUTTON_B_LONG || buttonsAtDeviceBoot == BUTTON_B_SHORT) {
#else
if (buttonsAtDeviceBoot == BUTTON_F_LONG || buttonsAtDeviceBoot == BUTTON_F_SHORT) {
#endif
buttonsAtDeviceBoot = BUTTON_NONE;
return OperatingMode::UsbPDDebug;
}
#endif
if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) {
return OperatingMode::CJCCalibration;
}
return OperatingMode::StartupWarnings;
}
/* StartGUITask function */
void startGUITask(void const *argument) {
(void)argument;
prepareTranslations();
OLED::initialize(); // start up the LCD
OLED::setBrightness(getSettingValue(SettingsOptions::OLEDBrightness));
OLED::setInverseDisplay(getSettingValue(SettingsOptions::OLEDInversion));
bool buttonLockout = false;
renderHomeScreenAssets();
getTipRawTemp(1); // reset filter
memset(&context, 0, sizeof(context));
OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1);
// Read boot button state
if (getButtonA()) {
buttonsAtDeviceBoot = BUTTON_F_LONG;
}
if (getButtonB()) {
buttonsAtDeviceBoot = BUTTON_B_LONG;
}
TickType_t startRender = xTaskGetTickCount();
for (;;) {
guiRenderLoop();
resetWatchdog();
vTaskDelayUntil(&startRender, TICKS_100MS * 4 / 10); // Try and maintain 20-25fps ish update rate, way to fast but if we can its nice
}
}