Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
jonasius
2024-08-07 20:39:30 +02:00
91 changed files with 2413 additions and 1654 deletions

View File

@@ -0,0 +1,42 @@
#include "OperatingModes.h"
#include "ui_drawing.hpp"
OperatingMode performCJCC(const ButtonState buttons, guiContext *cxt) {
// Calibrate Cold Junction Compensation directly at boot, before internal components get warm.
// While we wait for the pre-start checks to finish, we cant run CJC (as the pre-start checks control the tip)
if (preStartChecks() == 0) {
OLED::setCursor(0, 0);
OLED::print(translatedString(Tr->CJCCalibrating), FontStyle::SMALL);
return OperatingMode::CJCCalibration;
}
if (!isTipDisconnected() && abs(int(TipThermoModel::getTipInC() - getHandleTemperature(0) / 10)) < 10) {
// Take 16 samples, only sample
if (cxt->scratch_state.state1 < 16) {
if ((xTaskGetTickCount() - cxt->scratch_state.state4) > TICKS_100MS) {
cxt->scratch_state.state3 += getTipRawTemp(1);
cxt->scratch_state.state1++;
cxt->scratch_state.state4 = xTaskGetTickCount();
}
ui_draw_cjc_sampling(cxt->scratch_state.state1 / 4);
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.
uint16_t setOffset = TipThermoModel::convertTipRawADCTouV(cxt->scratch_state.state3 / 16, true);
setSettingValue(SettingsOptions::CalibrationOffset, setOffset);
if (warnUser(translatedString(Tr->CalibrationDone), buttons)) {
// Preventing to repeat calibration at boot automatically (only one shot).
setSettingValue(SettingsOptions::CalibrateCJC, 0);
saveSettings();
return OperatingMode::InitialisationDone;
}
return OperatingMode::CJCCalibration;
}
// Cant run calibration without the tip and for temps to be close
return OperatingMode::StartupWarnings;
}

View File

@@ -0,0 +1,20 @@
#include "OperatingModes.h"
#include "ui_drawing.hpp"
OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt) {
ui_draw_debug_menu(cxt->scratch_state.state1);
if (buttons == BUTTON_B_SHORT) {
cxt->transitionMode = TransitionAnimation::Down;
return OperatingMode::HomeScreen;
} 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
}

View File

@@ -0,0 +1,72 @@
#include "Buttons.hpp"
#include "OperatingModes.h"
#include "ui_drawing.hpp"
bool showExitMenuTransition = false;
OperatingMode handleHomeButtons(const ButtonState buttons, guiContext *cxt) {
if (buttons != BUTTON_NONE && cxt->scratch_state.state1 == 0) {
return OperatingMode::HomeScreen; // Ignore button press
} else {
cxt->scratch_state.state1 = 1;
}
switch (buttons) {
case BUTTON_NONE:
// Do nothing
break;
case BUTTON_BOTH:
break;
case BUTTON_B_LONG:
cxt->transitionMode = TransitionAnimation::Up;
return OperatingMode::DebugMenuReadout;
break;
case BUTTON_F_LONG:
#ifdef PROFILE_SUPPORT
if (!isTipDisconnected()) {
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::SolderingProfile;
} else {
return OperatingMode::HomeScreen;
}
#else
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::TemperatureAdjust;
#endif
break;
case BUTTON_F_SHORT:
if (!isTipDisconnected()) {
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::Soldering;
}
break;
case BUTTON_B_SHORT:
cxt->transitionMode = TransitionAnimation::Right;
return OperatingMode::SettingsMenu;
break;
default:
break;
}
return OperatingMode::HomeScreen;
}
OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt) {
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)) {
ui_draw_homescreen_detailed(tipTemp);
} else {
ui_draw_homescreen_simplified(tipTemp);
}
return handleHomeButtons(buttons, cxt);
}

View File

@@ -0,0 +1,5 @@
//
// Created by Thomas White on 3/02/2023.
//
#include "OperatingModes.h"

View File

@@ -0,0 +1,90 @@
#ifndef OPERATING_MODES_H_
#define OPERATING_MODES_H_
extern "C" {
#include "FreeRTOSConfig.h"
}
#include "Buttons.hpp"
#include "OLED.hpp"
#include "OperatingModeUtilities.h"
#include "Settings.h"
#include "TipThermoModel.h"
#include "Translation.h"
#include "Types.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
#if POW_PD_EXT == 2
#include "FS2711.hpp"
#include "FS2711_defines.h"
#endif
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.
};
enum class TransitionAnimation {
None = 0,
Right = 1,
Left = 2,
Down = 3,
Up = 4,
};
// 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;
TransitionAnimation transitionMode;
// Below is scratch state, this is retained over re-draws but blown away on state change
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
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_SettingsMenu(const ButtonState buttons, guiContext *cxt); //
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
extern bool heaterThermalRunaway;
#endif

View File

