This generates dedicates Translation.cpp files for translation language and derives all language-specific data from them. The Makefile is extended to also take care of generating these source files. This allows reuse of nearly all object files between builds of different languages for the same model and regenerating the translation sources if necessary. This speeds up the release builds and the normal write-compile-cycle considerably. It also eliminates miscompilations when manually building different languages.
941 lines
28 KiB
C++
941 lines
28 KiB
C++
/*
|
|
* GUIThread.cpp
|
|
*
|
|
* Created on: 19 Aug 2019
|
|
* Author: ralim
|
|
*/
|
|
extern "C" {
|
|
#include "FreeRTOSConfig.h"
|
|
}
|
|
#include "../../configuration.h"
|
|
#include "Buttons.hpp"
|
|
#include "I2CBB.hpp"
|
|
#include "LIS2DH12.hpp"
|
|
#include "Settings.h"
|
|
#include "TipThermoModel.h"
|
|
#include "Translation.h"
|
|
#include "cmsis_os.h"
|
|
#include "main.hpp"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include <MMA8652FC.hpp>
|
|
#include <gui.hpp>
|
|
#include <history.hpp>
|
|
#include <power.hpp>
|
|
#ifdef POW_PD
|
|
#include "policy_engine.h"
|
|
#endif
|
|
// File local variables
|
|
extern uint32_t currentTempTargetDegC;
|
|
extern TickType_t lastMovementTime;
|
|
extern osThreadId GUITaskHandle;
|
|
extern osThreadId MOVTaskHandle;
|
|
extern osThreadId PIDTaskHandle;
|
|
static bool shouldBeSleeping(bool inAutoStart = false);
|
|
static bool shouldShutdown();
|
|
void showWarnings();
|
|
#define MOVEMENT_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
|
#define BUTTON_INACTIVITY_TIME (60 * configTICK_RATE_HZ)
|
|
static TickType_t lastHallEffectSleepStart = 0;
|
|
static uint16_t min(uint16_t a, uint16_t b) {
|
|
if (a > b)
|
|
return b;
|
|
else
|
|
return a;
|
|
}
|
|
void warnUser(const char *warning, const int font, const int timeout) {
|
|
OLED::setFont(font);
|
|
OLED::clearScreen();
|
|
OLED::setCursor(0, 0);
|
|
OLED::print(warning);
|
|
OLED::refresh();
|
|
waitForButtonPressOrTimeout(timeout);
|
|
}
|
|
|
|
void printVoltage() {
|
|
uint32_t volt = getInputVoltageX10(systemSettings.voltageDiv, 0);
|
|
OLED::printNumber(volt / 10, 2);
|
|
OLED::print(SymbolDot);
|
|
OLED::printNumber(volt % 10, 1);
|
|
}
|
|
void GUIDelay() {
|
|
// Called in all UI looping tasks,
|
|
// This limits the re-draw rate to the LCD and also lets the DMA run
|
|
// As the gui task can very easily fill this bus with transactions, which will
|
|
// prevent the movement detection from running
|
|
osDelay(50);
|
|
}
|
|
void gui_drawTipTemp(bool symbol) {
|
|
// Draw tip temp handling unit conversion & tolerance near setpoint
|
|
uint32_t Temp = 0;
|
|
if (systemSettings.temperatureInF) {
|
|
Temp = TipThermoModel::getTipInF();
|
|
} else
|
|
{
|
|
Temp = TipThermoModel::getTipInC();
|
|
}
|
|
|
|
OLED::printNumber(Temp, 3); // Draw the tip temp out
|
|
if (symbol) {
|
|
if (OLED::getFont() == 0) {
|
|
// Big font, can draw nice symbols
|
|
if (systemSettings.temperatureInF)
|
|
OLED::drawSymbol(0);
|
|
else
|
|
OLED::drawSymbol(1);
|
|
} else {
|
|
// Otherwise fall back to chars
|
|
if (systemSettings.temperatureInF)
|
|
OLED::print(SymbolDegF);
|
|
else
|
|
OLED::print(SymbolDegC);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef POW_DC
|
|
// returns true if undervoltage has occured
|
|
static bool checkVoltageForExit() {
|
|
if (!getIsPoweredByDCIN()) {
|
|
return false;
|
|
}
|
|
uint16_t v = getInputVoltageX10(systemSettings.voltageDiv, 0);
|
|
|
|
// Dont check for first 2 seconds while the ADC stabilizes and the DMA fills
|
|
// the buffer
|
|
if (xTaskGetTickCount() > (TICKS_SECOND * 2)) {
|
|
if ((v < lookupVoltageLevel())) {
|
|
currentTempTargetDegC = 0;
|
|
OLED::clearScreen();
|
|
OLED::setCursor(0, 0);
|
|
if (systemSettings.detailedSoldering) {
|
|
OLED::setFont(1);
|
|
OLED::print(UndervoltageString);
|
|
OLED::setCursor(0, 8);
|
|
OLED::print(InputVoltageString);
|
|
printVoltage();
|
|
OLED::print(SymbolVolts);
|
|
} else {
|
|
OLED::setFont(0);
|
|
OLED::print(UVLOWarningString);
|
|
}
|
|
|
|
OLED::refresh();
|
|
GUIDelay();
|
|
waitForButtonPress();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
static void gui_drawBatteryIcon() {
|
|
#if defined(POW_PD) || defined(POW_QC)
|
|
if (!getIsPoweredByDCIN()) {
|
|
// On TS80 we replace this symbol with the voltage we are operating on
|
|
// If <9V then show single digit, if not show dual small ones vertically stacked
|
|
uint8_t V = getInputVoltageX10(systemSettings.voltageDiv, 0);
|
|
if (V % 10 >= 5)
|
|
V = V / 10 + 1; // round up
|
|
else
|
|
V = V / 10;
|
|
if (V >= 10) {
|
|
int16_t xPos = OLED::getCursorX();
|
|
OLED::setFont(1);
|
|
OLED::printNumber(V / 10, 1);
|
|
OLED::setCursor(xPos, 8);
|
|
OLED::printNumber(V % 10, 1);
|
|
OLED::setFont(0);
|
|
OLED::setCursor(xPos + 12, 0); // need to reset this as if we drew a wide char
|
|
} else {
|
|
OLED::printNumber(V, 1);
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef POW_DC
|
|
if (systemSettings.minDCVoltageCells) {
|
|
// User is on a lithium battery
|
|
// we need to calculate which of the 10 levels they are on
|
|
uint8_t cellCount = systemSettings.minDCVoltageCells + 2;
|
|
uint32_t cellV = getInputVoltageX10(systemSettings.voltageDiv, 0) / cellCount;
|
|
// Should give us approx cell voltage X10
|
|
// Range is 42 -> 33 = 9 steps therefore we will use battery 0-9
|
|
if (cellV < 33)
|
|
cellV = 33;
|
|
cellV -= 33; // Should leave us a number of 0-9
|
|
if (cellV > 9)
|
|
cellV = 9;
|
|
OLED::drawBattery(cellV + 1);
|
|
} else {
|
|
OLED::drawSymbol(15); // Draw the DC Logo
|
|
}
|
|
#endif
|
|
}
|
|
static void gui_solderingTempAdjust() {
|
|
uint32_t lastChange = xTaskGetTickCount();
|
|
currentTempTargetDegC = 0;
|
|
uint32_t autoRepeatTimer = 0;
|
|
uint8_t autoRepeatAcceleration = 0;
|
|
bool waitForRelease = false;
|
|
ButtonState buttons = getButtonState();
|
|
if (buttons != BUTTON_NONE) {
|
|
// Temp adjust entered by long-pressing F button.
|
|
waitForRelease = true;
|
|
}
|
|
for (;;) {
|
|
OLED::setCursor(0, 0);
|
|
OLED::clearScreen();
|
|
OLED::setFont(0);
|
|
buttons = getButtonState();
|
|
if (buttons) {
|
|
if (waitForRelease) {
|
|
buttons = BUTTON_NONE;
|
|
}
|
|
lastChange = xTaskGetTickCount();
|
|
} else {
|
|
waitForRelease = false;
|
|
}
|
|
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) {
|
|
if (systemSettings.ReverseButtonTempChangeEnabled) {
|
|
systemSettings.SolderingTemp += systemSettings.TempChangeLongStep;
|
|
} else
|
|
systemSettings.SolderingTemp -= systemSettings.TempChangeLongStep;
|
|
|
|
autoRepeatTimer = xTaskGetTickCount();
|
|
autoRepeatAcceleration += PRESS_ACCEL_STEP;
|
|
}
|
|
break;
|
|
case BUTTON_B_SHORT:
|
|
if (systemSettings.ReverseButtonTempChangeEnabled) {
|
|
systemSettings.SolderingTemp += systemSettings.TempChangeShortStep;
|
|
} else
|
|
systemSettings.SolderingTemp -= systemSettings.TempChangeShortStep;
|
|
break;
|
|
case BUTTON_F_LONG:
|
|
if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) {
|
|
if (systemSettings.ReverseButtonTempChangeEnabled) {
|
|
systemSettings.SolderingTemp -= systemSettings.TempChangeLongStep;
|
|
} else
|
|
systemSettings.SolderingTemp += systemSettings.TempChangeLongStep;
|
|
autoRepeatTimer = xTaskGetTickCount();
|
|
autoRepeatAcceleration += PRESS_ACCEL_STEP;
|
|
}
|
|
break;
|
|
case BUTTON_F_SHORT:
|
|
if (systemSettings.ReverseButtonTempChangeEnabled) {
|
|
systemSettings.SolderingTemp -= systemSettings.TempChangeShortStep; // add 10
|
|
} else
|
|
systemSettings.SolderingTemp += systemSettings.TempChangeShortStep; // add 10
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ((PRESS_ACCEL_INTERVAL_MAX - autoRepeatAcceleration) < PRESS_ACCEL_INTERVAL_MIN) {
|
|
autoRepeatAcceleration = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN;
|
|
}
|
|
// constrain between 10-450 C
|
|
if (systemSettings.temperatureInF) {
|
|
if (systemSettings.SolderingTemp > 850)
|
|
systemSettings.SolderingTemp = 850;
|
|
if (systemSettings.SolderingTemp < 60)
|
|
systemSettings.SolderingTemp = 60;
|
|
} else {
|
|
if (systemSettings.SolderingTemp > 450)
|
|
systemSettings.SolderingTemp = 450;
|
|
if (systemSettings.SolderingTemp < 10)
|
|
systemSettings.SolderingTemp = 10;
|
|
}
|
|
|
|
if (xTaskGetTickCount() - lastChange > 2000)
|
|
return; // exit if user just doesn't press anything for a bit
|
|
|
|
#ifdef OLED_FLIP
|
|
if (!OLED::getRotation()) {
|
|
#else
|
|
if (OLED::getRotation()) {
|
|
#endif
|
|
OLED::print(systemSettings.ReverseButtonTempChangeEnabled ? SymbolPlus : SymbolMinus);
|
|
} else {
|
|
OLED::print(systemSettings.ReverseButtonTempChangeEnabled ? SymbolMinus : SymbolPlus);
|
|
}
|
|
|
|
OLED::print(SymbolSpace);
|
|
OLED::printNumber(systemSettings.SolderingTemp, 3);
|
|
if (systemSettings.temperatureInF)
|
|
OLED::drawSymbol(0);
|
|
else
|
|
{
|
|
OLED::drawSymbol(1);
|
|
}
|
|
OLED::print(SymbolSpace);
|
|
#ifdef OLED_FLIP
|
|
if (!OLED::getRotation()) {
|
|
#else
|
|
if (OLED::getRotation()) {
|
|
#endif
|
|
OLED::print(systemSettings.ReverseButtonTempChangeEnabled ? SymbolMinus : SymbolPlus);
|
|
} else {
|
|
OLED::print(systemSettings.ReverseButtonTempChangeEnabled ? SymbolPlus : SymbolMinus);
|
|
}
|
|
OLED::refresh();
|
|
GUIDelay();
|
|
}
|
|
}
|
|
static bool shouldShutdown() {
|
|
if (systemSettings.ShutdownTime) { // only allow shutdown exit if time > 0
|
|
if (lastMovementTime) {
|
|
if (((TickType_t)(xTaskGetTickCount() - lastMovementTime)) > (TickType_t)(systemSettings.ShutdownTime * TICKS_MIN)) {
|
|
return true;
|
|
}
|
|
}
|
|
if (lastHallEffectSleepStart) {
|
|
if (((TickType_t)(xTaskGetTickCount() - lastHallEffectSleepStart)) > (TickType_t)(systemSettings.ShutdownTime * TICKS_MIN)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
static int gui_SolderingSleepingMode(bool stayOff, bool autoStarted) {
|
|
// Drop to sleep temperature and display until movement or button press
|
|
|
|
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
|
|
|
|
#ifdef POW_DC
|
|
if (checkVoltageForExit())
|
|
return 1; // return non-zero on error
|
|
#endif
|
|
if (systemSettings.temperatureInF) {
|
|
currentTempTargetDegC = stayOff ? 0 : TipThermoModel::convertFtoC(min(systemSettings.SleepTemp, systemSettings.SolderingTemp));
|
|
} else {
|
|
currentTempTargetDegC = stayOff ? 0 : min(systemSettings.SleepTemp, systemSettings.SolderingTemp);
|
|
}
|
|
// draw the lcd
|
|
uint16_t tipTemp;
|
|
if (systemSettings.temperatureInF)
|
|
tipTemp = TipThermoModel::getTipInF();
|
|
else {
|
|
tipTemp = TipThermoModel::getTipInC();
|
|
}
|
|
|
|
OLED::clearScreen();
|
|
OLED::setCursor(0, 0);
|
|
if (systemSettings.detailedSoldering) {
|
|
OLED::setFont(1);
|
|
OLED::print(SleepingAdvancedString);
|
|
OLED::setCursor(0, 8);
|
|
OLED::print(SleepingTipAdvancedString);
|
|
OLED::printNumber(tipTemp, 3);
|
|
if (systemSettings.temperatureInF)
|
|
OLED::print(SymbolDegF);
|
|
else {
|
|
OLED::print(SymbolDegC);
|
|
}
|
|
|
|
OLED::print(SymbolSpace);
|
|
printVoltage();
|
|
OLED::print(SymbolVolts);
|
|
} else {
|
|
OLED::setFont(0);
|
|
OLED::print(SleepingSimpleString);
|
|
OLED::printNumber(tipTemp, 3);
|
|
if (systemSettings.temperatureInF)
|
|
OLED::drawSymbol(0);
|
|
else {
|
|
OLED::drawSymbol(1);
|
|
}
|
|
}
|
|
|
|
OLED::refresh();
|
|
GUIDelay();
|
|
if (!shouldBeSleeping(autoStarted)) {
|
|
return 0;
|
|
}
|
|
if (shouldShutdown()) {
|
|
// shutdown
|
|
currentTempTargetDegC = 0;
|
|
return 1; // we want to exit soldering mode
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void display_countdown(int sleepThres) {
|
|
/*
|
|
* Print seconds or minutes (if > 99 seconds) until sleep
|
|
* mode is triggered.
|
|
*/
|
|
int lastEventTime = lastButtonTime < lastMovementTime ? lastMovementTime : lastButtonTime;
|
|
TickType_t downCount = sleepThres - xTaskGetTickCount() + lastEventTime;
|
|
if (downCount > (99 * TICKS_SECOND)) {
|
|
OLED::printNumber(downCount / 60000 + 1, 2);
|
|
OLED::print(SymbolMinutes);
|
|
} else {
|
|
OLED::printNumber(downCount / 1000 + 1, 2);
|
|
OLED::print(SymbolSeconds);
|
|
}
|
|
}
|
|
static uint32_t getSleepTimeout() {
|
|
if (systemSettings.sensitivity && systemSettings.SleepTime) {
|
|
|
|
uint32_t sleepThres = 0;
|
|
if (systemSettings.SleepTime < 6)
|
|
sleepThres = systemSettings.SleepTime * 10 * 1000;
|
|
else
|
|
sleepThres = (systemSettings.SleepTime - 5) * 60 * 1000;
|
|
return sleepThres;
|
|
}
|
|
return 0;
|
|
}
|
|
static bool shouldBeSleeping(bool inAutoStart) {
|
|
// Return true if the iron should be in sleep mode
|
|
if (systemSettings.sensitivity && systemSettings.SleepTime) {
|
|
if (inAutoStart) {
|
|
// In auto start we are asleep until movement
|
|
if (lastMovementTime == 0 && lastButtonTime == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
if (lastMovementTime > 0 || lastButtonTime > 0) {
|
|
if ((xTaskGetTickCount() - lastMovementTime) > getSleepTimeout() && (xTaskGetTickCount() - lastButtonTime) > getSleepTimeout()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HALL_SENSOR
|
|
// If the hall effect sensor is enabled in the build, check if its over
|
|
// threshold, and if so then we force sleep
|
|
if (lookupHallEffectThreshold()) {
|
|
int16_t hallEffectStrength = getRawHallEffect();
|
|
if (hallEffectStrength < 0)
|
|
hallEffectStrength = -hallEffectStrength;
|
|
// Have absolute value of measure of magnetic field strength
|
|
if (hallEffectStrength > lookupHallEffectThreshold()) {
|
|
if (lastHallEffectSleepStart == 0) {
|
|
lastHallEffectSleepStart = xTaskGetTickCount();
|
|
}
|
|
if ((xTaskGetTickCount() - lastHallEffectSleepStart) > TICKS_SECOND) {
|
|
return true;
|
|
}
|
|
} else {
|
|
lastHallEffectSleepStart = 0;
|
|
}
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
static void gui_solderingMode(uint8_t jumpToSleep) {
|
|
/*
|
|
* * Soldering (gui_solderingMode)
|
|
* -> Main loop where we draw temp, and animations
|
|
* --> User presses buttons and they goto the temperature adjust screen
|
|
* ---> Display the current setpoint temperature
|
|
* ---> Use buttons to change forward and back on temperature
|
|
* ---> Both buttons or timeout for exiting
|
|
* --> Long hold front button to enter boost mode
|
|
* ---> Just temporarily sets the system into the alternate temperature for
|
|
* PID control
|
|
* --> Long hold back button to exit
|
|
* --> Double button to exit
|
|
* --> Long hold double button to toggle key lock
|
|
*/
|
|
bool boostModeOn = false;
|
|
bool buttonsLocked = false;
|
|
|
|
if (jumpToSleep) {
|
|
if (gui_SolderingSleepingMode(jumpToSleep == 2, true) == 1) {
|
|
lastButtonTime = xTaskGetTickCount();
|
|
return; // If the function returns non-0 then exit
|
|
}
|
|
}
|
|
for (;;) {
|
|
ButtonState buttons = getButtonState();
|
|
if (buttonsLocked && (systemSettings.lockingMode != 0)) { // If buttons locked
|
|
switch (buttons) {
|
|
case BUTTON_NONE:
|
|
boostModeOn = false;
|
|
break;
|
|
case BUTTON_BOTH_LONG:
|
|
// Unlock buttons
|
|
buttonsLocked = false;
|
|
warnUser(UnlockingKeysString, 0, TICKS_SECOND);
|
|
break;
|
|
case BUTTON_F_LONG:
|
|
// if boost mode is enabled turn it on
|
|
if (systemSettings.BoostTemp && (systemSettings.lockingMode == 1)) {
|
|
boostModeOn = true;
|
|
}
|
|
break;
|
|
// fall through
|
|
case BUTTON_BOTH:
|
|
case BUTTON_B_LONG:
|
|
case BUTTON_F_SHORT:
|
|
case BUTTON_B_SHORT:
|
|
// Do nothing and display a lock warming
|
|
warnUser(WarningKeysLockedString, 0, TICKS_SECOND / 2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else { // Button not locked
|
|
switch (buttons) {
|
|
case BUTTON_NONE:
|
|
// stay
|
|
boostModeOn = false;
|
|
break;
|
|
case BUTTON_BOTH:
|
|
// exit
|
|
return;
|
|
break;
|
|
case BUTTON_B_LONG:
|
|
return; // exit on back long hold
|
|
break;
|
|
case BUTTON_F_LONG:
|
|
// if boost mode is enabled turn it on
|
|
if (systemSettings.BoostTemp)
|
|
boostModeOn = true;
|
|
break;
|
|
case BUTTON_F_SHORT:
|
|
case BUTTON_B_SHORT: {
|
|
uint16_t oldTemp = systemSettings.SolderingTemp;
|
|
gui_solderingTempAdjust(); // goto adjust temp mode
|
|
if (oldTemp != systemSettings.SolderingTemp) {
|
|
saveSettings(); // only save on change
|
|
}
|
|
} break;
|
|
case BUTTON_BOTH_LONG:
|
|
if (systemSettings.lockingMode != 0) {
|
|
// Lock buttons
|
|
buttonsLocked = true;
|
|
warnUser(LockingKeysString, 0, TICKS_SECOND);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
// else we update the screen information
|
|
OLED::setCursor(0, 0);
|
|
OLED::clearScreen();
|
|
OLED::setFont(0);
|
|
// Draw in the screen details
|
|
if (systemSettings.detailedSoldering) {
|
|
OLED::setFont(1);
|
|
OLED::print(SolderingAdvancedPowerPrompt); // Power:
|
|
OLED::printNumber(x10WattHistory.average() / 10, 2);
|
|
OLED::print(SymbolDot);
|
|
OLED::printNumber(x10WattHistory.average() % 10, 1);
|
|
OLED::print(SymbolWatts);
|
|
|
|
if (systemSettings.sensitivity && systemSettings.SleepTime) {
|
|
OLED::print(SymbolSpace);
|
|
display_countdown(getSleepTimeout());
|
|
}
|
|
|
|
OLED::setCursor(0, 8);
|
|
OLED::print(SleepingTipAdvancedString);
|
|
gui_drawTipTemp(true);
|
|
OLED::print(SymbolSpace);
|
|
printVoltage();
|
|
OLED::print(SymbolVolts);
|
|
} else {
|
|
// We switch the layout direction depending on the orientation of the oled
|
|
if (OLED::getRotation()) {
|
|
// battery
|
|
gui_drawBatteryIcon();
|
|
OLED::print(SymbolSpace); // Space out gap between battery <-> temp
|
|
gui_drawTipTemp(true); // Draw current tip temp
|
|
|
|
// We draw boost arrow if boosting, or else gap temp <-> heat
|
|
// indicator
|
|
if (boostModeOn)
|
|
OLED::drawSymbol(2);
|
|
else
|
|
OLED::print(SymbolSpace);
|
|
|
|
// Draw heating/cooling symbols
|
|
OLED::drawHeatSymbol(X10WattsToPWM(x10WattHistory.average()));
|
|
} else {
|
|
// Draw heating/cooling symbols
|
|
OLED::drawHeatSymbol(X10WattsToPWM(x10WattHistory.average()));
|
|
// We draw boost arrow if boosting, or else gap temp <-> heat
|
|
// indicator
|
|
if (boostModeOn)
|
|
OLED::drawSymbol(2);
|
|
else
|
|
OLED::print(SymbolSpace);
|
|
gui_drawTipTemp(true); // Draw current tip temp
|
|
|
|
OLED::print(SymbolSpace); // Space out gap between battery <-> temp
|
|
|
|
gui_drawBatteryIcon();
|
|
}
|
|
}
|
|
OLED::refresh();
|
|
|
|
// Update the setpoints for the temperature
|
|
if (boostModeOn) {
|
|
if (systemSettings.temperatureInF)
|
|
currentTempTargetDegC = TipThermoModel::convertFtoC(systemSettings.BoostTemp);
|
|
else {
|
|
currentTempTargetDegC = (systemSettings.BoostTemp);
|
|
}
|
|
} else {
|
|
if (systemSettings.temperatureInF)
|
|
currentTempTargetDegC = TipThermoModel::convertFtoC(systemSettings.SolderingTemp);
|
|
else {
|
|
currentTempTargetDegC = (systemSettings.SolderingTemp);
|
|
}
|
|
}
|
|
|
|
#ifdef POW_DC
|
|
// Undervoltage test
|
|
if (checkVoltageForExit()) {
|
|
lastButtonTime = xTaskGetTickCount();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (shouldBeSleeping()) {
|
|
if (gui_SolderingSleepingMode(false, false)) {
|
|
return; // If the function returns non-0 then exit
|
|
}
|
|
}
|
|
// slow down ui update rate
|
|
GUIDelay();
|
|
}
|
|
}
|
|
|
|
void showDebugMenu(void) {
|
|
uint8_t screen = 0;
|
|
ButtonState b;
|
|
OLED::setFont(1); // small font
|
|
for (;;) {
|
|
OLED::clearScreen(); // Ensure the buffer starts clean
|
|
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
|
|
OLED::print(SymbolVersionNumber); // Print version number
|
|
OLED::setCursor(0, 8); // second line
|
|
OLED::print(DebugMenu[screen]);
|
|
switch (screen) {
|
|
case 0: // Just prints date
|
|
break;
|
|
case 1:
|
|
// High water mark for GUI
|
|
OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 5);
|
|
break;
|
|
case 2:
|
|
// High water mark for the Movement task
|
|
OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 5);
|
|
break;
|
|
case 3:
|
|
// High water mark for the PID task
|
|
OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 5);
|
|
break;
|
|
case 4:
|
|
// system up time stamp
|
|
OLED::printNumber(xTaskGetTickCount() / 100, 5);
|
|
break;
|
|
case 5:
|
|
// Movement time stamp
|
|
OLED::printNumber(lastMovementTime / 100, 5);
|
|
break;
|
|
case 6:
|
|
// Raw Tip
|
|
{
|
|
uint32_t temp = systemSettings.CalibrationOffset;
|
|
systemSettings.CalibrationOffset = 0;
|
|
OLED::printNumber(TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0)), 6);
|
|
systemSettings.CalibrationOffset = temp;
|
|
}
|
|
break;
|
|
case 7:
|
|
// Temp in C
|
|
OLED::printNumber(TipThermoModel::getTipInC(), 5);
|
|
break;
|
|
case 8:
|
|
// Handle Temp
|
|
OLED::printNumber(getHandleTemperature(), 3);
|
|
break;
|
|
case 9:
|
|
// Voltage input
|
|
printVoltage();
|
|
break;
|
|
case 10:
|
|
// Print PCB ID number
|
|
OLED::printNumber(DetectedAccelerometerVersion, 2);
|
|
break;
|
|
case 11:
|
|
// Power negotiation status
|
|
if (getIsPoweredByDCIN()) {
|
|
OLED::printNumber(0, 1);
|
|
} else {
|
|
// We are not powered via DC, so want to display the appropriate state for PD or QC
|
|
bool poweredbyPD = false;
|
|
#ifdef POW_PD
|
|
if (usb_pd_detect()) {
|
|
// We are PD capable
|
|
if (PolicyEngine::pdHasNegotiated()) {
|
|
// We are powered via PD
|
|
poweredbyPD = true;
|
|
}
|
|
}
|
|
#endif
|
|
if (poweredbyPD) {
|
|
OLED::printNumber(2, 1);
|
|
} else {
|
|
|
|
OLED::printNumber(1, 1);
|
|
}
|
|
}
|
|
break;
|
|
case 12:
|
|
// Max deg C limit
|
|
OLED::printNumber(TipThermoModel::getTipMaxInC(), 3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
OLED::refresh();
|
|
b = getButtonState();
|
|
if (b == BUTTON_B_SHORT)
|
|
return;
|
|
else if (b == BUTTON_F_SHORT) {
|
|
screen++;
|
|
screen = screen % 13;
|
|
}
|
|
GUIDelay();
|
|
}
|
|
}
|
|
|
|
void showWarnings() {
|
|
// Display alert if settings were reset
|
|
if (settingsWereReset) {
|
|
warnUser(SettingsResetMessage, 1, 10 * TICKS_SECOND);
|
|
}
|
|
#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 == ACCELEROMETERS_SCANNING) {
|
|
osDelay(5);
|
|
}
|
|
// Display alert if accelerometer is not detected
|
|
if (DetectedAccelerometerVersion == NO_DETECTED_ACCELEROMETER) {
|
|
if (systemSettings.accelMissingWarningCounter < 2) {
|
|
systemSettings.accelMissingWarningCounter++;
|
|
saveSettings();
|
|
warnUser(NoAccelerometerMessage, 1, 10 * TICKS_SECOND);
|
|
}
|
|
}
|
|
#ifdef POW_PD
|
|
// We expect pd to be present
|
|
if (!usb_pd_detect()) {
|
|
if (systemSettings.pdMissingWarningCounter < 2) {
|
|
systemSettings.pdMissingWarningCounter++;
|
|
saveSettings();
|
|
warnUser(NoPowerDeliveryMessage, 1, 10 * TICKS_SECOND);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
uint8_t idleScreenBGF[sizeof(idleScreenBG)];
|
|
/* StartGUITask function */
|
|
void startGUITask(void const *argument __unused) {
|
|
OLED::initialize(); // start up the LCD
|
|
|
|
uint8_t tempWarningState = 0;
|
|
bool buttonLockout = false;
|
|
bool tempOnDisplay = false;
|
|
bool tipDisconnectedDisplay = false;
|
|
{
|
|
// Generate the flipped screen into ram for later use
|
|
// flipped is generated by flipping each row
|
|
for (int row = 0; row < 2; row++) {
|
|
for (int x = 0; x < 84; x++) {
|
|
idleScreenBGF[(row * 84) + x] = idleScreenBG[(row * 84) + (83 - x)];
|
|
}
|
|
}
|
|
}
|
|
getTipRawTemp(1); // reset filter
|
|
OLED::setRotation(systemSettings.OrientationMode & 1);
|
|
uint32_t ticks = xTaskGetTickCount();
|
|
ticks += 4000; // 4 seconds from now
|
|
while (xTaskGetTickCount() < ticks) {
|
|
if (showBootLogoIfavailable() == false)
|
|
ticks = xTaskGetTickCount();
|
|
ButtonState buttons = getButtonState();
|
|
if (buttons)
|
|
ticks = xTaskGetTickCount(); // make timeout now so we will exit
|
|
GUIDelay();
|
|
}
|
|
|
|
showWarnings();
|
|
|
|
if (systemSettings.autoStartMode) {
|
|
// jump directly to the autostart mode
|
|
gui_solderingMode(systemSettings.autoStartMode - 1);
|
|
buttonLockout = true;
|
|
}
|
|
|
|
for (;;) {
|
|
ButtonState buttons = getButtonState();
|
|
if (buttons != BUTTON_NONE) {
|
|
OLED::setDisplayState(OLED::DisplayState::ON);
|
|
OLED::setFont(0);
|
|
}
|
|
if (tempWarningState == 2)
|
|
buttons = BUTTON_F_SHORT;
|
|
if (buttons != BUTTON_NONE && buttonLockout)
|
|
buttons = BUTTON_NONE;
|
|
else
|
|
buttonLockout = false;
|
|
|
|
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();
|
|
break;
|
|
case BUTTON_F_LONG:
|
|
gui_solderingTempAdjust();
|
|
saveSettings();
|
|
break;
|
|
case BUTTON_F_SHORT:
|
|
gui_solderingMode(0); // enter soldering mode
|
|
buttonLockout = true;
|
|
break;
|
|
case BUTTON_B_SHORT:
|
|
enterSettingsMenu(); // enter the settings menu
|
|
buttonLockout = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
currentTempTargetDegC = 0; // ensure tip is off
|
|
getInputVoltageX10(systemSettings.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) && systemSettings.sensitivity && (((xTaskGetTickCount() - lastMovementTime) > MOVEMENT_INACTIVITY_TIME) && ((xTaskGetTickCount() - lastButtonTime) > BUTTON_INACTIVITY_TIME))) {
|
|
OLED::setDisplayState(OLED::DisplayState::OFF);
|
|
}
|
|
uint16_t tipDisconnectedThres = TipThermoModel::getTipMaxInC() - 5;
|
|
// Clear the lcd buffer
|
|
OLED::clearScreen();
|
|
OLED::setCursor(0, 0);
|
|
if (systemSettings.detailedIDLE) {
|
|
OLED::setFont(1);
|
|
if (tipTemp > tipDisconnectedThres) {
|
|
OLED::print(TipDisconnectedString);
|
|
} else {
|
|
OLED::print(IdleTipString);
|
|
gui_drawTipTemp(false);
|
|
OLED::print(IdleSetString);
|
|
OLED::printNumber(systemSettings.SolderingTemp, 3);
|
|
}
|
|
OLED::setCursor(0, 8);
|
|
|
|
OLED::print(InputVoltageString);
|
|
printVoltage();
|
|
|
|
} else {
|
|
OLED::setFont(0);
|
|
#ifdef OLED_FLIP
|
|
if (!OLED::getRotation()) {
|
|
#else
|
|
if (OLED::getRotation()) {
|
|
#endif
|
|
OLED::drawArea(12, 0, 84, 16, idleScreenBG);
|
|
OLED::setCursor(0, 0);
|
|
gui_drawBatteryIcon();
|
|
} else {
|
|
OLED::drawArea(0, 0, 84, 16, idleScreenBGF); // Needs to be flipped so button ends up
|
|
// on right side of screen
|
|
OLED::setCursor(84, 0);
|
|
gui_drawBatteryIcon();
|
|
}
|
|
tipDisconnectedDisplay = false;
|
|
if (tipTemp > 55)
|
|
tempOnDisplay = true;
|
|
else if (tipTemp < 45)
|
|
tempOnDisplay = false;
|
|
if (tipTemp > tipDisconnectedThres) {
|
|
tempOnDisplay = false;
|
|
tipDisconnectedDisplay = true;
|
|
}
|
|
if (tempOnDisplay || tipDisconnectedDisplay) {
|
|
// draw temp over the start soldering button
|
|
// Location changes on screen rotation
|
|
#ifdef OLED_FLIP
|
|
if (!OLED::getRotation()) {
|
|
#else
|
|
if (OLED::getRotation()) {
|
|
#endif
|
|
// in right handed mode we want to draw over the first part
|
|
OLED::fillArea(55, 0, 41, 16, 0); // clear the area for the temp
|
|
OLED::setCursor(56, 0);
|
|
|
|
} else {
|
|
OLED::fillArea(0, 0, 41, 16, 0); // clear the area
|
|
OLED::setCursor(0, 0);
|
|
}
|
|
// If we have a tip connected draw the temp, if not we leave it blank
|
|
if (!tipDisconnectedDisplay) {
|
|
// draw in the temp
|
|
if (!(systemSettings.coolingTempBlink && (xTaskGetTickCount() % 26 < 16)))
|
|
gui_drawTipTemp(false); // draw in the temp
|
|
} else {
|
|
// Draw in missing tip symbol
|
|
|
|
#ifdef OLED_FLIP
|
|
if (!OLED::getRotation()) {
|
|
#else
|
|
if (OLED::getRotation()) {
|
|
#endif
|
|
// in right handed mode we want to draw over the first part
|
|
OLED::drawArea(55, 0, 41, 16, disconnectedTipIcon);
|
|
|
|
} else {
|
|
OLED::drawArea(0, 0, 41, 16, disconnectedTipIcon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
OLED::refresh();
|
|
GUIDelay();
|
|
}
|
|
}
|