diff --git a/source/Core/Inc/settingsGUI.hpp b/source/Core/Inc/settingsGUI.hpp index f1d90852..3f89ad0f 100644 --- a/source/Core/Inc/settingsGUI.hpp +++ b/source/Core/Inc/settingsGUI.hpp @@ -9,6 +9,7 @@ #define GUI_HPP_ #include "BSP.h" #include "FreeRTOS.h" +#include "Buttons.hpp" #include "Settings.h" #include "Translation.h" @@ -37,7 +38,7 @@ typedef struct { } menuitem; void enterSettingsMenu(); -void warnUser(const char *warning, const TickType_t timeout); +bool warnUser(const char *warning, const ButtonState buttons); extern const menuitem rootSettingsMenu[]; #endif /* GUI_HPP_ */ diff --git a/source/Core/Src/settingsGUI.cpp b/source/Core/Src/settingsGUI.cpp index 9542b08c..48281704 100644 --- a/source/Core/Src/settingsGUI.cpp +++ b/source/Core/Src/settingsGUI.cpp @@ -942,7 +942,7 @@ static void displayPowerPulseDuration(void) { OLED::printNumber(getSettingValue( static bool setResetSettings(void) { if (userConfirmation(translatedString(Tr->SettingsResetWarning))) { resetSettings(); - warnUser(translatedString(Tr->ResetOKMessage), 3 * TICKS_SECOND); + // warnUser(translatedString(Tr->ResetOKMessage), buttons); //TODO reboot(); } return false; diff --git a/source/Core/Threads/GUIRendering.md b/source/Core/Threads/GUIRendering.md new file mode 100644 index 00000000..ec65038e --- /dev/null +++ b/source/Core/Threads/GUIRendering.md @@ -0,0 +1,18 @@ +# GUI Rendering + +The GUI aims to be somewhat similar to immediate mode rendering, where the screen is re-rendered each sweep. +This is due to a few aims: + +1. Functions should try and contain their state to the context struct (helps keep state usage flatter) +2. Allows external events to change the state +3. Means state can be read/write over BLE or other external control interfaces + +## TODO notes + +On settings menu exit: + +``` + OLED::useSecondaryFramebuffer(true); + showExitMenuTransition = true; + +``` diff --git a/source/Core/Threads/GUIThread.cpp b/source/Core/Threads/GUIThread.cpp index 56dc6574..33cc81bf 100644 --- a/source/Core/Threads/GUIThread.cpp +++ b/source/Core/Threads/GUIThread.cpp @@ -31,8 +31,123 @@ extern "C" { #include "pd.h" #endif // File local variables +#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ) +#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ) -extern bool heaterThermalRunaway; +ButtonState buttonsAtDeviceBoot; // We record button state at startup, incase of jumping to debug modes + +OperatingMode currentOperatingMode; // Current mode we are rendering +guiContext context; // Context passed to functions to aid in state during render passes + +void guiRenderLoop(void) { + OLED::clearScreen(); // Clear ready for render pass + // Read button state + ButtonState buttons = getButtonState(); + // Enforce screen on if buttons pressed + 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: + break; + case OperatingMode::InitialisationDone: + break; + case OperatingMode::Hibernating: + break; + case OperatingMode::ThermalRunaway: + break; + }; + // Render done, draw it out + OLED::refresh(); + // Update state holders + if (newMode != currentOperatingMode) { + context.viewEnterTime = xTaskGetTickCount(); + context.previousMode = currentOperatingMode; + memset(&context.scratch_state, 0, sizeof(context.scratch_state)); + currentOperatingMode = newMode; + } +} + +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) { @@ -48,41 +163,25 @@ void startGUITask(void const *argument) { getTipRawTemp(1); // reset filter OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1); - // If the front button is held down, on supported devices, show PD debugging metrics -#ifdef HAS_POWER_DEBUG_MENU -#ifdef DEBUG_POWER_MENU_BUTTON_B - if (getButtonB()) { -#else - if (getButtonA()) { -#endif - showPDDebug(); - } -#endif + buttonsAtDeviceBoot = getButtonState(); - if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) { - performCJCC(); + // // 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 / 2); } - - // If the boot logo is enabled (but it times out) 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); - } - - showBootLogo(); - showWarnings(); - if (getSettingValue(SettingsOptions::AutoStartMode)) { - // jump directly to the autostart mode - gui_solderingMode(getSettingValue(SettingsOptions::AutoStartMode) - 1); - buttonLockout = true; - } - - drawHomeScreen(buttonLockout); } diff --git a/source/Core/Threads/OperatingModes/CJC.cpp b/source/Core/Threads/OperatingModes/CJC.cpp index 4da688f9..2359aad1 100644 --- a/source/Core/Threads/OperatingModes/CJC.cpp +++ b/source/Core/Threads/OperatingModes/CJC.cpp @@ -1,39 +1,36 @@ #include "OperatingModes.h" -void performCJCC(void) { +OperatingMode performCJCC(const ButtonState buttons, guiContext *cxt) { // Calibrate Cold Junction Compensation directly at boot, before internal components get warm. - OLED::refresh(); - osDelay(50); if (!isTipDisconnected() && abs(int(TipThermoModel::getTipInC() - getHandleTemperature(0) / 10)) < 10) { - uint16_t setoffset = 0; + // Take 16 samples + if (cxt->scratch_state.state1 < 16) { + cxt->scratch_state.state3 += getTipRawTemp(1); + OLED::setCursor(0, 0); + OLED::print(translatedString(Tr->CJCCalibrating), FontStyle::SMALL); + OLED::setCursor(0, 8); + OLED::print(SmallSymbolDot, FontStyle::SMALL); + for (uint8_t x = 0; x < (cxt->scratch_state.state1 / 4); x++) + OLED::print(SmallSymbolDot, FontStyle::SMALL); + cxt->scratch_state.state1++; + return OperatingMode::CJCCalibration; + } + // If the thermo-couple at the end of the tip, and the handle are at // equilibrium, then the output should be zero, as there is no temperature // differential. - while (setoffset == 0) { - uint32_t offset = 0; - for (uint8_t i = 0; i < 16; i++) { - offset += getTipRawTemp(1); - // cycle through the filter a fair bit to ensure we're stable. - OLED::clearScreen(); - OLED::setCursor(0, 0); - OLED::print(translatedString(Tr->CJCCalibrating), FontStyle::SMALL); - OLED::setCursor(0, 8); - OLED::print(SmallSymbolDot, FontStyle::SMALL); - for (uint8_t x = 0; x < (i / 4); x++) { - OLED::print(SmallSymbolDot, FontStyle::SMALL); - } - OLED::refresh(); - osDelay(100); - } - setoffset = TipThermoModel::convertTipRawADCTouV(offset / 16, true); + + uint16_t setOffset = TipThermoModel::convertTipRawADCTouV(cxt->scratch_state.state3 / 16, true); + setSettingValue(SettingsOptions::CalibrationOffset, setOffset); + if (warnUser(translatedString(Tr->CJCCalibrationDone), buttons)) { + // Preventing to repeat calibration at boot automatically (only one shot). + setSettingValue(SettingsOptions::CalibrateCJC, 0); + saveSettings(); + return OperatingMode::InitialisationDone; } - setSettingValue(SettingsOptions::CalibrationOffset, setoffset); - OLED::clearScreen(); - warnUser(translatedString(Tr->CalibrationDone), 3 * TICKS_SECOND); - OLED::refresh(); - // Preventing to repeat calibration at boot automatically (only one shot). - setSettingValue(SettingsOptions::CalibrateCJC, 0); - saveSettings(); + return OperatingMode::CJCCalibration; } + // Cant run calibration without the tip and for temps to be close + return OperatingMode::InitialisationDone; } diff --git a/source/Core/Threads/OperatingModes/DebugMenu.cpp b/source/Core/Threads/OperatingModes/DebugMenu.cpp index adf03ddd..27695b6d 100644 --- a/source/Core/Threads/OperatingModes/DebugMenu.cpp +++ b/source/Core/Threads/OperatingModes/DebugMenu.cpp @@ -1,111 +1,100 @@ #include "OperatingModes.h" -extern osThreadId GUITaskHandle; -extern osThreadId MOVTaskHandle; -extern osThreadId PIDTaskHandle; -extern OperatingMode currentMode; +extern osThreadId GUITaskHandle; +extern osThreadId MOVTaskHandle; +extern osThreadId PIDTaskHandle; -void showDebugMenu(void) { - currentMode = OperatingMode::debug; - uint8_t screen = 0; - ButtonState b; - for (;;) { - OLED::clearScreen(); // Ensure the buffer starts clean - OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) - OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number - OLED::setCursor(0, 8); // second line - OLED::print(DebugMenu[screen], FontStyle::SMALL); - switch (screen) { - case 0: // Build Date - break; - case 1: // Device ID - { - uint64_t id = getDeviceID(); +OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt) { + OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) + OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number + OLED::setCursor(0, 8); // second line + OLED::print(DebugMenu[cxt->scratch_state.state1], FontStyle::SMALL); + switch (cxt->scratch_state.state1) { + case 0: // Build Date + break; + case 1: // Device ID + { + uint64_t id = getDeviceID(); #ifdef DEVICE_HAS_VALIDATION_CODE - // If device has validation code; then we want to take over both lines of the screen - OLED::clearScreen(); // Ensure the buffer starts clean - OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) - OLED::print(DebugMenu[screen], FontStyle::SMALL); - OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8); - OLED::setCursor(0, 8); // second line + // If device has validation code; then we want to take over both lines of the screen + OLED::clearScreen(); // Ensure the buffer starts clean + OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) + OLED::print(DebugMenu[screen], FontStyle::SMALL); + OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8); + OLED::setCursor(0, 8); // second line #endif - OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8); - OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8); - } break; - case 2: // ACC Type - OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL); - break; - case 3: // Power Negotiation Status - OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL); - break; - case 4: // Input Voltage - printVoltage(); - break; - case 5: // Temp in °C - OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL); - break; - case 6: // Handle Temp in °C - OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL); - OLED::print(SmallSymbolDot, FontStyle::SMALL); - OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL); - break; - case 7: // Max Temp Limit in °C - OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL); - break; - case 8: // System Uptime - OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL); - break; - case 9: // Movement Timestamp - OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL); - break; - case 10: // Tip Resistance in Ω large to pad over so that we cover ID left overs - OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL); - OLED::print(SmallSymbolDot, FontStyle::SMALL); - OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL); - break; - case 11: // Raw Tip in µV - OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL); - break; - case 12: // Tip Cold Junction Compensation Offset in µV - OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL); - break; - case 13: // High Water Mark for GUI - OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL); - break; - case 14: // High Water Mark for Movement Task - OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL); - break; - case 15: // High Water Mark for PID Task - OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL); - break; - break; + OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8); + OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8); + } break; + case 2: // ACC Type + OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL); + break; + case 3: // Power Negotiation Status + OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL); + break; + case 4: // Input Voltage + printVoltage(); + break; + case 5: // Temp in °C + OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL); + break; + case 6: // Handle Temp in °C + OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL); + OLED::print(SmallSymbolDot, FontStyle::SMALL); + OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL); + break; + case 7: // Max Temp Limit in °C + OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL); + break; + case 8: // System Uptime + OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL); + break; + case 9: // Movement Timestamp + OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL); + break; + case 10: // Tip Resistance in Ω + OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL); // large to pad over so that we cover ID left overs + OLED::print(SmallSymbolDot, FontStyle::SMALL); + OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL); + break; + case 11: // Raw Tip in µV + OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL); + break; + case 12: // Tip Cold Junction Compensation Offset in µV + OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL); + break; + case 13: // High Water Mark for GUI + OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL); + break; + case 14: // High Water Mark for Movement Task + OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL); + break; + case 15: // High Water Mark for PID Task + OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL); + break; + break; #ifdef HALL_SENSOR - case 16: // Raw Hall Effect Value - { - int16_t hallEffectStrength = getRawHallEffect(); - if (hallEffectStrength < 0) { - hallEffectStrength = -hallEffectStrength; - } - OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL); - } break; + case 16: // Raw Hall Effect Value + { + int16_t hallEffectStrength = getRawHallEffect(); + if (hallEffectStrength < 0) + hallEffectStrength = -hallEffectStrength; + OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL); + } break; #endif - default: - break; - } - - OLED::refresh(); - b = getButtonState(); - if (b == BUTTON_B_SHORT) { - return; - } else if (b == BUTTON_F_SHORT) { - screen++; -#ifdef HALL_SENSOR - screen = screen % 17; -#else - screen = screen % 16; -#endif - } - - GUIDelay(); + default: + break; } + + if (buttons == BUTTON_B_SHORT) + return OperatingMode::InitialisationDone; + else if (buttons == BUTTON_F_SHORT) { + cxt->scratch_state.state1++; +#ifdef HALL_SENSOR + cxt->scratch_state.state1 = cxt->scratch_state.state1 % 17; +#else + cxt->scratch_state.state1 = cxt->scratch_state.state1 % 16; +#endif + } + return OperatingMode::DebugMenuReadout; // Stay in debug menu } diff --git a/source/Core/Threads/OperatingModes/HomeScreen.cpp b/source/Core/Threads/OperatingModes/HomeScreen.cpp index 7ac03e9e..502fe1d2 100644 --- a/source/Core/Threads/OperatingModes/HomeScreen.cpp +++ b/source/Core/Threads/OperatingModes/HomeScreen.cpp @@ -2,14 +2,10 @@ #include "Buttons.hpp" #include "OperatingModes.h" -#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ) -#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ) - -uint8_t buttonAF[sizeof(buttonA)]; -uint8_t buttonBF[sizeof(buttonB)]; -uint8_t disconnectedTipF[sizeof(disconnectedTip)]; -extern OperatingMode currentMode; -bool showExitMenuTransition = false; +uint8_t buttonAF[sizeof(buttonA)]; +uint8_t buttonBF[sizeof(buttonB)]; +uint8_t disconnectedTipF[sizeof(disconnectedTip)]; +bool showExitMenuTransition = false; void renderHomeScreenAssets(void) { @@ -24,55 +20,42 @@ void renderHomeScreenAssets(void) { } } -void handleButtons(bool *buttonLockout) { - ButtonState buttons = getButtonState(); +OperatingMode handleHomeButtons(const ButtonState buttons, guiContext *cxt) { if (buttons != BUTTON_NONE) { OLED::setDisplayState(OLED::DisplayState::ON); } - if (buttons != BUTTON_NONE && *buttonLockout) { - buttons = BUTTON_NONE; + if (buttons != BUTTON_NONE && cxt->scratch_state.state1 == 0) { + return OperatingMode::HomeScreen; // Ignore button press } else { - *buttonLockout = false; + cxt->scratch_state.state1 == 1; } switch (buttons) { case BUTTON_NONE: // Do nothing break; case BUTTON_BOTH: - // Not used yet - // In multi-language this might be used to reset language on a long hold - // or some such break; case BUTTON_B_LONG: - // Show the version information - showDebugMenu(); + return OperatingMode::DebugMenuReadout; break; case BUTTON_F_LONG: #ifdef PROFILE_SUPPORT if (!isTipDisconnected()) { - gui_solderingProfileMode(); // enter profile mode - *buttonLockout = true; + return OperatingMode::SolderingProfile; } #else - gui_solderingTempAdjust(); + return OperatingMode::TemperatureAdjust; saveSettings(); #endif break; case BUTTON_F_SHORT: if (!isTipDisconnected()) { - gui_solderingMode(0); // enter soldering mode - *buttonLockout = true; + return OperatingMode::Soldering; } break; case BUTTON_B_SHORT: - currentMode = OperatingMode::settings; - enterSettingsMenu(); // enter the settings menu - { - OLED::useSecondaryFramebuffer(true); - showExitMenuTransition = true; - } - *buttonLockout = true; + return OperatingMode::SettingsMenu; break; default: break; @@ -181,55 +164,28 @@ void drawSimplifiedHomeScreen(uint32_t tipTemp) { } } } -void drawHomeScreen(bool buttonLockout) { +OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt) { - for (;;) { - currentMode = OperatingMode::idle; - handleButtons(&buttonLockout); - - currentTempTargetDegC = 0; // ensure tip is off - getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0); - uint32_t tipTemp = TipThermoModel::getTipInC(); - // Preemptively turn the display on. Turn it off if and only if - // the tip temperature is below 50 degrees C *and* motion sleep - // detection is enabled *and* there has been no activity (movement or - // button presses) in a while. - // This is zero cost really as state is only changed on display updates - OLED::setDisplayState(OLED::DisplayState::ON); - - 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); - } - } - - // Clear the lcd buffer - OLED::clearScreen(); - if (OLED::getRotation()) { - OLED::setCursor(50, 0); - } else { - OLED::setCursor(-1, 0); - } - if (getSettingValue(SettingsOptions::DetailedIDLE)) { - drawDetailedHomeScreen(tipTemp); - } else { - drawSimplifiedHomeScreen(tipTemp); - } - - if (showExitMenuTransition) { - OLED::useSecondaryFramebuffer(false); - OLED::transitionSecondaryFramebuffer(false); - showExitMenuTransition = false; - } else { - OLED::refresh(); - GUIDelay(); - } + OperatingMode newMode = handleHomeButtons(buttons, cxt); + if (newMode != OperatingMode::HomeScreen) { + return newMode; } + + currentTempTargetDegC = 0; // ensure tip is off + getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0); + uint32_t tipTemp = TipThermoModel::getTipInC(); + + // Setup LCD Cursor location + if (OLED::getRotation()) { + OLED::setCursor(50, 0); + } else { + OLED::setCursor(-1, 0); + } + if (getSettingValue(SettingsOptions::DetailedIDLE)) { + drawDetailedHomeScreen(tipTemp); + } else { + drawSimplifiedHomeScreen(tipTemp); + } + + return OperatingMode::HomeScreen; } diff --git a/source/Core/Threads/OperatingModes/OperatingModes.cpp b/source/Core/Threads/OperatingModes/OperatingModes.cpp index c09e71d0..d334d13b 100644 --- a/source/Core/Threads/OperatingModes/OperatingModes.cpp +++ b/source/Core/Threads/OperatingModes/OperatingModes.cpp @@ -3,6 +3,3 @@ // #include "OperatingModes.h" - -// Global variables -OperatingMode currentMode = OperatingMode::idle; \ No newline at end of file diff --git a/source/Core/Threads/OperatingModes/OperatingModes.h b/source/Core/Threads/OperatingModes/OperatingModes.h index c552e327..fb42251f 100644 --- a/source/Core/Threads/OperatingModes/OperatingModes.h +++ b/source/Core/Threads/OperatingModes/OperatingModes.h @@ -24,29 +24,53 @@ extern "C" { #include "pd.h" #endif -// Exposed modes -enum OperatingMode { - idle = 0, - soldering = 1, - boost = 2, - sleeping = 3, - settings = 4, - debug = 5 +enum class OperatingMode { + StartupLogo = 0, // Showing the startup logo + CJCCalibration, // Cold Junction Calibration + StartupWarnings, // Startup checks and warnings + InitialisationDone, // Special state we use just before we to home screen at first startup. Allows jumping to extra startup states + HomeScreen, // Home/Idle screen that is the main launchpad to other modes + Soldering, // Main soldering operating mode + SolderingProfile, // Soldering by following a profile, used for reflow for example + Sleeping, // Sleep state holds iron at lower sleep temp + Hibernating, // Like sleeping but keeps heater fully off until woken + SettingsMenu, // Settings Menu + DebugMenuReadout, // Debug metrics + TemperatureAdjust, // Set point temperature adjustment + UsbPDDebug, // USB PD debugging information + ThermalRunaway, // Thermal Runaway warning state. +}; + +// Generic context struct used for gui functions to be able to retain state +struct guiContext { + TickType_t viewEnterTime; // Set to ticks when this view state was first entered + OperatingMode previousMode; + struct scratch { + uint16_t state1; // 16 bit state scratch + uint16_t state2; // 16 bit state scratch + uint32_t state3; // 32 bit state scratch + uint32_t state4; // 32 bit state scratch + uint16_t state5; // 16 bit state scratch + uint16_t state6; // 16 bit state scratch + + } scratch_state; }; // Main functions -void performCJCC(void); // Used to calibrate the Cold Junction offset -void gui_solderingTempAdjust(void); // For adjusting the setpoint temperature of the iron -int gui_SolderingSleepingMode(bool stayOff, bool autoStarted); // Sleep mode -void gui_solderingMode(uint8_t jumpToSleep); // Main mode for hot pointy tool -void gui_solderingProfileMode(); // Profile mode for hot likely-not-so-pointy tool -void showDebugMenu(void); // Debugging values -void showPDDebug(void); // Debugging menu that shows PD adaptor info -void showWarnings(void); // Shows user warnings if required -void drawHomeScreen(bool buttonLockout) __attribute__((noreturn)); // IDLE / Home screen -void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics +OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt); // Sleep mode +OperatingMode gui_solderingMode(const ButtonState buttons, guiContext *cxt); // Main mode for hot pointy tool +OperatingMode gui_solderingTempAdjust(const ButtonState buttons, guiContext *cxt); // For adjusting the setpoint temperature of the iron +OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt); // IDLE / Home screen + +OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt); // Profile mode for hot likely-not-so-pointy tool +OperatingMode performCJCC(const ButtonState buttons, guiContext *cxt); // Used to calibrate the Cold Junction offset +OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt); // Debugging values +OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt); // Debugging menu that shows PD adaptor info +OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt); // Shows user warnings if required // Common helpers -int8_t getPowerSourceNumber(void); // Returns number ID of power source -TemperatureType_t getTipTemp(void); // Returns temperature of the tip in *C/*F (based on user settings) +int8_t getPowerSourceNumber(void); // Returns number ID of power source +void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics + +extern bool heaterThermalRunaway; #endif diff --git a/source/Core/Threads/OperatingModes/ShowStartupWarnings.cpp b/source/Core/Threads/OperatingModes/ShowStartupWarnings.cpp index 62ed5d0e..3598e9b1 100644 --- a/source/Core/Threads/OperatingModes/ShowStartupWarnings.cpp +++ b/source/Core/Threads/OperatingModes/ShowStartupWarnings.cpp @@ -1,56 +1,78 @@ #include "HUB238.hpp" #include "OperatingModes.h" -void showWarnings(void) { +OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt) { // Display alert if settings were reset - if (settingsWereReset) { - warnUser(translatedString(Tr->SettingsResetMessage), 10 * TICKS_SECOND); - } -#ifdef DEVICE_HAS_VALIDATION_SUPPORT - if (getDeviceValidationStatus()) { - // Warn user this device might be counterfeit - warnUser(translatedString(Tr->DeviceFailedValidationWarning), 10 * TICKS_SECOND); - } -#endif -#ifndef NO_WARN_MISSING - // We also want to alert if accel or pd is not detected / not responding - // In this case though, we dont want to nag the user _too_ much - // So only show first 2 times - while (DetectedAccelerometerVersion == AccelType::Scanning) { - osDelay(5); - resetWatchdog(); - } - // Display alert if accelerometer is not detected - if (DetectedAccelerometerVersion == AccelType::None) { - if (getSettingValue(SettingsOptions::AccelMissingWarningCounter) < 2) { - nextSettingValue(SettingsOptions::AccelMissingWarningCounter); - saveSettings(); - warnUser(translatedString(Tr->NoAccelerometerMessage), 10 * TICKS_SECOND); + switch (cxt->scratch_state.state1) { + case 0: // Settings reset warning + if (settingsWereReset) { + if (warnUser(translatedString(Tr->SettingsResetMessage), buttons)) { + settingsWereReset = false; + cxt->scratch_state.state1 = 1; + } } - } + break; + case 1: // Device validations +#ifdef DEVICE_HAS_VALIDATION_SUPPORT + if (getDeviceValidationStatus()) { + // Warn user this device might be counterfeit + if (warnUser(translatedString(Tr->DeviceFailedValidationWarning), buttons)) { + cxt->scratch_state.state1 = 2; + } + } +#else + cxt->scratch_state.state1 = 2; +#endif + break; + case 2: // Accelerometer detection + if (DetectedAccelerometerVersion == AccelType::Scanning) { + break; + } + // Display alert if accelerometer is not detected + if (DetectedAccelerometerVersion == AccelType::None) { + if (getSettingValue(SettingsOptions::AccelMissingWarningCounter) < 2) { + nextSettingValue(SettingsOptions::AccelMissingWarningCounter); + saveSettings(); + if (warnUser(translatedString(Tr->NoAccelerometerMessage), buttons)) { + cxt->scratch_state.state1 = 3; + } + } + } + break; + case 3: + #ifdef POW_PD - // We expect pd to be present - resetWatchdog(); - if (!USBPowerDelivery::fusbPresent()) { - if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { - nextSettingValue(SettingsOptions::PDMissingWarningCounter); - saveSettings(); - warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND); + // We expect pd to be present + if (!USBPowerDelivery::fusbPresent()) { + if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { + nextSettingValue(SettingsOptions::PDMissingWarningCounter); + saveSettings(); + if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) { + cxt->scratch_state.state1 = 4; + } + } } - } -#endif /*POW_PD*/ +#else #if POW_PD_EXT == 1 - if (!hub238_probe()) { - if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { - nextSettingValue(SettingsOptions::PDMissingWarningCounter); - saveSettings(); - warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND); + if (!hub238_probe()) { + if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { + nextSettingValue(SettingsOptions::PDMissingWarningCounter); + saveSettings(); + if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) { + cxt->scratch_state.state1 = 4; + } + } } - } +#else + cxt->scratch_state.state1 = 4; #endif /*POW_PD_EXT==1*/ - // If tip looks to be shorted, yell at user and dont auto dismiss - if (isTipShorted()) { - warnUser(translatedString(Tr->WarningTipShorted), portMAX_DELAY); +#endif /*POW_PD*/ + + break; + default: + // We are off the end, warnings done + return OperatingMode::InitialisationDone; } -#endif /*NO_WARN_MISSING*/ + + return OperatingMode::StartupWarnings; // Stay in warnings } diff --git a/source/Core/Threads/OperatingModes/Sleep.cpp b/source/Core/Threads/OperatingModes/Sleep.cpp index 5c3c47e7..bdfa76c4 100644 --- a/source/Core/Threads/OperatingModes/Sleep.cpp +++ b/source/Core/Threads/OperatingModes/Sleep.cpp @@ -1,64 +1,59 @@ #include "OperatingModes.h" -extern OperatingMode currentMode; - -int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { -#ifndef NO_SLEEP_MODE +OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt) { +#ifdef NO_SLEEP_MODE + return OperatingMode::SolderingMode; +#endif // Drop to sleep temperature and display until movement or button press - currentMode = OperatingMode::sleeping; - for (;;) { - // user moved or pressed a button, go back to soldering - // If in the first two seconds we disable this to let accelerometer warm up + // user moved or pressed a button, go back to soldering + // If in the first two seconds we disable this to let accelerometer warm up #ifdef POW_DC - if (checkForUnderVoltage()) { - // return non-zero on error - return 1; - } + if (checkForUnderVoltage()) + return OperatingMode::HomeScreen; // return non-zero on error #endif - - if (getSettingValue(SettingsOptions::TemperatureInF)) { - currentTempTargetDegC = stayOff ? 0 : TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp))); - } else { - currentTempTargetDegC = stayOff ? 0 : min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp)); - } - - // draw the lcd - TemperatureType_t tipTemp = getTipTemp(); - - OLED::clearScreen(); - OLED::setCursor(0, 0); - if (getSettingValue(SettingsOptions::DetailedSoldering)) { - OLED::print(translatedString(Tr->SleepingAdvancedString), FontStyle::SMALL); - OLED::setCursor(0, 8); - OLED::print(translatedString(Tr->SleepingTipAdvancedString), FontStyle::SMALL); - OLED::printNumber(tipTemp, 3, FontStyle::SMALL); - OLED::printSymbolDeg(FontStyle::SMALL); - OLED::print(SmallSymbolSpace, FontStyle::SMALL); - printVoltage(); - OLED::print(SmallSymbolVolts, FontStyle::SMALL); - } else { - OLED::print(translatedString(Tr->SleepingSimpleString), FontStyle::LARGE); - OLED::printNumber(tipTemp, 3, FontStyle::LARGE); - OLED::printSymbolDeg(FontStyle::EXTRAS); - } - - OLED::refresh(); - GUIDelay(); - - if (!shouldBeSleeping(autoStarted)) { - return 0; - } - - if (shouldShutdown()) { - // shutdown - currentTempTargetDegC = 0; - // we want to exit soldering mode - return 1; - } + if (getSettingValue(SettingsOptions::TemperatureInF)) { + currentTempTargetDegC = TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp))); + } else { + currentTempTargetDegC = min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp)); } -#endif + // draw the lcd + uint16_t tipTemp = getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC(); - return 0; + OLED::clearScreen(); + OLED::setCursor(0, 0); + if (getSettingValue(SettingsOptions::DetailedSoldering)) { + OLED::print(translatedString(Tr->SleepingAdvancedString), FontStyle::SMALL); + OLED::setCursor(0, 8); + OLED::print(translatedString(Tr->SleepingTipAdvancedString), FontStyle::SMALL); + OLED::printNumber(tipTemp, 3, FontStyle::SMALL); + if (getSettingValue(SettingsOptions::TemperatureInF)) + OLED::print(SmallSymbolDegF, FontStyle::SMALL); + else { + OLED::print(SmallSymbolDegC, FontStyle::SMALL); + } + + OLED::print(SmallSymbolSpace, FontStyle::SMALL); + printVoltage(); + OLED::print(SmallSymbolVolts, FontStyle::SMALL); + } else { + OLED::print(translatedString(Tr->SleepingSimpleString), FontStyle::LARGE); + OLED::printNumber(tipTemp, 3, FontStyle::LARGE); + OLED::printSymbolDeg(FontStyle::EXTRAS); + } + + OLED::refresh(); + GUIDelay(); + + if (!shouldBeSleeping()) { + return cxt->previousMode; + } + + if (shouldShutdown()) { + // shutdown + currentTempTargetDegC = 0; + return OperatingMode::HomeScreen; + } + return OperatingMode::Sleeping; } diff --git a/source/Core/Threads/OperatingModes/Soldering.cpp b/source/Core/Threads/OperatingModes/Soldering.cpp index d923871e..5604af6c 100644 --- a/source/Core/Threads/OperatingModes/Soldering.cpp +++ b/source/Core/Threads/OperatingModes/Soldering.cpp @@ -1,10 +1,61 @@ #include "OperatingModes.h" #include "SolderingCommon.h" +// State 1 = button locking +// State 2 = boost mode +// State 3 = buzzer timer -extern OperatingMode currentMode; +OperatingMode handleSolderingButtons(const ButtonState buttons, guiContext *cxt) { + if (cxt->scratch_state.state1 == 1) { + // Buttons are currently locked + if (buttons == BUTTON_F_LONG) { + if (getSettingValue(SettingsOptions::BoostTemp) && (getSettingValue(SettingsOptions::LockingMode) == 1)) { + cxt->scratch_state.state2 = 1; + } + } else if (buttons == BUTTON_BOTH_LONG) { + // Unlocking + if (warnUser(translatedString(Tr->UnlockingKeysString), buttons)) { + cxt->scratch_state.state1 = 0; + } + } else if (buttons != BUTTON_NONE) { + // Do nothing and display a lock warning + warnUser(translatedString(Tr->WarningKeysLockedString), buttons); + } + return OperatingMode::Soldering; + } + // otherwise we are unlocked + switch (buttons) { + case BUTTON_NONE: + cxt->scratch_state.state2 = 0; + break; + case BUTTON_BOTH: + case BUTTON_B_LONG: + return OperatingMode::HomeScreen; + case BUTTON_F_LONG: + // if boost mode is enabled turn it on + if (getSettingValue(SettingsOptions::BoostTemp)) { + cxt->scratch_state.state2 = 1; + } + break; + case BUTTON_F_SHORT: + case BUTTON_B_SHORT: { + return OperatingMode::TemperatureAdjust; + case BUTTON_BOTH_LONG: + if (getSettingValue(SettingsOptions::LockingMode) != 0) { + // Lock buttons -void gui_solderingMode(uint8_t jumpToSleep) { + if (warnUser(translatedString(Tr->LockingKeysString), buttons)) { + cxt->scratch_state.state1 = 1; + } + } + break; + default: + break; + } + } + return OperatingMode::Soldering; +} +OperatingMode gui_solderingMode(const ButtonState buttons, guiContext *cxt) { /* * * Soldering (gui_solderingMode) * -> Main loop where we draw temp, and animations @@ -19,171 +70,109 @@ void gui_solderingMode(uint8_t jumpToSleep) { * --> Double button to exit * --> Long hold double button to toggle key lock */ - bool boostModeOn = false; - bool buttonsLocked = false; - bool converged = false; - currentMode = OperatingMode::soldering; - TickType_t buzzerEnd = 0; + // First check for button locking & dispatch buttons - if (jumpToSleep) { - if (gui_SolderingSleepingMode(jumpToSleep == 2, true) == 1) { - lastButtonTime = xTaskGetTickCount(); - return; // If the function returns non-0 then exit + OperatingMode newMode = handleSolderingButtons(buttons, cxt); + if (newMode != OperatingMode::Soldering) { + return newMode; + } + // Check if we should bail due to undervoltage for example + if (checkExitSoldering()) { + setBuzzer(false); + return OperatingMode::HomeScreen; + } +#ifdef NO_SLEEP_MODE + + if (shouldShutdown()) { + // shutdown + currentTempTargetDegC = 0; + return OperatingMode::HomeScreen; + } +#endif + if (shouldBeSleeping()) { + return OperatingMode::Sleeping; + } + + if (heaterThermalRunaway) { + currentTempTargetDegC = 0; // heater control off + heaterThermalRunaway = false; + return OperatingMode::ThermalRunaway; + } + + // Update the setpoints for the temperature + if (cxt->scratch_state.state2) { + if (getSettingValue(SettingsOptions::TemperatureInF)) + currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::BoostTemp)); + else { + currentTempTargetDegC = (getSettingValue(SettingsOptions::BoostTemp)); + } + } else { + if (getSettingValue(SettingsOptions::TemperatureInF)) + currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::SolderingTemp)); + else { + currentTempTargetDegC = (getSettingValue(SettingsOptions::SolderingTemp)); } } - for (;;) { - ButtonState buttons = getButtonState(); - if (buttonsLocked && (getSettingValue(SettingsOptions::LockingMode) != 0)) { // If buttons locked - switch (buttons) { - case BUTTON_NONE: - boostModeOn = false; - break; - case BUTTON_BOTH_LONG: - // Unlock buttons - buttonsLocked = false; - warnUser(translatedString(Tr->UnlockingKeysString), TICKS_SECOND); - break; - case BUTTON_F_LONG: - // if boost mode is enabled turn it on - if (getSettingValue(SettingsOptions::BoostTemp) && (getSettingValue(SettingsOptions::LockingMode) == 1)) { - boostModeOn = true; - currentMode = OperatingMode::boost; - } - break; - // fall through - case BUTTON_BOTH: - case BUTTON_B_LONG: - case BUTTON_F_SHORT: - case BUTTON_B_SHORT: - // Do nothing and display a lock warning - warnUser(translatedString(Tr->WarningKeysLockedString), TICKS_SECOND / 2); - break; - default: - break; - } - } else { // Button not locked - switch (buttons) { - case BUTTON_NONE: - // stay - boostModeOn = false; - currentMode = OperatingMode::soldering; - break; - case BUTTON_BOTH: - case BUTTON_B_LONG: - return; // exit on back long hold - case BUTTON_F_LONG: - // if boost mode is enabled turn it on - if (getSettingValue(SettingsOptions::BoostTemp)) { - boostModeOn = true; - currentMode = OperatingMode::boost; - } - break; - case BUTTON_F_SHORT: - case BUTTON_B_SHORT: { - uint16_t oldTemp = getSettingValue(SettingsOptions::SolderingTemp); - gui_solderingTempAdjust(); // goto adjust temp mode - if (oldTemp != getSettingValue(SettingsOptions::SolderingTemp)) { - saveSettings(); // only save on change - } - } break; - case BUTTON_BOTH_LONG: - if (getSettingValue(SettingsOptions::LockingMode) != 0) { - // Lock buttons - buttonsLocked = true; - warnUser(translatedString(Tr->LockingKeysString), TICKS_SECOND); - } - break; - default: - break; - } + + // Update status + int error = currentTempTargetDegC - TipThermoModel::getTipInC(); + if (error >= -10 && error <= 10) { + // converged + if (!cxt->scratch_state.state5) { + setBuzzer(true); + cxt->scratch_state.state3 = xTaskGetTickCount() + TICKS_SECOND / 3; + cxt->scratch_state.state5 = true; } - // else we update the screen information + setStatusLED(LED_HOT); + } else { + setStatusLED(LED_HEATING); + cxt->scratch_state.state5 = false; + } + if (cxt->scratch_state.state3 != 0 && xTaskGetTickCount() >= cxt->scratch_state.state3) { + setBuzzer(false); + } - OLED::clearScreen(); - // Draw in the screen details - if (getSettingValue(SettingsOptions::DetailedSoldering)) { - if (OLED::getRotation()) { - OLED::setCursor(50, 0); - } else { - OLED::setCursor(-1, 0); - } + // Draw in the screen details + if (getSettingValue(SettingsOptions::DetailedSoldering)) { + if (OLED::getRotation()) { + OLED::setCursor(50, 0); + } else { + OLED::setCursor(-1, 0); + } - gui_drawTipTemp(true, FontStyle::LARGE); + gui_drawTipTemp(true, FontStyle::LARGE); #ifndef NO_SLEEP_MODE - if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) { - if (OLED::getRotation()) { - OLED::setCursor(32, 0); - } else { - OLED::setCursor(47, 0); - } - printCountdownUntilSleep(getSleepTimeout()); + if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) { + if (OLED::getRotation()) { + OLED::setCursor(32, 0); + } else { + OLED::setCursor(47, 0); } + printCountdownUntilSleep(getSleepTimeout()); + } #endif - if (boostModeOn) { - if (OLED::getRotation()) { - OLED::setCursor(38, 8); - } else { - OLED::setCursor(55, 8); - } - OLED::print(SmallSymbolPlus, FontStyle::SMALL); + if (cxt->scratch_state.state2) { // Boost mode is on + if (OLED::getRotation()) { + OLED::setCursor(38, 8); } else { - if (OLED::getRotation()) { - OLED::setCursor(32, 8); - } else { - OLED::setCursor(47, 8); - } - OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2); + OLED::setCursor(55, 8); } - - detailedPowerStatus(); - + OLED::print(SmallSymbolPlus, FontStyle::SMALL); } else { - basicSolderingStatus(boostModeOn); - } - - OLED::refresh(); - // Update the setpoints for the temperature - if (boostModeOn) { - if (getSettingValue(SettingsOptions::TemperatureInF)) { - currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::BoostTemp)); + if (OLED::getRotation()) { + OLED::setCursor(32, 8); } else { - currentTempTargetDegC = (getSettingValue(SettingsOptions::BoostTemp)); - } - } else { - if (getSettingValue(SettingsOptions::TemperatureInF)) { - currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::SolderingTemp)); - } else { - currentTempTargetDegC = (getSettingValue(SettingsOptions::SolderingTemp)); + OLED::setCursor(47, 8); } + OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2); } - if (checkExitSoldering()) { - setBuzzer(false); - return; - } + detailedPowerStatus(); - // Update status - int error = currentTempTargetDegC - TipThermoModel::getTipInC(); - if (error >= -10 && error <= 10) { - // converged - if (!converged) { - setBuzzer(true); - buzzerEnd = xTaskGetTickCount() + TICKS_SECOND / 3; - converged = true; - } - setStatusLED(LED_HOT); - } else { - setStatusLED(LED_HEATING); - converged = false; - } - if (buzzerEnd != 0 && xTaskGetTickCount() >= buzzerEnd) { - setBuzzer(false); - } - - // slow down ui update rate - GUIDelay(); + } else { + basicSolderingStatus(cxt->scratch_state.state2); } } diff --git a/source/Core/Threads/OperatingModes/SolderingProfile.cpp b/source/Core/Threads/OperatingModes/SolderingProfile.cpp index df6b5805..83cc065d 100644 --- a/source/Core/Threads/OperatingModes/SolderingProfile.cpp +++ b/source/Core/Threads/OperatingModes/SolderingProfile.cpp @@ -2,222 +2,209 @@ #include "OperatingModes.h" #include "SolderingCommon.h" -extern OperatingMode currentMode; - -void gui_solderingProfileMode() { +OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt) { /* - * * Soldering (gui_solderingMode) + * * Soldering * -> Main loop where we draw temp, and animations - * PID control * --> Long hold back button to exit * --> Double button to exit */ - currentMode = OperatingMode::soldering; - TickType_t buzzerEnd = 0; + uint16_t tipTemp = 0; - bool waitForRelease = true; - TickType_t phaseStartTime = xTaskGetTickCount(); - - uint16_t tipTemp = 0; - uint8_t profilePhase = 0; - - uint16_t phaseElapsedSeconds = 0; - uint16_t phaseTotalSeconds = 0; - uint16_t phaseStartTemp = 0; - uint16_t phaseEndTemp = getSettingValue(SettingsOptions::ProfilePreheatTemp); + // If this is during init, start at preheat + if (cxt->scratch_state.state1 == 0) { + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePreheatTemp); + } uint16_t phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfilePreheatSpeed); uint16_t profileCurrentTargetTemp = 0; - for (;;) { - ButtonState buttons = getButtonState(); - if (buttons) { - if (waitForRelease) { - buttons = BUTTON_NONE; - } + switch (buttons) { + case BUTTON_BOTH: + case BUTTON_B_LONG: + return OperatingMode::HomeScreen; // exit on back long hold + case BUTTON_F_LONG: + case BUTTON_F_SHORT: + case BUTTON_B_SHORT: + case BUTTON_NONE: + // Not used yet + break; + default: + break; + } + + if (getSettingValue(SettingsOptions::TemperatureInF)) { + tipTemp = TipThermoModel::getTipInF(); + } else { + tipTemp = TipThermoModel::getTipInC(); + } + // If time of entering is unknown; then we start now + if (cxt->scratch_state.state3 == 0) { + cxt->scratch_state.state3 = xTaskGetTickCount(); + } + + // if start temp is unknown (preheat), we're setting it now + if (cxt->scratch_state.state6 == 0) { + cxt->scratch_state.state6 = tipTemp; + // if this is hotter than the preheat temperature, we should fail + if (cxt->scratch_state.state6 >= 55) { + warnUser(translatedString(Tr->TooHotToStartProfileWarning), buttons); + return OperatingMode::HomeScreen; + } + } + uint16_t phaseElapsedSeconds = (xTaskGetTickCount() - cxt->scratch_state.state3) / TICKS_SECOND; + + // have we finished this phase? + if (phaseElapsedSeconds >= cxt->scratch_state.state2 && tipTemp == cxt->scratch_state.state5) { + cxt->scratch_state.state1++; + cxt->scratch_state.state6 = cxt->scratch_state.state5; + cxt->scratch_state.state3 = xTaskGetTickCount(); + phaseElapsedSeconds = 0; + if (cxt->scratch_state.state1 > getSettingValue(SettingsOptions::ProfilePhases)) { + // done with all phases, lets go to cooldown + cxt->scratch_state.state2 = 0; + cxt->scratch_state.state5 = 0; + phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfileCooldownSpeed); } else { - waitForRelease = false; - } - - switch (buttons) { - case BUTTON_NONE: - break; - case BUTTON_BOTH: - case BUTTON_B_LONG: - return; // exit on back long hold - case BUTTON_F_LONG: - case BUTTON_F_SHORT: - case BUTTON_B_SHORT: - // Not used yet - break; - default: - break; - } - - tipTemp = getTipTemp(); - - // if start temp is unknown (preheat), we're setting it now - if (phaseStartTemp == 0) { - phaseStartTemp = tipTemp; - // if this is hotter than the preheat temperature, we should fail - if (phaseStartTemp >= 55) { - warnUser(translatedString(Tr->TooHotToStartProfileWarning), 10 * TICKS_SECOND); - return; + // set up next phase + switch (cxt->scratch_state.state1) { + case 1: + cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase1Duration); + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase1Temp); + break; + case 2: + cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase2Duration); + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase2Temp); + break; + case 3: + cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase3Duration); + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase3Temp); + break; + case 4: + cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase4Duration); + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase4Temp); + break; + case 5: + cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase5Duration); + cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase5Temp); + break; + default: + break; } - } - - phaseElapsedSeconds = (xTaskGetTickCount() - phaseStartTime) / TICKS_SECOND; - - // have we finished this phase? - if (phaseElapsedSeconds >= phaseTotalSeconds && tipTemp == phaseEndTemp) { - profilePhase++; - - phaseStartTemp = phaseEndTemp; - phaseStartTime = xTaskGetTickCount(); - phaseElapsedSeconds = 0; - - if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { - // done with all phases, lets go to cooldown - phaseTotalSeconds = 0; - phaseEndTemp = 0; - phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfileCooldownSpeed); + if (cxt->scratch_state.state6 < cxt->scratch_state.state5) { + phaseTicksPerDegree = (cxt->scratch_state.state2 * TICKS_SECOND) / (cxt->scratch_state.state5 - cxt->scratch_state.state6); } else { - // set up next phase - switch (profilePhase) { - case 1: - phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase1Duration); - phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase1Temp); - break; - case 2: - phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase2Duration); - phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase2Temp); - break; - case 3: - phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase3Duration); - phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase3Temp); - break; - case 4: - phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase4Duration); - phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase4Temp); - break; - case 5: - phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase5Duration); - phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase5Temp); - break; - default: - break; - } - if (phaseStartTemp < phaseEndTemp) { - phaseTicksPerDegree = (phaseTotalSeconds * TICKS_SECOND) / (phaseEndTemp - phaseStartTemp); - } else { - phaseTicksPerDegree = (phaseTotalSeconds * TICKS_SECOND) / (phaseStartTemp - phaseEndTemp); - } + phaseTicksPerDegree = (cxt->scratch_state.state2 * TICKS_SECOND) / (cxt->scratch_state.state6 - cxt->scratch_state.state5); } } + } - // cooldown phase done? - if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { - if (TipThermoModel::getTipInC() < 55) { - // we're done, let the buzzer beep too - setStatusLED(LED_STANDBY); - if (buzzerEnd == 0) { - setBuzzer(true); - buzzerEnd = xTaskGetTickCount() + TICKS_SECOND / 3; - } + // cooldown phase done? + if (cxt->scratch_state.state1 > getSettingValue(SettingsOptions::ProfilePhases)) { + if (TipThermoModel::getTipInC() < 55) { + // we're done, let the buzzer beep too + setStatusLED(LED_STANDBY); + if (cxt->scratch_state.state4 == 0) { + setBuzzer(true); + cxt->scratch_state.state4 = xTaskGetTickCount() + TICKS_SECOND / 3; } } + } - // determine current target temp - if (phaseStartTemp < phaseEndTemp) { - if (profileCurrentTargetTemp < phaseEndTemp) { - profileCurrentTargetTemp = phaseStartTemp + ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree); - } + // determine current target temp + if (cxt->scratch_state.state6 < cxt->scratch_state.state5) { + if (profileCurrentTargetTemp < cxt->scratch_state.state5) { + profileCurrentTargetTemp = cxt->scratch_state.state6 + ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree); + } + } else { + if (profileCurrentTargetTemp > cxt->scratch_state.state5) { + profileCurrentTargetTemp = cxt->scratch_state.state6 - ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree); + } + } + + // Draw in the screen details + if (getSettingValue(SettingsOptions::DetailedSoldering)) { + // print temperature + if (OLED::getRotation()) { + OLED::setCursor(48, 0); } else { - if (profileCurrentTargetTemp > phaseEndTemp) { - profileCurrentTargetTemp = phaseStartTemp - ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree); - } + OLED::setCursor(0, 0); } - OLED::clearScreen(); - // Draw in the screen details - if (getSettingValue(SettingsOptions::DetailedSoldering)) { - // print temperature + OLED::printNumber(tipTemp, 3, FontStyle::SMALL); + OLED::print(SmallSymbolSlash, FontStyle::SMALL); + OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL); + + if (getSettingValue(SettingsOptions::TemperatureInF)) + OLED::print(SmallSymbolDegF, FontStyle::SMALL); + else + OLED::print(SmallSymbolDegC, FontStyle::SMALL); + + // print phase + if (cxt->scratch_state.state1 > 0 && cxt->scratch_state.state1 <= getSettingValue(SettingsOptions::ProfilePhases)) { if (OLED::getRotation()) { - OLED::setCursor(48, 0); + OLED::setCursor(36, 0); } else { - OLED::setCursor(0, 0); + OLED::setCursor(55, 0); } + OLED::printNumber(cxt->scratch_state.state1, 1, FontStyle::SMALL); + } + + // print time progress / preheat / cooldown + if (OLED::getRotation()) { + OLED::setCursor(42, 8); + } else { + OLED::setCursor(0, 8); + } + + if (cxt->scratch_state.state1 == 0) { + OLED::print(translatedString(Tr->ProfilePreheatString), FontStyle::SMALL); + } else if (cxt->scratch_state.state1 > getSettingValue(SettingsOptions::ProfilePhases)) { + OLED::print(translatedString(Tr->ProfileCooldownString), FontStyle::SMALL); + } else { + OLED::printNumber(phaseElapsedSeconds / 60, 1, FontStyle::SMALL); + OLED::print(SmallSymbolColon, FontStyle::SMALL); + OLED::printNumber(phaseElapsedSeconds % 60, 2, FontStyle::SMALL, false); - OLED::printNumber(tipTemp, 3, FontStyle::SMALL); OLED::print(SmallSymbolSlash, FontStyle::SMALL); - OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL); - OLED::printSymbolDeg(FontStyle::SMALL); - // print phase - if (profilePhase > 0 && profilePhase <= getSettingValue(SettingsOptions::ProfilePhases)) { - if (OLED::getRotation()) { - OLED::setCursor(36, 0); - } else { - OLED::setCursor(55, 0); - } - OLED::printNumber(profilePhase, 1, FontStyle::SMALL); - } - - // print time progress / preheat / cooldown - if (OLED::getRotation()) { - OLED::setCursor(42, 8); - } else { - OLED::setCursor(0, 8); - } - - if (profilePhase == 0) { - OLED::print(translatedString(Tr->ProfilePreheatString), FontStyle::SMALL); - } else if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { - OLED::print(translatedString(Tr->ProfileCooldownString), FontStyle::SMALL); - } else { - OLED::printNumber(phaseElapsedSeconds / 60, 1, FontStyle::SMALL); + // blink if we can't keep up with the time goal + if (phaseElapsedSeconds < cxt->scratch_state.state2 + 2 || (xTaskGetTickCount() / TICKS_SECOND) % 2 == 0) { + OLED::printNumber(cxt->scratch_state.state2 / 60, 1, FontStyle::SMALL); OLED::print(SmallSymbolColon, FontStyle::SMALL); - OLED::printNumber(phaseElapsedSeconds % 60, 2, FontStyle::SMALL, false); - - OLED::print(SmallSymbolSlash, FontStyle::SMALL); - - // blink if we can't keep up with the time goal - if (phaseElapsedSeconds < phaseTotalSeconds + 2 || (xTaskGetTickCount() / TICKS_SECOND) % 2 == 0) { - OLED::printNumber(phaseTotalSeconds / 60, 1, FontStyle::SMALL); - OLED::print(SmallSymbolColon, FontStyle::SMALL); - OLED::printNumber(phaseTotalSeconds % 60, 2, FontStyle::SMALL, false); - } + OLED::printNumber(cxt->scratch_state.state2 % 60, 2, FontStyle::SMALL, false); } - - detailedPowerStatus(); - - } else { - basicSolderingStatus(false); } - OLED::refresh(); - // Update the setpoints for the temperature - if (getSettingValue(SettingsOptions::TemperatureInF)) { - currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp); - } else { - currentTempTargetDegC = profileCurrentTargetTemp; - } + detailedPowerStatus(); - if (checkExitSoldering() || (buzzerEnd != 0 && xTaskGetTickCount() >= buzzerEnd)) { - setBuzzer(false); - return; - } + } else { + basicSolderingStatus(false); + } - // Update LED status - if (profilePhase == 0) { - setStatusLED(LED_HEATING); - } else if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { - setStatusLED(LED_COOLING_STILL_HOT); - } else { - setStatusLED(LED_HOT); - } + // Update the setpoints for the temperature + if (getSettingValue(SettingsOptions::TemperatureInF)) { + currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp); + } else { + currentTempTargetDegC = profileCurrentTargetTemp; + } - // slow down ui update rate - GUIDelay(); + if (checkExitSoldering() || (cxt->scratch_state.state4 != 0 && xTaskGetTickCount() >= cxt->scratch_state.state4)) { + setBuzzer(false); + return OperatingMode::HomeScreen; + } + if (heaterThermalRunaway) { + currentTempTargetDegC = 0; // heater control off + heaterThermalRunaway = false; + return OperatingMode::ThermalRunaway; + } + + // Update LED status + if (cxt->scratch_state.state1 == 0) { + setStatusLED(LED_HEATING); + } else if (cxt->scratch_state.state1 > getSettingValue(SettingsOptions::ProfilePhases)) { + setStatusLED(LED_COOLING_STILL_HOT); + } else { + setStatusLED(LED_HOT); } } diff --git a/source/Core/Threads/OperatingModes/TemperatureAdjust.cpp b/source/Core/Threads/OperatingModes/TemperatureAdjust.cpp index ce06e83b..3f750d31 100644 --- a/source/Core/Threads/OperatingModes/TemperatureAdjust.cpp +++ b/source/Core/Threads/OperatingModes/TemperatureAdjust.cpp @@ -1,120 +1,99 @@ #include "OperatingModes.h" -void gui_solderingTempAdjust(void) { - TickType_t lastChange = xTaskGetTickCount(); - currentTempTargetDegC = 0; // Turn off heater while adjusting temp - TickType_t autoRepeatTimer = 0; - uint8_t autoRepeatAcceleration = 0; -#ifndef PROFILE_SUPPORT - bool waitForRelease = false; - ButtonState buttons = getButtonState(); +OperatingMode gui_solderingTempAdjust(const ButtonState buttons, guiContext *cxt) { - if (buttons != BUTTON_NONE) { - // Temp adjust entered by long-pressing F button. - waitForRelease = true; + currentTempTargetDegC = 0; // Turn off heater while adjusting temp + uint16_t *buttonLockout = &(cxt->scratch_state.state1); + uint32_t *lastButtonTime = &(cxt->scratch_state.state3); + uint16_t *buttonAccel = &(cxt->scratch_state.state2); + + if (*buttonLockout == 0) { + // When we first enter we wait for the user to release buttons before enabling changes + if (buttons != BUTTON_NONE) { + return OperatingMode::TemperatureAdjust; + } + (*buttonLockout)++; } -#else - ButtonState buttons; -#endif - for (;;) { - OLED::setCursor(0, 0); - OLED::clearScreen(); - buttons = getButtonState(); - if (buttons) { - lastChange = xTaskGetTickCount(); -#ifndef PROFILE_SUPPORT - if (waitForRelease) { - buttons = BUTTON_NONE; - } - } else { - waitForRelease = false; -#endif - } - int16_t delta = 0; - switch (buttons) { - case BUTTON_NONE: - // stay - autoRepeatAcceleration = 0; - break; - case BUTTON_BOTH: - // exit - return; - break; - case BUTTON_B_LONG: - if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) { - delta = -getSettingValue(SettingsOptions::TempChangeLongStep); - autoRepeatTimer = xTaskGetTickCount(); - autoRepeatAcceleration += PRESS_ACCEL_STEP; - } - break; - case BUTTON_B_SHORT: - delta = -getSettingValue(SettingsOptions::TempChangeShortStep); - break; - case BUTTON_F_LONG: - if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) { - delta = getSettingValue(SettingsOptions::TempChangeLongStep); - autoRepeatTimer = xTaskGetTickCount(); - autoRepeatAcceleration += PRESS_ACCEL_STEP; - } - break; - case BUTTON_F_SHORT: - delta = getSettingValue(SettingsOptions::TempChangeShortStep); - break; - default: - break; - } - if ((PRESS_ACCEL_INTERVAL_MAX - autoRepeatAcceleration) < PRESS_ACCEL_INTERVAL_MIN) { - autoRepeatAcceleration = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN; - } - // If buttons are flipped; flip the delta - if (getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled)) { - delta = -delta; - } - if (delta != 0) { - // constrain between the set temp limits, i.e. 10-450 C - int16_t newTemp = getSettingValue(SettingsOptions::SolderingTemp); - newTemp += delta; - // Round to nearest increment of delta - delta = abs(delta); - newTemp = (newTemp / delta) * delta; + OLED::setCursor(0, 0); - if (getSettingValue(SettingsOptions::TemperatureInF)) { - if (newTemp > MAX_TEMP_F) { - newTemp = MAX_TEMP_F; - } - if (newTemp < MIN_TEMP_F) { - newTemp = MIN_TEMP_F; - } - } else { - if (newTemp > MAX_TEMP_C) { - newTemp = MAX_TEMP_C; - } - if (newTemp < MIN_TEMP_C) { - newTemp = MIN_TEMP_C; - } - } - setSettingValue(SettingsOptions::SolderingTemp, (uint16_t)newTemp); + int16_t delta = 0; + switch (buttons) { + case BUTTON_NONE: + // stay + (*buttonAccel) = 0; + break; + case BUTTON_BOTH: + // exit + return cxt->previousMode; + case BUTTON_B_LONG: + if (xTaskGetTickCount() - (*lastButtonTime) + (*buttonAccel) > PRESS_ACCEL_INTERVAL_MAX) { + delta = -getSettingValue(SettingsOptions::TempChangeLongStep); + (*lastButtonTime) = xTaskGetTickCount(); + (*buttonAccel) += PRESS_ACCEL_STEP; } - if (xTaskGetTickCount() - lastChange > (TICKS_SECOND * 2)) { - return; // exit if user just doesn't press anything for a bit + break; + case BUTTON_B_SHORT: + delta = -getSettingValue(SettingsOptions::TempChangeShortStep); + break; + case BUTTON_F_LONG: + if (xTaskGetTickCount() - (*lastButtonTime) + (*buttonAccel) > PRESS_ACCEL_INTERVAL_MAX) { + delta = getSettingValue(SettingsOptions::TempChangeLongStep); + (*lastButtonTime) = xTaskGetTickCount(); + (*buttonAccel) += PRESS_ACCEL_STEP; } - - if (OLED::getRotation()) { - OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE); - } else { - OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE); - } - - OLED::print(LargeSymbolSpace, FontStyle::LARGE); - OLED::printNumber(getSettingValue(SettingsOptions::SolderingTemp), 3, FontStyle::LARGE); - OLED::printSymbolDeg(FontStyle::EXTRAS); - OLED::print(LargeSymbolSpace, FontStyle::LARGE); - if (OLED::getRotation()) { - OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE); - } else { - OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE); - } - OLED::refresh(); - GUIDelay(); + break; + case BUTTON_F_SHORT: + delta = getSettingValue(SettingsOptions::TempChangeShortStep); + break; + default: + break; } + if ((PRESS_ACCEL_INTERVAL_MAX - (*buttonAccel)) < PRESS_ACCEL_INTERVAL_MIN) { + (*buttonAccel) = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN; + } + // If buttons are flipped; flip the delta + if (getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled)) { + delta = -delta; + } + if (delta != 0) { + // constrain between the set temp limits, i.e. 10-450 C + int16_t newTemp = getSettingValue(SettingsOptions::SolderingTemp); + newTemp += delta; + // Round to nearest increment of delta + delta = abs(delta); + newTemp = (newTemp / delta) * delta; + + if (getSettingValue(SettingsOptions::TemperatureInF)) { + if (newTemp > MAX_TEMP_F) + newTemp = MAX_TEMP_F; + if (newTemp < MIN_TEMP_F) + newTemp = MIN_TEMP_F; + } else { + if (newTemp > MAX_TEMP_C) + newTemp = MAX_TEMP_C; + if (newTemp < MIN_TEMP_C) + newTemp = MIN_TEMP_C; + } + setSettingValue(SettingsOptions::SolderingTemp, (uint16_t)newTemp); + } + if (xTaskGetTickCount() - cxt->viewEnterTime > (TICKS_SECOND * 2)) { + return cxt->previousMode; // exit if user just doesn't press anything for a bit + } + if (OLED::getRotation()) { + OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE); + } else { + OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE); + } + + OLED::print(LargeSymbolSpace, FontStyle::LARGE); + OLED::printNumber(getSettingValue(SettingsOptions::SolderingTemp), 3, FontStyle::LARGE); + OLED::printSymbolDeg(FontStyle::EXTRAS); + OLED::print(LargeSymbolSpace, FontStyle::LARGE); + if (OLED::getRotation()) { + OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE); + } else { + OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE); + } + + return OperatingMode::TemperatureAdjust; // Stay in temp adjust } diff --git a/source/Core/Threads/OperatingModes/USBPDDebug_FUSB.cpp b/source/Core/Threads/OperatingModes/USBPDDebug_FUSB.cpp index 65776970..9be7b7e2 100644 --- a/source/Core/Threads/OperatingModes/USBPDDebug_FUSB.cpp +++ b/source/Core/Threads/OperatingModes/USBPDDebug_FUSB.cpp @@ -2,93 +2,89 @@ #ifdef POW_PD #ifdef HAS_POWER_DEBUG_MENU -void showPDDebug(void) { +OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) { // Print out the USB-PD state // Basically this is like the Debug menu, but instead we want to print out the PD status - uint8_t screen = 0; - ButtonState b; - for (;;) { - OLED::clearScreen(); // Ensure the buffer starts clean - OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) - OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title - OLED::setCursor(0, 8); // second line - if (screen == 0) { - // Print the PD state machine - OLED::print(SmallSymbolState, FontStyle::SMALL); - OLED::print(SmallSymbolSpace, FontStyle::SMALL); - OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true); - OLED::print(SmallSymbolSpace, FontStyle::SMALL); - // Also print vbus mod status - if (USBPowerDelivery::fusbPresent()) { - if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) { - if (!USBPowerDelivery::isVBUSConnected()) { - OLED::print(SmallSymbolNoVBus, FontStyle::SMALL); - } else { - OLED::print(SmallSymbolVBus, FontStyle::SMALL); - } + uint16_t *screen = &(cxt->scratch_state.state1); + OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) + OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title + OLED::setCursor(0, 8); // second line + if ((*screen) == 0) { + // Print the PD state machine + OLED::print(SmallSymbolState, FontStyle::SMALL); + OLED::print(SmallSymbolSpace, FontStyle::SMALL); + OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true); + OLED::print(SmallSymbolSpace, FontStyle::SMALL); + // Also print vbus mod status + if (USBPowerDelivery::fusbPresent()) { + if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) { + if (!USBPowerDelivery::isVBUSConnected()) { + OLED::print(SmallSymbolNoVBus, FontStyle::SMALL); + } else { + OLED::print(SmallSymbolVBus, FontStyle::SMALL); + } + } + } + } else { + // Print out the Proposed power options one by one + auto lastCaps = USBPowerDelivery::getLastSeenCapabilities(); + if (((*screen) - 1) < 11) { + int voltage_mv = 0; + int min_voltage = 0; + int current_a_x100 = 0; + int wattage = 0; + + if ((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { + voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(lastCaps[(*screen) - 1])); // voltage in mV units + current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(lastCaps[(*screen) - 1]); // current in 10mA units + } else if (((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[(*screen) - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_AVS)) { + voltage_mv = PD_PAV2MV(PD_APDO_AVS_MAX_VOLTAGE_GET(lastCaps[(*screen) - 1])); + min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[(*screen) - 1])); + // Last value is wattage + wattage = PD_APDO_AVS_MAX_POWER_GET(lastCaps[(*screen) - 1]); + } else if (((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[(*screen) - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS)) { + voltage_mv = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(lastCaps[(*screen) - 1])); + min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[(*screen) - 1])); + current_a_x100 = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(lastCaps[(*screen) - 1])); // max current in 10mA units + } + // Skip not used entries + if (voltage_mv == 0) { + *screen++; + } else { + // print out this entry of the proposal + OLED::printNumber(*screen, 2, FontStyle::SMALL, true); // print the entry number + OLED::print(SmallSymbolSpace, FontStyle::SMALL); + if (min_voltage > 0) { + OLED::printNumber(min_voltage / 1000, 2, FontStyle::SMALL, true); // print the voltage + OLED::print(SmallSymbolMinus, FontStyle::SMALL); + } + OLED::printNumber(voltage_mv / 1000, 2, FontStyle::SMALL, true); // print the voltage + OLED::print(SmallSymbolVolts, FontStyle::SMALL); + OLED::print(SmallSymbolSpace, FontStyle::SMALL); + if (wattage) { + OLED::printNumber(wattage, 3, FontStyle::SMALL, true); // print the current in 0.1A res + OLED::print(SmallSymbolWatts, FontStyle::SMALL); + } else { + OLED::printNumber(current_a_x100 / 100, 2, FontStyle::SMALL, true); // print the current in 0.1A res + OLED::print(SmallSymbolDot, FontStyle::SMALL); + OLED::printNumber(current_a_x100 % 100, 2, FontStyle::SMALL, false); // print the current in 0.1A res + OLED::print(SmallSymbolAmps, FontStyle::SMALL); } } } else { - // Print out the Proposed power options one by one - auto lastCaps = USBPowerDelivery::getLastSeenCapabilities(); - if ((screen - 1) < 11) { - int voltage_mv = 0; - int min_voltage = 0; - int current_a_x100 = 0; - int wattage = 0; - - if ((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { - voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(lastCaps[screen - 1])); // voltage in mV units - current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(lastCaps[screen - 1]); // current in 10mA units - } else if (((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[screen - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_AVS)) { - voltage_mv = PD_PAV2MV(PD_APDO_AVS_MAX_VOLTAGE_GET(lastCaps[screen - 1])); - min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[screen - 1])); - // Last value is wattage - wattage = PD_APDO_AVS_MAX_POWER_GET(lastCaps[screen - 1]); - } else if (((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[screen - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS)) { - voltage_mv = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(lastCaps[screen - 1])); - min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[screen - 1])); - current_a_x100 = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(lastCaps[screen - 1])); // max current in 10mA units - } - // Skip not used entries - if (voltage_mv == 0) { - screen++; - } else { - // print out this entry of the proposal - OLED::printNumber(screen, 2, FontStyle::SMALL, true); // print the entry number - OLED::print(SmallSymbolSpace, FontStyle::SMALL); - if (min_voltage > 0) { - OLED::printNumber(min_voltage / 1000, 2, FontStyle::SMALL, true); // print the voltage - OLED::print(SmallSymbolMinus, FontStyle::SMALL); - } - OLED::printNumber(voltage_mv / 1000, 2, FontStyle::SMALL, true); // print the voltage - OLED::print(SmallSymbolVolts, FontStyle::SMALL); - OLED::print(SmallSymbolSpace, FontStyle::SMALL); - if (wattage) { - OLED::printNumber(wattage, 3, FontStyle::SMALL, true); // print the current in 0.1A res - OLED::print(SmallSymbolWatts, FontStyle::SMALL); - } else { - OLED::printNumber(current_a_x100 / 100, 2, FontStyle::SMALL, true); // print the current in 0.1A res - OLED::print(SmallSymbolDot, FontStyle::SMALL); - OLED::printNumber(current_a_x100 % 100, 2, FontStyle::SMALL, false); // print the current in 0.1A res - OLED::print(SmallSymbolAmps, FontStyle::SMALL); - } - } - } else { - screen = 0; - } + *screen = 0; } OLED::refresh(); - b = getButtonState(); - if (b == BUTTON_B_SHORT) { - return; - } else if (b == BUTTON_F_SHORT) { - screen++; + if (buttons == BUTTON_B_SHORT) + return OperatingMode::InitialisationDone; + else if (buttons == BUTTON_F_SHORT) { + *screen++; } GUIDelay(); } + return OperatingMode::UsbPDDebug; } #endif #endif diff --git a/source/Core/Threads/OperatingModes/USBPDDebug_HUSB238.cpp b/source/Core/Threads/OperatingModes/USBPDDebug_HUSB238.cpp index 5841e47c..db9c7ff6 100644 --- a/source/Core/Threads/OperatingModes/USBPDDebug_HUSB238.cpp +++ b/source/Core/Threads/OperatingModes/USBPDDebug_HUSB238.cpp @@ -2,7 +2,7 @@ #include "OperatingModes.h" #if POW_PD_EXT == 1 #ifdef HAS_POWER_DEBUG_MENU -void showPDDebug(void) { +OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) { // Print out the USB-PD state // Basically this is like the Debug menu, but instead we want to print out the PD status uint8_t screen = 0; diff --git a/source/Core/Threads/OperatingModes/utils/OperatingModeUtilities.h b/source/Core/Threads/OperatingModes/utils/OperatingModeUtilities.h index ab3f36f9..e204adf3 100644 --- a/source/Core/Threads/OperatingModes/utils/OperatingModeUtilities.h +++ b/source/Core/Threads/OperatingModes/utils/OperatingModeUtilities.h @@ -1,18 +1,19 @@ #ifndef OPERATING_MODE_UTILITIES_H_ #define OPERATING_MODE_UTILITIES_H_ +#include "Buttons.hpp" #include "OLED.hpp" #include -void GUIDelay(); // -bool checkForUnderVoltage(void); // -uint32_t getSleepTimeout(void); // -bool shouldBeSleeping(bool inAutoStart); // -bool shouldShutdown(void); // -void gui_drawTipTemp(bool symbol, const FontStyle font); // -void printVoltage(void); // -void warnUser(const char *warning, const TickType_t timeout); // -void gui_drawBatteryIcon(void); // -bool checkForUnderVoltage(void); // -uint16_t min(uint16_t a, uint16_t b); // -void printCountdownUntilSleep(int sleepThres); // +void GUIDelay(); // +bool checkForUnderVoltage(void); // +uint32_t getSleepTimeout(void); // +bool shouldBeSleeping(); // +bool shouldShutdown(void); // +void gui_drawTipTemp(bool symbol, const FontStyle font); // +void printVoltage(void); // +bool warnUser(const char *warning, const ButtonState buttons); // +void gui_drawBatteryIcon(void); // +bool checkForUnderVoltage(void); // +uint16_t min(uint16_t a, uint16_t b); // +void printCountdownUntilSleep(int sleepThres); // #endif \ No newline at end of file diff --git a/source/Core/Threads/OperatingModes/utils/ShowWarning.cpp b/source/Core/Threads/OperatingModes/utils/ShowWarning.cpp index fcd2972e..80bfa2df 100644 --- a/source/Core/Threads/OperatingModes/utils/ShowWarning.cpp +++ b/source/Core/Threads/OperatingModes/utils/ShowWarning.cpp @@ -1,8 +1,9 @@ #include "Buttons.hpp" #include "OperatingModeUtilities.h" -void warnUser(const char *warning, const TickType_t timeout) { +#include "OperatingModes.h" +bool warnUser(const char *warning, const ButtonState buttons) { OLED::clearScreen(); OLED::printWholeScreen(warning); - OLED::refresh(); - waitForButtonPressOrTimeout(timeout); + // TODO also timeout + return buttons != BUTTON_NONE; } diff --git a/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp b/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp index 0f1bbd2a..5975a1b8 100644 --- a/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp +++ b/source/Core/Threads/OperatingModes/utils/SolderingCommon.cpp @@ -106,30 +106,8 @@ bool checkExitSoldering(void) { } } #endif -#ifdef NO_SLEEP_MODE - // No sleep mode, but still want shutdown timeout - - if (shouldShutdown()) { - // shutdown - currentTempTargetDegC = 0; - lastMovementTime = xTaskGetTickCount(); // We manually move the movement time to now such that shutdown timer is reset - - return true; // we want to exit soldering mode - } -#endif - if (shouldBeSleeping(false)) { - if (gui_SolderingSleepingMode(false, false)) { - return true; // If the function returns non-0 then exit - } - } // If we have tripped thermal runaway, turn off heater and show warning - if (heaterThermalRunaway) { - currentTempTargetDegC = 0; // heater control off - warnUser(translatedString(Tr->WarningThermalRunaway), 10 * TICKS_SECOND); - heaterThermalRunaway = false; - return true; - } return false; } diff --git a/source/Core/Threads/OperatingModes/utils/shouldDeviceSleep.cpp b/source/Core/Threads/OperatingModes/utils/shouldDeviceSleep.cpp index 92a99fc9..9e27f2eb 100644 --- a/source/Core/Threads/OperatingModes/utils/shouldDeviceSleep.cpp +++ b/source/Core/Threads/OperatingModes/utils/shouldDeviceSleep.cpp @@ -4,15 +4,13 @@ TickType_t lastHallEffectSleepStart = 0; extern TickType_t lastMovementTime; -bool shouldBeSleeping(bool inAutoStart) { +bool shouldBeSleeping() { #ifndef NO_SLEEP_MODE // Return true if the iron should be in sleep mode if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) { - if (inAutoStart) { - // In auto start we are asleep until movement - if (lastMovementTime == 0 && lastButtonTime == 0) { - return true; - } + // In auto start we are asleep until movement + if (lastMovementTime == 0 && lastButtonTime == 0) { + return true; } if (lastMovementTime > 0 || lastButtonTime > 0) { if (((xTaskGetTickCount() - lastMovementTime) > getSleepTimeout()) && ((xTaskGetTickCount() - lastButtonTime) > getSleepTimeout())) {