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();
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->init(bESP32PowerUpInit || RTC_Store.getBootInit()); // ensure persistent memory variable are reset after powerup, or OTA update
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);
delay(1000); // just to hold the splash screeen for while
@ -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

View File

@ -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();

View File

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

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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);
}
}

View File

@ -31,11 +31,13 @@
void
CHourMeter::init(bool poweron)
{
if(poweron) {
_RunTime = 0; // definitely untrustworthy after power on or OTA updates
_GlowTime = 0;
// power on reset or OTA update - cannot trust persistent values - they are likely un-initialised
if(poweron) {
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;
if(frame.getGlowPlug_Voltage() != 0) {
if(_lastGlowTime != 0) {
_GlowTime += tDelta;
}
_lastGlowTime = now;
}
else {
_lastGlowTime = 0;
}
unsigned long now = millis();
RunTime.recordTime(now); // track run time of heater
if(frame.getGlowPlug_Voltage() != 0) {
GlowTime.recordTime(now); // track on time of glow plug
}
_lastRunTime = now;
else {
GlowTime.stop();
}
// 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;
}

View File

@ -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;