@@ -0,0 +1,275 @@
#include "OperatingModes.h"
#include "ScrollMessage.hpp"
#define HELP_TEXT_TIMEOUT_TICKS (TICKS_SECOND * 3)
/*
* The settings menu is the most complex bit of GUI code we have
* The menu consists of a two tier menu
* Main menu -> Categories
* Secondary menu -> Settings
*
* For each entry in the menu
*/
/**
* Prints two small lines (or one line for CJK) of short description for
* setting items and prepares cursor after it.
* @param settingsItemIndex Index of the setting item.
* @param cursorCharPosition Custom cursor char position to set after printing
* description.
*/
static void printShortDescription(SettingsItemIndex settingsItemIndex, uint16_t cursorCharPosition) {
// print short description (default single line, explicit double line)
uint8_t shortDescIndex = static_cast<uint8_t>(settingsItemIndex);
OLED::printWholeScreen(translatedString(Tr->SettingsShortNames[shortDescIndex]));
// prepare cursor for value
// make room for scroll indicator
OLED::setCursor(cursorCharPosition * FONT_12_WIDTH - 2, 0);
}
// Render a menu, based on the position given
// This will either draw the menu item, or the help text depending on how long its been since button press
void render_menu(const menuitem *item, guiContext *cxt) {
// If recent interaction or not help text draw the entry
if ((xTaskGetTickCount() - lastButtonTime < HELP_TEXT_TIMEOUT_TICKS) || item->description == 0) {
if (item->shortDescriptionSize > 0) {
printShortDescription(item->shortDescriptionIndex, item->shortDescriptionSize);
}
item->draw();
} else {
uint16_t *isRenderingHelp = &(cxt->scratch_state.state6);
*isRenderingHelp = 1;
// Draw description
const char *description = translatedString(Tr->SettingsDescriptions[item->description - 1]);
drawScrollingText(description, (xTaskGetTickCount() - lastButtonTime) - HELP_TEXT_TIMEOUT_TICKS);
}
}
uint16_t getMenuLength(const menuitem *menu, const uint16_t stop) {
// walk this menu to find the length
uint16_t counter = 0;
for (uint16_t pos = 0; pos < stop; pos++) {
// End of list
if (menu[pos].draw == nullptr) {
return counter;
}
// Otherwise increment for each visible item (null == always, or if not check function)
if (menu[pos].isVisible == nullptr || menu[pos].isVisible()) {
counter++;
}
}
return counter;
}
OperatingMode moveToNextEntry(guiContext *cxt) {
uint16_t *mainEntry = &(cxt->scratch_state.state1);
uint16_t *subEntry = &(cxt->scratch_state.state2);
uint16_t *currentMenuLength = &(cxt->scratch_state.state5);
uint16_t *isRenderingHelp = &(cxt->scratch_state.state6);
if (*isRenderingHelp) {
*isRenderingHelp = 0;
} else {
*currentMenuLength = 0; // Reset menu length
// Scroll down
// We can increment freely _once_
cxt->transitionMode = TransitionAnimation::Down;
if (*subEntry == 0) {
(*mainEntry) += 1;
if (rootSettingsMenu[*mainEntry].draw == nullptr) {
// We are off the end of the menu now
saveSettings();
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::HomeScreen;
}
// Check if visible
if (rootSettingsMenu[*mainEntry].isVisible != nullptr && !rootSettingsMenu[*mainEntry].isVisible()) {
// We need to move on as this one isn't visible
return moveToNextEntry(cxt);
}
} else {
(*subEntry) += 1;
// If the new entry is null, we need to exit
if (subSettingsMenus[*mainEntry][(*subEntry) - 1].draw == nullptr) {
(*subEntry) = 0; // Reset back to the main menu
cxt->transitionMode = TransitionAnimation::Left;
// Have to break early to avoid the below check underflowing
return OperatingMode::SettingsMenu;
}
// Check if visible
if (subSettingsMenus[*mainEntry][(*subEntry) - 1].isVisible != nullptr && !subSettingsMenus[*mainEntry][(*subEntry) - 1].isVisible()) {
// We need to move on as this one isn't visible
return moveToNextEntry(cxt);
}
}
}
return OperatingMode::SettingsMenu;
}
OperatingMode gui_SettingsMenu(const ButtonState buttons, guiContext *cxt) {
// Render out the current settings menu
// State 1 -> Root menu
// State 2 -> Sub entry
// Draw main entry if sub-entry is 0, otherwise draw sub-entry
uint16_t *mainEntry = &(cxt->scratch_state.state1);
uint16_t *subEntry = &(cxt->scratch_state.state2);
uint32_t *autoRepeatAcceleration = &(cxt->scratch_state.state3);
uint32_t *autoRepeatTimer = &(cxt->scratch_state.state4);
uint16_t *currentMenuLength = &(cxt->scratch_state.state5);
uint16_t *isRenderingHelp = &(cxt->scratch_state.state6);
const menuitem *currentMenu;
// Draw the currently on screen item
uint16_t currentScreen;
if (*subEntry == 0) {
// Drawing main menu
currentMenu = rootSettingsMenu;
currentScreen = *mainEntry;
} else {
// Drawing sub menu
currentMenu = subSettingsMenus[*mainEntry];
currentScreen = (*subEntry) - 1;
}
render_menu(&(currentMenu[currentScreen]), cxt);
// Update the cached menu length if unknown
if (*currentMenuLength == 0) {
// We walk the current menu to find the length
*currentMenuLength = getMenuLength(currentMenu, 128 /* Max length of any menu*/);
}
if (*isRenderingHelp == 0) {
// Draw scroll
// Get virtual pos by counting entries from start to _here_
uint16_t currentVirtualPosition = getMenuLength(currentMenu, currentScreen + 1);
if (currentVirtualPosition > 0) {
currentVirtualPosition--;
}
// The height of the indicator is screen res height / total menu entries
uint8_t indicatorHeight = OLED_HEIGHT / *currentMenuLength;
if (indicatorHeight == 0) {
indicatorHeight = 1; // always at least 1 pixel
}
uint16_t position = (OLED_HEIGHT * (uint16_t)currentVirtualPosition) / *currentMenuLength;
bool showScrollbar = true;
// Store if its the last option for this setting
bool isLastOptionForSetting = false;
if ((int)currentMenu[currentScreen].autoSettingOption < (int)SettingsOptions::SettingsOptionsLength) {
isLastOptionForSetting = isLastSettingValue(currentMenu[currentScreen].autoSettingOption);
}
// Last settings menu entry, reset scroll show back so it flashes
if (isLastOptionForSetting) {
showScrollbar = false;
}
// Or Flash it
showScrollbar |= (xTaskGetTickCount() % (TICKS_SECOND / 4) < (TICKS_SECOND / 8));
if (showScrollbar) {
OLED::drawScrollIndicator((uint8_t)position, indicatorHeight);
}
}
// Now handle user button input
auto callIncrementHandler = [&]() {
if (currentMenu[currentScreen].incrementHandler != nullptr) {
currentMenu[currentScreen].incrementHandler();
} else if ((int)currentMenu[currentScreen].autoSettingOption < (int)SettingsOptions::SettingsOptionsLength) {
nextSettingValue(currentMenu[currentScreen].autoSettingOption);
}
return false;
};
//
OperatingMode newMode = OperatingMode::SettingsMenu;
switch (buttons) {
case BUTTON_NONE:
(*autoRepeatAcceleration) = 0; // reset acceleration
(*autoRepeatTimer) = 0; // reset acceleration
break;
case BUTTON_BOTH:
if (*subEntry == 0) {
saveSettings();
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::HomeScreen;
} else {
cxt->transitionMode = TransitionAnimation::Left;
*subEntry = 0;
return OperatingMode::SettingsMenu;
}
break;
case BUTTON_F_LONG:
if (xTaskGetTickCount() + (*autoRepeatAcceleration) > (*autoRepeatTimer) + PRESS_ACCEL_INTERVAL_MAX) {
callIncrementHandler();
// Update the check for if its the last version
bool isLastOptionForSetting = false;
if ((int)currentMenu[currentScreen].autoSettingOption < (int)SettingsOptions::SettingsOptionsLength) {
isLastOptionForSetting = isLastSettingValue(currentMenu[currentScreen].autoSettingOption);
}
if (isLastOptionForSetting) {
(*autoRepeatTimer) = TICKS_SECOND * 2;
} else {
(*autoRepeatTimer) = 0;
}
(*autoRepeatTimer) += xTaskGetTickCount();
(*autoRepeatAcceleration) += PRESS_ACCEL_STEP;
*currentMenuLength = 0; // Reset incase menu visible changes
}
break;
case BUTTON_F_SHORT:
// Increment setting
if (*isRenderingHelp) {
*isRenderingHelp = 0;
} else {
*currentMenuLength = 0; // Reset incase menu visible changes
if (*subEntry == 0) {
// In a root menu, if its null handler we enter the menu
if (currentMenu[currentScreen].incrementHandler != nullptr) {
currentMenu[currentScreen].incrementHandler();
} else {
(*subEntry) += 1;
cxt->transitionMode = TransitionAnimation::Right;
}
} else {
callIncrementHandler();
}
}
break;
case BUTTON_B_LONG:
if (xTaskGetTickCount() + (*autoRepeatAcceleration) > (*autoRepeatTimer) + PRESS_ACCEL_INTERVAL_MAX) {
(*autoRepeatTimer) = xTaskGetTickCount();
(*autoRepeatAcceleration) += PRESS_ACCEL_STEP;
} else {
break;
}
/* Fall through*/
case BUTTON_B_SHORT:
// Increment menu item
newMode = moveToNextEntry(cxt);
break;
default:
break;
}
if ((PRESS_ACCEL_INTERVAL_MAX - (*autoRepeatAcceleration)) < PRESS_ACCEL_INTERVAL_MIN) {
(*autoRepeatAcceleration) = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN;
}
// Otherwise we stay put for next render iteration
return newMode;
}

