/* * 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 showPDDebug(buttons, &context); break; #else /*fallthrough*/ #endif case OperatingMode::StartupLogo: BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); // TODO needs refactor newMode = OperatingMode::StartupWarnings; break; default: /* Fallthrough */ case OperatingMode::HomeScreen: newMode = drawHomeScreen(buttons, &context); break; case OperatingMode::Soldering: 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: break; case OperatingMode::ThermalRunaway: 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; 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(); break; case TransitionAnimation::Left: OLED::transitionSecondaryFramebuffer(false); break; case TransitionAnimation::Right: OLED::transitionSecondaryFramebuffer(true); break; 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 return OperatingMode::UsbPDDebug; } #endif if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) { return OperatingMode::CJCCalibration; } if (getSettingValue(SettingsOptions::AutoStartMode) == 1) { // jump directly to the autostart mode return OperatingMode::Sleeping; } if (getSettingValue(SettingsOptions::AutoStartMode) == 2) { return OperatingMode::Hibernating; } return OperatingMode::HomeScreen; } /* 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); buttonsAtDeviceBoot = getButtonState(); // // If the boot logo is enabled with timeout and the autostart mode is enabled (but not set to sleep w/o heat), start heating during boot logo // if (getSettingValue(SettingsOptions::LOGOTime) > 0 && getSettingValue(SettingsOptions::LOGOTime) < 5 && getSettingValue(SettingsOptions::AutoStartMode) > 0 // && getSettingValue(SettingsOptions::AutoStartMode) < 3) { // uint16_t sleepTempDegC; // if (getSettingValue(SettingsOptions::TemperatureInF)) { // sleepTempDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::SleepTemp)); // } else { // sleepTempDegC = getSettingValue(SettingsOptions::SleepTemp); // } // // Only heat to sleep temperature (but no higher than 75°C for safety) // currentTempTargetDegC = min(sleepTempDegC, 75); // } // TODO 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 } }