Big overhaul of the UI framework (#1749)
* Starting GUI render refactor to be more immediate mode Update TemperatureAdjust.cpp . Cleanup Soldering Sleep SolderingProfiles Soldering Rework Rough pass GUI Temp Adjust Cleanup old OperatingMode Debug Menu * Update TemperatureAdjust.cpp * Roughing some transition work * Fixup! Hook in the init starter helper * Better home screen button handler * FIXUP! Fix typo's . * Update SettingsMenu.cpp * More settings rework * More settings rendering * Fixup * Transitions Update SolderingProfile.cpp Hook in transistions * Update TemperatureAdjust.cpp * Update push.yml * Add auto-repeat to settings menu * Miniware: Use IT for I2C writes * Update USBPDDebug_HUSB238.cpp * Force write screen on side animation cancel . * Refactor moving down the settings list * Update settingsGUI.cpp * Update I2C_Wrapper.cpp * Update OLED.cpp * Rework button handling * Fix PD debug at boot * Fixup not showing right menu options * silence some warnings * Style cleanup * Fkit use bit-bang I2C for Miniware * Update GUIRendering.md * Fixup transition on enter soldering mode * Save Settings * Fixes for some animations not running Dont bail on animations if keypress is still held * Fixup settings acceleration * OLED Up animation * Link up/down on debug meny * Make all accelerometers I2C bus aware Update accelerometers_common.h * Make I2C mag optional * Miniware -> Only Bit-Bang I2C * Fixup for scrollbar FIXUP! Debug menu returns to home screen FIXUP! Up oled animation Fix temp exit * Settings menu -> Both buttons return a menu layer * Merge fixup * Update BMA223.cpp * Re-Enable OLED sleep * Save Setting on temp adjust exit * WiP on startup mode * Some autostart working * Add hibernation mode & more autostart fixes * If cant CJC; go to startup * Hibernate in sleep * Cleanup scroll indicator * FIXUP! Ensure startup warnings are linked in * FIXUP! Ensure we render out temp change before timing out * Ensure 100ms delay between CJC samples * Fix not re-calculating menu length on entering menu * Implement NegotiationinProgress for USB-PD * Mask heating until PD finishes negotiation * Fixup staying in hibernate correctly * Warning timeout * Show reset settings warning * Correctly compensate help text start time * Update GUIThread.cpp * Update USBPD.cpp * . * Fixup sleep time * Update printSleepCountdown.cpp * replacing countdown with big plus while in boost mode * bringing back the + 1 since it was missing when not in boost mode * Bail on USB-PD check after 3 seconds incase of DC source * Fix hibernate * Update PIDThread.cpp * did center plus symbol (boost mode) * Big refactor to not make settings increment handler handle the "is last item" return * Fixup boot logo * Fix flashing * Fixup recalculate the menu length on long hold * Fixup missing menu entries * Fix junk left on screen after user confirmation * Re-order button handler to use custom, then default order to allow setting associated setting * Attach setting for settings using custom handler * Fix swap +/- keys * Fix boost temp * Implement last menu option for Language selector * Wait for init before CJC runs * Check last setting via increment value * Update BSP.cpp * removed = from >= Otherwise incrementing would stop and the scroll bar would already flash at the second to last value. * (Hacky) Fix for Settings reset --------- Co-authored-by: discip <53649486+discip@users.noreply.github.com>
This commit is contained in:
40
source/Core/Threads/GUIRendering.md
Normal file
40
source/Core/Threads/GUIRendering.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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
|
||||
|
||||
## Transitions
|
||||
|
||||
When changing the view to a new view it can be preferable to transition using an animation.
|
||||
The tooling provides for left, right and down animations at this point.
|
||||
The use of these gives a notion of "direction" when navigating the menu.
|
||||
|
||||
```
|
||||
┌───────────┐
|
||||
│ Debug Menu│
|
||||
└─────┬─────┘
|
||||
│
|
||||
│
|
||||
│
|
||||
┌──────────────┐ ┌────┴─────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
│Soldering Mode│ │ │ │ │ │ │
|
||||
│ OR ├───────────┤Home Menu ├───────────┤Settings Main Menu├───────────┤Settings sub menu│
|
||||
│Reflow Mode│ │ │ │ │ │ │
|
||||
└──────────────┘ └──────────┘ └──────────────────┘ └─────────┬───────┘
|
||||
│
|
||||
┌─────────┴───────┐
|
||||
│ │
|
||||
│Settings sub menu│
|
||||
│ │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
The downside of supporting transitions is that for these to work, the code should render the screen _first_ then return the new state.
|
||||
This ensures there is a good working copy in the buffer before the transition changes the view.
|
||||
|
||||
The code that handles the dispatch will run a new render pass again to get the new buffer contents and then transition between the two for you.
|
||||
At the moment scrolling "Up" isn't implemented but the enumeration is there so that its implementation can follow.
|
||||
@@ -32,8 +32,179 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
// File local variables
|
||||
#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
||||
#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
||||
|
||||
extern bool heaterThermalRunaway;
|
||||
ButtonState buttonsAtDeviceBoot; // We record button state at startup, incase of jumping to debug modes
|
||||
OperatingMode currentOperatingMode = OperatingMode::InitialisationDone; // Current mode we are rendering
|
||||
guiContext context; // Context passed to functions to aid in state during render passes
|
||||
|
||||
OperatingMode handle_post_init_state();
|
||||
OperatingMode guiHandleDraw(void) {
|
||||
OLED::clearScreen(); // Clear ready for render pass
|
||||
// Read button state
|
||||
ButtonState buttons = getButtonState();
|
||||
// Enforce screen on if buttons pressed, movement, hot tip etc
|
||||
if (buttons != BUTTON_NONE) {
|
||||
OLED::setDisplayState(OLED::DisplayState::ON);
|
||||
} else {
|
||||
// Buttons are none; check if we can sleep display
|
||||
uint32_t tipTemp = TipThermoModel::getTipInC();
|
||||
if ((tipTemp < 50) && getSettingValue(SettingsOptions::Sensitivity) &&
|
||||
(((xTaskGetTickCount() - lastMovementTime) > MOVEMENT_INACTIVITY_TIME) && ((xTaskGetTickCount() - lastButtonTime) > BUTTON_INACTIVITY_TIME))) {
|
||||
OLED::setDisplayState(OLED::DisplayState::OFF);
|
||||
setStatusLED(LED_OFF);
|
||||
} else {
|
||||
OLED::setDisplayState(OLED::DisplayState::ON);
|
||||
if (tipTemp > 55) {
|
||||
setStatusLED(LED_COOLING_STILL_HOT);
|
||||
} else {
|
||||
setStatusLED(LED_STANDBY);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dispatch button state to gui mode
|
||||
OperatingMode newMode = currentOperatingMode;
|
||||
switch (currentOperatingMode) {
|
||||
case OperatingMode::StartupWarnings:
|
||||
newMode = showWarnings(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::UsbPDDebug:
|
||||
#ifdef HAS_POWER_DEBUG_MENU
|
||||
newMode = showPDDebug(buttons, &context);
|
||||
break;
|
||||
#else
|
||||
newMode = OperatingMode::InitialisationDone;
|
||||
#endif
|
||||
case OperatingMode::StartupLogo:
|
||||
showBootLogo();
|
||||
|
||||
if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::SLEEP) {
|
||||
lastMovementTime = lastButtonTime = 0; // We mask the values so that sleep goes until user moves again or presses a button
|
||||
newMode = OperatingMode::Sleeping;
|
||||
} else if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::SOLDER) {
|
||||
lastMovementTime = lastButtonTime = xTaskGetTickCount(); // Move forward so we dont go to sleep
|
||||
newMode = OperatingMode::Soldering;
|
||||
} else if (getSettingValue(SettingsOptions::AutoStartMode) == autoStartMode_t::ZERO) {
|
||||
lastMovementTime = lastButtonTime = 0; // We mask the values so that sleep goes until user moves again or presses a button
|
||||
newMode = OperatingMode::Hibernating;
|
||||
} else {
|
||||
newMode = OperatingMode::HomeScreen;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Fallthrough */
|
||||
case OperatingMode::HomeScreen:
|
||||
newMode = drawHomeScreen(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::Soldering:
|
||||
context.scratch_state.state4 = 0;
|
||||
newMode = gui_solderingMode(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::SolderingProfile:
|
||||
newMode = gui_solderingProfileMode(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::Sleeping:
|
||||
newMode = gui_SolderingSleepingMode(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::TemperatureAdjust:
|
||||
newMode = gui_solderingTempAdjust(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::DebugMenuReadout:
|
||||
newMode = showDebugMenu(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::CJCCalibration:
|
||||
newMode = performCJCC(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::SettingsMenu:
|
||||
newMode = gui_SettingsMenu(buttons, &context);
|
||||
break;
|
||||
case OperatingMode::InitialisationDone:
|
||||
newMode = handle_post_init_state();
|
||||
break;
|
||||
case OperatingMode::Hibernating:
|
||||
context.scratch_state.state4 = 1;
|
||||
gui_SolderingSleepingMode(buttons, &context);
|
||||
if (lastButtonTime > 0 || lastMovementTime > 0) {
|
||||
newMode = OperatingMode::Soldering;
|
||||
}
|
||||
break;
|
||||
case OperatingMode::ThermalRunaway:
|
||||
/*TODO*/
|
||||
newMode = OperatingMode::HomeScreen;
|
||||
break;
|
||||
};
|
||||
return newMode;
|
||||
}
|
||||
void guiRenderLoop(void) {
|
||||
OperatingMode newMode = guiHandleDraw(); // This does the screen drawing
|
||||
|
||||
// Post draw we handle any state transitions
|
||||
|
||||
if (newMode != currentOperatingMode) {
|
||||
context.viewEnterTime = xTaskGetTickCount();
|
||||
context.previousMode = currentOperatingMode;
|
||||
// If the previous mode is the startup logo; we dont want to return to it, but instead dispatch out to either home or soldering
|
||||
if (currentOperatingMode == OperatingMode::StartupLogo) {
|
||||
if (getSettingValue(SettingsOptions::AutoStartMode)) {
|
||||
context.previousMode = OperatingMode::Soldering;
|
||||
} else {
|
||||
newMode = OperatingMode::HomeScreen;
|
||||
}
|
||||
}
|
||||
memset(&context.scratch_state, 0, sizeof(context.scratch_state));
|
||||
currentOperatingMode = newMode;
|
||||
}
|
||||
// If the transition marker is set, we need to make the next draw occur to the secondary buffer so we have something to transition to
|
||||
if (context.transitionMode != TransitionAnimation::None) {
|
||||
OLED::useSecondaryFramebuffer(true);
|
||||
// Now we need to fill the secondary buffer with the _next_ frame to transistion to
|
||||
guiHandleDraw();
|
||||
OLED::useSecondaryFramebuffer(false);
|
||||
// Now dispatch the transition
|
||||
switch (context.transitionMode) {
|
||||
case TransitionAnimation::Down:
|
||||
OLED::transitionScrollDown(context.viewEnterTime);
|
||||
break;
|
||||
case TransitionAnimation::Left:
|
||||
OLED::transitionSecondaryFramebuffer(false, context.viewEnterTime);
|
||||
break;
|
||||
case TransitionAnimation::Right:
|
||||
OLED::transitionSecondaryFramebuffer(true, context.viewEnterTime);
|
||||
break;
|
||||
case TransitionAnimation::Up:
|
||||
OLED::transitionScrollUp(context.viewEnterTime);
|
||||
|
||||
case TransitionAnimation::None:
|
||||
default:
|
||||
break; // Do nothing on unknown
|
||||
}
|
||||
|
||||
context.transitionMode = TransitionAnimation::None; // Clear transition flag
|
||||
}
|
||||
// Render done, draw it out
|
||||
OLED::refresh();
|
||||
}
|
||||
|
||||
OperatingMode handle_post_init_state() {
|
||||
#ifdef HAS_POWER_DEBUG_MENU
|
||||
#ifdef DEBUG_POWER_MENU_BUTTON_B
|
||||
if (buttonsAtDeviceBoot == BUTTON_B_LONG || buttonsAtDeviceBoot == BUTTON_B_SHORT) {
|
||||
#else
|
||||
if (buttonsAtDeviceBoot == BUTTON_F_LONG || buttonsAtDeviceBoot == BUTTON_F_SHORT) {
|
||||
#endif
|
||||
buttonsAtDeviceBoot = BUTTON_NONE;
|
||||
return OperatingMode::UsbPDDebug;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) {
|
||||
return OperatingMode::CJCCalibration;
|
||||
}
|
||||
|
||||
return OperatingMode::StartupWarnings;
|
||||
}
|
||||
|
||||
/* StartGUITask function */
|
||||
void startGUITask(void const *argument) {
|
||||
@@ -47,42 +218,22 @@ void startGUITask(void const *argument) {
|
||||
bool buttonLockout = false;
|
||||
renderHomeScreenAssets();
|
||||
getTipRawTemp(1); // reset filter
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1);
|
||||
// If the front button is held down, on supported devices, show PD debugging metrics
|
||||
#ifdef HAS_POWER_DEBUG_MENU
|
||||
#ifdef DEBUG_POWER_MENU_BUTTON_B
|
||||
if (getButtonB()) {
|
||||
#else
|
||||
|
||||
// Read boot button state
|
||||
if (getButtonA()) {
|
||||
#endif
|
||||
showPDDebug();
|
||||
buttonsAtDeviceBoot = BUTTON_F_LONG;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getSettingValue(SettingsOptions::CalibrateCJC) > 0) {
|
||||
performCJCC();
|
||||
if (getButtonB()) {
|
||||
buttonsAtDeviceBoot = BUTTON_B_LONG;
|
||||
}
|
||||
|
||||
uint16_t logoMode = getSettingValue(SettingsOptions::LOGOTime);
|
||||
uint16_t startMode = getSettingValue(SettingsOptions::AutoStartMode);
|
||||
// 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 (logoMode && logoMode < logoMode_t::ONETIME && startMode && startMode < autoStartMode_t::ZERO) {
|
||||
uint16_t sleepTempDegC = getSettingValue(SettingsOptions::SleepTemp);
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
sleepTempDegC = TipThermoModel::convertFtoC(sleepTempDegC);
|
||||
}
|
||||
// Only heat to sleep temperature (but no higher than 75°C for safety)
|
||||
currentTempTargetDegC = min(sleepTempDegC, 75);
|
||||
TickType_t startRender = xTaskGetTickCount();
|
||||
for (;;) {
|
||||
guiRenderLoop();
|
||||
resetWatchdog();
|
||||
vTaskDelayUntil(&startRender, TICKS_100MS * 4 / 10); // Try and maintain 20-25fps ish update rate, way to fast but if we can its nice
|
||||
}
|
||||
|
||||
showBootLogo();
|
||||
showWarnings();
|
||||
if (getSettingValue(SettingsOptions::AutoStartMode)) {
|
||||
// jump directly to the autostart mode
|
||||
gui_solderingMode(getSettingValue(SettingsOptions::AutoStartMode) - 1);
|
||||
buttonLockout = true;
|
||||
}
|
||||
|
||||
drawHomeScreen(buttonLockout);
|
||||
}
|
||||
|
||||
@@ -1,39 +1,49 @@
|
||||
|
||||
|
||||
#include "OperatingModes.h"
|
||||
void performCJCC(void) {
|
||||
OperatingMode performCJCC(const ButtonState buttons, guiContext *cxt) {
|
||||
// Calibrate Cold Junction Compensation directly at boot, before internal components get warm.
|
||||
OLED::refresh();
|
||||
osDelay(50);
|
||||
|
||||
// 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) {
|
||||
uint16_t setoffset = 0;
|
||||
// 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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return OperatingMode::CJCCalibration;
|
||||
}
|
||||
|
||||
// If the thermo-couple at the end of the tip, and the handle are at
|
||||
// equilibrium, then the output should be zero, as there is no temperature
|
||||
// differential.
|
||||
while (setoffset == 0) {
|
||||
uint32_t offset = 0;
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
offset += getTipRawTemp(1);
|
||||
// cycle through the filter a fair bit to ensure we're stable.
|
||||
OLED::clearScreen();
|
||||
OLED::setCursor(0, 0);
|
||||
OLED::print(translatedString(Tr->CJCCalibrating), FontStyle::SMALL);
|
||||
OLED::setCursor(0, 8);
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
for (uint8_t x = 0; x < (i / 4); x++) {
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
}
|
||||
OLED::refresh();
|
||||
osDelay(100);
|
||||
}
|
||||
setoffset = TipThermoModel::convertTipRawADCTouV(offset / 16, true);
|
||||
|
||||
uint16_t setOffset = TipThermoModel::convertTipRawADCTouV(cxt->scratch_state.state3 / 16, true);
|
||||
setSettingValue(SettingsOptions::CalibrationOffset, setOffset);
|
||||
if (warnUser(translatedString(Tr->CalibrationDone), buttons)) {
|
||||
// Preventing to repeat calibration at boot automatically (only one shot).
|
||||
setSettingValue(SettingsOptions::CalibrateCJC, 0);
|
||||
saveSettings();
|
||||
return OperatingMode::InitialisationDone;
|
||||
}
|
||||
setSettingValue(SettingsOptions::CalibrationOffset, setoffset);
|
||||
OLED::clearScreen();
|
||||
warnUser(translatedString(Tr->CalibrationDone), 3 * TICKS_SECOND);
|
||||
OLED::refresh();
|
||||
// Preventing to repeat calibration at boot automatically (only one shot).
|
||||
setSettingValue(SettingsOptions::CalibrateCJC, 0);
|
||||
saveSettings();
|
||||
return OperatingMode::CJCCalibration;
|
||||
}
|
||||
// Cant run calibration without the tip and for temps to be close
|
||||
return OperatingMode::StartupWarnings;
|
||||
}
|
||||
|
||||
@@ -1,111 +1,102 @@
|
||||
#include "OperatingModes.h"
|
||||
extern osThreadId GUITaskHandle;
|
||||
extern osThreadId MOVTaskHandle;
|
||||
extern osThreadId PIDTaskHandle;
|
||||
extern OperatingMode currentMode;
|
||||
extern osThreadId GUITaskHandle;
|
||||
extern osThreadId MOVTaskHandle;
|
||||
extern osThreadId PIDTaskHandle;
|
||||
|
||||
void showDebugMenu(void) {
|
||||
currentMode = OperatingMode::debug;
|
||||
uint8_t screen = 0;
|
||||
ButtonState b;
|
||||
for (;;) {
|
||||
OLED::clearScreen(); // Ensure the buffer starts clean
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number
|
||||
OLED::setCursor(0, 8); // second line
|
||||
OLED::print(DebugMenu[screen], FontStyle::SMALL);
|
||||
switch (screen) {
|
||||
case 0: // Build Date
|
||||
break;
|
||||
case 1: // Device ID
|
||||
{
|
||||
uint64_t id = getDeviceID();
|
||||
OperatingMode showDebugMenu(const ButtonState buttons, guiContext *cxt) {
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(SmallSymbolVersionNumber, FontStyle::SMALL); // Print version number
|
||||
OLED::setCursor(0, 8); // second line
|
||||
OLED::print(DebugMenu[cxt->scratch_state.state1], FontStyle::SMALL);
|
||||
switch (cxt->scratch_state.state1) {
|
||||
case 0: // Build Date
|
||||
break;
|
||||
case 1: // Device ID
|
||||
{
|
||||
uint64_t id = getDeviceID();
|
||||
#ifdef DEVICE_HAS_VALIDATION_CODE
|
||||
// If device has validation code; then we want to take over both lines of the screen
|
||||
OLED::clearScreen(); // Ensure the buffer starts clean
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(DebugMenu[screen], FontStyle::SMALL);
|
||||
OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8);
|
||||
OLED::setCursor(0, 8); // second line
|
||||
// If device has validation code; then we want to take over both lines of the screen
|
||||
OLED::clearScreen(); // Ensure the buffer starts clean
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(DebugMenu[cxt->scratch_state.state1], FontStyle::SMALL);
|
||||
OLED::drawHex(getDeviceValidation(), FontStyle::SMALL, 8);
|
||||
OLED::setCursor(0, 8); // second line
|
||||
#endif
|
||||
OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8);
|
||||
OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8);
|
||||
} break;
|
||||
case 2: // ACC Type
|
||||
OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL);
|
||||
break;
|
||||
case 3: // Power Negotiation Status
|
||||
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL);
|
||||
break;
|
||||
case 4: // Input Voltage
|
||||
printVoltage();
|
||||
break;
|
||||
case 5: // Temp in °C
|
||||
OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL);
|
||||
break;
|
||||
case 6: // Handle Temp in °C
|
||||
OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL);
|
||||
break;
|
||||
case 7: // Max Temp Limit in °C
|
||||
OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL);
|
||||
break;
|
||||
case 8: // System Uptime
|
||||
OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 9: // Movement Timestamp
|
||||
OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 10: // Tip Resistance in Ω large to pad over so that we cover ID left overs
|
||||
OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL);
|
||||
break;
|
||||
case 11: // Raw Tip in µV
|
||||
OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 12: // Tip Cold Junction Compensation Offset in µV
|
||||
OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 13: // High Water Mark for GUI
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 14: // High Water Mark for Movement Task
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 15: // High Water Mark for PID Task
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
break;
|
||||
OLED::drawHex((uint32_t)(id >> 32), FontStyle::SMALL, 8);
|
||||
OLED::drawHex((uint32_t)(id & 0xFFFFFFFF), FontStyle::SMALL, 8);
|
||||
} break;
|
||||
case 2: // ACC Type
|
||||
OLED::print(AccelTypeNames[(int)DetectedAccelerometerVersion], FontStyle::SMALL);
|
||||
break;
|
||||
case 3: // Power Negotiation Status
|
||||
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL);
|
||||
break;
|
||||
case 4: // Input Voltage
|
||||
printVoltage();
|
||||
break;
|
||||
case 5: // Temp in °C
|
||||
OLED::printNumber(TipThermoModel::getTipInC(), 6, FontStyle::SMALL);
|
||||
break;
|
||||
case 6: // Handle Temp in °C
|
||||
OLED::printNumber(getHandleTemperature(0) / 10, 6, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(getHandleTemperature(0) % 10, 1, FontStyle::SMALL);
|
||||
break;
|
||||
case 7: // Max Temp Limit in °C
|
||||
OLED::printNumber(TipThermoModel::getTipMaxInC(), 6, FontStyle::SMALL);
|
||||
break;
|
||||
case 8: // System Uptime
|
||||
OLED::printNumber(xTaskGetTickCount() / TICKS_100MS, 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 9: // Movement Timestamp
|
||||
OLED::printNumber(lastMovementTime / TICKS_100MS, 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 10: // Tip Resistance in Ω
|
||||
OLED::printNumber(getTipResistanceX10() / 10, 6, FontStyle::SMALL); // large to pad over so that we cover ID left overs
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(getTipResistanceX10() % 10, 1, FontStyle::SMALL);
|
||||
break;
|
||||
case 11: // Raw Tip in µV
|
||||
OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 12: // Tip Cold Junction Compensation Offset in µV
|
||||
OLED::printNumber(getSettingValue(SettingsOptions::CalibrationOffset), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 13: // High Water Mark for GUI
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 14: // High Water Mark for Movement Task
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
case 15: // High Water Mark for PID Task
|
||||
OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 8, FontStyle::SMALL);
|
||||
break;
|
||||
break;
|
||||
#ifdef HALL_SENSOR
|
||||
case 16: // Raw Hall Effect Value
|
||||
{
|
||||
int16_t hallEffectStrength = getRawHallEffect();
|
||||
if (hallEffectStrength < 0) {
|
||||
hallEffectStrength = -hallEffectStrength;
|
||||
}
|
||||
OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL);
|
||||
} break;
|
||||
case 16: // Raw Hall Effect Value
|
||||
{
|
||||
int16_t hallEffectStrength = getRawHallEffect();
|
||||
if (hallEffectStrength < 0) {
|
||||
hallEffectStrength = -hallEffectStrength;
|
||||
}
|
||||
OLED::printNumber(hallEffectStrength, 6, FontStyle::SMALL);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
OLED::refresh();
|
||||
b = getButtonState();
|
||||
if (b == BUTTON_B_SHORT) {
|
||||
return;
|
||||
} else if (b == BUTTON_F_SHORT) {
|
||||
screen++;
|
||||
#ifdef HALL_SENSOR
|
||||
screen = screen % 17;
|
||||
#else
|
||||
screen = screen % 16;
|
||||
#endif
|
||||
}
|
||||
|
||||
GUIDelay();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (buttons == BUTTON_B_SHORT) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
#include "Buttons.hpp"
|
||||
#include "OperatingModes.h"
|
||||
|
||||
#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
||||
#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
||||
|
||||
uint8_t buttonAF[sizeof(buttonA)];
|
||||
uint8_t buttonBF[sizeof(buttonB)];
|
||||
uint8_t disconnectedTipF[sizeof(disconnectedTip)];
|
||||
extern OperatingMode currentMode;
|
||||
bool showExitMenuTransition = false;
|
||||
uint8_t buttonAF[sizeof(buttonA)];
|
||||
uint8_t buttonBF[sizeof(buttonB)];
|
||||
uint8_t disconnectedTipF[sizeof(disconnectedTip)];
|
||||
bool showExitMenuTransition = false;
|
||||
|
||||
void renderHomeScreenAssets(void) {
|
||||
|
||||
@@ -24,59 +20,50 @@ void renderHomeScreenAssets(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void handleButtons(bool *buttonLockout) {
|
||||
ButtonState buttons = getButtonState();
|
||||
if (buttons != BUTTON_NONE) {
|
||||
OLED::setDisplayState(OLED::DisplayState::ON);
|
||||
}
|
||||
if (buttons != BUTTON_NONE && *buttonLockout) {
|
||||
buttons = BUTTON_NONE;
|
||||
OperatingMode handleHomeButtons(const ButtonState buttons, guiContext *cxt) {
|
||||
if (buttons != BUTTON_NONE && cxt->scratch_state.state1 == 0) {
|
||||
return OperatingMode::HomeScreen; // Ignore button press
|
||||
} else {
|
||||
*buttonLockout = false;
|
||||
cxt->scratch_state.state1 = 1;
|
||||
}
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
case BUTTON_BOTH:
|
||||
// Not used yet
|
||||
// In multi-language this might be used to reset language on a long hold
|
||||
// or some such
|
||||
break;
|
||||
|
||||
case BUTTON_B_LONG:
|
||||
// Show the version information
|
||||
showDebugMenu();
|
||||
cxt->transitionMode = TransitionAnimation::Up;
|
||||
return OperatingMode::DebugMenuReadout;
|
||||
break;
|
||||
case BUTTON_F_LONG:
|
||||
#ifdef PROFILE_SUPPORT
|
||||
if (!isTipDisconnected()) {
|
||||
gui_solderingProfileMode(); // enter profile mode
|
||||
*buttonLockout = true;
|
||||
cxt->transitionMode = TransitionAnimation::Left;
|
||||
return OperatingMode::SolderingProfile;
|
||||
} else {
|
||||
return OperatingMode::HomeScreen;
|
||||
}
|
||||
#else
|
||||
gui_solderingTempAdjust();
|
||||
saveSettings();
|
||||
cxt->transitionMode = TransitionAnimation::Left;
|
||||
return OperatingMode::TemperatureAdjust;
|
||||
#endif
|
||||
break;
|
||||
case BUTTON_F_SHORT:
|
||||
if (!isTipDisconnected()) {
|
||||
gui_solderingMode(0); // enter soldering mode
|
||||
*buttonLockout = true;
|
||||
cxt->transitionMode = TransitionAnimation::Left;
|
||||
return OperatingMode::Soldering;
|
||||
}
|
||||
break;
|
||||
case BUTTON_B_SHORT:
|
||||
currentMode = OperatingMode::settings;
|
||||
enterSettingsMenu(); // enter the settings menu
|
||||
{
|
||||
OLED::useSecondaryFramebuffer(true);
|
||||
showExitMenuTransition = true;
|
||||
}
|
||||
*buttonLockout = true;
|
||||
cxt->transitionMode = TransitionAnimation::Right;
|
||||
return OperatingMode::SettingsMenu;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return OperatingMode::HomeScreen;
|
||||
}
|
||||
|
||||
void drawDetailedHomeScreen(uint32_t tipTemp) {
|
||||
@@ -181,55 +168,22 @@ void drawSimplifiedHomeScreen(uint32_t tipTemp) {
|
||||
}
|
||||
}
|
||||
}
|
||||
void drawHomeScreen(bool buttonLockout) {
|
||||
OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt) {
|
||||
|
||||
for (;;) {
|
||||
currentMode = OperatingMode::idle;
|
||||
handleButtons(&buttonLockout);
|
||||
currentTempTargetDegC = 0; // ensure tip is off
|
||||
getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0);
|
||||
uint32_t tipTemp = TipThermoModel::getTipInC();
|
||||
|
||||
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();
|
||||
}
|
||||
// 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 handleHomeButtons(buttons, cxt);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,3 @@
|
||||
//
|
||||
|
||||
#include "OperatingModes.h"
|
||||
|
||||
// Global variables
|
||||
OperatingMode currentMode = OperatingMode::idle;
|
||||
@@ -24,29 +24,64 @@ extern "C" {
|
||||
#include "pd.h"
|
||||
#endif
|
||||
|
||||
// Exposed modes
|
||||
enum OperatingMode {
|
||||
idle = 0,
|
||||
soldering = 1,
|
||||
boost = 2,
|
||||
sleeping = 3,
|
||||
settings = 4,
|
||||
debug = 5
|
||||
enum class OperatingMode {
|
||||
StartupLogo = 0, // Showing the startup logo
|
||||
CJCCalibration, // Cold Junction Calibration
|
||||
StartupWarnings, // Startup checks and warnings
|
||||
InitialisationDone, // Special state we use just before we to home screen at first startup. Allows jumping to extra startup states
|
||||
HomeScreen, // Home/Idle screen that is the main launchpad to other modes
|
||||
Soldering, // Main soldering operating mode
|
||||
SolderingProfile, // Soldering by following a profile, used for reflow for example
|
||||
Sleeping, // Sleep state holds iron at lower sleep temp
|
||||
Hibernating, // Like sleeping but keeps heater fully off until woken
|
||||
SettingsMenu, // Settings Menu
|
||||
DebugMenuReadout, // Debug metrics
|
||||
TemperatureAdjust, // Set point temperature adjustment
|
||||
UsbPDDebug, // USB PD debugging information
|
||||
ThermalRunaway, // Thermal Runaway warning state.
|
||||
};
|
||||
|
||||
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
|
||||
void performCJCC(void); // Used to calibrate the Cold Junction offset
|
||||
void gui_solderingTempAdjust(void); // For adjusting the setpoint temperature of the iron
|
||||
int gui_SolderingSleepingMode(bool stayOff, bool autoStarted); // Sleep mode
|
||||
void gui_solderingMode(uint8_t jumpToSleep); // Main mode for hot pointy tool
|
||||
void gui_solderingProfileMode(); // Profile mode for hot likely-not-so-pointy tool
|
||||
void showDebugMenu(void); // Debugging values
|
||||
void showPDDebug(void); // Debugging menu that shows PD adaptor info
|
||||
void showWarnings(void); // Shows user warnings if required
|
||||
void drawHomeScreen(bool buttonLockout) __attribute__((noreturn)); // IDLE / Home screen
|
||||
void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics
|
||||
OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt); // Sleep mode
|
||||
OperatingMode gui_solderingMode(const ButtonState buttons, guiContext *cxt); // Main mode for hot pointy tool
|
||||
OperatingMode gui_solderingTempAdjust(const ButtonState buttons, guiContext *cxt); // For adjusting the setpoint temperature of the iron
|
||||
OperatingMode drawHomeScreen(const ButtonState buttons, guiContext *cxt); // IDLE / Home screen
|
||||
OperatingMode gui_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
|
||||
TemperatureType_t getTipTemp(void); // Returns temperature of the tip in *C/*F (based on user settings)
|
||||
int8_t getPowerSourceNumber(void); // Returns number ID of power source
|
||||
void renderHomeScreenAssets(void); // Called to act as start delay and used to render out flipped images for home screen graphics
|
||||
|
||||
extern bool heaterThermalRunaway;
|
||||
#endif
|
||||
|
||||
275
source/Core/Threads/OperatingModes/SettingsMenu.cpp
Normal file
275
source/Core/Threads/OperatingModes/SettingsMenu.cpp
Normal 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;
|
||||
}
|
||||
@@ -1,56 +1,95 @@
|
||||
#include "HUB238.hpp"
|
||||
#include "OperatingModes.h"
|
||||
void showWarnings(void) {
|
||||
OperatingMode showWarnings(const ButtonState buttons, guiContext *cxt) {
|
||||
// Display alert if settings were reset
|
||||
if (settingsWereReset) {
|
||||
warnUser(translatedString(Tr->SettingsResetMessage), 10 * TICKS_SECOND);
|
||||
}
|
||||
#ifdef DEVICE_HAS_VALIDATION_SUPPORT
|
||||
if (getDeviceValidationStatus()) {
|
||||
// Warn user this device might be counterfeit
|
||||
warnUser(translatedString(Tr->DeviceFailedValidationWarning), 10 * TICKS_SECOND);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_WARN_MISSING
|
||||
// We also want to alert if accel or pd is not detected / not responding
|
||||
// In this case though, we dont want to nag the user _too_ much
|
||||
// So only show first 2 times
|
||||
while (DetectedAccelerometerVersion == AccelType::Scanning) {
|
||||
osDelay(5);
|
||||
resetWatchdog();
|
||||
}
|
||||
// Display alert if accelerometer is not detected
|
||||
if (DetectedAccelerometerVersion == AccelType::None) {
|
||||
if (getSettingValue(SettingsOptions::AccelMissingWarningCounter) < 2) {
|
||||
nextSettingValue(SettingsOptions::AccelMissingWarningCounter);
|
||||
saveSettings();
|
||||
warnUser(translatedString(Tr->NoAccelerometerMessage), 10 * TICKS_SECOND);
|
||||
switch (cxt->scratch_state.state1) {
|
||||
case 0: // Settings reset warning
|
||||
if (settingsWereReset) {
|
||||
if (warnUser(translatedString(Tr->SettingsResetMessage), buttons)) {
|
||||
settingsWereReset = false;
|
||||
cxt->scratch_state.state1 = 1;
|
||||
}
|
||||
} 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
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
|
||||
#ifdef POW_PD
|
||||
// We expect pd to be present
|
||||
resetWatchdog();
|
||||
if (!USBPowerDelivery::fusbPresent()) {
|
||||
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
|
||||
nextSettingValue(SettingsOptions::PDMissingWarningCounter);
|
||||
saveSettings();
|
||||
warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND);
|
||||
// We expect pd to be present
|
||||
if (!USBPowerDelivery::fusbPresent()) {
|
||||
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif /*POW_PD*/
|
||||
#else
|
||||
#if POW_PD_EXT == 1
|
||||
if (!hub238_probe()) {
|
||||
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
|
||||
nextSettingValue(SettingsOptions::PDMissingWarningCounter);
|
||||
saveSettings();
|
||||
warnUser(translatedString(Tr->NoPowerDeliveryMessage), 10 * TICKS_SECOND);
|
||||
if (!hub238_probe()) {
|
||||
if (getSettingValue(SettingsOptions::PDMissingWarningCounter) < 2) {
|
||||
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*/
|
||||
// If tip looks to be shorted, yell at user and dont auto dismiss
|
||||
if (isTipShorted()) {
|
||||
warnUser(translatedString(Tr->WarningTipShorted), portMAX_DELAY);
|
||||
#endif /*POW_PD*/
|
||||
|
||||
break;
|
||||
default:
|
||||
// We are off the end, warnings done
|
||||
return OperatingMode::StartupLogo;
|
||||
}
|
||||
#endif /*NO_WARN_MISSING*/
|
||||
|
||||
return OperatingMode::StartupWarnings; // Stay in warnings
|
||||
}
|
||||
|
||||
@@ -1,64 +1,70 @@
|
||||
#include "OperatingModes.h"
|
||||
|
||||
extern OperatingMode currentMode;
|
||||
|
||||
int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) {
|
||||
#ifndef NO_SLEEP_MODE
|
||||
OperatingMode gui_SolderingSleepingMode(const ButtonState buttons, guiContext *cxt) {
|
||||
#ifdef NO_SLEEP_MODE
|
||||
return OperatingMode::Soldering;
|
||||
#endif
|
||||
// Drop to sleep temperature and display until movement or button press
|
||||
currentMode = OperatingMode::sleeping;
|
||||
|
||||
for (;;) {
|
||||
// user moved or pressed a button, go back to soldering
|
||||
// If in the first two seconds we disable this to let accelerometer warm up
|
||||
// user moved or pressed a button, go back to soldering
|
||||
// If in the first two seconds we disable this to let accelerometer warm up
|
||||
|
||||
#ifdef POW_DC
|
||||
if (checkForUnderVoltage()) {
|
||||
// return non-zero on error
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
currentTempTargetDegC = stayOff ? 0 : TipThermoModel::convertFtoC(min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp)));
|
||||
} else {
|
||||
currentTempTargetDegC = stayOff ? 0 : min(getSettingValue(SettingsOptions::SleepTemp), getSettingValue(SettingsOptions::SolderingTemp));
|
||||
}
|
||||
|
||||
// draw the lcd
|
||||
TemperatureType_t tipTemp = getTipTemp();
|
||||
|
||||
OLED::clearScreen();
|
||||
OLED::setCursor(0, 0);
|
||||
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
|
||||
OLED::print(translatedString(Tr->SleepingAdvancedString), FontStyle::SMALL);
|
||||
OLED::setCursor(0, 8);
|
||||
OLED::print(translatedString(Tr->SleepingTipAdvancedString), FontStyle::SMALL);
|
||||
OLED::printNumber(tipTemp, 3, FontStyle::SMALL);
|
||||
OLED::printSymbolDeg(FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
printVoltage();
|
||||
OLED::print(SmallSymbolVolts, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::print(translatedString(Tr->SleepingSimpleString), FontStyle::LARGE);
|
||||
OLED::printNumber(tipTemp, 3, FontStyle::LARGE);
|
||||
OLED::printSymbolDeg(FontStyle::EXTRAS);
|
||||
}
|
||||
|
||||
OLED::refresh();
|
||||
GUIDelay();
|
||||
|
||||
if (!shouldBeSleeping(autoStarted)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (shouldShutdown()) {
|
||||
// shutdown
|
||||
currentTempTargetDegC = 0;
|
||||
// we want to exit soldering mode
|
||||
return 1;
|
||||
}
|
||||
if (checkForUnderVoltage()) {
|
||||
return OperatingMode::HomeScreen; // return non-zero on error
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
if (cxt->scratch_state.state4) {
|
||||
return OperatingMode::Hibernating;
|
||||
} else {
|
||||
return OperatingMode::Sleeping;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,62 @@
|
||||
|
||||
#include "OperatingModes.h"
|
||||
#include "SolderingCommon.h"
|
||||
// State 1 = button locking
|
||||
// State 2 = boost mode
|
||||
// State 3 = buzzer timer
|
||||
|
||||
extern OperatingMode currentMode;
|
||||
|
||||
void gui_solderingMode(uint8_t jumpToSleep) {
|
||||
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:
|
||||
/*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) != 0) {
|
||||
// Lock buttons
|
||||
if (warnUser(translatedString(Tr->LockingKeysString), buttons)) {
|
||||
cxt->scratch_state.state1 = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return OperatingMode::Soldering;
|
||||
}
|
||||
OperatingMode gui_solderingMode(const ButtonState buttons, guiContext *cxt) {
|
||||
/*
|
||||
* * Soldering (gui_solderingMode)
|
||||
* -> Main loop where we draw temp, and animations
|
||||
@@ -19,98 +71,58 @@ void gui_solderingMode(uint8_t jumpToSleep) {
|
||||
* --> Double button to exit
|
||||
* --> Long hold double button to toggle key lock
|
||||
*/
|
||||
bool boostModeOn = false;
|
||||
bool buttonsLocked = false;
|
||||
bool converged = false;
|
||||
currentMode = OperatingMode::soldering;
|
||||
|
||||
TickType_t buzzerEnd = 0;
|
||||
|
||||
if (jumpToSleep) {
|
||||
if (gui_SolderingSleepingMode(jumpToSleep == 2, true) == 1) {
|
||||
lastButtonTime = xTaskGetTickCount();
|
||||
return; // If the function returns non-0 then exit
|
||||
// Update the setpoints for the temperature
|
||||
if (cxt->scratch_state.state2) {
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::BoostTemp));
|
||||
} else {
|
||||
currentTempTargetDegC = (getSettingValue(SettingsOptions::BoostTemp));
|
||||
}
|
||||
} else {
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
currentTempTargetDegC = TipThermoModel::convertFtoC(getSettingValue(SettingsOptions::SolderingTemp));
|
||||
} else {
|
||||
currentTempTargetDegC = (getSettingValue(SettingsOptions::SolderingTemp));
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
ButtonState buttons = getButtonState();
|
||||
if (buttonsLocked && (getSettingValue(SettingsOptions::LockingMode) != 0)) { // If buttons locked
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
boostModeOn = false;
|
||||
break;
|
||||
case BUTTON_BOTH_LONG:
|
||||
// Unlock buttons
|
||||
buttonsLocked = false;
|
||||
warnUser(translatedString(Tr->UnlockingKeysString), TICKS_SECOND);
|
||||
break;
|
||||
case BUTTON_F_LONG:
|
||||
// if boost mode is enabled turn it on
|
||||
if (getSettingValue(SettingsOptions::BoostTemp) && (getSettingValue(SettingsOptions::LockingMode) == 1)) {
|
||||
boostModeOn = true;
|
||||
currentMode = OperatingMode::boost;
|
||||
}
|
||||
break;
|
||||
// fall through
|
||||
case BUTTON_BOTH:
|
||||
case BUTTON_B_LONG:
|
||||
case BUTTON_F_SHORT:
|
||||
case BUTTON_B_SHORT:
|
||||
// Do nothing and display a lock warning
|
||||
warnUser(translatedString(Tr->WarningKeysLockedString), TICKS_SECOND / 2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else { // Button not locked
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
// stay
|
||||
boostModeOn = false;
|
||||
currentMode = OperatingMode::soldering;
|
||||
break;
|
||||
case BUTTON_BOTH:
|
||||
case BUTTON_B_LONG:
|
||||
return; // exit on back long hold
|
||||
case BUTTON_F_LONG:
|
||||
// if boost mode is enabled turn it on
|
||||
if (getSettingValue(SettingsOptions::BoostTemp)) {
|
||||
boostModeOn = true;
|
||||
currentMode = OperatingMode::boost;
|
||||
}
|
||||
break;
|
||||
case BUTTON_F_SHORT:
|
||||
case BUTTON_B_SHORT: {
|
||||
uint16_t oldTemp = getSettingValue(SettingsOptions::SolderingTemp);
|
||||
gui_solderingTempAdjust(); // goto adjust temp mode
|
||||
if (oldTemp != getSettingValue(SettingsOptions::SolderingTemp)) {
|
||||
saveSettings(); // only save on change
|
||||
}
|
||||
} break;
|
||||
case BUTTON_BOTH_LONG:
|
||||
if (getSettingValue(SettingsOptions::LockingMode) != 0) {
|
||||
// Lock buttons
|
||||
buttonsLocked = true;
|
||||
warnUser(translatedString(Tr->LockingKeysString), TICKS_SECOND);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Update status
|
||||
int error = currentTempTargetDegC - TipThermoModel::getTipInC();
|
||||
if (error >= -10 && error <= 10) {
|
||||
// converged
|
||||
if (!cxt->scratch_state.state5) {
|
||||
setBuzzer(true);
|
||||
cxt->scratch_state.state3 = xTaskGetTickCount() + TICKS_SECOND / 3;
|
||||
cxt->scratch_state.state5 = true;
|
||||
}
|
||||
// else we update the screen information
|
||||
setStatusLED(LED_HOT);
|
||||
} else {
|
||||
setStatusLED(LED_HEATING);
|
||||
cxt->scratch_state.state5 = false;
|
||||
}
|
||||
if (cxt->scratch_state.state3 != 0 && xTaskGetTickCount() >= cxt->scratch_state.state3) {
|
||||
setBuzzer(false);
|
||||
}
|
||||
|
||||
OLED::clearScreen();
|
||||
// Draw in the screen details
|
||||
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
|
||||
// Draw in the screen details
|
||||
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(50, 0);
|
||||
} else {
|
||||
OLED::setCursor(-1, 0);
|
||||
}
|
||||
|
||||
gui_drawTipTemp(true, FontStyle::LARGE);
|
||||
|
||||
if (cxt->scratch_state.state2) { // Boost mode is on
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(50, 0);
|
||||
OLED::setCursor(34, 0);
|
||||
} else {
|
||||
OLED::setCursor(-1, 0);
|
||||
OLED::setCursor(50, 0);
|
||||
}
|
||||
|
||||
gui_drawTipTemp(true, FontStyle::LARGE);
|
||||
|
||||
OLED::print(LargeSymbolPlus, FontStyle::LARGE);
|
||||
} else {
|
||||
#ifndef NO_SLEEP_MODE
|
||||
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
|
||||
if (OLED::getRotation()) {
|
||||
@@ -121,69 +133,43 @@ void gui_solderingMode(uint8_t jumpToSleep) {
|
||||
printCountdownUntilSleep(getSleepTimeout());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (boostModeOn) {
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(38, 8);
|
||||
} else {
|
||||
OLED::setCursor(55, 8);
|
||||
}
|
||||
OLED::print(SmallSymbolPlus, FontStyle::SMALL);
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(32, 8);
|
||||
} else {
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(32, 8);
|
||||
} else {
|
||||
OLED::setCursor(47, 8);
|
||||
}
|
||||
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2);
|
||||
OLED::setCursor(47, 8);
|
||||
}
|
||||
|
||||
detailedPowerStatus();
|
||||
|
||||
} else {
|
||||
basicSolderingStatus(boostModeOn);
|
||||
OLED::print(PowerSourceNames[getPowerSourceNumber()], FontStyle::SMALL, 2);
|
||||
}
|
||||
|
||||
OLED::refresh();
|
||||
// Update the setpoints for the temperature
|
||||
if (boostModeOn) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
detailedPowerStatus();
|
||||
|
||||
if (checkExitSoldering()) {
|
||||
setBuzzer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update status
|
||||
int error = currentTempTargetDegC - TipThermoModel::getTipInC();
|
||||
if (error >= -10 && error <= 10) {
|
||||
// converged
|
||||
if (!converged) {
|
||||
setBuzzer(true);
|
||||
buzzerEnd = xTaskGetTickCount() + TICKS_SECOND / 3;
|
||||
converged = true;
|
||||
}
|
||||
setStatusLED(LED_HOT);
|
||||
} else {
|
||||
setStatusLED(LED_HEATING);
|
||||
converged = false;
|
||||
}
|
||||
if (buzzerEnd != 0 && xTaskGetTickCount() >= buzzerEnd) {
|
||||
setBuzzer(false);
|
||||
}
|
||||
|
||||
// slow down ui update rate
|
||||
GUIDelay();
|
||||
} else {
|
||||
basicSolderingStatus(cxt->scratch_state.state2);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -2,222 +2,212 @@
|
||||
#include "OperatingModes.h"
|
||||
#include "SolderingCommon.h"
|
||||
|
||||
extern OperatingMode currentMode;
|
||||
|
||||
void gui_solderingProfileMode() {
|
||||
OperatingMode gui_solderingProfileMode(const ButtonState buttons, guiContext *cxt) {
|
||||
/*
|
||||
* * Soldering (gui_solderingMode)
|
||||
* * Soldering
|
||||
* -> Main loop where we draw temp, and animations
|
||||
* PID control
|
||||
* --> Long hold back button to exit
|
||||
* --> Double button to exit
|
||||
*/
|
||||
currentMode = OperatingMode::soldering;
|
||||
|
||||
TickType_t buzzerEnd = 0;
|
||||
uint16_t tipTemp = 0;
|
||||
|
||||
bool waitForRelease = true;
|
||||
TickType_t phaseStartTime = xTaskGetTickCount();
|
||||
|
||||
uint16_t tipTemp = 0;
|
||||
uint8_t profilePhase = 0;
|
||||
|
||||
uint16_t phaseElapsedSeconds = 0;
|
||||
uint16_t phaseTotalSeconds = 0;
|
||||
uint16_t phaseStartTemp = 0;
|
||||
uint16_t phaseEndTemp = getSettingValue(SettingsOptions::ProfilePreheatTemp);
|
||||
// If this is during init, start at preheat
|
||||
if (cxt->scratch_state.state1 == 0) {
|
||||
cxt->scratch_state.state5 = getSettingValue(SettingsOptions::ProfilePreheatTemp);
|
||||
}
|
||||
uint16_t phaseTicksPerDegree = TICKS_SECOND / getSettingValue(SettingsOptions::ProfilePreheatSpeed);
|
||||
uint16_t profileCurrentTargetTemp = 0;
|
||||
|
||||
for (;;) {
|
||||
ButtonState buttons = getButtonState();
|
||||
if (buttons) {
|
||||
if (waitForRelease) {
|
||||
buttons = BUTTON_NONE;
|
||||
}
|
||||
} else {
|
||||
waitForRelease = false;
|
||||
}
|
||||
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
break;
|
||||
case BUTTON_BOTH:
|
||||
case BUTTON_B_LONG:
|
||||
return; // exit on back long hold
|
||||
case BUTTON_F_LONG:
|
||||
case BUTTON_F_SHORT:
|
||||
case BUTTON_B_SHORT:
|
||||
// Not used yet
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tipTemp = getTipTemp();
|
||||
|
||||
// if start temp is unknown (preheat), we're setting it now
|
||||
if (phaseStartTemp == 0) {
|
||||
phaseStartTemp = tipTemp;
|
||||
// if this is hotter than the preheat temperature, we should fail
|
||||
if (phaseStartTemp >= 55) {
|
||||
warnUser(translatedString(Tr->TooHotToStartProfileWarning), 10 * TICKS_SECOND);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
// set up next phase
|
||||
switch (profilePhase) {
|
||||
case 1:
|
||||
phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase1Duration);
|
||||
phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase1Temp);
|
||||
break;
|
||||
case 2:
|
||||
phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase2Duration);
|
||||
phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase2Temp);
|
||||
break;
|
||||
case 3:
|
||||
phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase3Duration);
|
||||
phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase3Temp);
|
||||
break;
|
||||
case 4:
|
||||
phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase4Duration);
|
||||
phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase4Temp);
|
||||
break;
|
||||
case 5:
|
||||
phaseTotalSeconds = getSettingValue(SettingsOptions::ProfilePhase5Duration);
|
||||
phaseEndTemp = getSettingValue(SettingsOptions::ProfilePhase5Temp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (phaseStartTemp < phaseEndTemp) {
|
||||
phaseTicksPerDegree = (phaseTotalSeconds * TICKS_SECOND) / (phaseEndTemp - phaseStartTemp);
|
||||
} else {
|
||||
phaseTicksPerDegree = (phaseTotalSeconds * TICKS_SECOND) / (phaseStartTemp - phaseEndTemp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cooldown phase done?
|
||||
if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) {
|
||||
if (TipThermoModel::getTipInC() < 55) {
|
||||
// we're done, let the buzzer beep too
|
||||
setStatusLED(LED_STANDBY);
|
||||
if (buzzerEnd == 0) {
|
||||
setBuzzer(true);
|
||||
buzzerEnd = xTaskGetTickCount() + TICKS_SECOND / 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// determine current target temp
|
||||
if (phaseStartTemp < phaseEndTemp) {
|
||||
if (profileCurrentTargetTemp < phaseEndTemp) {
|
||||
profileCurrentTargetTemp = phaseStartTemp + ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree);
|
||||
}
|
||||
} else {
|
||||
if (profileCurrentTargetTemp > phaseEndTemp) {
|
||||
profileCurrentTargetTemp = phaseStartTemp - ((xTaskGetTickCount() - phaseStartTime) / phaseTicksPerDegree);
|
||||
}
|
||||
}
|
||||
|
||||
OLED::clearScreen();
|
||||
// Draw in the screen details
|
||||
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
|
||||
// print temperature
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(48, 0);
|
||||
} else {
|
||||
OLED::setCursor(0, 0);
|
||||
}
|
||||
|
||||
OLED::printNumber(tipTemp, 3, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSlash, FontStyle::SMALL);
|
||||
OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL);
|
||||
OLED::printSymbolDeg(FontStyle::SMALL);
|
||||
|
||||
// print phase
|
||||
if (profilePhase > 0 && profilePhase <= getSettingValue(SettingsOptions::ProfilePhases)) {
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(36, 0);
|
||||
} else {
|
||||
OLED::setCursor(55, 0);
|
||||
}
|
||||
OLED::printNumber(profilePhase, 1, FontStyle::SMALL);
|
||||
}
|
||||
|
||||
// print time progress / preheat / cooldown
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(42, 8);
|
||||
} else {
|
||||
OLED::setCursor(0, 8);
|
||||
}
|
||||
|
||||
if (profilePhase == 0) {
|
||||
OLED::print(translatedString(Tr->ProfilePreheatString), FontStyle::SMALL);
|
||||
} else if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) {
|
||||
OLED::print(translatedString(Tr->ProfileCooldownString), FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::printNumber(phaseElapsedSeconds / 60, 1, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolColon, FontStyle::SMALL);
|
||||
OLED::printNumber(phaseElapsedSeconds % 60, 2, FontStyle::SMALL, false);
|
||||
|
||||
OLED::print(SmallSymbolSlash, FontStyle::SMALL);
|
||||
|
||||
// blink if we can't keep up with the time goal
|
||||
if (phaseElapsedSeconds < phaseTotalSeconds + 2 || (xTaskGetTickCount() / TICKS_SECOND) % 2 == 0) {
|
||||
OLED::printNumber(phaseTotalSeconds / 60, 1, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolColon, FontStyle::SMALL);
|
||||
OLED::printNumber(phaseTotalSeconds % 60, 2, FontStyle::SMALL, false);
|
||||
}
|
||||
}
|
||||
|
||||
detailedPowerStatus();
|
||||
|
||||
} else {
|
||||
basicSolderingStatus(false);
|
||||
}
|
||||
|
||||
OLED::refresh();
|
||||
// Update the setpoints for the temperature
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
currentTempTargetDegC = TipThermoModel::convertFtoC(profileCurrentTargetTemp);
|
||||
} else {
|
||||
currentTempTargetDegC = profileCurrentTargetTemp;
|
||||
}
|
||||
|
||||
if (checkExitSoldering() || (buzzerEnd != 0 && xTaskGetTickCount() >= buzzerEnd)) {
|
||||
setBuzzer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update LED status
|
||||
if (profilePhase == 0) {
|
||||
setStatusLED(LED_HEATING);
|
||||
} else if (profilePhase > getSettingValue(SettingsOptions::ProfilePhases)) {
|
||||
setStatusLED(LED_COOLING_STILL_HOT);
|
||||
} else {
|
||||
setStatusLED(LED_HOT);
|
||||
}
|
||||
|
||||
// slow down ui update rate
|
||||
GUIDelay();
|
||||
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 >= 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 {
|
||||
// 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) {
|
||||
if (profileCurrentTargetTemp < cxt->scratch_state.state5) {
|
||||
profileCurrentTargetTemp = cxt->scratch_state.state6 + ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree);
|
||||
}
|
||||
} else {
|
||||
if (profileCurrentTargetTemp > cxt->scratch_state.state5) {
|
||||
profileCurrentTargetTemp = cxt->scratch_state.state6 - ((xTaskGetTickCount() - cxt->viewEnterTime) / phaseTicksPerDegree);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw in the screen details
|
||||
if (getSettingValue(SettingsOptions::DetailedSoldering)) {
|
||||
// print temperature
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(48, 0);
|
||||
} else {
|
||||
OLED::setCursor(0, 0);
|
||||
}
|
||||
|
||||
OLED::printNumber(tipTemp, 3, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSlash, FontStyle::SMALL);
|
||||
OLED::printNumber(profileCurrentTargetTemp, 3, FontStyle::SMALL);
|
||||
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
OLED::print(SmallSymbolDegF, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::print(SmallSymbolDegC, FontStyle::SMALL);
|
||||
}
|
||||
|
||||
// print phase
|
||||
if (cxt->scratch_state.state1 > 0 && cxt->scratch_state.state1 <= getSettingValue(SettingsOptions::ProfilePhases)) {
|
||||
if (OLED::getRotation()) {
|
||||
OLED::setCursor(36, 0);
|
||||
} else {
|
||||
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::print(SmallSymbolSlash, FontStyle::SMALL);
|
||||
|
||||
// blink if we can't keep up with the time goal
|
||||
if (phaseElapsedSeconds < cxt->scratch_state.state2 + 2 || (xTaskGetTickCount() / TICKS_SECOND) % 2 == 0) {
|
||||
OLED::printNumber(cxt->scratch_state.state2 / 60, 1, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolColon, FontStyle::SMALL);
|
||||
OLED::printNumber(cxt->scratch_state.state2 % 60, 2, FontStyle::SMALL, false);
|
||||
}
|
||||
}
|
||||
|
||||
detailedPowerStatus();
|
||||
|
||||
} else {
|
||||
basicSolderingStatus(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;
|
||||
}
|
||||
|
||||
@@ -1,120 +1,106 @@
|
||||
#include "OperatingModes.h"
|
||||
void gui_solderingTempAdjust(void) {
|
||||
TickType_t lastChange = xTaskGetTickCount();
|
||||
currentTempTargetDegC = 0; // Turn off heater while adjusting temp
|
||||
TickType_t autoRepeatTimer = 0;
|
||||
uint8_t autoRepeatAcceleration = 0;
|
||||
#ifndef PROFILE_SUPPORT
|
||||
bool waitForRelease = false;
|
||||
ButtonState buttons = getButtonState();
|
||||
OperatingMode gui_solderingTempAdjust(const ButtonState buttonIn, guiContext *cxt) {
|
||||
|
||||
if (buttons != BUTTON_NONE) {
|
||||
// Temp adjust entered by long-pressing F button.
|
||||
waitForRelease = true;
|
||||
currentTempTargetDegC = 0; // Turn off heater while adjusting temp
|
||||
uint16_t *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)++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ButtonState buttons;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
OLED::setCursor(0, 0);
|
||||
OLED::clearScreen();
|
||||
buttons = getButtonState();
|
||||
if (buttons) {
|
||||
lastChange = xTaskGetTickCount();
|
||||
#ifndef PROFILE_SUPPORT
|
||||
if (waitForRelease) {
|
||||
buttons = BUTTON_NONE;
|
||||
}
|
||||
} else {
|
||||
waitForRelease = false;
|
||||
#endif
|
||||
}
|
||||
int16_t delta = 0;
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
// stay
|
||||
autoRepeatAcceleration = 0;
|
||||
break;
|
||||
case BUTTON_BOTH:
|
||||
// exit
|
||||
return;
|
||||
break;
|
||||
case BUTTON_B_LONG:
|
||||
if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) {
|
||||
delta = -getSettingValue(SettingsOptions::TempChangeLongStep);
|
||||
autoRepeatTimer = xTaskGetTickCount();
|
||||
autoRepeatAcceleration += PRESS_ACCEL_STEP;
|
||||
}
|
||||
break;
|
||||
case BUTTON_B_SHORT:
|
||||
delta = -getSettingValue(SettingsOptions::TempChangeShortStep);
|
||||
break;
|
||||
case BUTTON_F_LONG:
|
||||
if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) {
|
||||
delta = getSettingValue(SettingsOptions::TempChangeLongStep);
|
||||
autoRepeatTimer = xTaskGetTickCount();
|
||||
autoRepeatAcceleration += PRESS_ACCEL_STEP;
|
||||
}
|
||||
break;
|
||||
case BUTTON_F_SHORT:
|
||||
delta = getSettingValue(SettingsOptions::TempChangeShortStep);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((PRESS_ACCEL_INTERVAL_MAX - autoRepeatAcceleration) < PRESS_ACCEL_INTERVAL_MIN) {
|
||||
autoRepeatAcceleration = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN;
|
||||
}
|
||||
// If buttons are flipped; flip the delta
|
||||
if (getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled)) {
|
||||
delta = -delta;
|
||||
}
|
||||
if (delta != 0) {
|
||||
// constrain between the set temp limits, i.e. 10-450 C
|
||||
int16_t newTemp = getSettingValue(SettingsOptions::SolderingTemp);
|
||||
newTemp += delta;
|
||||
// Round to nearest increment of delta
|
||||
delta = abs(delta);
|
||||
newTemp = (newTemp / delta) * delta;
|
||||
OLED::setCursor(0, 0);
|
||||
|
||||
if (getSettingValue(SettingsOptions::TemperatureInF)) {
|
||||
if (newTemp > MAX_TEMP_F) {
|
||||
newTemp = MAX_TEMP_F;
|
||||
}
|
||||
if (newTemp < MIN_TEMP_F) {
|
||||
newTemp = MIN_TEMP_F;
|
||||
}
|
||||
} else {
|
||||
if (newTemp > MAX_TEMP_C) {
|
||||
newTemp = MAX_TEMP_C;
|
||||
}
|
||||
if (newTemp < MIN_TEMP_C) {
|
||||
newTemp = MIN_TEMP_C;
|
||||
}
|
||||
}
|
||||
setSettingValue(SettingsOptions::SolderingTemp, (uint16_t)newTemp);
|
||||
int16_t delta = 0;
|
||||
switch (buttons) {
|
||||
case BUTTON_NONE:
|
||||
// stay
|
||||
(*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;
|
||||
}
|
||||
if (xTaskGetTickCount() - lastChange > (TICKS_SECOND * 2)) {
|
||||
return; // exit if user just doesn't press anything for a bit
|
||||
break;
|
||||
case BUTTON_B_SHORT:
|
||||
delta = -getSettingValue(SettingsOptions::TempChangeShortStep);
|
||||
break;
|
||||
case BUTTON_F_LONG:
|
||||
if (xTaskGetTickCount() - (*autoRepeatTimer) + (*autoRepeatAcceleration) > PRESS_ACCEL_INTERVAL_MAX) {
|
||||
delta = getSettingValue(SettingsOptions::TempChangeLongStep);
|
||||
(*autoRepeatTimer) = xTaskGetTickCount();
|
||||
(*autoRepeatAcceleration) += PRESS_ACCEL_STEP;
|
||||
}
|
||||
|
||||
if (OLED::getRotation()) {
|
||||
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE);
|
||||
} else {
|
||||
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE);
|
||||
}
|
||||
|
||||
OLED::print(LargeSymbolSpace, FontStyle::LARGE);
|
||||
OLED::printNumber(getSettingValue(SettingsOptions::SolderingTemp), 3, FontStyle::LARGE);
|
||||
OLED::printSymbolDeg(FontStyle::EXTRAS);
|
||||
OLED::print(LargeSymbolSpace, FontStyle::LARGE);
|
||||
if (OLED::getRotation()) {
|
||||
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolMinus : LargeSymbolPlus, FontStyle::LARGE);
|
||||
} else {
|
||||
OLED::print(getSettingValue(SettingsOptions::ReverseButtonTempChangeEnabled) ? LargeSymbolPlus : LargeSymbolMinus, FontStyle::LARGE);
|
||||
}
|
||||
OLED::refresh();
|
||||
GUIDelay();
|
||||
break;
|
||||
case BUTTON_F_SHORT:
|
||||
delta = getSettingValue(SettingsOptions::TempChangeShortStep);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((PRESS_ACCEL_INTERVAL_MAX - (*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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2,93 +2,85 @@
|
||||
|
||||
#ifdef POW_PD
|
||||
#ifdef HAS_POWER_DEBUG_MENU
|
||||
void showPDDebug(void) {
|
||||
OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) {
|
||||
// Print out the USB-PD state
|
||||
// Basically this is like the Debug menu, but instead we want to print out the PD status
|
||||
uint8_t screen = 0;
|
||||
ButtonState b;
|
||||
for (;;) {
|
||||
OLED::clearScreen(); // Ensure the buffer starts clean
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title
|
||||
OLED::setCursor(0, 8); // second line
|
||||
if (screen == 0) {
|
||||
// Print the PD state machine
|
||||
OLED::print(SmallSymbolState, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
// Also print vbus mod status
|
||||
if (USBPowerDelivery::fusbPresent()) {
|
||||
if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) {
|
||||
if (!USBPowerDelivery::isVBUSConnected()) {
|
||||
OLED::print(SmallSymbolNoVBus, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::print(SmallSymbolVBus, FontStyle::SMALL);
|
||||
}
|
||||
uint16_t *screen = &(cxt->scratch_state.state1);
|
||||
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
||||
OLED::print(SmallSymbolPDDebug, FontStyle::SMALL); // Print Title
|
||||
OLED::setCursor(0, 8); // second line
|
||||
if ((*screen) == 0) {
|
||||
// Print the PD state machine
|
||||
OLED::print(SmallSymbolState, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
OLED::printNumber(USBPowerDelivery::getStateNumber(), 2, FontStyle::SMALL, true);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
// Also print vbus mod status
|
||||
if (USBPowerDelivery::fusbPresent()) {
|
||||
if (USBPowerDelivery::negotiationComplete() || (xTaskGetTickCount() > (TICKS_SECOND * 10))) {
|
||||
if (!USBPowerDelivery::isVBUSConnected()) {
|
||||
OLED::print(SmallSymbolNoVBus, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::print(SmallSymbolVBus, FontStyle::SMALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Print out the Proposed power options one by one
|
||||
auto lastCaps = USBPowerDelivery::getLastSeenCapabilities();
|
||||
if (((*screen) - 1) < 11) {
|
||||
int voltage_mv = 0;
|
||||
int min_voltage = 0;
|
||||
int current_a_x100 = 0;
|
||||
int wattage = 0;
|
||||
|
||||
if ((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(lastCaps[(*screen) - 1])); // voltage in mV units
|
||||
current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(lastCaps[(*screen) - 1]); // current in 10mA units
|
||||
} else if (((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[(*screen) - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_AVS)) {
|
||||
voltage_mv = PD_PAV2MV(PD_APDO_AVS_MAX_VOLTAGE_GET(lastCaps[(*screen) - 1]));
|
||||
min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[(*screen) - 1]));
|
||||
// Last value is wattage
|
||||
wattage = PD_APDO_AVS_MAX_POWER_GET(lastCaps[(*screen) - 1]);
|
||||
} else if (((lastCaps[(*screen) - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[(*screen) - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS)) {
|
||||
voltage_mv = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(lastCaps[(*screen) - 1]));
|
||||
min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[(*screen) - 1]));
|
||||
current_a_x100 = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(lastCaps[(*screen) - 1])); // max current in 10mA units
|
||||
}
|
||||
// Skip not used entries
|
||||
if (voltage_mv == 0) {
|
||||
(*screen) += 1;
|
||||
} else {
|
||||
// print out this entry of the proposal
|
||||
OLED::printNumber(*screen, 2, FontStyle::SMALL, true); // print the entry number
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
if (min_voltage > 0) {
|
||||
OLED::printNumber(min_voltage / 1000, 2, FontStyle::SMALL, true); // print the voltage
|
||||
OLED::print(SmallSymbolMinus, FontStyle::SMALL);
|
||||
}
|
||||
OLED::printNumber(voltage_mv / 1000, 2, FontStyle::SMALL, true); // print the voltage
|
||||
OLED::print(SmallSymbolVolts, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
if (wattage) {
|
||||
OLED::printNumber(wattage, 3, FontStyle::SMALL, true); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolWatts, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::printNumber(current_a_x100 / 100, 2, FontStyle::SMALL, true); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(current_a_x100 % 100, 2, FontStyle::SMALL, false); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolAmps, FontStyle::SMALL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Print out the Proposed power options one by one
|
||||
auto lastCaps = USBPowerDelivery::getLastSeenCapabilities();
|
||||
if ((screen - 1) < 11) {
|
||||
int voltage_mv = 0;
|
||||
int min_voltage = 0;
|
||||
int current_a_x100 = 0;
|
||||
int wattage = 0;
|
||||
|
||||
if ((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
|
||||
voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(lastCaps[screen - 1])); // voltage in mV units
|
||||
current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(lastCaps[screen - 1]); // current in 10mA units
|
||||
} else if (((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[screen - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_AVS)) {
|
||||
voltage_mv = PD_PAV2MV(PD_APDO_AVS_MAX_VOLTAGE_GET(lastCaps[screen - 1]));
|
||||
min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[screen - 1]));
|
||||
// Last value is wattage
|
||||
wattage = PD_APDO_AVS_MAX_POWER_GET(lastCaps[screen - 1]);
|
||||
} else if (((lastCaps[screen - 1] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED) && ((lastCaps[screen - 1] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS)) {
|
||||
voltage_mv = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(lastCaps[screen - 1]));
|
||||
min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(lastCaps[screen - 1]));
|
||||
current_a_x100 = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(lastCaps[screen - 1])); // max current in 10mA units
|
||||
}
|
||||
// Skip not used entries
|
||||
if (voltage_mv == 0) {
|
||||
screen++;
|
||||
} else {
|
||||
// print out this entry of the proposal
|
||||
OLED::printNumber(screen, 2, FontStyle::SMALL, true); // print the entry number
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
if (min_voltage > 0) {
|
||||
OLED::printNumber(min_voltage / 1000, 2, FontStyle::SMALL, true); // print the voltage
|
||||
OLED::print(SmallSymbolMinus, FontStyle::SMALL);
|
||||
}
|
||||
OLED::printNumber(voltage_mv / 1000, 2, FontStyle::SMALL, true); // print the voltage
|
||||
OLED::print(SmallSymbolVolts, FontStyle::SMALL);
|
||||
OLED::print(SmallSymbolSpace, FontStyle::SMALL);
|
||||
if (wattage) {
|
||||
OLED::printNumber(wattage, 3, FontStyle::SMALL, true); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolWatts, FontStyle::SMALL);
|
||||
} else {
|
||||
OLED::printNumber(current_a_x100 / 100, 2, FontStyle::SMALL, true); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolDot, FontStyle::SMALL);
|
||||
OLED::printNumber(current_a_x100 % 100, 2, FontStyle::SMALL, false); // print the current in 0.1A res
|
||||
OLED::print(SmallSymbolAmps, FontStyle::SMALL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
screen = 0;
|
||||
}
|
||||
(*screen) = 0;
|
||||
}
|
||||
|
||||
OLED::refresh();
|
||||
b = getButtonState();
|
||||
if (b == BUTTON_B_SHORT) {
|
||||
return;
|
||||
} else if (b == BUTTON_F_SHORT) {
|
||||
screen++;
|
||||
}
|
||||
|
||||
GUIDelay();
|
||||
}
|
||||
if (buttons == BUTTON_B_SHORT) {
|
||||
return OperatingMode::InitialisationDone;
|
||||
} else if (buttons == BUTTON_F_SHORT) {
|
||||
(*screen) += 1;
|
||||
}
|
||||
return OperatingMode::UsbPDDebug;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "OperatingModes.h"
|
||||
#if POW_PD_EXT == 1
|
||||
#ifdef HAS_POWER_DEBUG_MENU
|
||||
void showPDDebug(void) {
|
||||
OperatingMode showPDDebug(const ButtonState buttons, guiContext *cxt) {
|
||||
// Print out the USB-PD state
|
||||
// Basically this is like the Debug menu, but instead we want to print out the PD status
|
||||
uint8_t screen = 0;
|
||||
@@ -44,13 +44,14 @@ void showPDDebug(void) {
|
||||
OLED::refresh();
|
||||
b = getButtonState();
|
||||
if (b == BUTTON_B_SHORT) {
|
||||
return;
|
||||
return OperatingMode::InitialisationDone;
|
||||
} else if (b == BUTTON_F_SHORT) {
|
||||
screen++;
|
||||
}
|
||||
|
||||
GUIDelay();
|
||||
}
|
||||
return OperatingMode::UsbPDDebug;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "OperatingModeUtilities.h"
|
||||
#include "OperatingModes.h"
|
||||
#include "SolderingCommon.h"
|
||||
#include "TipThermoModel.h"
|
||||
|
||||
void gui_drawTipTemp(bool symbol, const FontStyle font) {
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
#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 inAutoStart); //
|
||||
bool shouldShutdown(void); //
|
||||
void gui_drawTipTemp(bool symbol, const FontStyle font); //
|
||||
void printVoltage(void); //
|
||||
void warnUser(const char *warning, const TickType_t timeout); //
|
||||
void gui_drawBatteryIcon(void); //
|
||||
bool checkForUnderVoltage(void); //
|
||||
uint16_t min(uint16_t a, uint16_t b); //
|
||||
void printCountdownUntilSleep(int sleepThres); //
|
||||
void GUIDelay(); //
|
||||
bool checkForUnderVoltage(void); //
|
||||
uint32_t getSleepTimeout(void); //
|
||||
bool shouldBeSleeping(); //
|
||||
bool shouldShutdown(void); //
|
||||
void gui_drawTipTemp(bool symbol, const FontStyle font); //
|
||||
void printVoltage(void); //
|
||||
bool warnUser(const char *warning, const ButtonState buttons); //
|
||||
void gui_drawBatteryIcon(void); //
|
||||
bool checkForUnderVoltage(void); //
|
||||
uint16_t min(uint16_t a, uint16_t b); //
|
||||
void printCountdownUntilSleep(int sleepThres); //
|
||||
#endif
|
||||
@@ -1,8 +1,12 @@
|
||||
#include "Buttons.hpp"
|
||||
#include "OperatingModeUtilities.h"
|
||||
void warnUser(const char *warning, const TickType_t timeout) {
|
||||
#include "OperatingModes.h"
|
||||
bool warnUser(const char *warning, const ButtonState buttons) {
|
||||
OLED::clearScreen();
|
||||
OLED::printWholeScreen(warning);
|
||||
OLED::refresh();
|
||||
waitForButtonPressOrTimeout(timeout);
|
||||
// Also timeout after 5 seconds
|
||||
if ((xTaskGetTickCount() - lastButtonTime) > TICKS_SECOND * 5) {
|
||||
return true;
|
||||
}
|
||||
return buttons != BUTTON_NONE;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "SolderingCommon.h"
|
||||
#include "OperatingModes.h"
|
||||
#include "Types.h"
|
||||
#include "configuration.h"
|
||||
#include "history.hpp"
|
||||
|
||||
@@ -106,30 +107,8 @@ bool checkExitSoldering(void) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef NO_SLEEP_MODE
|
||||
// No sleep mode, but still want shutdown timeout
|
||||
|
||||
if (shouldShutdown()) {
|
||||
// shutdown
|
||||
currentTempTargetDegC = 0;
|
||||
lastMovementTime = xTaskGetTickCount(); // We manually move the movement time to now such that shutdown timer is reset
|
||||
|
||||
return true; // we want to exit soldering mode
|
||||
}
|
||||
#endif
|
||||
if (shouldBeSleeping(false)) {
|
||||
if (gui_SolderingSleepingMode(false, false)) {
|
||||
return true; // If the function returns non-0 then exit
|
||||
}
|
||||
}
|
||||
|
||||
// If we have tripped thermal runaway, turn off heater and show warning
|
||||
if (heaterThermalRunaway) {
|
||||
currentTempTargetDegC = 0; // heater control off
|
||||
warnUser(translatedString(Tr->WarningThermalRunaway), 10 * TICKS_SECOND);
|
||||
heaterThermalRunaway = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#ifndef SOLDERING_COMMON_H
|
||||
#define SOLDERING_COMMON_H
|
||||
#include "Types.h"
|
||||
#include <stdint.h>
|
||||
#ifndef SOLDERING_COMMON_H_
|
||||
#define SOLDERING_COMMON_H_
|
||||
|
||||
void detailedPowerStatus();
|
||||
void basicSolderingStatus(bool boostModeOn);
|
||||
bool checkExitSoldering();
|
||||
void detailedPowerStatus();
|
||||
void basicSolderingStatus(bool boostModeOn);
|
||||
bool checkExitSoldering();
|
||||
TemperatureType_t getTipTemp(void);
|
||||
|
||||
#endif //SOLDERING_COMMON_H
|
||||
#endif // SOLDERING_COMMON_H_
|
||||
|
||||
@@ -17,4 +17,4 @@ void printCountdownUntilSleep(int sleepThres) {
|
||||
OLED::print(SmallSymbolSeconds, FontStyle::SMALL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
TickType_t lastHallEffectSleepStart = 0;
|
||||
extern TickType_t lastMovementTime;
|
||||
|
||||
bool shouldBeSleeping(bool inAutoStart) {
|
||||
bool shouldBeSleeping() {
|
||||
#ifndef NO_SLEEP_MODE
|
||||
// Return true if the iron should be in sleep mode
|
||||
if (getSettingValue(SettingsOptions::Sensitivity) && getSettingValue(SettingsOptions::SleepTime)) {
|
||||
if (inAutoStart) {
|
||||
// In auto start we are asleep until movement
|
||||
if (lastMovementTime == 0 && lastButtonTime == 0) {
|
||||
return true;
|
||||
}
|
||||
// In auto start we are asleep until movement
|
||||
if (lastMovementTime == 0 && lastButtonTime == 0) {
|
||||
return true;
|
||||
}
|
||||
if (lastMovementTime > 0 || lastButtonTime > 0) {
|
||||
if (((xTaskGetTickCount() - lastMovementTime) > getSleepTimeout()) && ((xTaskGetTickCount() - lastButtonTime) > getSleepTimeout())) {
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#include "power.hpp"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef POW_PD
|
||||
#if POW_PD == 1
|
||||
#include "USBPD.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static TickType_t powerPulseWaitUnit = 25 * TICKS_100MS; // 2.5 s
|
||||
static TickType_t powerPulseDurationUnit = (5 * TICKS_100MS) / 2; // 250 ms
|
||||
TaskHandle_t pidTaskNotification = NULL;
|
||||
@@ -38,7 +44,9 @@ void startPIDTask(void const *argument __unused) {
|
||||
|
||||
currentTempTargetDegC = 0; // Force start with no output (off). If in sleep / soldering this will
|
||||
// be over-ridden rapidly
|
||||
pidTaskNotification = xTaskGetCurrentTaskHandle();
|
||||
|
||||
pidTaskNotification = xTaskGetCurrentTaskHandle();
|
||||
|
||||
TemperatureType_t PIDTempTarget = 0;
|
||||
// Pre-seed the adc filters
|
||||
for (int i = 0; i < 32; i++) {
|
||||
@@ -51,6 +59,17 @@ void startPIDTask(void const *argument __unused) {
|
||||
resetWatchdog();
|
||||
ulTaskNotifyTake(pdTRUE, 2000);
|
||||
}
|
||||
// Wait for PD if its in the middle of negotiation
|
||||
#ifdef POW_PD
|
||||
#if POW_PD == 1
|
||||
// This is an FUSB based PD capable device
|
||||
// Wait up to 3 seconds for USB-PD to settle
|
||||
while (USBPowerDelivery::negotiationInProgress() && xTaskGetTickCount() < (TICKS_SECOND * 3)) {
|
||||
resetWatchdog();
|
||||
ulTaskNotifyTake(pdTRUE, TICKS_100MS);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int32_t x10WattsOut = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user