View File

@@ -0,0 +1,118 @@
#include "FS2711.hpp"
#include "HUB238.hpp"
#include "OperatingModes.h"
#include "ui_drawing.hpp"
OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt) {
// Display alert if settings were reset
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;
}
} else {
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;
}
#else
cxt->scratch_state.state1 = 2;
#endif
break;
case 2: // Accelerometer detection
#ifdef NO_ACCEL
cxt->scratch_state.state1 = 3;
#else
if (DetectedAccelerometerVersion == AccelType::Scanning) {
break;
}
// Display alert if accelerometer is not detected
if (DetectedAccelerometerVersion == AccelType::None) {
if (getSettingValue(SettingsOptions::AccelMissingWarningCounter) < 2) {
if (warnUser(translatedString(Tr->NoAccelerometerMessage), buttons)) {
cxt->scratch_state.state1 = 3;
nextSettingValue(SettingsOptions::AccelMissingWarningCounter);
saveSettings();
}
} else {
cxt->scratch_state.state1 = 3;
}
} else {
cxt->scratch_state.state1 = 3;
}
#endif
break;
case 3:
#ifdef POW_PD
// We expect pd to be present
if (!USBPowerDelivery::fusbPresent()) {
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) {
nextSettingValue(SettingsOptions::PDMissingWarningCounter);
saveSettings();
cxt->scratch_state.state1 = 4;
}
} else {
cxt->scratch_state.state1 = 4;
}
} else {
cxt->scratch_state.state1 = 4;
}
#else
#if POW_PD_EXT == 1
if (!hub238_probe()) {
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) {
cxt->scratch_state.state1 = 4;
nextSettingValue(SettingsOptions::PDMissingWarningCounter);
saveSettings();
}
} else {
cxt->scratch_state.state1 = 4;
}
} else {
cxt->scratch_state.state1 = 4;
}
#else
#if POW_PD_EXT == 2
if (!FS2711::probe()) {
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) {
cxt->scratch_state.state1 = 4;
nextSettingValue(SettingsOptions::PDMissingWarningCounter);
saveSettings();
}
} else {
cxt->scratch_state.state1 = 4;
}
} else {
cxt->scratch_state.state1 = 4;
}
#else
cxt->scratch_state.state1 = 4;
#endif /*POW_PD_EXT==1*/
#endif /*POW_PD_EXT==2*/
#endif /*POW_PD*/
break;
default:
// We are off the end, warnings done
return OperatingMode::StartupLogo;
}
return OperatingMode::StartupWarnings; // Stay in warnings
}

