Cleaner hourmeter handling using a new class for each counter.
Added a warning animation to LVC, ether <12V, or 0.5V > LVC if that result is over 12V
This commit is contained in:
parent
f86ae7cffb
commit
d2116fc18c
|
@ -458,7 +458,7 @@ void setup() {
|
|||
// bCyclicEngaged = RTC_Store.getCyclicEngaged();
|
||||
DebugPort.printf("Previous cyclic active = %d\r\n", RTC_Store.getCyclicEngaged()); // state flag required for cyclic mode to persist properly after a WD reboot :-)
|
||||
|
||||
pHourMeter = new CHourMeter(persistentRunTime, persistentGlowTime); // persistent vars are only trustworthy with SW reboots
|
||||
pHourMeter = new CHourMeter(persistentRunTime, persistentGlowTime); // persistent vars passed by reference so they can be valid after SW reboots
|
||||
pHourMeter->init(bESP32PowerUpInit || RTC_Store.getBootInit()); // ensure persistent memory variable are reset after powerup, or OTA update
|
||||
RTC_Store.setBootInit(false);
|
||||
|
||||
|
@ -908,7 +908,7 @@ bool validateFrame(const CProtocol& frame, const char* name)
|
|||
|
||||
void requestOn()
|
||||
{
|
||||
if(bHasHtrData && SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
|
||||
if(bHasHtrData && (0 == SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()))) {
|
||||
heaterOn();
|
||||
RTC_Store.setCyclicEngaged(true); // for cyclic mode
|
||||
}
|
||||
|
@ -1249,14 +1249,7 @@ void checkDebugCommands()
|
|||
ESP.restart(); // reset the esp
|
||||
}
|
||||
else if(rxVal == ('h' & 0x1f)) { // CTRL-H hourmeter reset
|
||||
sHourMeter FLASHmem = NVstore.getHourMeter();
|
||||
FLASHmem.RunTime = 0;
|
||||
FLASHmem.GlowTime = 0;
|
||||
NVstore.setHourMeter(FLASHmem);
|
||||
RTC_Store.resetRunTime();
|
||||
RTC_Store.resetGlowTime();
|
||||
persistentRunTime = 0;
|
||||
persistentGlowTime = 0;
|
||||
pHourMeter->resetHard();
|
||||
}
|
||||
}
|
||||
#ifdef PROTOCOL_INVESTIGATION
|
||||
|
|
|
@ -134,9 +134,43 @@ CScreenHeader::animate()
|
|||
int xPos = X_BATT_ICON;
|
||||
int yPos = Y_BATT_ICON;
|
||||
showTimers();
|
||||
|
||||
switch(_batteryCount) {
|
||||
case 0:
|
||||
// establish battery icon flash pattern
|
||||
// > 0.5 over LVC - solid
|
||||
// < 0.5 over LVC - slow flash
|
||||
// < LVC - fast flash
|
||||
_batteryWarn = SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue(), false);
|
||||
|
||||
showBatteryIcon(getBatteryVoltage(true));
|
||||
break;
|
||||
case 1:
|
||||
if(_batteryWarn == 2)
|
||||
_display.fillRect(xPos, yPos, BatteryIconInfo.width, BatteryIconInfo.height, BLACK);
|
||||
break;
|
||||
case 2:
|
||||
if(_batteryWarn == 2)
|
||||
showBatteryIcon(getBatteryVoltage(true));
|
||||
break;
|
||||
case 3:
|
||||
if(_batteryWarn) // works for either < LVC, or < LVC+0.5
|
||||
_display.fillRect(xPos, yPos, BatteryIconInfo.width, BatteryIconInfo.height, BLACK);
|
||||
break;
|
||||
case 4:
|
||||
if(_batteryWarn == 2)
|
||||
showBatteryIcon(getBatteryVoltage(true));
|
||||
break;
|
||||
case 5:
|
||||
if(_batteryWarn == 2)
|
||||
_display.fillRect(xPos, yPos, BatteryIconInfo.width, BatteryIconInfo.height, BLACK);
|
||||
break;
|
||||
|
||||
}
|
||||
/*
|
||||
switch(_batteryCount) {
|
||||
case 3:
|
||||
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue(), false)) { // check but do not fault
|
||||
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue(), false) == 0) { // check but do not fault
|
||||
showBatteryIcon(getBatteryVoltage(true));
|
||||
}
|
||||
else {
|
||||
|
@ -147,6 +181,7 @@ CScreenHeader::animate()
|
|||
showBatteryIcon(getBatteryVoltage(true));
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
showWifiIcon();
|
||||
|
|
|
@ -46,6 +46,7 @@ class CScreenHeader : public CScreen {
|
|||
bool _colon;
|
||||
uint8_t _animateCount;
|
||||
uint8_t _batteryCount;
|
||||
uint8_t _batteryWarn;
|
||||
protected:
|
||||
void showBTicon();
|
||||
void showWifiIcon();
|
||||
|
|
|
@ -113,7 +113,12 @@ CSmartError::monitor(uint8_t newRunState)
|
|||
_prevRunState = newRunState;
|
||||
}
|
||||
|
||||
bool
|
||||
//
|
||||
// retval:
|
||||
// 0 - OK
|
||||
// 1 - Warning less than 12/24 (or .5V over LVC for higher LVC levels)
|
||||
// 2 - Warning less than LVC
|
||||
int
|
||||
CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
||||
{
|
||||
// check for low voltage
|
||||
|
@ -126,10 +131,22 @@ CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
|||
_Error = 2; // +1 over displayed error code
|
||||
requestOff();
|
||||
}
|
||||
return false;
|
||||
return 2;
|
||||
}
|
||||
int alert = Thresh + 0.5;
|
||||
if(NVstore.getHeaterTuning().sysVoltage == 120) {
|
||||
if(alert < 12)
|
||||
alert = 12;
|
||||
}
|
||||
else {
|
||||
if(alert < 24)
|
||||
alert = 24;
|
||||
}
|
||||
if(ipVolts < alert) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
void inhibit();
|
||||
void monitor(const CProtocol& heaterFrame);
|
||||
void monitor(uint8_t runstate);
|
||||
bool checkVolts(float volts, float plugI, bool throwfault=true);
|
||||
int checkVolts(float volts, float plugI, bool throwfault=true); // 0 = OK, 1 = within 0.5V of LVC, 2 = under LVC
|
||||
uint8_t getError();
|
||||
};
|
||||
|
||||
|
|
|
@ -245,6 +245,7 @@ CRTC_Store::_PackAndSaveByte5()
|
|||
void
|
||||
CRTC_Store::_PackAndSaveByte6()
|
||||
{
|
||||
DebugPort.printf("RTC_Store - save byte 6: Run=%d, Glow=%d\r\n", _RunTime, _GlowTime);
|
||||
uint8_t NVval = ((_GlowTime & 0x07)<<5) | (_RunTime & 0x1f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 6);
|
||||
}
|
||||
|
@ -258,7 +259,7 @@ CRTC_Store::_ReadAndUnpackByte6()
|
|||
_GlowTime = (NVval >> 5) & 0x07;
|
||||
_RunTime = NVval & 0x1f;
|
||||
_accessed[3] = true;
|
||||
DebugPort.printf("RTC_Store - read byte6: glow=%d, run=%d\r\n", _GlowTime, _RunTime);
|
||||
DebugPort.printf("RTC_Store - read byte6: Run=%d, Glow=%d\r\n", _RunTime, _GlowTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,13 @@
|
|||
void
|
||||
CHourMeter::init(bool poweron)
|
||||
{
|
||||
// power on reset or OTA update - cannot trust persistent values - they are likely un-initialised
|
||||
if(poweron) {
|
||||
_RunTime = 0; // definitely untrustworthy after power on or OTA updates
|
||||
_GlowTime = 0;
|
||||
RunTime.reset();
|
||||
GlowTime.reset();
|
||||
}
|
||||
if(_RunTime || _GlowTime || RTC_Store.getRunTime() || RTC_Store.getGlowTime()) {
|
||||
// if there is a remnant time held, add it to the real NV stored value
|
||||
if(RunTime.get() || GlowTime.get() || RTC_Store.getRunTime() || RTC_Store.getGlowTime()) {
|
||||
store();
|
||||
}
|
||||
}
|
||||
|
@ -45,101 +47,110 @@ CHourMeter::reset()
|
|||
{
|
||||
RTC_Store.resetRunTime();
|
||||
RTC_Store.resetGlowTime();
|
||||
_RunTime = 0;
|
||||
_GlowTime = 0;
|
||||
RunTime.reset();
|
||||
GlowTime.reset();
|
||||
}
|
||||
|
||||
void
|
||||
CHourMeter::resetHard()
|
||||
{
|
||||
reset();
|
||||
sHourMeter NV = NVstore.getHourMeter();
|
||||
NV.RunTime = 0;
|
||||
NV.GlowTime = 0;
|
||||
NVstore.setHourMeter(NV);
|
||||
}
|
||||
|
||||
void
|
||||
CHourMeter::store()
|
||||
{
|
||||
sHourMeter NV = NVstore.getHourMeter();
|
||||
NV.RunTime += _RunTime + baseSeconds * RTC_Store.getRunTime(); // add any residual to the real NV stored value
|
||||
NV.GlowTime += _GlowTime + baseSeconds * RTC_Store.getGlowTime();
|
||||
NVstore.setHourMeter(NV);
|
||||
reset();
|
||||
NV.RunTime += RunTime.get() + RTC_storageInterval * RTC_Store.getRunTime(); // add any residual to the real NV stored value
|
||||
NV.GlowTime += GlowTime.get() + RTC_storageInterval * RTC_Store.getGlowTime();
|
||||
NVstore.setHourMeter(NV); // stage new values, and setup for save (if changed)
|
||||
reset(); // zero time tracked in this class
|
||||
}
|
||||
|
||||
void
|
||||
CHourMeter::monitor(const CProtocol& frame)
|
||||
{
|
||||
// long now = Clock.get().secondstime();
|
||||
unsigned long now = millis();
|
||||
if(frame.getRunState() == 0) {
|
||||
// heater is stopped - save remnant times to flash
|
||||
if(_lastRunTime) {
|
||||
store(); // heater hass stopped - save remnant times to flash
|
||||
// heater is stopped
|
||||
if(RunTime.active()) {
|
||||
store(); // initial stop of heater - save residual times to NV
|
||||
}
|
||||
_lastRunTime = 0;
|
||||
_lastGlowTime = 0;
|
||||
RunTime.stop(); // cancel time tracking
|
||||
GlowTime.stop();
|
||||
}
|
||||
else {
|
||||
// heater is running
|
||||
if(_lastRunTime != 0) {
|
||||
// first sample after start is ignored
|
||||
float tDelta = float(now - _lastRunTime) * 0.001;
|
||||
_RunTime += tDelta;
|
||||
unsigned long now = millis();
|
||||
RunTime.recordTime(now); // track run time of heater
|
||||
if(frame.getGlowPlug_Voltage() != 0) {
|
||||
if(_lastGlowTime != 0) {
|
||||
_GlowTime += tDelta;
|
||||
}
|
||||
_lastGlowTime = now;
|
||||
GlowTime.recordTime(now); // track on time of glow plug
|
||||
}
|
||||
else {
|
||||
_lastGlowTime = 0;
|
||||
GlowTime.stop();
|
||||
}
|
||||
}
|
||||
_lastRunTime = now;
|
||||
// check for RAM counters time interval rollover
|
||||
sHourMeter NV = NVstore.getHourMeter();
|
||||
// test for rollover of our local run time tracking
|
||||
if(_RunTime > baseSeconds) {
|
||||
_RunTime -= baseSeconds;
|
||||
if(RTC_Store.incRunTime()) { // returns true if rolled back to zero
|
||||
// rollover run time tracking?
|
||||
if(RunTime.get() > RTC_storageInterval) {
|
||||
RunTime.offset(-RTC_storageInterval);
|
||||
if(RTC_Store.incRunTime()) { // returns true if RTC counter rolled back to zero
|
||||
// rolled RTC intermediate store - push into FLASH
|
||||
NV.RunTime += baseSeconds * RTC_Store.getMaxRunTime(); // bump by our maximum storable time
|
||||
NV.RunTime += RTC_storageInterval * RTC_Store.getMaxRunTime(); // bump NV by our maximum storable time
|
||||
}
|
||||
}
|
||||
// test for rollover of our local glow time tracking
|
||||
if(_GlowTime > baseSeconds) {
|
||||
_GlowTime -= baseSeconds;
|
||||
// rollover glow time tracking?
|
||||
if(GlowTime.get() > RTC_storageInterval) {
|
||||
GlowTime.offset(-RTC_storageInterval);
|
||||
if(RTC_Store.incGlowTime()) { // returns true if rolled back to zero
|
||||
// rolled RTC intermediate store - push into FLASH
|
||||
NV.GlowTime += baseSeconds * RTC_Store.getMaxGlowTime(); // bump by our maximum storable time
|
||||
NV.GlowTime += RTC_storageInterval * RTC_Store.getMaxGlowTime(); // bump NV by our maximum storable time
|
||||
}
|
||||
}
|
||||
NVstore.setHourMeter(NV); // internally moderated, only actually saves if values have changed
|
||||
NVstore.setHourMeter(NV); // internally moderated, will only actually save if a value has changed
|
||||
}
|
||||
// DebugPort.printf("CHourMeter %f %f\r\n", _RunTime, _GlowTime);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CHourMeter::_getLclRunTime()
|
||||
{
|
||||
uint32_t rt = (uint32_t)_RunTime;
|
||||
uint32_t rt = RunTime.get();
|
||||
#ifdef DEBUG_HOURMETER
|
||||
DebugPort.printf("HrMtr _GetLclRunTime(): %d %d\r\n", rt, RTC_Store.getRunTime());
|
||||
return rt + baseSeconds * RTC_Store.getRunTime();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CHourMeter::_getLclGlowTime()
|
||||
{
|
||||
uint32_t gt = (uint32_t)_GlowTime;
|
||||
DebugPort.printf("HrMtr _GetLclGlowTime(): %d %d\r\n", gt, RTC_Store.getGlowTime());
|
||||
return gt + baseSeconds * RTC_Store.getGlowTime();
|
||||
#endif
|
||||
return rt + RTC_storageInterval * RTC_Store.getRunTime();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CHourMeter::getRunTime()
|
||||
{
|
||||
uint32_t rt = _getLclRunTime();
|
||||
#ifdef DEBUG_HOURMETER
|
||||
DebugPort.printf("HrMtr GetRunTime(): %d %d\r\n", rt, NVstore.getHourMeter().RunTime);
|
||||
#endif
|
||||
return rt + NVstore.getHourMeter().RunTime;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CHourMeter::_getLclGlowTime()
|
||||
{
|
||||
uint32_t gt = GlowTime.get();
|
||||
#ifdef DEBUG_HOURMETER
|
||||
DebugPort.printf("HrMtr _GetLclGlowTime(): %d %d\r\n", gt, RTC_Store.getGlowTime());
|
||||
#endif
|
||||
return gt + RTC_storageInterval * RTC_Store.getGlowTime();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CHourMeter::getGlowTime()
|
||||
{
|
||||
uint32_t gt = _getLclGlowTime();
|
||||
DebugPort.printf("HrMtr GetGlowTime(): %d %d\r\n", gt, NVstore.getHourMeter().RunTime);
|
||||
#ifdef DEBUG_HOURMETER
|
||||
DebugPort.printf("HrMtr GetGlowTime(): %d %d\r\n", gt, NVstore.getHourMeter().GlowTime);
|
||||
#endif
|
||||
return gt + NVstore.getHourMeter().GlowTime;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,29 +23,59 @@
|
|||
#include "../RTC/RTCStore.h"
|
||||
#include "NVStorage.h"
|
||||
|
||||
#define DEBUG_HOURMETER
|
||||
|
||||
|
||||
class CProtocol;
|
||||
|
||||
class CHourMeter {
|
||||
const int baseSeconds = 60 * 15; // 15 minutes
|
||||
class sRunTime {
|
||||
float& persistentVal;
|
||||
unsigned long lastSampleTime;
|
||||
public:
|
||||
sRunTime(float& refVal) : persistentVal(refVal) {
|
||||
lastSampleTime = 0;
|
||||
};
|
||||
void reset() {
|
||||
persistentVal = 0;
|
||||
};
|
||||
uint32_t get() const {
|
||||
return (uint32_t)persistentVal;
|
||||
}
|
||||
bool active() const {
|
||||
return lastSampleTime != 0;
|
||||
}
|
||||
void stop() {
|
||||
lastSampleTime = 0;
|
||||
}
|
||||
float recordTime(unsigned long now) {
|
||||
float rVal = 0;
|
||||
if(lastSampleTime)
|
||||
rVal = float((unsigned long)(now - lastSampleTime)) * 0.001;
|
||||
lastSampleTime = now;
|
||||
persistentVal += rVal;
|
||||
return rVal;
|
||||
}
|
||||
void offset(float ofs) {
|
||||
persistentVal += ofs;
|
||||
}
|
||||
|
||||
float& _RunTime;
|
||||
float& _GlowTime;
|
||||
unsigned long _lastRunTime;
|
||||
unsigned long _lastGlowTime;
|
||||
};
|
||||
|
||||
class CHourMeter {
|
||||
const int RTC_storageInterval = 60 * 10; // 10 minutes
|
||||
|
||||
sRunTime RunTime;
|
||||
sRunTime GlowTime;
|
||||
uint32_t _getLclRunTime(); // volatile persistent variable + RTC stored rollovers
|
||||
uint32_t _getLclGlowTime(); // volatile persistent variable + RTC stored rollovers
|
||||
public:
|
||||
CHourMeter(float &runtime, float& glowtime) :
|
||||
_RunTime(runtime),
|
||||
_GlowTime(glowtime)
|
||||
RunTime(runtime),
|
||||
GlowTime(glowtime)
|
||||
{
|
||||
_lastRunTime = 0;
|
||||
_lastGlowTime = 0;
|
||||
DebugPort.printf("CHourMeter %f %f\r\n", _RunTime, _GlowTime);
|
||||
};
|
||||
void associate(float &runtime, float& glowtime) {
|
||||
_RunTime = runtime;
|
||||
_GlowTime = glowtime;
|
||||
#ifdef DEBUG_HOURMETER
|
||||
DebugPort.printf("CHourMeter %d %d\r\n", RunTime.get(), GlowTime.get());
|
||||
#endif
|
||||
};
|
||||
void init(bool poweron);
|
||||
void reset();
|
||||
|
@ -53,6 +83,7 @@ public:
|
|||
void monitor(const CProtocol& frame);
|
||||
uint32_t getRunTime(); // total time, local tracked + last NV stored value
|
||||
uint32_t getGlowTime(); // total time, local tracked + last NV stored value
|
||||
void resetHard();
|
||||
};
|
||||
|
||||
extern CHourMeter* pHourMeter;
|
Loading…
Reference in a new issue