1
0
forked from me/IronOS

Starting GUI render refactor to be more immediate mode

Update TemperatureAdjust.cpp

.

Cleanup Soldering

Sleep

SolderingProfiles

Soldering Rework

Rough pass GUI

Temp Adjust

Cleanup old OperatingMode

Debug Menu
This commit is contained in:
Ben V. Brown
2023-07-11 08:36:32 +10:00
parent c308fe8cc2
commit 5303d27f96
20 changed files with 955 additions and 928 deletions

View File

@@ -9,6 +9,7 @@
#define GUI_HPP_ #define GUI_HPP_
#include "BSP.h" #include "BSP.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "Buttons.hpp"
#include "Settings.h" #include "Settings.h"
#include "Translation.h" #include "Translation.h"
@@ -37,7 +38,7 @@ typedef struct {
} menuitem; } menuitem;
void enterSettingsMenu(); void enterSettingsMenu();
void warnUser(const char *warning, const TickType_t timeout); bool warnUser(const char *warning, const ButtonState buttons);
extern const menuitem rootSettingsMenu[]; extern const menuitem rootSettingsMenu[];
#endif /* GUI_HPP_ */ #endif /* GUI_HPP_ */

View File

@@ -942,7 +942,7 @@ static void displayPowerPulseDuration(void) { OLED::printNumber(getSettingValue(
static bool setResetSettings(void) { static bool setResetSettings(void) {
if (userConfirmation(translatedString(Tr->SettingsResetWarning))) { if (userConfirmation(translatedString(Tr->SettingsResetWarning))) {
resetSettings(); resetSettings();
warnUser(translatedString(Tr->ResetOKMessage), 3 * TICKS_SECOND); // warnUser(translatedString(Tr->ResetOKMessage), buttons); //TODO
reboot(); reboot();
} }
return false; return false;

View File

@@ -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;
```

View File

@@ -31,8 +31,123 @@ extern "C" {
#include "pd.h" #include "pd.h"
#endif #endif
// File local variables // 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 */ /* StartGUITask function */
void startGUITask(void const *argument) { void startGUITask(void const *argument) {
@@ -48,41 +163,25 @@ void startGUITask(void const *argument) {
getTipRawTemp(1); // reset filter getTipRawTemp(1); // reset filter
OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1); OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1);
// If the front button is held down, on supported devices, show PD debugging metrics buttonsAtDeviceBoot = getButtonState();
#ifdef HAS_POWER_DEBUG_MENU
#ifdef DEBUG_POWER_MENU_BUTTON_B
if (getButtonB()) {
#else
if (getButtonA()) {
#endif
showPDDebug();
}
#endif
if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) { // // 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
performCJCC(); // 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);
} }

View File

@@ -1,39 +1,36 @@
#include "OperatingModes.h" #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. // 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) { 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 // 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 // equilibrium, then the output should be zero, as there is no temperature
// differential. // differential.
while (setoffset == 0) {
uint32_t offset = 0; uint16_t setOffset = TipThermoModel::convertTipRawADCTouV(cxt->scratch_state.state3 / 16, true);
for (uint8_t i = 0; i < 16; i++) { setSettingValue(SettingsOptions::CalibrationOffset, setOffset);
offset += getTipRawTemp(1); if (warnUser(translatedString(Tr->CJCCalibrationDone), buttons)) {
// cycle through the filter a fair bit to ensure we're stable. // Preventing to repeat calibration at boot automatically (only one shot).
OLED::clearScreen(); setSettingValue(SettingsOptions::CalibrateCJC, 0);
OLED::setCursor(0, 0); saveSettings();
OLED::print(translatedString(Tr->CJCCalibrating), FontStyle::SMALL); return OperatingMode::InitialisationDone;
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);
} }
setSettingValue(SettingsOptions::CalibrationOffset, setoffset); return OperatingMode::CJCCalibration;
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();
} }
// Cant run calibration without the tip and for temps to be close
return OperatingMode::InitialisationDone;
} }

View File

@@ -1,111 +1,100 @@
#include "OperatingModes.h" #include "OperatingModes.h"
extern osThreadId GUITaskHandle; extern osThreadId GUITaskHandle;
extern osThreadId MOVTaskHandle; extern osThreadId MOVTaskHandle;
extern osThreadId PIDTaskHandle; extern osThreadId PIDTaskHandle;
extern OperatingMode currentMode;
void showDebugMenu(void) { OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt) {
currentMode = OperatingMode::debug; OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
uint8_t screen = 0; OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number
ButtonState b; OLED::setCursor(0, 8); // second line
for (;;) { OLED::print(DebugMenu[cxt->scratch_state.state1], FontStyle::SMALL);
OLED::clearScreen(); // Ensure the buffer starts clean switch (cxt->scratch_state.state1) {
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) case 0: // Build Date
OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number break;
OLED::setCursor(0, 8); // second line case 1: // Device ID
OLED::print(DebugMenu[screen], FontStyle::SMALL); {
switch (screen) { uint64_t id = getDeviceID();
case 0: // Build Date
break;
case 1: // Device ID
{
uint64_t id = getDeviceID();
#ifdef DEVICE_HAS_VALIDATION_CODE #ifdef DEVICE_HAS_VALIDATION_CODE
// If device has validation code; then we want to take over both lines of the screen // If device has validation code; then we want to take over both lines of the screen
OLED::clearScreen(); // Ensure the buffer starts clean OLED::clearScreen(); // Ensure the buffer starts clean
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
OLED::print(DebugMenu[screen], FontStyle::SMALL); OLED::print(DebugMenu[screen], FontStyle::SMALL);
OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8); OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8);
OLED::setCursor(0, 8); // second line OLED::setCursor(0, 8); // second line
#endif #endif
OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8); OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8);
OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8); OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8);
} break; } break;
case 2: // ACC Type case 2: // ACC Type
OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL); OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL);
break; break;
case 3: // Power Negotiation Status case 3: // Power Negotiation Status
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL); OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL);
break; break;
case 4: // Input Voltage case 4: // Input Voltage
printVoltage(); printVoltage();
break; break;
case 5: // Temp in °C case 5: // Temp in °C
OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL); OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL);
break; break;
case 6: // Handle Temp in °C case 6: // Handle Temp in °C
OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL); OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL);
OLED::print(SmallSymbolDot, FontStyle::SMALL); OLED::print(SmallSymbolDot, FontStyle::SMALL);
OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL); OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL);
break; break;
case 7: // Max Temp Limit in °C case 7: // Max Temp Limit in °C
OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL); OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL);
break; break;
case 8: // System Uptime case 8: // System Uptime
OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL); OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL);
break; break;
case 9: // Movement Timestamp case 9: // Movement Timestamp
OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL); OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL);
break; break;
case 10: // Tip Resistance in Ω large to pad over so that we cover ID left overs case 10: // Tip Resistance in Ω
OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL); OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL); // large to pad over so that we cover ID left overs
OLED::print(SmallSymbolDot, FontStyle::SMALL); OLED::print(SmallSymbolDot, FontStyle::SMALL);
OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL); OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL);
break; break;
case 11: // Raw Tip in µV case 11: // Raw Tip in µV
OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL); OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL);
break; break;
case 12: // Tip Cold Junction Compensation Offset in µV case 12: // Tip Cold Junction Compensation Offset in µV
OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL); OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL);
break; break;
case 13: // High Water Mark for GUI case 13: // High Water Mark for GUI
OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL); OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL);
break; break;
case 14: // High Water Mark for Movement Task case 14: // High Water Mark for Movement Task
OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL); OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL);
break; break;
case 15: // High Water Mark for PID Task case 15: // High Water Mark for PID Task
OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL); OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL);
break; break;
break; break;
#ifdef HALL_SENSOR #ifdef HALL_SENSOR
case 16: // Raw Hall Effect Value case 16: // Raw Hall Effect Value
{ {
int16_t hallEffectStrength = getRawHallEffect(); int16_t hallEffectStrength = getRawHallEffect();
if (hallEffectStrength < 0) { if (hallEffectStrength < 0)
hallEffectStrength = -hallEffectStrength; hallEffectStrength = -hallEffectStrength;
} OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL);
OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL); } break;
} break;
#endif #endif
default: default:
break; 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();
} }
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
} }

View File

@@ -2,14 +2,10 @@
#include "Buttons.hpp" #include "Buttons.hpp"
#include "OperatingModes.h" #include "OperatingModes.h"
#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ) uint8_t buttonAF[sizeof(buttonA)];
#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ) uint8_t buttonBF[sizeof(buttonB)];
uint8_t disconnectedTipF[sizeof(disconnectedTip)];
uint8_t buttonAF[sizeof(buttonA)]; bool showExitMenuTransition = false;
uint8_t buttonBF[sizeof(buttonB)];
uint8_t disconnectedTipF[sizeof(disconnectedTip)];
extern OperatingMode currentMode;
bool showExitMenuTransition = false;
void renderHomeScreenAssets(void) { void renderHomeScreenAssets(void) {
@@ -24,55 +20,42 @@ void renderHomeScreenAssets(void) {
} }
} }
void handleButtons(bool *buttonLockout) { OperatingMode handleHomeButtons(const ButtonState buttons, guiContext *cxt) {
ButtonState buttons = getButtonState();
if (buttons != BUTTON_NONE) { if (buttons != BUTTON_NONE) {
OLED::setDisplayState(OLED::DisplayState::ON); OLED::setDisplayState(OLED::DisplayState::ON);
} }
if (buttons != BUTTON_NONE && *buttonLockout) { if (buttons != BUTTON_NONE && cxt->scratch_state.state1 == 0) {
buttons = BUTTON_NONE; return OperatingMode::HomeScreen; // Ignore button press
} else { } else {
*buttonLockout = false; cxt->scratch_state.state1 == 1;
} }
switch (buttons) { switch (buttons) {
case BUTTON_NONE: case BUTTON_NONE:
// Do nothing // Do nothing
break; break;
case BUTTON_BOTH: case BUTTON_BOTH:
// Not used yet
// In multi-language this might be used to reset language on a long hold
// or some such
break; break;
case BUTTON_B_LONG: case BUTTON_B_LONG:
// Show the version information return OperatingMode::DebugMenuReadout;
showDebugMenu();
break; break;
case BUTTON_F_LONG: case BUTTON_F_LONG:
#ifdef PROFILE_SUPPORT #ifdef PROFILE_SUPPORT
if (!isTipDisconnected()) { if (!isTipDisconnected()) {
gui_solderingProfileMode(); // enter profile mode return OperatingMode::SolderingProfile;
*buttonLockout = true;
} }
#else #else
gui_solderingTempAdjust(); return OperatingMode::TemperatureAdjust;
saveSettings(); saveSettings();
#endif #endif
break; break;
case BUTTON_F_SHORT: case BUTTON_F_SHORT:
if (!isTipDisconnected()) { if (!isTipDisconnected()) {
gui_solderingMode(0); // enter soldering mode return OperatingMode::Soldering;
*buttonLockout = true;
} }
break; break;
case BUTTON_B_SHORT: case BUTTON_B_SHORT:
currentMode = OperatingMode::settings; return OperatingMode::SettingsMenu;
enterSettingsMenu(); // enter the settings menu
{
OLED::useSecondaryFramebuffer(true);
showExitMenuTransition = true;
}
*buttonLockout = true;
break; break;
default: default:
break; break;
@@ -181,55 +164,28 @@ void drawSimplifiedHomeScreen(uint32_t tipTemp) {
} }
} }
} }
void drawHomeScreen(bool buttonLockout) { OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt) {
for (;;) { OperatingMode newMode = handleHomeButtons(buttons, cxt);
currentMode = OperatingMode::idle; if (newMode != OperatingMode::HomeScreen) {
handleButtons(&buttonLockout); return newMode;
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();
}
} }
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;
} }

View File

@@ -3,6 +3,3 @@
// //
#include "OperatingModes.h" #include "OperatingModes.h"
// Global variables
OperatingMode currentMode = OperatingMode::idle;

View File

@@ -24,29 +24,53 @@ extern "C" {
#include "pd.h" #include "pd.h"
#endif #endif
// Exposed modes enum class OperatingMode {
enum OperatingMode { StartupLogo = 0, // Showing the startup logo
idle = 0, CJCCalibration, // Cold Junction Calibration
soldering = 1, StartupWarnings, // Startup checks and warnings
boost = 2, InitialisationDone, // Special state we use just before we to home screen at first startup. Allows jumping to extra startup states
sleeping = 3, HomeScreen, // Home/Idle screen that is the main launchpad to other modes
settings = 4, Soldering, // Main soldering operating mode
debug = 5 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 // Main functions
void performCJCC(void); // Used to calibrate the Cold Junction offset OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt); // Sleep mode
void gui_solderingTempAdjust(void); // For adjusting the setpoint temperature of the iron OperatingMode gui_solderingMode(const ButtonState buttons, guiContext *cxt); // Main mode for hot pointy tool
int gui_SolderingSleepingMode(bool stayOff, bool autoStarted); // Sleep mode OperatingMode gui_solderingTempAdjust(const ButtonState buttons, guiContext *cxt); // For adjusting the setpoint temperature of the iron
void gui_solderingMode(uint8_t jumpToSleep); // Main mode for hot pointy tool OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt); // IDLE / Home screen
void gui_solderingProfileMode(); // Profile mode for hot likely-not-so-pointy tool
void showDebugMenu(void); // Debugging values OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt); // Profile mode for hot likely-not-so-pointy tool
void showPDDebug(void); // Debugging menu that shows PD adaptor info OperatingMode performCJCC(const ButtonState buttons, guiContext *cxt); // Used to calibrate the Cold Junction offset
void showWarnings(void); // Shows user warnings if required OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt); // Debugging values
void drawHomeScreen(bool buttonLockout) __attribute__((noreturn)); // IDLE / Home screen OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt); // Debugging menu that shows PD adaptor info
void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt); // Shows user warnings if required
// Common helpers // Common helpers
int8_t getPowerSourceNumber(void); // Returns number ID of power source 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) void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics
extern bool heaterThermalRunaway;
#endif #endif

View File

@@ -1,56 +1,78 @@
#include "HUB238.hpp" #include "HUB238.hpp"
#include "OperatingModes.h" #include "OperatingModes.h"
void showWarnings(void) { OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt) {
// Display alert if settings were reset // 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 switch (cxt->scratch_state.state1) {
// We also want to alert if accel or pd is not detected / not responding case 0: // Settings reset warning
// In this case though, we dont want to nag the user _too_ much if (settingsWereReset) {
// So only show first 2 times if (warnUser(translatedString(Tr->SettingsResetMessage), buttons)) {
while (DetectedAccelerometerVersion == AccelType::Scanning) { settingsWereReset = false;
osDelay(5); cxt->scratch_state.state1 = 1;
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);
} }
} 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 #ifdef POW_PD
// We expect pd to be present // We expect pd to be present
resetWatchdog(); if (!USBPowerDelivery::fusbPresent()) {
if (!USBPowerDelivery::fusbPresent()) { if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { nextSettingValue(SettingsOptions::PDMissingWarningCounter);
nextSettingValue(SettingsOptions::PDMissingWarningCounter); saveSettings();
saveSettings(); if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) {
warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND); cxt->scratch_state.state1 = 4;
}
}
} }
} #else
#endif /*POW_PD*/
#if POW_PD_EXT == 1 #if POW_PD_EXT == 1
if (!hub238_probe()) { if (!hub238_probe()) {
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) { if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
nextSettingValue(SettingsOptions::PDMissingWarningCounter); nextSettingValue(SettingsOptions::PDMissingWarningCounter);
saveSettings(); saveSettings();
warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND); if (warnUser(translatedString(Tr->NoPowerDeliveryMessage), buttons)) {
cxt->scratch_state.state1 = 4;
}
}
} }
} #else
cxt->scratch_state.state1 = 4;
#endif /*POW_PD_EXT==1*/ #endif /*POW_PD_EXT==1*/
// If tip looks to be shorted, yell at user and dont auto dismiss #endif /*POW_PD*/
if (isTipShorted()) {
warnUser(translatedString(Tr->WarningTipShorted), portMAX_DELAY); break;
default:
// We are off the end, warnings done
return OperatingMode::InitialisationDone;
} }
#endif /*NO_WARN_MISSING*/
return OperatingMode::StartupWarnings; // Stay in warnings
} }

View File

@@ -1,64 +1,59 @@
#include "OperatingModes.h" #include "OperatingModes.h"
extern OperatingMode currentMode; OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt) {
#ifdef NO_SLEEP_MODE
int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) { return OperatingMode::SolderingMode;
#ifndef NO_SLEEP_MODE #endif
// Drop to sleep temperature and display until movement or button press // 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
// user moved or pressed a button, go back to soldering // If in the first two seconds we disable this to let accelerometer warm up
// If in the first two seconds we disable this to let accelerometer warm up
#ifdef POW_DC #ifdef POW_DC
if (checkForUnderVoltage()) { if (checkForUnderVoltage())
// return non-zero on error return OperatingMode::HomeScreen; // return non-zero on error
return 1;
}
#endif #endif
if (getSettingValue(SettingsOptions::TemperatureInF)) {
if (getSettingValue(SettingsOptions::TemperatureInF)) { currentTempTargetDegC = TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp)));
currentTempTargetDegC = stayOff ? 0 : TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp))); } else {
} else { currentTempTargetDegC = min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp));
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;
}
} }
#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;
} }

View File

@@ -1,10 +1,61 @@
#include "OperatingModes.h" #include "OperatingModes.h"
#include "SolderingCommon.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) * * Soldering (gui_solderingMode)
* -> Main loop where we draw temp, and animations * -> Main loop where we draw temp, and animations
@@ -19,171 +70,109 @@ void gui_solderingMode(uint8_t jumpToSleep) {
* --> Double button to exit * --> Double button to exit
* --> Long hold double button to toggle key lock * --> 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) { OperatingMode newMode = handleSolderingButtons(buttons, cxt);
if (gui_SolderingSleepingMode(jumpToSleep == 2, true) == 1) { if (newMode != OperatingMode::Soldering) {
lastButtonTime = xTaskGetTickCount(); return newMode;
return; // If the function returns non-0 then exit }
// 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(); // Update status
if (buttonsLocked && (getSettingValue(SettingsOptions::LockingMode) != 0)) { // If buttons locked int error = currentTempTargetDegC - TipThermoModel::getTipInC();
switch (buttons) { if (error >= -10 && error <= 10) {
case BUTTON_NONE: // converged
boostModeOn = false; if (!cxt->scratch_state.state5) {
break; setBuzzer(true);
case BUTTON_BOTH_LONG: cxt->scratch_state.state3 = xTaskGetTickCount() + TICKS_SECOND / 3;
// Unlock buttons cxt->scratch_state.state5 = true;
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;
}
} }
// 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
// Draw in the screen details if (getSettingValue(SettingsOptions::DetailedSoldering)) {
if (getSettingValue(SettingsOptions::DetailedSoldering)) { if (OLED::getRotation()) {
if (OLED::getRotation()) { OLED::setCursor(50, 0);
OLED::setCursor(50, 0); } else {
} else { OLED::setCursor(-1, 0);
OLED::setCursor(-1, 0); }
}
gui_drawTipTemp(true, FontStyle::LARGE); gui_drawTipTemp(true, FontStyle::LARGE);
#ifndef NO_SLEEP_MODE #ifndef NO_SLEEP_MODE
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) { if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
if (OLED::getRotation()) { if (OLED::getRotation()) {
OLED::setCursor(32, 0); OLED::setCursor(32, 0);
} else { } else {
OLED::setCursor(47, 0); OLED::setCursor(47, 0);
}
printCountdownUntilSleep(getSleepTimeout());
} }
printCountdownUntilSleep(getSleepTimeout());
}
#endif #endif
if (boostModeOn) { if (cxt->scratch_state.state2) { // Boost mode is on
if (OLED::getRotation()) { if (OLED::getRotation()) {
OLED::setCursor(38, 8); OLED::setCursor(38, 8);
} else {
OLED::setCursor(55, 8);
}
OLED::print(SmallSymbolPlus, FontStyle::SMALL);
} else { } else {
if (OLED::getRotation()) { OLED::setCursor(55, 8);
OLED::setCursor(32, 8);
} else {
OLED::setCursor(47, 8);
}
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2);
} }
OLED::print(SmallSymbolPlus, FontStyle::SMALL);
detailedPowerStatus();
} else { } else {
basicSolderingStatus(boostModeOn); if (OLED::getRotation()) {
} OLED::setCursor(32, 8);
OLED::refresh();
// Update the setpoints for the temperature
if (boostModeOn) {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::BoostTemp));
} else { } else {
currentTempTargetDegC = (getSettingValue(SettingsOptions::BoostTemp)); OLED::setCursor(47, 8);
}
} else {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::SolderingTemp));
} else {
currentTempTargetDegC = (getSettingValue(SettingsOptions::SolderingTemp));
} }
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2);
} }
if (checkExitSoldering()) { detailedPowerStatus();
setBuzzer(false);
return;
}
// Update status } else {
int error = currentTempTargetDegC - TipThermoModel::getTipInC(); basicSolderingStatus(cxt->scratch_state.state2);
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();
} }
} }

View File

@@ -2,222 +2,209 @@
#include "OperatingModes.h" #include "OperatingModes.h"
#include "SolderingCommon.h" #include "SolderingCommon.h"
extern OperatingMode currentMode; OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt) {
void gui_solderingProfileMode() {
/* /*
* * Soldering (gui_solderingMode) * * Soldering
* -> Main loop where we draw temp, and animations * -> Main loop where we draw temp, and animations
* PID control
* --> Long hold back button to exit * --> Long hold back button to exit
* --> Double button to exit * --> Double button to exit
*/ */
currentMode = OperatingMode::soldering;
TickType_t buzzerEnd = 0; uint16_t tipTemp = 0;
bool waitForRelease = true; // If this is during init, start at preheat
TickType_t phaseStartTime = xTaskGetTickCount(); if (cxt->scratch_state.state1 == 0) {
cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePreheatTemp);
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);
uint16_t phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfilePreheatSpeed); uint16_t phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfilePreheatSpeed);
uint16_t profileCurrentTargetTemp = 0; uint16_t profileCurrentTargetTemp = 0;
for (;;) { switch (buttons) {
ButtonState buttons = getButtonState(); case BUTTON_BOTH:
if (buttons) { case BUTTON_B_LONG:
if (waitForRelease) { return OperatingMode::HomeScreen; // exit on back long hold
buttons = BUTTON_NONE; 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 { } else {
waitForRelease = false; // set up next phase
} switch (cxt->scratch_state.state1) {
case 1:
switch (buttons) { cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase1Duration);
case BUTTON_NONE: cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase1Temp);
break; break;
case BUTTON_BOTH: case 2:
case BUTTON_B_LONG: cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase2Duration);
return; // exit on back long hold cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase2Temp);
case BUTTON_F_LONG: break;
case BUTTON_F_SHORT: case 3:
case BUTTON_B_SHORT: cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase3Duration);
// Not used yet cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase3Temp);
break; break;
default: case 4:
break; cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase4Duration);
} cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase4Temp);
break;
tipTemp = getTipTemp(); case 5:
cxt->scratch_state.state2 = getSettingValue(SettingsOptions::ProfilePhase5Duration);
// if start temp is unknown (preheat), we're setting it now cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePhase5Temp);
if (phaseStartTemp == 0) { break;
phaseStartTemp = tipTemp; default:
// if this is hotter than the preheat temperature, we should fail break;
if (phaseStartTemp >= 55) {
warnUser(translatedString(Tr->TooHotToStartProfileWarning), 10 * TICKS_SECOND);
return;
} }
} if (cxt->scratch_state.state6 < cxt->scratch_state.state5) {
phaseTicksPerDegree = (cxt->scratch_state.state2 * TICKS_SECOND) / (cxt->scratch_state.state5 - cxt->scratch_state.state6);
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);
} else { } else {
// set up next phase phaseTicksPerDegree = (cxt->scratch_state.state2 * TICKS_SECOND) / (cxt->scratch_state.state6 - cxt->scratch_state.state5);
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);
}
} }
} }
}
// cooldown phase done? // cooldown phase done?
if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { if (cxt->scratch_state.state1 > getSettingValue(SettingsOptions::ProfilePhases)) {
if (TipThermoModel::getTipInC() < 55) { if (TipThermoModel::getTipInC() < 55) {
// we're done, let the buzzer beep too // we're done, let the buzzer beep too
setStatusLED(LED_STANDBY); setStatusLED(LED_STANDBY);
if (buzzerEnd == 0) { if (cxt->scratch_state.state4 == 0) {
setBuzzer(true); setBuzzer(true);
buzzerEnd = xTaskGetTickCount() + TICKS_SECOND / 3; cxt->scratch_state.state4 = xTaskGetTickCount() + TICKS_SECOND / 3;
}
} }
} }
}
// determine current target temp // determine current target temp
if (phaseStartTemp < phaseEndTemp) { if (cxt->scratch_state.state6 < cxt->scratch_state.state5) {
if (profileCurrentTargetTemp < phaseEndTemp) { if (profileCurrentTargetTemp < cxt->scratch_state.state5) {
profileCurrentTargetTemp = phaseStartTemp + ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree); 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 { } else {
if (profileCurrentTargetTemp > phaseEndTemp) { OLED::setCursor(0, 0);
profileCurrentTargetTemp = phaseStartTemp - ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree);
}
} }
OLED::clearScreen(); OLED::printNumber(tipTemp, 3, FontStyle::SMALL);
// Draw in the screen details OLED::print(SmallSymbolSlash, FontStyle::SMALL);
if (getSettingValue(SettingsOptions::DetailedSoldering)) { OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL);
// print temperature
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()) { if (OLED::getRotation()) {
OLED::setCursor(48, 0); OLED::setCursor(36, 0);
} else { } 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::print(SmallSymbolSlash, FontStyle::SMALL);
OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL);
OLED::printSymbolDeg(FontStyle::SMALL);
// print phase // blink if we can't keep up with the time goal
if (profilePhase > 0 && profilePhase <= getSettingValue(SettingsOptions::ProfilePhases)) { if (phaseElapsedSeconds < cxt->scratch_state.state2 + 2 || (xTaskGetTickCount() / TICKS_SECOND) % 2 == 0) {
if (OLED::getRotation()) { OLED::printNumber(cxt->scratch_state.state2 / 60, 1, FontStyle::SMALL);
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);
OLED::print(SmallSymbolColon, FontStyle::SMALL); OLED::print(SmallSymbolColon, FontStyle::SMALL);
OLED::printNumber(phaseElapsedSeconds % 60, 2, FontStyle::SMALL, false); OLED::printNumber(cxt->scratch_state.state2 % 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);
}
} }
detailedPowerStatus();
} else {
basicSolderingStatus(false);
} }
OLED::refresh(); detailedPowerStatus();
// Update the setpoints for the temperature
if (getSettingValue(SettingsOptions::TemperatureInF)) {
currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp);
} else {
currentTempTargetDegC = profileCurrentTargetTemp;
}
if (checkExitSoldering() || (buzzerEnd != 0 && xTaskGetTickCount() >= buzzerEnd)) { } else {
setBuzzer(false); basicSolderingStatus(false);
return; }
}
// Update LED status // Update the setpoints for the temperature
if (profilePhase == 0) { if (getSettingValue(SettingsOptions::TemperatureInF)) {
setStatusLED(LED_HEATING); currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp);
} else if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) { } else {
setStatusLED(LED_COOLING_STILL_HOT); currentTempTargetDegC = profileCurrentTargetTemp;
} else { }
setStatusLED(LED_HOT);
}
// slow down ui update rate if (checkExitSoldering() || (cxt->scratch_state.state4 != 0 && xTaskGetTickCount() >= cxt->scratch_state.state4)) {
GUIDelay(); 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);
} }
} }

View File

@@ -1,120 +1,99 @@
#include "OperatingModes.h" #include "OperatingModes.h"
void gui_solderingTempAdjust(void) { OperatingMode gui_solderingTempAdjust(const ButtonState buttons, guiContext *cxt) {
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();
if (buttons != BUTTON_NONE) { currentTempTargetDegC = 0; // Turn off heater while adjusting temp
// Temp adjust entered by long-pressing F button. uint16_t *buttonLockout = &(cxt->scratch_state.state1);
waitForRelease = true; 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::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;
if (getSettingValue(SettingsOptions::TemperatureInF)) { int16_t delta = 0;
if (newTemp > MAX_TEMP_F) { switch (buttons) {
newTemp = MAX_TEMP_F; case BUTTON_NONE:
} // stay
if (newTemp < MIN_TEMP_F) { (*buttonAccel) = 0;
newTemp = MIN_TEMP_F; break;
} case BUTTON_BOTH:
} else { // exit
if (newTemp > MAX_TEMP_C) { return cxt->previousMode;
newTemp = MAX_TEMP_C; case BUTTON_B_LONG:
} if (xTaskGetTickCount() - (*lastButtonTime) + (*buttonAccel) > PRESS_ACCEL_INTERVAL_MAX) {
if (newTemp < MIN_TEMP_C) { delta = -getSettingValue(SettingsOptions::TempChangeLongStep);
newTemp = MIN_TEMP_C; (*lastButtonTime) = xTaskGetTickCount();
} (*buttonAccel) += PRESS_ACCEL_STEP;
}
setSettingValue(SettingsOptions::SolderingTemp, (uint16_t)newTemp);
} }
if (xTaskGetTickCount() - lastChange > (TICKS_SECOND * 2)) { break;
return; // exit if user just doesn't press anything for a bit 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;
} }
break;
if (OLED::getRotation()) { case BUTTON_F_SHORT:
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE); delta = getSettingValue(SettingsOptions::TempChangeShortStep);
} else { break;
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE); default:
} break;
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();
} }
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
} }

View File

@@ -2,93 +2,89 @@
#ifdef POW_PD #ifdef POW_PD
#ifdef HAS_POWER_DEBUG_MENU #ifdef HAS_POWER_DEBUG_MENU
void showPDDebug(void) { OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) {
// Print out the USB-PD state // Print out the USB-PD state
// Basically this is like the Debug menu, but instead we want to print out the PD status // Basically this is like the Debug menu, but instead we want to print out the PD status
uint8_t screen = 0; uint16_t *screen = &(cxt->scratch_state.state1);
ButtonState b; OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
for (;;) { OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title
OLED::clearScreen(); // Ensure the buffer starts clean OLED::setCursor(0, 8); // second line
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left) if ((*screen) == 0) {
OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title // Print the PD state machine
OLED::setCursor(0, 8); // second line OLED::print(SmallSymbolState, FontStyle::SMALL);
if (screen == 0) { OLED::print(SmallSymbolSpace, FontStyle::SMALL);
// Print the PD state machine OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true);
OLED::print(SmallSymbolState, FontStyle::SMALL); OLED::print(SmallSymbolSpace, FontStyle::SMALL);
OLED::print(SmallSymbolSpace, FontStyle::SMALL); // Also print vbus mod status
OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true); if (USBPowerDelivery::fusbPresent()) {
OLED::print(SmallSymbolSpace, FontStyle::SMALL); if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) {
// Also print vbus mod status if (!USBPowerDelivery::isVBUSConnected()) {
if (USBPowerDelivery::fusbPresent()) { OLED::print(SmallSymbolNoVBus, FontStyle::SMALL);
if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) { } else {
if (!USBPowerDelivery::isVBUSConnected()) { OLED::print(SmallSymbolVBus, FontStyle::SMALL);
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 { } else {
// Print out the Proposed power options one by one *screen = 0;
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;
}
} }
OLED::refresh(); OLED::refresh();
b = getButtonState(); if (buttons == BUTTON_B_SHORT)
if (b == BUTTON_B_SHORT) { return OperatingMode::InitialisationDone;
return; else if (buttons == BUTTON_F_SHORT) {
} else if (b == BUTTON_F_SHORT) { *screen++;
screen++;
} }
GUIDelay(); GUIDelay();
} }
return OperatingMode::UsbPDDebug;
} }
#endif #endif
#endif #endif

View File

@@ -2,7 +2,7 @@
#include "OperatingModes.h" #include "OperatingModes.h"
#if POW_PD_EXT == 1 #if POW_PD_EXT == 1
#ifdef HAS_POWER_DEBUG_MENU #ifdef HAS_POWER_DEBUG_MENU
void showPDDebug(void) { OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) {
// Print out the USB-PD state // Print out the USB-PD state
// Basically this is like the Debug menu, but instead we want to print out the PD status // Basically this is like the Debug menu, but instead we want to print out the PD status
uint8_t screen = 0; uint8_t screen = 0;

View File

@@ -1,18 +1,19 @@
#ifndef OPERATING_MODE_UTILITIES_H_ #ifndef OPERATING_MODE_UTILITIES_H_
#define OPERATING_MODE_UTILITIES_H_ #define OPERATING_MODE_UTILITIES_H_
#include "Buttons.hpp"
#include "OLED.hpp" #include "OLED.hpp"
#include <stdbool.h> #include <stdbool.h>
void GUIDelay(); // void GUIDelay(); //
bool checkForUnderVoltage(void); // bool checkForUnderVoltage(void); //
uint32_t getSleepTimeout(void); // uint32_t getSleepTimeout(void); //
bool shouldBeSleeping(bool inAutoStart); // bool shouldBeSleeping(); //
bool shouldShutdown(void); // bool shouldShutdown(void); //
void gui_drawTipTemp(bool symbol, const FontStyle font); // void gui_drawTipTemp(bool symbol, const FontStyle font); //
void printVoltage(void); // void printVoltage(void); //
void warnUser(const char *warning, const TickType_t timeout); // bool warnUser(const char *warning, const ButtonState buttons); //
void gui_drawBatteryIcon(void); // void gui_drawBatteryIcon(void); //
bool checkForUnderVoltage(void); // bool checkForUnderVoltage(void); //
uint16_t min(uint16_t a, uint16_t b); // uint16_t min(uint16_t a, uint16_t b); //
void printCountdownUntilSleep(int sleepThres); // void printCountdownUntilSleep(int sleepThres); //
#endif #endif

View File

@@ -1,8 +1,9 @@
#include "Buttons.hpp" #include "Buttons.hpp"
#include "OperatingModeUtilities.h" #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::clearScreen();
OLED::printWholeScreen(warning); OLED::printWholeScreen(warning);
OLED::refresh(); // TODO also timeout
waitForButtonPressOrTimeout(timeout); return buttons != BUTTON_NONE;
} }

View File

@@ -106,30 +106,8 @@ bool checkExitSoldering(void) {
} }
} }
#endif #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 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; return false;
} }

View File

@@ -4,15 +4,13 @@
TickType_t lastHallEffectSleepStart = 0; TickType_t lastHallEffectSleepStart = 0;
extern TickType_t lastMovementTime; extern TickType_t lastMovementTime;
bool shouldBeSleeping(bool inAutoStart) { bool shouldBeSleeping() {
#ifndef NO_SLEEP_MODE #ifndef NO_SLEEP_MODE
// Return true if the iron should be in sleep mode // Return true if the iron should be in sleep mode
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) { if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
if (inAutoStart) { // In auto start we are asleep until movement
// In auto start we are asleep until movement if (lastMovementTime == 0 && lastButtonTime == 0) {
if (lastMovementTime == 0 && lastButtonTime == 0) { return true;
return true;
}
} }
if (lastMovementTime > 0 || lastButtonTime > 0) { if (lastMovementTime > 0 || lastButtonTime > 0) {
if (((xTaskGetTickCount() - lastMovementTime) > getSleepTimeout()) && ((xTaskGetTickCount() - lastButtonTime) > getSleepTimeout())) { if (((xTaskGetTickCount() - lastMovementTime) > getSleepTimeout()) && ((xTaskGetTickCount() - lastButtonTime) > getSleepTimeout())) {