View File

@@ -0,0 +1,51 @@
#include "OperatingModes.h"
#include "ui_drawing.hpp"
OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt) {
#ifdef NO_SLEEP_MODE
return OperatingMode::Soldering;
#endif
// Drop to sleep temperature and display until movement or button press
// 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 OperatingMode::HomeScreen; // return non-zero on error
}
#endif
if (cxt->scratch_state.state4) {
// Hibernating mode
currentTempTargetDegC = 0;
} else {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
currentTempTargetDegC = TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp)));
} else {
currentTempTargetDegC = min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp));
}
}
// draw the lcd
uint16_t tipTemp = getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC();
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
ui_draw_soldering_detailed_sleep(tipTemp);
} else {
ui_draw_soldering_basic_sleep(tipTemp);
}
if (!shouldBeSleeping()) {
return cxt->previousMode;
}
if (shouldShutdown()) {
// shutdown
currentTempTargetDegC = 0;
return OperatingMode::HomeScreen;
}
if (cxt->scratch_state.state4) {
return OperatingMode::Hibernating;
} else {
return OperatingMode::Sleeping;
}
}

View File

@@ -0,0 +1,160 @@
#include "OperatingModes.h"
#include "SolderingCommon.h"
#include "ui_drawing.hpp"
// State 1 = button locking (0:unlocked+released, 1:unlocked, 2:locked, 3:locked+released)
// State 2 = boost mode
// State 3 = buzzer timer
OperatingMode handleSolderingButtons(const ButtonState buttons, guiContext *cxt) {
if (cxt->scratch_state.state1 >= 2) {
// Buttons are currently locked
switch (buttons) {
case BUTTON_F_LONG:
if (getSettingValue(SettingsOptions::BoostTemp) && (getSettingValue(SettingsOptions::LockingMode) == lockingMode_t::BOOST)) {
cxt->scratch_state.state2 = 1;
}
break;
case BUTTON_BOTH_LONG:
if (cxt->scratch_state.state1 == 3) {
// Unlocking
if (warnUser(translatedString(Tr->UnlockingKeysString), buttons)) {
cxt->scratch_state.state1 = 1;
}
} else {
warnUser(translatedString(Tr->WarningKeysLockedString), buttons);
}
break;
case BUTTON_NONE:
cxt->scratch_state.state1 = 3;
break;
default: // Do nothing and display a lock warning
warnUser(translatedString(Tr->WarningKeysLockedString), buttons);
break;
}
return OperatingMode::Soldering;
}
// otherwise we are unlocked
switch (buttons) {
case BUTTON_NONE:
cxt->scratch_state.state2 = 0;
cxt->scratch_state.state1 = 0;
break;
case BUTTON_BOTH:
/*Fall through*/
case BUTTON_B_LONG:
cxt->transitionMode = TransitionAnimation::Right;
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:
cxt->transitionMode = TransitionAnimation::Left;
return OperatingMode::TemperatureAdjust;
case BUTTON_BOTH_LONG:
if (getSettingValue(SettingsOptions::LockingMode)) {
// Lock buttons
if (cxt->scratch_state.state1 == 0) {
if (warnUser(translatedString(Tr->LockingKeysString), buttons)) {
cxt->scratch_state.state1 = 2;
}
} else {
// FIXME should be WarningKeysUnlockedString
warnUser(translatedString(Tr->UnlockingKeysString), buttons);
}
}
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
* --> User presses buttons and they goto the temperature adjust screen
* ---> Display the current setpoint temperature
* ---> Use buttons to change forward and back on temperature
* ---> Both buttons or timeout for exiting
* --> Long hold front button to enter boost mode
* ---> Just temporarily sets the system into the alternate temperature for
* PID control
* --> Long hold back button to exit
* --> Double button to exit
* --> Long hold double button to toggle key lock
*/
// 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));
}
}
// 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;
}
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);
}
// Draw in the screen details
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
ui_draw_soldering_power_status(cxt->scratch_state.state2);
} else {
ui_draw_soldering_basic_status(cxt->scratch_state.state2);
}
// Check if we should bail due to undervoltage for example
if (checkExitSoldering()) {
setBuzzer(false);
cxt->transitionMode = TransitionAnimation::Right;
return OperatingMode::HomeScreen;
}
#ifdef NO_SLEEP_MODE
if (shouldShutdown()) {
// shutdown
currentTempTargetDegC = 0;
cxt->transitionMode = TransitionAnimation::Right;
return OperatingMode::HomeScreen;
}
#endif
if (shouldBeSleeping()) {
return OperatingMode::Sleeping;
}
if (heaterThermalRunaway) {
currentTempTargetDegC = 0; // heater control off
heaterThermalRunaway = false;
cxt->transitionMode = TransitionAnimation::Right;
return OperatingMode::ThermalRunaway;
}
return handleSolderingButtons(buttons, cxt);
}

