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:
Ray Jones 2019-07-26 22:13:46 +10:00
parent f86ae7cffb
commit d2116fc18c
8 changed files with 174 additions and 85 deletions

View file

@ -458,8 +458,8 @@ void setup() {
// bCyclicEngaged = RTC_Store.getCyclicEngaged(); // 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 :-) 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 pHourMeter->init(bESP32PowerUpInit || RTC_Store.getBootInit()); // ensure persistent memory variable are reset after powerup, or OTA update
RTC_Store.setBootInit(false); RTC_Store.setBootInit(false);
delay(1000); // just to hold the splash screeen for while delay(1000); // just to hold the splash screeen for while
@ -908,7 +908,7 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn() void requestOn()
{ {
if(bHasHtrData && SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) { if(bHasHtrData && (0 == SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()))) {
heaterOn(); heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode RTC_Store.setCyclicEngaged(true); // for cyclic mode
} }
@ -1249,14 +1249,7 @@ void checkDebugCommands()
ESP.restart(); // reset the esp ESP.restart(); // reset the esp
} }
else if(rxVal == ('h' & 0x1f)) { // CTRL-H hourmeter reset else if(rxVal == ('h' & 0x1f)) { // CTRL-H hourmeter reset
sHourMeter FLASHmem = NVstore.getHourMeter(); pHourMeter->resetHard();
FLASHmem.RunTime = 0;
FLASHmem.GlowTime = 0;
NVstore.setHourMeter(FLASHmem);
RTC_Store.resetRunTime();
RTC_Store.resetGlowTime();
persistentRunTime = 0;
persistentGlowTime = 0;
} }
} }
#ifdef PROTOCOL_INVESTIGATION #ifdef PROTOCOL_INVESTIGATION

View file

@ -134,9 +134,43 @@ CScreenHeader::animate()
int xPos = X_BATT_ICON; int xPos = X_BATT_ICON;
int yPos = Y_BATT_ICON; int yPos = Y_BATT_ICON;
showTimers(); 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) { switch(_batteryCount) {
case 3: 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)); showBatteryIcon(getBatteryVoltage(true));
} }
else { else {
@ -147,6 +181,7 @@ CScreenHeader::animate()
showBatteryIcon(getBatteryVoltage(true)); showBatteryIcon(getBatteryVoltage(true));
break; break;
} }
*/
} }
showWifiIcon(); showWifiIcon();

View file

@ -46,6 +46,7 @@ class CScreenHeader : public CScreen {
bool _colon; bool _colon;
uint8_t _animateCount; uint8_t _animateCount;
uint8_t _batteryCount; uint8_t _batteryCount;
uint8_t _batteryWarn;
protected: protected:
void showBTicon(); void showBTicon();
void showWifiIcon(); void showWifiIcon();

View file

@ -113,7 +113,12 @@ CSmartError::monitor(uint8_t newRunState)
_prevRunState = 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) CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
{ {
// check for low voltage // check for low voltage
@ -126,10 +131,22 @@ CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
_Error = 2; // +1 over displayed error code _Error = 2; // +1 over displayed error code
requestOff(); 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;
} }

View file

@ -31,7 +31,7 @@ public:
void inhibit(); void inhibit();
void monitor(const CProtocol& heaterFrame); void monitor(const CProtocol& heaterFrame);
void monitor(uint8_t runstate); 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(); uint8_t getError();
}; };

View file

@ -245,6 +245,7 @@ CRTC_Store::_PackAndSaveByte5()
void void
CRTC_Store::_PackAndSaveByte6() 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); uint8_t NVval = ((_GlowTime & 0x07)<<5) | (_RunTime & 0x1f);
Clock.saveData((uint8_t*)&NVval, 1, 6); Clock.saveData((uint8_t*)&NVval, 1, 6);
} }
@ -258,7 +259,7 @@ CRTC_Store::_ReadAndUnpackByte6()
_GlowTime = (NVval >> 5) & 0x07; _GlowTime = (NVval >> 5) & 0x07;
_RunTime = NVval & 0x1f; _RunTime = NVval & 0x1f;
_accessed[3] = true; _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);
} }
} }

View file

