1
0
forked from me/IronOS
Files
IronOS/source/Core/Src/Settings.cpp
Ben V. Brown ebdff59293 Default to no EPR/PPS so its opt in (#2073)
Some chargers have funky PPS.
Plus some do not want EPR be default (even though 28V is safe by designer on PinecilV2).

So take the safest option by default and make it opt-in
2025-02-08 09:17:01 +03:00

378 lines
19 KiB
C++

/*
* Settings.c
*
* Created on: 29 Sep 2016
* Author: Ralim
*
* This file holds the users settings and saves / restores them to the
* devices flash
*/
#include "Settings.h"
#include "BSP.h"
#include "Setup.h"
#include "Translation.h"
#include "configuration.h"
#include <string.h> // for memset
bool sanitiseSettings();
/*
* Used to constrain the QC 3.0 Voltage selection to suit hardware.
* We allow a little overvoltage for users who want to push it
*/
#ifdef POW_QC_20V
#define QC_VOLTAGE_MAX 220
#else
#define QC_VOLTAGE_MAX 140
#endif /* POW_QC_20V */
/*
* This struct must be a multiple of 2 bytes as it is saved / restored from
* flash in uint16_t chunks
*/
typedef struct {
uint16_t versionMarker;
uint16_t length; // Length of valid bytes following
uint16_t settingsValues[SettingsOptionsLength];
// used to make this nicely "good enough" aligned to 32 bytes to make driver code trivial
uint32_t padding;
} systemSettingsType;
//~1024 is common programming size, setting threshold to be lower so we have warning
static_assert(sizeof(systemSettingsType) < 512);
// char (*__kaboom)[sizeof(systemSettingsType)] = 1; // Uncomment to print size at compile time
volatile systemSettingsType systemSettings;
// For every setting we need to store the min/max/increment values
typedef struct {
const uint16_t min; // Inclusive minimum value
const uint16_t max; // Inclusive maximum value
const uint16_t increment; // Standard increment
const uint16_t defaultValue; // Default vaue after reset
} SettingConstants;
static const SettingConstants settingsConstants[(int)SettingsOptions::SettingsOptionsLength] = {
//{ min, max, increment, default}
{ MIN_TEMP_C, MAX_TEMP_F, 5, SOLDERING_TEMP}, // SolderingTemp
{ MIN_TEMP_C, MAX_TEMP_F, 5, 150}, // SleepTemp
{ 0, 15, 1, SLEEP_TIME}, // SleepTime
{ 0, 4, 1, CUT_OUT_SETTING}, // MinDCVoltageCells
{ 24, 38, 1, RECOM_VOL_CELL}, // MinVoltageCells
{ 90, QC_VOLTAGE_MAX, 2, 90}, // QCIdealVoltage
{ 0, MAX_ORIENTATION_MODE, 1, ORIENTATION_MODE}, // OrientationMode
{ 0, 9, 1, SENSITIVITY}, // Sensitivity
{ 0, 1, 1, ANIMATION_LOOP}, // AnimationLoop
{ 0, settingOffSpeed_t::MAX_VALUE - 1, 1, ANIMATION_SPEED}, // AnimationSpeed
{ 0, 3, 1, AUTO_START_MODE}, // AutoStartMode
{ 0, 60, 1, SHUTDOWN_TIME}, // ShutdownTime
{ 0, 1, 1, COOLING_TEMP_BLINK}, // CoolingTempBlink
{ 0, 1, 1, DETAILED_IDLE}, // DetailedIDLE
{ 0, 1, 1, DETAILED_SOLDERING}, // DetailedSoldering
{ 0, (uint16_t)(HasFahrenheit ? 1 : 0), 1, TEMPERATURE_INF}, // TemperatureInF
{ 0, 1, 1, DESCRIPTION_SCROLL_SPEED}, // DescriptionScrollSpeed
{ 0, 2, 1, LOCKING_MODE}, // LockingMode
{ 0, 99, 1, POWER_PULSE_DEFAULT}, // KeepAwakePulse
{ 1, POWER_PULSE_WAIT_MAX, 1, POWER_PULSE_WAIT_DEFAULT}, // KeepAwakePulseWait
{ 1, POWER_PULSE_DURATION_MAX, 1, POWER_PULSE_DURATION_DEFAULT}, // KeepAwakePulseDuration
{ 360, 900, 1, VOLTAGE_DIV}, // VoltageDiv
{ 0, MAX_TEMP_F, 10, BOOST_TEMP}, // BoostTemp
{MIN_CALIBRATION_OFFSET, 2500, 1, CALIBRATION_OFFSET}, // CalibrationOffset
{ 0, MAX_POWER_LIMIT, POWER_LIMIT_STEPS, POWER_LIMIT}, // PowerLimit
{ 0, 1, 1, REVERSE_BUTTON_TEMP_CHANGE}, // ReverseButtonTempChangeEnabled
{ 5, TEMP_CHANGE_LONG_STEP_MAX, 5, TEMP_CHANGE_LONG_STEP}, // TempChangeLongStep
{ 1, TEMP_CHANGE_SHORT_STEP_MAX, 1, TEMP_CHANGE_SHORT_STEP}, // TempChangeShortStep
{ 0, 9, 1, 7}, // HallEffectSensitivity
{ 0, 9, 1, 0}, // AccelMissingWarningCounter
{ 0, 9, 1, 0}, // PDMissingWarningCounter
{ 0, 0xFFFF, 0, 41431 /*EN*/}, // UILanguage
{ 0, 50, 1, 20}, // PDNegTimeout
{ 0, 1, 1, 0}, // OLEDInversion
{ MIN_BRIGHTNESS, MAX_BRIGHTNESS, BRIGHTNESS_STEP, DEFAULT_BRIGHTNESS}, // OLEDBrightness
{ 0, 6, 1, 1}, // LOGOTime
{ 0, 1, 1, 0}, // CalibrateCJC
{ 0, 1, 1, 0}, // BluetoothLE
{ 0, 2, 1, 0}, // USBPDMode
{ 1, 5, 1, 4}, // ProfilePhases
{ MIN_TEMP_C, MAX_TEMP_F, 5, 90}, // ProfilePreheatTemp
{ 1, 10, 1, 1}, // ProfilePreheatSpeed
{ MIN_TEMP_C, MAX_TEMP_F, 5, 130}, // ProfilePhase1Temp
{ 10, 180, 5, 90}, // ProfilePhase1Duration
{ MIN_TEMP_C, MAX_TEMP_F, 5, 140}, // ProfilePhase2Temp
{ 10, 180, 5, 30}, // ProfilePhase2Duration
{ MIN_TEMP_C, MAX_TEMP_F, 5, 165}, // ProfilePhase3Temp
{ 10, 180, 5, 30}, // ProfilePhase3Duration
{ MIN_TEMP_C, MAX_TEMP_F, 5, 140}, // ProfilePhase4Temp
{ 10, 180, 5, 30}, // ProfilePhase4Duration
{ MIN_TEMP_C, MAX_TEMP_F, 5, 90}, // ProfilePhase5Temp
{ 10, 180, 5, 30}, // ProfilePhase5Duration
{ 1, 10, 1, 2}, // ProfileCooldownSpeed
{ 0, 12, 1, 0}, // HallEffectSleepTime
{ 0, (tipType_t::TIP_TYPE_MAX - 1) > 0 ? (tipType_t::TIP_TYPE_MAX - 1) : 0, 1, 0}, // SolderingTipType
};
static_assert((sizeof(settingsConstants) / sizeof(SettingConstants)) == ((int)SettingsOptions::SettingsOptionsLength));
void saveSettings() {
#ifdef CANT_DIRECT_READ_SETTINGS
// For these devices flash is not 1:1 mapped, so need to read into staging buffer
systemSettingsType settings;
flash_read_buffer((uint8_t *)&settings, sizeof(systemSettingsType));
if (memcmp((void *)&settings, (void *)&systemSettings, sizeof(systemSettingsType))) {
flash_save_buffer((uint8_t *)&systemSettings, sizeof(systemSettingsType));
}
#else
if (memcmp((void *)SETTINGS_START_PAGE, (void *)&systemSettings, sizeof(systemSettingsType))) {
flash_save_buffer((uint8_t *)&systemSettings, sizeof(systemSettingsType));
}
#endif /* CANT_DIRECT_READ_SETTINGS */
}
bool loadSettings() {
// We read the flash
flash_read_buffer((uint8_t *)&systemSettings, sizeof(systemSettingsType));
// Then ensure all values are valid
return sanitiseSettings();
}
bool sanitiseSettings() {
// For all settings, need to ensure settings are in a valid range
// First for any not know about due to array growth, reset them and update the length value
bool dirty = false;
if (systemSettings.versionMarker != SETTINGSVERSION) {
memset((void *)&systemSettings, 0xFF, sizeof(systemSettings));
systemSettings.versionMarker = SETTINGSVERSION;
dirty = true;
}
if (systemSettings.padding != 0xFFFFFFFF) {
systemSettings.padding = 0xFFFFFFFF; // Force padding to 0xFFFFFFFF so that rolling forwards / back should be easier
dirty = true;
}
if (systemSettings.length < (int)SettingsOptions::SettingsOptionsLength) {
dirty = true;
for (int i = systemSettings.length; i < (int)SettingsOptions::SettingsOptionsLength; i++) {
systemSettings.settingsValues[i] = 0xFFFF; // Ensure its as if it was erased
}
systemSettings.length = (int)SettingsOptions::SettingsOptionsLength;
}
for (int i = 0; i < (int)SettingsOptions::SettingsOptionsLength; i++) {
// Check min max for all settings, if outside the range, move to default
if (systemSettings.settingsValues[i] < settingsConstants[i].min || systemSettings.settingsValues[i] > settingsConstants[i].max) {
systemSettings.settingsValues[i] = settingsConstants[i].defaultValue;
dirty = true;
}
}
if (dirty) {
saveSettings();
}
return dirty;
}
void resetSettings() {
memset((void *)&systemSettings, 0xFF, sizeof(systemSettingsType));
sanitiseSettings();
saveSettings(); // Save defaults
}
void setSettingValue(const enum SettingsOptions option, const uint16_t newValue) {
const auto constants = settingsConstants[(int)option];
uint16_t constrainedValue = newValue;
if (constrainedValue < constants.min) {
// If less than min, constrain
constrainedValue = constants.min;
} else if (constrainedValue > constants.max) {
// If hit max, constrain
constrainedValue = constants.max;
}
systemSettings.settingsValues[(int)option] = constrainedValue;
}
// Lookup wrapper for ease of use (with typing)
uint16_t getSettingValue(const enum SettingsOptions option) { return systemSettings.settingsValues[(int)option]; }
// Increment by the step size to the next value. If past the end wrap to the minimum
// Returns true if we are on the _last_ value
void nextSettingValue(const enum SettingsOptions option) {
const auto constants = settingsConstants[(int)option];
if (systemSettings.settingsValues[(int)option] == (constants.max)) {
// Already at max, wrap to the start
systemSettings.settingsValues[(int)option] = constants.min;
} else if (systemSettings.settingsValues[(int)option] >= (constants.max - constants.increment)) {
// If within one increment of the end, constrain to the end
systemSettings.settingsValues[(int)option] = constants.max;
} else {
// Otherwise increment
systemSettings.settingsValues[(int)option] += constants.increment;
}
}
bool isLastSettingValue(const enum SettingsOptions option) {
const auto constants = settingsConstants[(int)option];
uint16_t max = constants.max;
// handle temp unit limitations
if (option == SettingsOptions::SolderingTemp) {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
max = MAX_TEMP_F;
} else {
max = MAX_TEMP_C;
}
} else if (option == SettingsOptions::BoostTemp) {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
max = MAX_TEMP_F;
} else {
max = MAX_TEMP_C;
}
} else if (option == SettingsOptions::SleepTemp) {
if (getSettingValue(SettingsOptions::TemperatureInF)) {
max = 580;
} else {
max = 300;
}
} else if (option == SettingsOptions::UILanguage) {
return isLastLanguageOption();
}
return systemSettings.settingsValues[(int)option] > (max - constants.increment);
}
// Step backwards on the settings item
// Return true if we are at the end (min)
void prevSettingValue(const enum SettingsOptions option) {
const auto constants = settingsConstants[(int)option];
if (systemSettings.settingsValues[(int)option] == (constants.min)) {
// Already at min, wrap to the max
systemSettings.settingsValues[(int)option] = constants.max;
} else if (systemSettings.settingsValues[(int)option] <= (constants.min + constants.increment)) {
// If within one increment of the start, constrain to the start
systemSettings.settingsValues[(int)option] = constants.min;
} else {
// Otherwise decrement
systemSettings.settingsValues[(int)option] -= constants.increment;
}
}
uint16_t lookupHallEffectThreshold() {
// Return the threshold above which the hall effect sensor is "activated"
// We want this to be roughly exponentially mapped from 0-1000
switch (getSettingValue(SettingsOptions::HallEffectSensitivity)) {
case 0:
return 0;
case 1:
return 1000;
case 2:
return 750;
case 3:
return 500;
case 4:
return 250;
case 5:
return 150;
case 6:
return 100;
case 7:
return 75;
case 8:
return 50;
case 9:
return 25;
default:
return 0; // Off
}
}
// Lookup function for cutoff setting -> X10 voltage
/*
* 0=DC
* 1=3S
* 2=4S
* 3=5S
* 4=6S
*/
uint8_t lookupVoltageLevel() {
auto minVoltageOnCell = getSettingValue(SettingsOptions::MinDCVoltageCells);
auto minVoltageCellCount = getSettingValue(SettingsOptions::MinVoltageCells);
if (minVoltageOnCell == 0) {
return 90; // 9V since iron does not function effectively below this
} else {
return (minVoltageOnCell * minVoltageCellCount) + (minVoltageCellCount * 2);
}
}
#ifdef TIP_TYPE_SUPPORT
const char *lookupTipName() {
// Get the name string for the current soldering tip
tipType_t value = (tipType_t)getSettingValue(SettingsOptions::SolderingTipType);
switch (value) {
#ifdef TIPTYPE_T12
case tipType_t::T12_8_OHM:
return translatedString(Tr->TipTypeT12Long);
break;
case tipType_t::T12_6_2_OHM:
return translatedString(Tr->TipTypeT12Short);
break;
case tipType_t::T12_4_OHM:
return translatedString(Tr->TipTypeT12PTS);
break;
#endif
#ifdef TIPTYPE_TS80
case tipType_t::TS80_4_5_OHM:
return translatedString(Tr->TipTypeTS80);
break;
#endif
#ifdef TIPTYPE_JBC
case tipType_t::JBC_210_2_5_OHM:
return translatedString(Tr->TipTypeJBCC210);
break;
#endif
#ifdef AUTO_TIP_SELECTION
case tipType_t::TIP_TYPE_AUTO:
#endif
default:
return translatedString(Tr->TipTypeAuto);
break;
}
}
#endif /* TIP_TYPE_SUPPORT */
// Returns the resistance for the current tip selected by the user or 0 for auto
#ifdef TIP_TYPE_SUPPORT
uint8_t getUserSelectedTipResistance() {
tipType_t value = (tipType_t)getSettingValue(SettingsOptions::SolderingTipType);
switch (value) {
#ifdef AUTO_TIP_SELECTION
case tipType_t::TIP_TYPE_AUTO:
return 0;
break;
#endif
#ifdef TIPTYPE_T12
case tipType_t::T12_8_OHM:
return 80;
break;
case tipType_t::T12_6_2_OHM:
return 62;
break;
case tipType_t::T12_4_OHM:
return 40;
break;
#endif
#ifdef TIPTYE_TS80
case tipType_t::TS80_4_5_OHM:
return 45;
break;
#endif
#ifdef TIPTYPE_JBC
case tipType_t::JBC_210_2_5_OHM:
return 25;
break;
#endif
default:
return 0;
break;
}
}
#else
uint8_t getUserSelectedTipResistance() { return tipType_t::TIP_TYPE_AUTO; }
#endif /* TIP_TYPE_SUPPORT */