View File

@@ -0,0 +1,177 @@
#include "OperatingModes.h"
#include "SolderingCommon.h"
#include "ui_drawing.hpp"
OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt) {
/*
* * Soldering
* -> Main loop where we draw temp, and animations
* --> Long hold back button to exit
* --> Double button to exit
*/
uint16_t tipTemp = 0;
// 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;
switch (buttons) {
case BUTTON_BOTH:
case BUTTON_B_LONG:
cxt->transitionMode = TransitionAnimation::Right;
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 >= cxt->scratch_state.state5) {
warnUser(translatedString(Tr->TooHotToStartProfileWarning), buttons);
return OperatingMode::HomeScreen;
}
}
uint16_t phaseElapsedSeconds = (xTaskGetTickCount() - cxt->scratch_state.state3) / TICKS_SECOND;
// Have we finished this phase?
// Check if we have hit our temperature target in either direction.
bool phaseTargetReached = false;
if (cxt->scratch_state.state6 < cxt->scratch_state.state5 && tipTemp >= cxt->scratch_state.state5) {
phaseTargetReached = true;
} else if (cxt->scratch_state.state6 > cxt->scratch_state.state5 && tipTemp <= cxt->scratch_state.state5) {
phaseTargetReached = true;
} else if (tipTemp == cxt->scratch_state.state5) {
phaseTargetReached = true;
}
// If we both hit the temperature target and enough time has passed, phase complete.
if (phaseElapsedSeconds >= cxt->scratch_state.state2 && phaseTargetReached) {
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 {
// 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;
}
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 {
phaseTicksPerDegree = (cxt->scratch_state.state2 * TICKS_SECOND) / (cxt->scratch_state.state6 - cxt->scratch_state.state5);
}
}
}
// 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 (cxt->scratch_state.state6 < cxt->scratch_state.state5) {
profileCurrentTargetTemp = cxt->scratch_state.state6 + ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree);
if (profileCurrentTargetTemp > cxt->scratch_state.state5) {
profileCurrentTargetTemp = cxt->scratch_state.state5;
}
} else if (cxt->scratch_state.state6 > cxt->scratch_state.state5) {
profileCurrentTargetTemp = cxt->scratch_state.state6 - ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree);
// Chance of an overflow when ramping up is basically zero, but chance of an underflow here is quite high. If the target underflowed, snap it back.
if (profileCurrentTargetTemp < cxt->scratch_state.state5 || profileCurrentTargetTemp > cxt->scratch_state.state6) {
profileCurrentTargetTemp = cxt->scratch_state.state5;
}
} else {
profileCurrentTargetTemp = cxt->scratch_state.state5;
}
// Draw in the screen details
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
ui_draw_soldering_profile_advanced(tipTemp, profileCurrentTargetTemp, phaseElapsedSeconds, cxt->scratch_state.state1, cxt->scratch_state.state2);
ui_draw_soldering_power_status(false);
} else {
ui_draw_soldering_basic_status(false);
}
// Update the setpoints for the temperature
if (getSettingValue(SettingsOptions::TemperatureInF)) {
currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp);
} else {
currentTempTargetDegC = profileCurrentTargetTemp;
}
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);
}
return OperatingMode::SolderingProfile;
}