@ -31,11 +31,13 @@
void void
CHourMeter::init(bool poweron) CHourMeter::init(bool poweron)
{ {
if(poweron) { // power on reset or OTA update - cannot trust persistent values - they are likely un-initialised
_RunTime = 0; // definitely untrustworthy after power on or OTA updates if(poweron) {
_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(); store();
} }
} }
@ -45,101 +47,110 @@ CHourMeter::reset()
{ {
RTC_Store.resetRunTime(); RTC_Store.resetRunTime();
RTC_Store.resetGlowTime(); RTC_Store.resetGlowTime();
_RunTime = 0; RunTime.reset();
_GlowTime = 0; GlowTime.reset();
}
void
CHourMeter::resetHard()
{
reset();
sHourMeter NV = NVstore.getHourMeter();
NV.RunTime = 0;
NV.GlowTime = 0;
NVstore.setHourMeter(NV);
} }
void void
CHourMeter::store() CHourMeter::store()
{ {
sHourMeter NV = NVstore.getHourMeter(); sHourMeter NV = NVstore.getHourMeter();
NV.RunTime += _RunTime + baseSeconds * RTC_Store.getRunTime(); // add any residual to the real NV stored value NV.RunTime += RunTime.get() + RTC_storageInterval * RTC_Store.getRunTime(); // add any residual to the real NV stored value
NV.GlowTime += _GlowTime + baseSeconds * RTC_Store.getGlowTime(); NV.GlowTime += GlowTime.get() + RTC_storageInterval * RTC_Store.getGlowTime();
NVstore.setHourMeter(NV); NVstore.setHourMeter(NV); // stage new values, and setup for save (if changed)
reset(); reset(); // zero time tracked in this class
} }
void void
CHourMeter::monitor(const CProtocol& frame) CHourMeter::monitor(const CProtocol& frame)
{ {
// long now = Clock.get().secondstime();
unsigned long now = millis();
if(frame.getRunState() == 0) { if(frame.getRunState() == 0) {
// heater is stopped - save remnant times to flash // heater is stopped
if(_lastRunTime) { if(RunTime.active()) {
store(); // heater hass stopped - save remnant times to flash store(); // initial stop of heater - save residual times to NV
} }
_lastRunTime = 0; RunTime.stop(); // cancel time tracking
_lastGlowTime = 0; GlowTime.stop();
} }
else { else {
// heater is running // heater is running
if(_lastRunTime != 0) { unsigned long now = millis();
// first sample after start is ignored RunTime.recordTime(now); // track run time of heater
float tDelta = float(now - _lastRunTime) * 0.001; if(frame.getGlowPlug_Voltage() != 0) {
_RunTime += tDelta; GlowTime.recordTime(now); // track on time of glow plug
if(frame.getGlowPlug_Voltage() != 0) {
if(_lastGlowTime != 0) {
_GlowTime += tDelta;
}
_lastGlowTime = now;
}
else {
_lastGlowTime = 0;
}
} }
_lastRunTime = now; else {
GlowTime.stop();
}
// check for RAM counters time interval rollover
sHourMeter NV = NVstore.getHourMeter(); sHourMeter NV = NVstore.getHourMeter();
// test for rollover of our local run time tracking // rollover run time tracking?
if(_RunTime > baseSeconds) { if(RunTime.get() > RTC_storageInterval) {
_RunTime -= baseSeconds; RunTime.offset(-RTC_storageInterval);
if(RTC_Store.incRunTime()) { // returns true if rolled back to zero if(RTC_Store.incRunTime()) { // returns true if RTC counter rolled back to zero
// rolled RTC intermediate store - push into FLASH // 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 // rollover glow time tracking?
if(_GlowTime > baseSeconds) { if(GlowTime.get() > RTC_storageInterval) {
_GlowTime -= baseSeconds; GlowTime.offset(-RTC_storageInterval);
if(RTC_Store.incGlowTime()) { // returns true if rolled back to zero if(RTC_Store.incGlowTime()) { // returns true if rolled back to zero
// rolled RTC intermediate store - push into FLASH // 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 uint32_t
CHourMeter::_getLclRunTime() 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()); DebugPort.printf("HrMtr _GetLclRunTime(): %d %d\r\n", rt, RTC_Store.getRunTime());
return rt + baseSeconds * RTC_Store.getRunTime(); #endif
} return rt + RTC_storageInterval * 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();
} }
uint32_t uint32_t
CHourMeter::getRunTime() CHourMeter::getRunTime()
{ {
uint32_t rt = _getLclRunTime(); uint32_t rt = _getLclRunTime();
#ifdef DEBUG_HOURMETER
DebugPort.printf("HrMtr GetRunTime(): %d %d\r\n", rt, NVstore.getHourMeter().RunTime); DebugPort.printf("HrMtr GetRunTime(): %d %d\r\n", rt, NVstore.getHourMeter().RunTime);
#endif
return rt + NVstore.getHourMeter().RunTime; 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 uint32_t
CHourMeter::getGlowTime() CHourMeter::getGlowTime()
{ {
uint32_t gt = _getLclGlowTime(); 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; return gt + NVstore.getHourMeter().GlowTime;
} }

View file

@ -23,29 +23,59 @@
#include "../RTC/RTCStore.h" #include "../RTC/RTCStore.h"
#include "NVStorage.h" #include "NVStorage.h"
#define DEBUG_HOURMETER
class CProtocol; class CProtocol;
class CHourMeter { class sRunTime {
const int baseSeconds = 60 * 15; // 15 minutes 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; class CHourMeter {
unsigned long _lastGlowTime; const int RTC_storageInterval = 60 * 10; // 10 minutes
sRunTime RunTime;
sRunTime GlowTime;
uint32_t _getLclRunTime(); // volatile persistent variable + RTC stored rollovers uint32_t _getLclRunTime(); // volatile persistent variable + RTC stored rollovers
uint32_t _getLclGlowTime(); // volatile persistent variable + RTC stored rollovers uint32_t _getLclGlowTime(); // volatile persistent variable + RTC stored rollovers
public: public:
CHourMeter(float &runtime, float& glowtime) : CHourMeter(float &runtime, float& glowtime) :
_RunTime(runtime), RunTime(runtime),
_GlowTime(glowtime) GlowTime(glowtime)
{ {
_lastRunTime = 0; #ifdef DEBUG_HOURMETER
_lastGlowTime = 0; DebugPort.printf("CHourMeter %d %d\r\n", RunTime.get(), GlowTime.get());
DebugPort.printf("CHourMeter %f %f\r\n", _RunTime, _GlowTime); #endif
};
void associate(float &runtime, float& glowtime) {
_RunTime = runtime;
_GlowTime = glowtime;
}; };
void init(bool poweron); void init(bool poweron);
void reset(); void reset();
@ -53,6 +83,7 @@ public:
void monitor(const CProtocol& frame); void monitor(const CProtocol& frame);
uint32_t getRunTime(); // total time, local tracked + last NV stored value uint32_t getRunTime(); // total time, local tracked + last NV stored value
uint32_t getGlowTime(); // total time, local tracked + last NV stored value uint32_t getGlowTime(); // total time, local tracked + last NV stored value
void resetHard();
}; };
extern CHourMeter* pHourMeter; extern CHourMeter* pHourMeter;