View File

@@ -0,0 +1,92 @@
#include "OperatingModes.h"
#include "ui_drawing.hpp"
OperatingMode gui_solderingTempAdjust(const ButtonState buttonIn, guiContext *cxt) {
currentTempTargetDegC = 0; // Turn off heater while adjusting temp
uint16_t *waitForRelease = &(cxt->scratch_state.state1);
uint32_t *autoRepeatTimer = &(cxt->scratch_state.state3);
uint16_t *autoRepeatAcceleration = &(cxt->scratch_state.state2);
ButtonState buttons = buttonIn;
if (*waitForRelease == 0) {
// When we first enter we wait for the user to release buttons before enabling changes
if (buttons != BUTTON_NONE) {
buttons = BUTTON_NONE;
} else {
(*waitForRelease)++;
}
}
int16_t delta = 0;
switch (buttons) {
case BUTTON_NONE:
// stay
(*autoRepeatAcceleration) = 0;
break;
case BUTTON_BOTH:
// exit
saveSettings();
cxt->transitionMode = TransitionAnimation::Right;
return cxt->previousMode;
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;
if (getSettingValue(SettingsOptions::TemperatureInF)) {
if (newTemp > MAX_TEMP_F) {
newTemp = MAX_TEMP_F;
} else if (newTemp < MIN_TEMP_F) {
newTemp = MIN_TEMP_F;
}
} else {
if (newTemp > MAX_TEMP_C) {
newTemp = MAX_TEMP_C;
} else if (newTemp < MIN_TEMP_C) {
newTemp = MIN_TEMP_C;
}
}
setSettingValue(SettingsOptions::SolderingTemp, (uint16_t)newTemp);
}
ui_draw_temperature_change();
if (xTaskGetTickCount() - lastButtonTime > (TICKS_SECOND * 3)) {
saveSettings();
cxt->transitionMode = TransitionAnimation::Right;
return cxt->previousMode; // exit if user just doesn't press anything for a bit
}
return OperatingMode::TemperatureAdjust; // Stay in temp adjust
}

View File

@@ -0,0 +1,50 @@
#include "FS2711.hpp"
#include "OperatingModes.h"
#include "stdbool.h"
#include "ui_drawing.hpp"
#if POW_PD_EXT == 2
#ifdef HAS_POWER_DEBUG_MENU
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
uint16_t *screen = &(cxt->scratch_state.state1);
if (*screen > 7) {
*screen = 0;
}
if (*screen == 0) {
// Print the PD Debug state
fs2711_state_t state = FS2711::debug_get_state();
ui_draw_usb_pd_debug_state(0, state.pdo_num);
} else {
// Print out the Proposed power options one by one
uint16_t max_voltage = FS2711::debug_pdo_max_voltage(*screen - 1);
if (max_voltage == 0) {
*screen += 1;
} else {
uint16_t min_voltage = FS2711::debug_pdo_min_voltage(*screen - 1);
uint16_t current = FS2711::debug_pdo_source_current(*screen - 1);
uint16_t pdo_type = FS2711::debug_pdo_type(*screen - 1);
if (pdo_type != 1) {
min_voltage = 0;
}
ui_draw_usb_pd_debug_pdo(*screen, min_voltage / 1000, max_voltage / 1000, current * 1, 0);
}
}
OLED::refresh();
if (buttons == BUTTON_B_SHORT) {
return OperatingMode::InitialisationDone;
} else if (buttons == BUTTON_F_SHORT) {
*screen++;
}
return OperatingMode::UsbPDDebug;
}
#endif
#endif

View File

@@ -0,0 +1,75 @@
#include "OperatingModes.h"
#include "ui_drawing.hpp"
#ifdef POW_PD
#include "pd.h"
#ifdef HAS_POWER_DEBUG_MENU
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
uint16_t *screen = &(cxt->scratch_state.state1);
if ((*screen) == 0) {
// Print the PD state machine
uint8_t vbusState = 0;
if (USBPowerDelivery::fusbPresent()) {
if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) {
if (!USBPowerDelivery::isVBUSConnected()) {
vbusState = 2;
} else {
vbusState = 1;
}
}
}
ui_draw_usb_pd_debug_state(vbusState, USBPowerDelivery::getStateNumber());
} else {
// Print out the Proposed power options one by one
auto lastCaps = USBPowerDelivery::getLastSeenCapabilities();
bool sourceIsEPRCapable = lastCaps[0] & PD_PDO_SRC_FIXED_EPR_CAPABLE;
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) {
if (sourceIsEPRCapable) {
if ((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_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
}
} else {
// Doesn't have EPR support. So treat as PPS
// https://github.com/Ralim/IronOS/issues/1906
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) += 1;
} else {
ui_draw_usb_pd_debug_pdo(*screen, min_voltage / 1000, voltage_mv / 1000, current_a_x100, wattage);
}
} else {
(*screen) = 0;
}
}
if (buttons == BUTTON_B_SHORT) {
return OperatingMode::InitialisationDone;
} else if (buttons == BUTTON_F_SHORT) {
(*screen) += 1;
}
return OperatingMode::UsbPDDebug;
}
#endif
#endif

View File

@@ -0,0 +1,37 @@
#include "HUB238.hpp"
#include "OperatingModes.h"
#include "ui_drawing.hpp"
#if POW_PD_EXT == 1
#ifdef HAS_POWER_DEBUG_MENU
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
uint16_t *screen = &(cxt->scratch_state.state1);
if (*screen > 6) {
*screen = 0;
}
if (*screen == 0) {
// Print the PD Debug state
uint16_t temp = hub238_debug_state();
ui_draw_usb_pd_debug_state(0, temp);
} else {
// Print out the Proposed power options one by one
const uint8_t voltages[] = {5, 9, 12, 15, 18, 20};
uint16_t voltage = voltages[*screen - 1];
uint16_t currentx100 = hub238_getVoltagePDOCurrent(voltage);
ui_draw_usb_pd_debug_pdo(*screen, 0, voltage, currentx100, 0);
}
if (buttons == BUTTON_B_SHORT) {
return OperatingMode::InitialisationDone;
} else if (buttons == BUTTON_F_SHORT) {
*screen++;
}
return OperatingMode::UsbPDDebug;
}
#endif
#endif

View File

@@ -0,0 +1,10 @@
#include "OperatingModeUtilities.h"
void GUIDelay() {
// Called in all UI looping tasks,
// This limits the re-draw rate to the LCD and also lets the DMA run
// As the gui task can very easily fill this bus with transactions, which will
// prevent the movement detection from running
vTaskDelay(5 * TICKS_10MS);
}

View File

@@ -0,0 +1,16 @@
#ifndef OPERATING_MODE_UTILITIES_H_
#define OPERATING_MODE_UTILITIES_H_
#include "Buttons.hpp"
#include "OLED.hpp"
#include <stdbool.h>
void GUIDelay(); //
bool checkForUnderVoltage(void); //
uint32_t getSleepTimeout(void); //
bool shouldBeSleeping(); //
bool shouldShutdown(void); //
void printVoltage(void); //
bool checkForUnderVoltage(void); //
uint16_t min(uint16_t a, uint16_t b); //
void printCountdownUntilSleep(int sleepThres); //
#endif

View File

@@ -0,0 +1,98 @@
//
// Created by laura on 24.04.23.
//
#include "SolderingCommon.h"
#include "OperatingModes.h"
#include "Types.h"
#include "configuration.h"
#include "history.hpp"
#include "ui_drawing.hpp"
extern bool heaterThermalRunaway;
bool checkExitSoldering(void) {
#ifdef POW_DC
// Undervoltage test
if (checkForUnderVoltage()) {
lastButtonTime = xTaskGetTickCount();
return true;
}
#endif
#ifdef ACCEL_EXITS_ON_MOVEMENT
// If the accel works in reverse where movement will cause exiting the soldering mode
if (getSettingValue(Sensitivity)) {
if (lastMovementTime) {
if (lastMovementTime > TICKS_SECOND * 10) {
// If we have moved recently; in the last second
// Then exit soldering mode
// Movement occurred in last update
if (((TickType_t)(xTaskGetTickCount() - lastMovementTime)) < (TickType_t)(TICKS_SECOND / 5)) {
currentTempTargetDegC = 0;
lastMovementTime = 0;
return true;
}
}
}
}
#endif
// If we have tripped thermal runaway, turn off heater and show warning
return false;
}
int8_t getPowerSourceNumber(void) {
int8_t sourceNumber = 0;
if (getIsPoweredByDCIN()) {
sourceNumber = 0;
} else {
// We are not powered via DC, so want to display the appropriate state for PD or QC
bool poweredbyPD = false;
bool pdHasVBUSConnected = false;
#ifdef POW_PD
if (USBPowerDelivery::fusbPresent()) {
// We are PD capable
if (USBPowerDelivery::negotiationComplete()) {
// We are powered via PD
poweredbyPD = true;
#ifdef VBUS_MOD_TEST
pdHasVBUSConnected = USBPowerDelivery::isVBUSConnected();
#endif
}
}
#endif
#if POW_PD_EXT == 2
if (FS2711::has_run_selection()) {
poweredbyPD = true;
// FS2711IC has VBUS always connected
pdHasVBUSConnected = true;
}
#endif
if (poweredbyPD) {
if (pdHasVBUSConnected) {
sourceNumber = 2;
} else {
sourceNumber = 3;
}
} else {
sourceNumber = 1;
}
}
return sourceNumber;
}
// Returns temperature of the tip in *C/*F (based on user settings)
TemperatureType_t getTipTemp(void) {
#ifdef FILTER_DISPLAYED_TIP_TEMP
static history<TemperatureType_t, FILTER_DISPLAYED_TIP_TEMP> Filter_Temp;
TemperatureType_t reading = getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC();
Filter_Temp.update(reading);
return Filter_Temp.average();
#else
return getSettingValue(SettingsOptions::TemperatureInF) ? TipThermoModel::getTipInF() : TipThermoModel::getTipInC();
#endif
}

View File

@@ -0,0 +1,9 @@
#include "Types.h"
#include <stdint.h>
#ifndef SOLDERING_COMMON_H_
#define SOLDERING_COMMON_H_
bool checkExitSoldering();
TemperatureType_t getTipTemp(void);
#endif // SOLDERING_COMMON_H_

View File

@@ -0,0 +1,25 @@
#include "Buttons.hpp"
#include "OperatingModeUtilities.h"
#include "configuration.h"
#include "ui_drawing.hpp"
#ifdef POW_DC
extern volatile TemperatureType_t currentTempTargetDegC;
// returns true if undervoltage has occured
bool checkForUnderVoltage(void) {
if (!getIsPoweredByDCIN()) {
return false;
}
uint16_t v = getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0);
// Dont check for first 2 seconds while the ADC stabilizes and the DMA fills
// the buffer
if (xTaskGetTickCount() > (TICKS_SECOND * 2)) {
if ((v < lookupVoltageLevel())) {
currentTempTargetDegC = 0;
ui_draw_warning_undervoltage();
return true;
}
}
return false;
}
#endif

View File

@@ -0,0 +1,19 @@
#include "OperatingModeUtilities.h"
#ifndef NO_SLEEP_MODE
uint32_t getSleepTimeout(void) {
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
uint32_t sleepThres = 0;
if (getSettingValue(SettingsOptions::SleepTime) < 6) {
sleepThres = getSettingValue(SettingsOptions::SleepTime) * 10 * 1000;
} else {
sleepThres = (getSettingValue(SettingsOptions::SleepTime) - 5) * 60 * 1000;
}
return sleepThres;
}
return 0;
}
#endif

View File

@@ -0,0 +1,11 @@
#include "OperatingModeUtilities.h"
#include <stdint.h>
uint16_t min(uint16_t a, uint16_t b) {
if (a > b) {
return b;
} else {
return a;
}
}

View File

@@ -0,0 +1,24 @@
#include "OperatingModeUtilities.h"
extern TickType_t lastMovementTime;
extern TickType_t lastHallEffectSleepStart;
#include "Buttons.hpp"
bool shouldShutdown(void) {
if (getSettingValue(SettingsOptions::ShutdownTime)) { // only allow shutdown exit if time > 0
if (lastMovementTime) {
if (((TickType_t)(xTaskGetTickCount() - lastMovementTime)) > (TickType_t)(getSettingValue(SettingsOptions::ShutdownTime) * TICKS_MIN)) {
return true;
}
}
if (lastHallEffectSleepStart) {
if (((TickType_t)(xTaskGetTickCount() - lastHallEffectSleepStart)) > (TickType_t)(getSettingValue(SettingsOptions::ShutdownTime) * TICKS_MIN)) {
return true;
}
}
}
if (getButtonState() == BUTTON_B_LONG) { // allow also if back button is pressed long
return true;
}
return false;
}

View File

@@ -0,0 +1,45 @@
#include "Buttons.hpp"
#include "OperatingModeUtilities.h"
TickType_t lastHallEffectSleepStart = 0;
extern TickType_t lastMovementTime;
bool shouldBeSleeping() {
#ifndef NO_SLEEP_MODE
// Return true if the iron should be in sleep mode
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
// 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())) {
return true;
}
}
}
#ifdef HALL_SENSOR
// If the hall effect sensor is enabled in the build, check if its over
// threshold, and if so then we force sleep
if (getHallSensorFitted() && lookupHallEffectThreshold()) {
int16_t hallEffectStrength = getRawHallEffect();
if (hallEffectStrength < 0) {
hallEffectStrength = -hallEffectStrength;
}
// Have absolute value of measure of magnetic field strength
if (hallEffectStrength > lookupHallEffectThreshold()) {
if (lastHallEffectSleepStart == 0) {
lastHallEffectSleepStart = xTaskGetTickCount();
}
if ((xTaskGetTickCount() - lastHallEffectSleepStart) > TICKS_SECOND) {
return true;
}
} else {
lastHallEffectSleepStart = 0;
}
}
#endif
#endif
return false;
}