diff --git a/Arduino/Afterburner/Afterburner.ino b/Arduino/Afterburner/Afterburner.ino index b033a45..57a18d0 100644 --- a/Arduino/Afterburner/Afterburner.ino +++ b/Arduino/Afterburner/Afterburner.ino @@ -99,6 +99,7 @@ #include "src/Utility/helpers.h" #include "src/Utility/NVStorage.h" #include "src/Utility/DebugPort.h" +#include "src/Utility/macros.h" #include "src/Utility/UtilClasses.h" #include "src/Utility/BTC_JSON.h" #include "src/Utility/BTC_GPIO.h" @@ -446,7 +447,11 @@ void setup() { FilteredSamples.Fan.setRounding(10); FilteredSamples.Fan.setAlpha(0.7); FilteredSamples.AmbientTemp.reset(-100.0); - + FilteredSamples.FastipVolts.setRounding(0.1); + FilteredSamples.FastipVolts.setAlpha(0.7); + FilteredSamples.FastGlowAmps.setRounding(0.01); + FilteredSamples.FastGlowAmps.setAlpha(0.7); + RTC_Store.begin(); FuelGauge.init(RTC_Store.getFuelGauge()); // demandDegC = RTC_Store.getDesiredTemp(); @@ -796,6 +801,9 @@ void loop() updateFilteredData(); FuelGauge.Integrate(HeaterFrame2.getPump_Actual()); } + if(INBOUNDS(HeaterFrame2.getRunState(), 1, 5)) { // check for Low Voltage Cutout + SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()); + } updateJSONclients(bReportJSONData); CommState.set(CommStates::Idle); NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity @@ -822,7 +830,7 @@ void manageCyclicMode() const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic; if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // cyclic mode enabled, and user has started heater int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over! - float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC(); + float deltaT = getTemperatureSensor() - getDemandDegC(); // DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT); // ensure we cancel user ON mode if heater throws an error @@ -883,8 +891,10 @@ bool validateFrame(const CProtocol& frame, const char* name) void requestOn() { - heaterOn(); - RTC_Store.setCyclicEngaged(true); // for cyclic mode + if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) { + heaterOn(); + RTC_Store.setCyclicEngaged(true); // for cyclic mode + } } void requestOff() @@ -1041,7 +1051,7 @@ float getTemperatureDesired() float getTemperatureSensor() { - return FilteredSamples.AmbientTemp.getValue(); + return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs; } void setPumpMin(float val) @@ -1449,12 +1459,15 @@ void simulateGPIOin(uint8_t newKey) GPIOin.simulateKey(newKey); } -float getBatteryVoltage() +float getBatteryVoltage(bool fast) { #ifdef RAW_SAMPLES return getHeaterInfo().getBattVoltage(); #else - return FilteredSamples.ipVolts.getValue(); + if(fast) + return FilteredSamples.FastipVolts.getValue(); + else + return FilteredSamples.ipVolts.getValue(); #endif } @@ -1491,6 +1504,8 @@ void updateFilteredData() FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); + FilteredSamples.FastipVolts.update(HeaterFrame2.getVoltage_Supply()); + FilteredSamples.FastGlowAmps.update(HeaterFrame2.getGlowPlug_Current()); } int sysUptime() diff --git a/README.md b/README.md index afa12d8..690a7e8 100644 --- a/README.md +++ b/README.md @@ -51,15 +51,15 @@ Working so far: Web browser upload new binary to controller (AP or STA mode) Direct discovery and download of updates from internet server (STA mode) * Factory default menu option +* "Fuel gauge" - Integrates pump frequency, assumes a repeatable dose of fuel per pump stroke. +* Low voltage cut out, definable threshold - auto adjusts for cable voltage drop during start +* Temperature probe offset to correct adverse readings. To be implemented -------------------------- * 433MHz Rx stream, 433MHz Tx stream connections. This would allow external timer units for example, or analogue temperature demand (which is still only 1 degree resolution with standard heater thermostat). -* Low voltage cut out -* Temperature probe offset or mapping to correct adverse readings. * MQTT pub/sub -* "fuel gauge" - Integrate pump frequency, assuming a repeatable dose of fuel per pump cycle... * Regular Hot Burn cycle (DPF mode!) * Hour meter - run time, glow time * list under construction..... diff --git a/icons/BatteryIcon.bmp b/icons/BatteryIcon.bmp index 5cf003a..fdd9ec9 100644 Binary files a/icons/BatteryIcon.bmp and b/icons/BatteryIcon.bmp differ diff --git a/icons/FuelIcon.bmp b/icons/FuelIcon.bmp index a590cf3..cd72aec 100644 Binary files a/icons/FuelIcon.bmp and b/icons/FuelIcon.bmp differ diff --git a/icons/FuelIconSmall.bmp b/icons/FuelIconSmall.bmp new file mode 100644 index 0000000..5dba1b2 Binary files /dev/null and b/icons/FuelIconSmall.bmp differ diff --git a/icons/MiniThermo.bmp b/icons/MiniThermo.bmp new file mode 100644 index 0000000..91aa1d4 Binary files /dev/null and b/icons/MiniThermo.bmp differ diff --git a/src/Afterburner/Afterburner.cpp b/src/Afterburner/Afterburner.cpp index b033a45..57a18d0 100644 --- a/src/Afterburner/Afterburner.cpp +++ b/src/Afterburner/Afterburner.cpp @@ -99,6 +99,7 @@ #include "src/Utility/helpers.h" #include "src/Utility/NVStorage.h" #include "src/Utility/DebugPort.h" +#include "src/Utility/macros.h" #include "src/Utility/UtilClasses.h" #include "src/Utility/BTC_JSON.h" #include "src/Utility/BTC_GPIO.h" @@ -446,7 +447,11 @@ void setup() { FilteredSamples.Fan.setRounding(10); FilteredSamples.Fan.setAlpha(0.7); FilteredSamples.AmbientTemp.reset(-100.0); - + FilteredSamples.FastipVolts.setRounding(0.1); + FilteredSamples.FastipVolts.setAlpha(0.7); + FilteredSamples.FastGlowAmps.setRounding(0.01); + FilteredSamples.FastGlowAmps.setAlpha(0.7); + RTC_Store.begin(); FuelGauge.init(RTC_Store.getFuelGauge()); // demandDegC = RTC_Store.getDesiredTemp(); @@ -796,6 +801,9 @@ void loop() updateFilteredData(); FuelGauge.Integrate(HeaterFrame2.getPump_Actual()); } + if(INBOUNDS(HeaterFrame2.getRunState(), 1, 5)) { // check for Low Voltage Cutout + SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()); + } updateJSONclients(bReportJSONData); CommState.set(CommStates::Idle); NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity @@ -822,7 +830,7 @@ void manageCyclicMode() const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic; if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // cyclic mode enabled, and user has started heater int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over! - float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC(); + float deltaT = getTemperatureSensor() - getDemandDegC(); // DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT); // ensure we cancel user ON mode if heater throws an error @@ -883,8 +891,10 @@ bool validateFrame(const CProtocol& frame, const char* name) void requestOn() { - heaterOn(); - RTC_Store.setCyclicEngaged(true); // for cyclic mode + if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) { + heaterOn(); + RTC_Store.setCyclicEngaged(true); // for cyclic mode + } } void requestOff() @@ -1041,7 +1051,7 @@ float getTemperatureDesired() float getTemperatureSensor() { - return FilteredSamples.AmbientTemp.getValue(); + return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs; } void setPumpMin(float val) @@ -1449,12 +1459,15 @@ void simulateGPIOin(uint8_t newKey) GPIOin.simulateKey(newKey); } -float getBatteryVoltage() +float getBatteryVoltage(bool fast) { #ifdef RAW_SAMPLES return getHeaterInfo().getBattVoltage(); #else - return FilteredSamples.ipVolts.getValue(); + if(fast) + return FilteredSamples.FastipVolts.getValue(); + else + return FilteredSamples.ipVolts.getValue(); #endif } @@ -1491,6 +1504,8 @@ void updateFilteredData() FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); + FilteredSamples.FastipVolts.update(HeaterFrame2.getVoltage_Supply()); + FilteredSamples.FastGlowAmps.update(HeaterFrame2.getGlowPlug_Current()); } int sysUptime() diff --git a/src/Afterburner/src/OLED/BasicScreen.cpp b/src/Afterburner/src/OLED/BasicScreen.cpp index 9538c88..d643eb3 100644 --- a/src/Afterburner/src/OLED/BasicScreen.cpp +++ b/src/Afterburner/src/OLED/BasicScreen.cpp @@ -50,7 +50,7 @@ CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen bool CBasicScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); char msg[20]; int xPos, yPos; diff --git a/src/Afterburner/src/OLED/ClockScreen.cpp b/src/Afterburner/src/OLED/ClockScreen.cpp index a16c40e..9fcb39a 100644 --- a/src/Afterburner/src/OLED/ClockScreen.cpp +++ b/src/Afterburner/src/OLED/ClockScreen.cpp @@ -43,10 +43,11 @@ CClockScreen::CClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen } + bool CClockScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); const BTCDateTime& now = Clock.get(); diff --git a/src/Afterburner/src/OLED/DetailedScreen.cpp b/src/Afterburner/src/OLED/DetailedScreen.cpp index 414ff42..4532436 100644 --- a/src/Afterburner/src/OLED/DetailedScreen.cpp +++ b/src/Afterburner/src/OLED/DetailedScreen.cpp @@ -82,7 +82,7 @@ CDetailedScreen::CDetailedScreen(C128x64_OLED& display, CScreenManager& mgr) : C bool CDetailedScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); int runstate = getHeaterInfo().getRunStateEx(); int errstate = getHeaterInfo().getErrState(); @@ -133,7 +133,7 @@ CDetailedScreen::show() } if(!bGlowActive) { - showBowser(FuelGauge.Used_ml()); + showBowser(FuelGauge.Used_mL()); } showRunState(runstate, errstate); return true; diff --git a/src/Afterburner/src/OLED/FuelCalScreen.h b/src/Afterburner/src/OLED/FuelCalScreen.h new file mode 100644 index 0000000..8bbe878 --- /dev/null +++ b/src/Afterburner/src/OLED/FuelCalScreen.h @@ -0,0 +1,48 @@ +/* + * This file is part of the "bluetoothheater" distribution + * (https://gitlab.com/mrjones.id.au/bluetoothheater) + * + * Copyright (C) 2018 Ray Jones + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __FUELCALSCREEN_H__ +#define __FUELCALSCREEN_H__ + +#include +#include "PasswordScreen.h" + +class C128x64_OLED; +class CScreenManager; + +class CFuelCalScreen : public CPasswordScreen +{ + int _rowSel; + void _adjust(int dir); + float _mlPerStroke; + float _tOfs; + uint8_t _LVC; + int _animateCount; + void _initUI(); +public: + CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr); + bool show(); + bool animate(); + bool keyHandler(uint8_t event); + void onSelect(); +}; + +#endif diff --git a/src/Afterburner/src/OLED/FuelMixtureScreen.cpp b/src/Afterburner/src/OLED/FuelMixtureScreen.cpp index 0f12062..8347ffe 100644 --- a/src/Afterburner/src/OLED/FuelMixtureScreen.cpp +++ b/src/Afterburner/src/OLED/FuelMixtureScreen.cpp @@ -34,6 +34,7 @@ #include "../Utility/DebugPort.h" #include "../Utility/macros.h" #include "../Protocol/Protocol.h" +#include "fonts/Icons.h" CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr) @@ -47,6 +48,12 @@ CFuelMixtureScreen::onSelect() CPasswordScreen::onSelect(); _initUI(); + _load(); +} + +void +CFuelMixtureScreen::_load() +{ adjPump[0] = getHeaterInfo().getPump_Min(); adjPump[1] = getHeaterInfo().getPump_Max(); adjFan[0] = getHeaterInfo().getFan_Min(); @@ -58,6 +65,7 @@ CFuelMixtureScreen::_initUI() { _rowSel = 0; _colSel = 0; + _animateCount = 0; } bool @@ -67,34 +75,40 @@ CFuelMixtureScreen::show() int xPos, yPos; const int col3 = _display.width() - border; - _display.clearDisplay(); + _display.fillRect(70, 0, 58, 64, BLACK); // scrub variables + _display.fillRect(0, 50, 128, 14, BLACK); // scrub footer if(!CPasswordScreen::show()) { + switch(_rowSel) { case 0: case 1: case 2: case 3: case 4: + if(_animateCount == -1) { + _animateCount = 0; + _display.clearDisplay(); + } // Pump Minimum adjustment yPos = border + 36; - _printMenuText(80, yPos, "Min", false, eRightJustify); - sprintf(str, "%.1f", adjPump[0]); + _printMenuText(65, yPos, "Min", false, eRightJustify); + sprintf(str, "%.1f Hz", adjPump[0]); _printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify); // Pump Maximum adjustment yPos = border + 24; - _printMenuText(80, yPos, "Pump Hz Max", false, eRightJustify); - sprintf(str, "%.1f", adjPump[1]); + _printMenuText(65, yPos, "Max", false, eRightJustify); + sprintf(str, "%.1f Hz", adjPump[1]); _printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify); // Fan Minimum adjustment yPos = border + 12; - _printMenuText(80, yPos, "Min", false, eRightJustify); - sprintf(str, "%d", adjFan[0]); + _printMenuText(65, yPos, "Min", false, eRightJustify); + sprintf(str, "%d RPM", adjFan[0]); _printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify); // Fan Maximum adjustment yPos = border; - _printMenuText(80, yPos, "Fan RPM Max", false, eRightJustify); - sprintf(str, "%d", adjFan[1]); + _printMenuText(65, yPos, "Max", false, eRightJustify); + sprintf(str, "%d RPM", adjFan[1]); _printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify); // navigation line yPos = 53; @@ -128,6 +142,29 @@ CFuelMixtureScreen::show() return true; } +bool +CFuelMixtureScreen::animate() +{ + if(_animateCount >= 0) { + + int xPos = 20; + int yPos = 5; + int yFuel = 30; + _display.fillRect(xPos, yPos, FanIcon1Info.width, FanIcon1Info.height, BLACK); + _display.fillRect(xPos+5, yFuel, FuelIconInfo.width, FuelIconInfo.height + 4, BLACK); + _drawBitmap(xPos+5, yFuel+_animateCount, FuelIconInfo); + switch(_animateCount) { + case 0: _drawBitmap(xPos, yPos, FanIcon1Info); break; + case 1: _drawBitmap(xPos, yPos, FanIcon2Info); break; + case 2: _drawBitmap(xPos, yPos, FanIcon3Info); break; + case 3: _drawBitmap(xPos, yPos, FanIcon4Info); break; + } + + _animateCount++; + WRAPUPPERLIMIT(_animateCount, 3, 0); + } + return true; +} bool CFuelMixtureScreen::keyHandler(uint8_t event) @@ -143,6 +180,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event) case 2: case 3: case 4: + _animateCount = -1; + _display.clearDisplay(); _rowSel = 5; // enter save confirm mode break; case 5: @@ -204,6 +243,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event) UPPERLIMIT(_rowSel, 4); break; case 5: + _display.clearDisplay(); + _animateCount = -1; _showStoringMessage(); setPumpMin(adjPump[0]); setPumpMax(adjPump[1]); @@ -233,7 +274,10 @@ CFuelMixtureScreen::keyHandler(uint8_t event) _ScreenManager.reqUpdate(); } - + if(_rowSel == 0) { + _load(); // dispose of any changes, re-obtain current settings + } + if(event & keyRepeat) { switch(_rowSel) { case 1: diff --git a/src/Afterburner/src/OLED/FuelMixtureScreen.h b/src/Afterburner/src/OLED/FuelMixtureScreen.h index 44d5ea1..25f563f 100644 --- a/src/Afterburner/src/OLED/FuelMixtureScreen.h +++ b/src/Afterburner/src/OLED/FuelMixtureScreen.h @@ -33,12 +33,15 @@ class CFuelMixtureScreen : public CPasswordScreen { uint16_t adjFan[2]; int _rowSel; int _colSel; + int _animateCount; void _adjustSetting(int dir); void _initUI(); + void _load(); public: CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr); bool show(); + bool animate(); bool keyHandler(uint8_t event); void onSelect(); }; diff --git a/src/Afterburner/src/OLED/GPIOScreen.cpp b/src/Afterburner/src/OLED/GPIOScreen.cpp index f75d904..f160c95 100644 --- a/src/Afterburner/src/OLED/GPIOScreen.cpp +++ b/src/Afterburner/src/OLED/GPIOScreen.cpp @@ -291,12 +291,6 @@ CGPIOInfoScreen::CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : C _keyRepeatCount = -1; } -void -CGPIOInfoScreen::onSelect() -{ - CScreenHeader::onSelect(); -} - void CGPIOInfoScreen::_initUI() { @@ -305,7 +299,7 @@ CGPIOInfoScreen::_initUI() bool CGPIOInfoScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); char msg[16]; _display.writeFillRect(49, 18, 30, 12, WHITE); diff --git a/src/Afterburner/src/OLED/GPIOScreen.h b/src/Afterburner/src/OLED/GPIOScreen.h index fdcceb5..7ad720f 100644 --- a/src/Afterburner/src/OLED/GPIOScreen.h +++ b/src/Afterburner/src/OLED/GPIOScreen.h @@ -53,7 +53,6 @@ public: CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr); bool show(); bool keyHandler(uint8_t event); - void onSelect(); }; #endif diff --git a/src/Afterburner/src/OLED/HeaterSettingsScreen.cpp b/src/Afterburner/src/OLED/HeaterSettingsScreen.cpp index f481b7d..f2c1c50 100644 --- a/src/Afterburner/src/OLED/HeaterSettingsScreen.cpp +++ b/src/Afterburner/src/OLED/HeaterSettingsScreen.cpp @@ -21,11 +21,13 @@ #include "128x64OLED.h" #include "HeaterSettingsScreen.h" +#include "FuelCalScreen.h" #include "KeyPad.h" #include "../Utility/helpers.h" #include "../Utility/macros.h" #include "../Utility/NVStorage.h" #include "../Protocol/Protocol.h" +#include "fonts/Icons.h" /////////////////////////////////////////////////////////////////////////// // @@ -264,6 +266,8 @@ CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPa { _initUI(); _mlPerStroke = 0.02; + _LVC = 115; + _tOfs = 0; } void @@ -272,6 +276,8 @@ CFuelCalScreen::onSelect() CPasswordScreen::onSelect(); _initUI(); _mlPerStroke = NVstore.getHeaterTuning().pumpCal; + _LVC = NVstore.getHeaterTuning().lowVolts; + _tOfs = NVstore.getHeaterTuning().tempOfs; } void @@ -285,7 +291,10 @@ bool CFuelCalScreen::show() { char msg[20]; - _display.clearDisplay(); + const int col = 90; + + _display.fillRect(0, 50, 128, 14, BLACK); + _display.fillRect(col-border, Line3-border, 128-(col-1), 64-Line3-border, BLACK); if(!CPasswordScreen::show()) { // for showing "saving settings" @@ -295,13 +304,31 @@ CFuelCalScreen::show() _printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify); } else { - int col = 80; - _printInverted(_display.xCentre(), 0, " Fuel Calibration ", true, eCentreJustify); - _printMenuText(col, Line1, "ml / stroke:", false, eRightJustify); + if(_animateCount < 0) { + _display.clearDisplay(); + _animateCount = 0; + } + _printInverted(_display.xCentre(), 0, " Special Features ", true, eCentreJustify); + // fuel calibration + int yPos = Line1; + _printMenuText(col, yPos, "mL/stroke : ", false, eRightJustify); sprintf(msg, "%.03f", _mlPerStroke); - _printMenuText(col+1, Line1, msg, _rowSel == 1); + _printMenuText(col, yPos, msg, _rowSel == 1); + // low voltage cutout + yPos = Line2; + _printMenuText(col, yPos, "L.V.C. < ", false, eRightJustify); + if(_LVC) + sprintf(msg, "%.1fV", float(_LVC) * 0.1); + else + strcpy(msg, "OFF"); + _printMenuText(col, yPos, msg, _rowSel == 2); + // temp offset + yPos = Line3; + _printMenuText(col, yPos, "\367C offset : ", false, eRightJustify); + sprintf(msg, "%+.1f", _tOfs); + _printMenuText(col, yPos, msg, _rowSel == 3); // navigation line - int yPos = 53; + yPos = 53; int xPos = _display.xCentre(); switch(_rowSel) { @@ -324,43 +351,44 @@ CFuelCalScreen::show() bool CFuelCalScreen::animate() { -/* char msg[16]; + if(_animateCount >= 0) { + switch(_animateCount) { + case 0: + _display.fillRect(0, Line3-4, BatteryIconInfo.width, 40, BLACK); + _drawBitmap(6, Line1-3, FuelIconSmallInfo); + _drawBitmap(0, Line2-1 , BatteryIconInfo); + _drawBitmap(5, Line3-4, miniThermoIconInfo); + break; + case 2: + _display.fillRect(6, Line1-3, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip + _drawBitmap(6, Line1-2, FuelIconSmallInfo); // drip fuel + _display.fillRect(BatteryIconInfo.width - 4, Line2+2, 2, 5, BLACK); // deplete battery + _display.fillRect(7, Line3+2, 2, 2, WHITE); // grow thermometer + break; + case 4: + _display.fillRect(6, Line1-2, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip + _drawBitmap(6, Line1-1, FuelIconSmallInfo); // drip fuel + _display.fillRect(BatteryIconInfo.width - 7, Line2+2, 2, 5, BLACK); // deplete battery + _display.fillRect(7, Line3+1, 2, 1, WHITE); // grow thermometer + break; + case 6: + _display.fillRect(6, Line1-1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip + _drawBitmap(6, Line1, FuelIconSmallInfo); // drip fuel + _display.fillRect(BatteryIconInfo.width - 10, Line2+2, 2, 5, BLACK); // deplete battery + _display.fillRect(7, Line3, 2, 1, WHITE); // grow thermometer + break; + case 8: + _display.fillRect(6, Line1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip + _drawBitmap(6, Line1+1, FuelIconSmallInfo); // drip fuel + _display.fillRect(BatteryIconInfo.width - 13, Line2+2, 2, 5, BLACK); // deplete battery + _display.fillRect(7, Line3-1, 2, 1, WHITE); // grow thermometer + break; + } - if(isPasswordBusy() || (_rowSel == 4)) { // Password screen activity - _printMenuText(Column, Line2, " "); - _printMenuText(Column, Line1, " "); - if(_rowSel == 4) - _printMenuText(_display.xCentre(), 43, "Confirm save", false, eCentreJustify); - } - else { _animateCount++; WRAPUPPERLIMIT(_animateCount, 9, 0); + } - if(_rowSel == 1) { - _display.drawRect(Column-border, Line1-border, 34, 8+2*border, BLACK); - _display.drawRoundRect(Column-border, Line1-border, 34, 8+2*border, radius, WHITE); - } - else { - _printMenuText(Column, Line1, " "); - } - - if(_animateCount < 4) - sprintf(msg, "PF-%d ", _glowDrive); - else - sprintf(msg, "(%dW)", plugPowers[_glowDrive-1]); - _printMenuText(Column, Line1, msg); - - int xPos = Column; - _printMenuText(xPos, Line2, " ", _rowSel == 2); // erase, but create selection loop - if(_animateCount < 4) { - sprintf(msg, "SN-%d", _fanSensor); - _printMenuText(Column, Line2, msg); - } - else { - sprintf(msg, "(\365%d)", _fanSensor); // \365 is division character - _printMenuText(xPos, Line2, msg); - } - }*/ return true; } @@ -370,6 +398,15 @@ CFuelCalScreen::keyHandler(uint8_t event) { sHeaterTuning tuning; + if(event & keyRepeat) { + if(event & key_Left) { + _adjust(-1); + } + if(event & key_Right) { + _adjust(+1); + } + } + if(event & keyPressed) { // press LEFT to select previous screen if(event & key_Left) { @@ -418,9 +455,13 @@ CFuelCalScreen::keyHandler(uint8_t event) UPPERLIMIT(_rowSel, 3); break; case 4: // confirmed save + _display.clearDisplay(); + _animateCount = -1; _showStoringMessage(); tuning = NVstore.getHeaterTuning(); tuning.pumpCal = _mlPerStroke; + tuning.lowVolts = _LVC; + tuning.tempOfs = _tOfs; NVstore.setHeaterTuning(tuning); saveNV(); _rowSel = 0; @@ -436,6 +477,8 @@ CFuelCalScreen::keyHandler(uint8_t event) case 1: case 2: case 3: + _animateCount = -1; + _display.clearDisplay(); _rowSel = 4; break; } @@ -452,10 +495,34 @@ CFuelCalScreen::_adjust(int dir) switch(_rowSel) { case 1: _mlPerStroke += dir * 0.001; + BOUNDSLIMIT(_mlPerStroke, 0.001, 1); break; - case 2: + case 2: + if(_LVC == 0) { + if(NVstore.getHeaterTuning().sysVoltage == 120) + _LVC = dir > 0 ? 115 : 0; + else + _LVC = dir > 0 ? 230 : 0; + } + else { + _LVC += dir; + if(NVstore.getHeaterTuning().sysVoltage == 120) { + if(_LVC < 100) + _LVC = 0; + else + UPPERLIMIT(_LVC, 125); + } + else { + if(_LVC < 200) + _LVC = 0; + else + UPPERLIMIT(_LVC, 250); + } + } break; - case 3: + case 3: + _tOfs += dir * 0.1; + BOUNDSLIMIT(_tOfs, -10, 10); break; } } diff --git a/src/Afterburner/src/OLED/HeaterSettingsScreen.h b/src/Afterburner/src/OLED/HeaterSettingsScreen.h index fd1b6b4..36f439a 100644 --- a/src/Afterburner/src/OLED/HeaterSettingsScreen.h +++ b/src/Afterburner/src/OLED/HeaterSettingsScreen.h @@ -45,19 +45,4 @@ public: void onSelect(); }; -class CFuelCalScreen : public CPasswordScreen -{ - int _rowSel; - void _adjust(int dir); - float _mlPerStroke; - int _animateCount; - void _initUI(); -public: - CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr); - bool show(); - bool animate(); - bool keyHandler(uint8_t event); - void onSelect(); -}; - #endif diff --git a/src/Afterburner/src/OLED/InheritSettingsScreen.cpp b/src/Afterburner/src/OLED/InheritSettingsScreen.cpp index d68e8f2..be5fb5a 100644 --- a/src/Afterburner/src/OLED/InheritSettingsScreen.cpp +++ b/src/Afterburner/src/OLED/InheritSettingsScreen.cpp @@ -57,7 +57,7 @@ CInheritSettingsScreen::_initUI() bool CInheritSettingsScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); _display.writeFillRect(0, 16, 96, 12, WHITE); _printInverted(3, 18, "Inherit Settings", true); diff --git a/src/Afterburner/src/OLED/PasswordScreen.cpp b/src/Afterburner/src/OLED/PasswordScreen.cpp index 8bb808d..f1d890d 100644 --- a/src/Afterburner/src/OLED/PasswordScreen.cpp +++ b/src/Afterburner/src/OLED/PasswordScreen.cpp @@ -41,6 +41,7 @@ CPasswordScreen::CPasswordScreen(C128x64_OLED& display, CScreenManager& mgr) : C void CPasswordScreen::onSelect() { + CScreenHeader::onSelect(); _initUI(); } diff --git a/src/Afterburner/src/OLED/PrimingScreen.cpp b/src/Afterburner/src/OLED/PrimingScreen.cpp index 9a2f48f..0a0674f 100644 --- a/src/Afterburner/src/OLED/PrimingScreen.cpp +++ b/src/Afterburner/src/OLED/PrimingScreen.cpp @@ -46,6 +46,7 @@ CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CSc void CPrimingScreen::onSelect() { + CScreenHeader::onSelect(); _stopPump(); _initUI(); } @@ -69,7 +70,7 @@ CPrimingScreen::_initUI() bool CPrimingScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); CRect extents; @@ -200,7 +201,7 @@ CPrimingScreen::show() } else { char msg[16]; - sprintf(msg, "%.02fL", FuelGauge.Used_ml() * 0.001); + sprintf(msg, "%.02fL", FuelGauge.Used_mL() * 0.001); _printMenuText(loc.xPos+1, midline+3, msg); } diff --git a/src/Afterburner/src/OLED/Screen.cpp b/src/Afterburner/src/OLED/Screen.cpp index a2b40ba..5bc8d52 100644 --- a/src/Afterburner/src/OLED/Screen.cpp +++ b/src/Afterburner/src/OLED/Screen.cpp @@ -63,6 +63,7 @@ CScreen::show() void CScreen::onSelect() { + _display.clearDisplay(); } void diff --git a/src/Afterburner/src/OLED/ScreenHeader.cpp b/src/Afterburner/src/OLED/ScreenHeader.cpp index 5f08d95..2d5c602 100644 --- a/src/Afterburner/src/OLED/ScreenHeader.cpp +++ b/src/Afterburner/src/OLED/ScreenHeader.cpp @@ -31,6 +31,8 @@ #include "fonts/Icons.h" #include "fonts/MiniFont.h" #include "../RTC/TimerManager.h" +#include "../Protocol/SmartError.h" +#include "../Utility/DataFilter.h" #define MINIFONT miniFontInfo @@ -65,9 +67,15 @@ CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen( } bool -CScreenHeader::show() +CScreenHeader::show(bool erase) { - _display.clearDisplay(); + if(erase) + _display.clearDisplay(); // erase everything + else { + _display.fillRect(0, 17, 128, 47, BLACK); // only erase below the header + _display.fillRect(119, 0, 9, 17, BLACK); // erase top of body thermo + _display.fillRect(0, 0, 9, 17, BLACK); // erase top of ambient thermo + } // standard header items // Bluetooth @@ -75,8 +83,7 @@ CScreenHeader::show() // WiFi icon is updated in animate() - // battery - showBatteryIcon(getBatteryVoltage()); + // Battery is updated in animate // clock showTime(); @@ -104,7 +111,9 @@ CScreenHeader::animate() // animate timer icon, // inserting an update icon if new firmware available from internet web server _animateCount++; - WRAPUPPERLIMIT(_animateCount, 10, 0); + _batteryCount++; + WRAPUPPERLIMIT(_animateCount, 9, 0); + WRAPUPPERLIMIT(_batteryCount, 5, 0); if(isUpdateAvailable(true)) { int xPos = X_TIMER_ICON - 3; int yPos = Y_TIMER_ICON; @@ -122,7 +131,22 @@ CScreenHeader::animate() } } else { + int xPos = X_BATT_ICON; + int yPos = Y_BATT_ICON; showTimers(); + switch(_batteryCount) { + case 3: + if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) { + showBatteryIcon(getBatteryVoltage(true)); + } + else { + _display.fillRect(xPos, yPos, BatteryIconInfo.width, BatteryIconInfo.height, BLACK); + } + break; + case 0: + showBatteryIcon(getBatteryVoltage(true)); + break; + } } showWifiIcon(); @@ -285,6 +309,7 @@ CScreenHeader::showTime() int xPos = X_WIFI_ICON + WifiIconInfo.width + WifiInIconInfo.width; // rhs of wifi conglomeration if(isWifiAP()) xPos += 4; // add more if an Access Point + _display.fillRect(xPos - 15, Y_CLOCK, 30, arial_8ptFontInfo.nBitsPerLine, BLACK); _printMenuText(X_CLOCK, Y_CLOCK, msg); } } diff --git a/src/Afterburner/src/OLED/ScreenHeader.h b/src/Afterburner/src/OLED/ScreenHeader.h index e263d8c..d9aeed1 100644 --- a/src/Afterburner/src/OLED/ScreenHeader.h +++ b/src/Afterburner/src/OLED/ScreenHeader.h @@ -44,7 +44,8 @@ class CScreenHeader : public CScreen { sScreenholdoff _UpAnnotation; sScreenholdoff _DnAnnotation; bool _colon; - int _animateCount; + uint8_t _animateCount; + uint8_t _batteryCount; protected: void showBTicon(); void showWifiIcon(); @@ -53,7 +54,7 @@ protected: virtual void showTime(); // x location depends upon how many timers are active public: CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr); - bool show(); + bool show(bool erase); bool animate(); }; diff --git a/src/Afterburner/src/OLED/ScreenManager.cpp b/src/Afterburner/src/OLED/ScreenManager.cpp index ad3eb55..15d2dc7 100644 --- a/src/Afterburner/src/OLED/ScreenManager.cpp +++ b/src/Afterburner/src/OLED/ScreenManager.cpp @@ -30,6 +30,7 @@ #include "ClockScreen.h" #include "RebootScreen.h" #include "HeaterSettingsScreen.h" +#include "FuelCalScreen.h" #include "SettingsScreen.h" #include "ThermostatModeScreen.h" #include "FontDumpScreen.h" diff --git a/src/Afterburner/src/OLED/SetClockScreen.cpp b/src/Afterburner/src/OLED/SetClockScreen.cpp index 7e6280e..9275d2b 100644 --- a/src/Afterburner/src/OLED/SetClockScreen.cpp +++ b/src/Afterburner/src/OLED/SetClockScreen.cpp @@ -43,6 +43,7 @@ CSetClockScreen::CSetClockScreen(C128x64_OLED& display, CScreenManager& mgr) : C void CSetClockScreen::onSelect() { + CScreenHeader::onSelect(); _initUI(); } @@ -67,7 +68,7 @@ CSetClockScreen::show() if(deltaT >= 0) { _nextT += 1000; - CScreenHeader::show(); + CScreenHeader::show(false); char str[16]; int xPos, yPos; diff --git a/src/Afterburner/src/OLED/SetTimerScreen.cpp b/src/Afterburner/src/OLED/SetTimerScreen.cpp index 482f36b..3dcf636 100644 --- a/src/Afterburner/src/OLED/SetTimerScreen.cpp +++ b/src/Afterburner/src/OLED/SetTimerScreen.cpp @@ -47,6 +47,7 @@ CSetTimerScreen::CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int void CSetTimerScreen::onSelect() { + CScreenHeader::onSelect(); _initUI(); NVstore.getTimerInfo(_timerID, _timerInfo); } @@ -62,7 +63,7 @@ CSetTimerScreen::_initUI() bool CSetTimerScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); char str[20]; int xPos, yPos; diff --git a/src/Afterburner/src/OLED/SettingsScreen.cpp b/src/Afterburner/src/OLED/SettingsScreen.cpp index 4de30b8..fc65b93 100644 --- a/src/Afterburner/src/OLED/SettingsScreen.cpp +++ b/src/Afterburner/src/OLED/SettingsScreen.cpp @@ -66,7 +66,7 @@ CSettingsScreen::show() { char str[16]; - CScreenHeader::show(); + CScreenHeader::show(false); _display.writeFillRect(0, 16, 84, 12, WHITE); _printInverted(3, 18, "Heater Tuning", true); diff --git a/src/Afterburner/src/OLED/WiFiScreen.cpp b/src/Afterburner/src/OLED/WiFiScreen.cpp index 083f4e4..c47fc3e 100644 --- a/src/Afterburner/src/OLED/WiFiScreen.cpp +++ b/src/Afterburner/src/OLED/WiFiScreen.cpp @@ -48,6 +48,7 @@ CWiFiScreen::CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHe void CWiFiScreen::onSelect() { + CScreenHeader::onSelect(); _initUI(); } @@ -87,7 +88,7 @@ CWiFiScreen::_initUI() bool CWiFiScreen::show() { - CScreenHeader::show(); + CScreenHeader::show(false); int yPos = 18; diff --git a/src/Afterburner/src/OLED/fonts/Arial.c b/src/Afterburner/src/OLED/fonts/Arial.c index d06e8fa..48f80f5 100644 --- a/src/Afterburner/src/OLED/fonts/Arial.c +++ b/src/Afterburner/src/OLED/fonts/Arial.c @@ -662,11 +662,19 @@ const uint8_t PROGMEM arial_8ptBitmaps [] = 0x01, 0x00, // # // @870 '~' (5 pixels wide) - 0x03, 0x00, // ## + 0x01, 0x00, // # 0x02, 0x00, // # 0x03, 0x00, // ## 0x01, 0x00, // # 0x02, 0x00, // # + + // @880 '1' (5 pixels wide) + 0x00, 0x00, // + 0x04, 0x00, // # + 0x08, 0x00, // # + 0x1F, 0xE0, // ######## + 0x00, 0x00, // + }; // Character descriptors for Arial 8pt @@ -690,7 +698,7 @@ const FONT_CHAR_INFO PROGMEM arial_8ptDescriptors[] = {1, 14, 100}, // '.' {3, 14, 102}, // '/' {5, 14, 108}, // '0' - {3, 14, 118}, // '1' + {5, 14, 880}, // '1' {5, 14, 124}, // '2' {5, 14, 134}, // '3' {5, 14, 144}, // '4' diff --git a/src/Afterburner/src/OLED/fonts/Icons.cpp b/src/Afterburner/src/OLED/fonts/Icons.cpp index 5d48e70..6ebf1aa 100644 --- a/src/Afterburner/src/OLED/fonts/Icons.cpp +++ b/src/Afterburner/src/OLED/fonts/Icons.cpp @@ -375,6 +375,25 @@ const uint8_t FuelIcon [] PROGMEM = { }; const BITMAP_INFO FuelIconInfo(7, 12, FuelIcon); +// +// Image data for FuelIconSmall +// + +const uint8_t PROGMEM FuelIconSmall[] = +{ + 0x20, // # + 0x20, // # + 0x70, // ### + 0x70, // ### + 0xF8, // ##### + 0xF8, // ##### + 0xF8, // ##### + 0xF8, // ##### + 0x70, // ### +}; +const BITMAP_INFO FuelIconSmallInfo(5, 9, FuelIconSmall); + + // 'Target', 13x13px const uint8_t TargetIcon [] PROGMEM = { 0x0f, 0x80, // ##### @@ -1083,3 +1102,25 @@ const uint8_t PROGMEM resetIcon[] = }; const BITMAP_INFO resetIconInfo(17, 10, resetIcon); +// +// Image data for miniThermo +// + +const uint8_t PROGMEM miniThermoIcon[] = +{ + 0x30, // ## + 0x48, // # # + 0x48, // # # + 0x48, // # # + 0x48, // # # + 0x48, // # # + 0x48, // # # + 0x48, // # # + 0x78, // #### + 0xFC, // ###### + 0xFC, // ###### + 0xFC, // ###### + 0x78, // #### +}; +const BITMAP_INFO miniThermoIconInfo(6, 13, miniThermoIcon); + diff --git a/src/Afterburner/src/OLED/fonts/Icons.h b/src/Afterburner/src/OLED/fonts/Icons.h index fa202bb..a7a1c6c 100644 --- a/src/Afterburner/src/OLED/fonts/Icons.h +++ b/src/Afterburner/src/OLED/fonts/Icons.h @@ -65,8 +65,8 @@ extern const BITMAP_INFO FanIcon4Info; // 'FuelIcon', 7x12px extern const BITMAP_INFO FuelIconInfo; +extern const BITMAP_INFO FuelIconSmallInfo; -// 'Target', 13x13px extern const BITMAP_INFO TargetIconInfo; extern const BITMAP_INFO RepeatIconInfo; @@ -77,7 +77,8 @@ extern const BITMAP_INFO LargeTimerIconInfo; extern const BITMAP_INFO VerticalRepeatIconInfo; extern const BITMAP_INFO CrossLgIconInfo; -extern const BITMAP_INFO CrossIconInfo; +extern const BITMAP_INFO CrossIconInfo +; // Bitmap for open extern const BITMAP_INFO OpenIconInfo; @@ -137,3 +138,4 @@ extern const BITMAP_INFO ThermostatDegCIconInfo; extern const BITMAP_INFO ThermostatDegFIconInfo; extern const BITMAP_INFO ThermostatHzIconInfo; extern const BITMAP_INFO resetIconInfo; +extern const BITMAP_INFO miniThermoIconInfo; diff --git a/src/Afterburner/src/Protocol/Protocol.cpp b/src/Afterburner/src/Protocol/Protocol.cpp index b97bb2f..5426403 100644 --- a/src/Afterburner/src/Protocol/Protocol.cpp +++ b/src/Afterburner/src/Protocol/Protocol.cpp @@ -368,7 +368,7 @@ const char* Errstates [] PROGMEM = { "Flame out", // [9] E-08 "Temp sense", // [10] E-09 "Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5 - "Failed 1st ignition attempt", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 + "Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 "Unknown error?" // mystery code! }; @@ -385,7 +385,7 @@ const char* ErrstatesEx [] PROGMEM = { "E-08: Flame out", // [9] E-08 "E-09: Temp sense", // [10] E-09 "E-10: Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5 - "E-11: Failed 1st ignition attempt", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 + "E-11: Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 "Unknown error?" // mystery code! }; diff --git a/src/Afterburner/src/Protocol/SmartError.cpp b/src/Afterburner/src/Protocol/SmartError.cpp index 57e6174..723cd20 100644 --- a/src/Afterburner/src/Protocol/SmartError.cpp +++ b/src/Afterburner/src/Protocol/SmartError.cpp @@ -2,7 +2,7 @@ * This file is part of the "bluetoothheater" distribution * (https://gitlab.com/mrjones.id.au/bluetoothheater) * - * Copyright (C) 2018 Ray Jones + * Copyright (C) 2019 Ray Jones * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,10 @@ #include "SmartError.h" #include "TxManage.h" +#include "../Utility/helpers.h" +#include "../Utility/macros.h" +#include "../Utility/NVStorage.h" +#include "../Utility/DataFilter.h" CSmartError::CSmartError() { @@ -83,12 +87,12 @@ CSmartError::monitor(uint8_t newRunState) else if(newRunState > 5) { // transitioned from preheat to post glow // - second ignition attempt failed, heater is shutting down - m_Error = 11; + m_Error = 11; // +1 over displayed error code } else if(newRunState == 3) { // transitioned from preheat to retry // - first ignition attempt failed, heater will retry - m_Error = 12; + m_Error = 12; // +1 over displayed error code } } } @@ -106,7 +110,24 @@ CSmartError::monitor(uint8_t newRunState) } } - m_prevRunState = newRunState; + m_prevRunState = newRunState; +} + +bool +CSmartError::checkVolts(float ipVolts, float glowI) +{ + // check for low voltage + // values here are x10 integers + if(NVstore.getHeaterTuning().lowVolts) { // only if enabled + float cableComp = glowI * 0.1; // allow 1V drop for 10A current (bit naive but better than no compensation) + float Thresh = NVstore.getHeaterTuning().getLVC() - cableComp; // NVstore + if(ipVolts < Thresh) { + m_Error = 2; // +1 over displayed error code + requestOff(); + return false; + } + } + return true; } // return our smart error, if it exists, as the registered code diff --git a/src/Afterburner/src/Protocol/SmartError.h b/src/Afterburner/src/Protocol/SmartError.h index 90ad624..0c91d09 100644 --- a/src/Afterburner/src/Protocol/SmartError.h +++ b/src/Afterburner/src/Protocol/SmartError.h @@ -31,6 +31,7 @@ public: void inhibit(); void monitor(const CProtocol& heaterFrame); void monitor(uint8_t runstate); + bool checkVolts(float volts, float plugI); uint8_t getError(); }; diff --git a/src/Afterburner/src/Utility/BTC_JSON.cpp b/src/Afterburner/src/Utility/BTC_JSON.cpp index a3e4a90..94d7625 100644 --- a/src/Afterburner/src/Utility/BTC_JSON.cpp +++ b/src/Afterburner/src/Utility/BTC_JSON.cpp @@ -277,7 +277,29 @@ void interpretJsonCommand(char* pLine) sHeaterTuning ht = NVstore.getHeaterTuning(); ht.pumpCal = fCal; NVstore.setHeaterTuning(ht); - NVstore.save(); + } + } + else if(strcmp("TempOffset", it->key) == 0) { + float fCal = it->value.as(); + if(INBOUNDS(fCal, -10.0, +10.0)) { + sHeaterTuning ht = NVstore.getHeaterTuning(); + ht.tempOfs = fCal; + NVstore.setHeaterTuning(ht); + } + } + else if(strcmp("LowVoltCutout", it->key) == 0) { + float fCal = it->value.as(); + if(fCal != 0) { + bool bOK = false; + if(NVstore.getHeaterTuning().sysVoltage == 120) + bOK = INBOUNDS(fCal, 10.0, 12.5); + else + bOK = INBOUNDS(fCal, 20.0, 25.0); + if(bOK) { + sHeaterTuning ht = NVstore.getHeaterTuning(); + ht.lowVolts = fCal; + NVstore.setHeaterTuning(ht); + } } } } @@ -325,7 +347,7 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len) bSend |= moderator.addJson("FanRPM", getFanSpeed(), root ); bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root ); bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root ); - bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(), root ); + bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(false), root ); bSend |= moderator.addJson("SystemVoltage", getHeaterInfo().getSystemVoltage(), root ); bSend |= moderator.addJson("GlowVoltage", getGlowVolts(), root ); bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root ); @@ -354,9 +376,11 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len) bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getUserSettings().cyclic.Start, root); bSend |= moderator.addJson("CyclicTemp", getDemandDegC(), root); // actual pivot point for cyclic mode bSend |= moderator.addJson("CyclicOff", stop, root); // threshold of over temp for cyclic mode - bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode - bSend |= moderator.addJson("PumpCount", RTC_Store.getFuelGauge(), root); // running count of pump strokes - bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // ml/stroke + bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode + bSend |= moderator.addJson("PumpCount", RTC_Store.getFuelGauge(), root); // running count of pump strokes + bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // mL/stroke + bSend |= moderator.addJson("TempOffset", NVstore.getHeaterTuning().tempOfs, root); // degC offset + bSend |= moderator.addJson("LowVoltCutout", NVstore.getHeaterTuning().lowVolts, root); // low volatge cutout if(bSend) { root.printTo(opStr, len); diff --git a/src/Afterburner/src/Utility/DataFilter.h b/src/Afterburner/src/Utility/DataFilter.h index 218e4c0..b25e31a 100644 --- a/src/Afterburner/src/Utility/DataFilter.h +++ b/src/Afterburner/src/Utility/DataFilter.h @@ -2,7 +2,7 @@ * This file is part of the "bluetoothheater" distribution * (https://gitlab.com/mrjones.id.au/bluetoothheater) * - * Copyright (C) 2018 Ray Jones + * Copyright (C) 2019 Ray Jones * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +44,11 @@ struct sFilteredData { CExpMean GlowAmps; CExpMean Fan; CExpMean AmbientTemp; + CExpMean FastipVolts; + CExpMean FastGlowAmps; }; +extern sFilteredData FilteredSamples; + + #endif diff --git a/src/Afterburner/src/Utility/FuelGauge.cpp b/src/Afterburner/src/Utility/FuelGauge.cpp index 61c665e..2d985ba 100644 --- a/src/Afterburner/src/Utility/FuelGauge.cpp +++ b/src/Afterburner/src/Utility/FuelGauge.cpp @@ -71,7 +71,7 @@ CFuelGauge::Integrate(float Hz) } float -CFuelGauge::Used_ml() +CFuelGauge::Used_mL() { return _pumpStrokes * _pumpCal; // strokes * millilitre / stroke } diff --git a/src/Afterburner/src/Utility/FuelGauge.h b/src/Afterburner/src/Utility/FuelGauge.h index 20ca094..88c0af9 100644 --- a/src/Afterburner/src/Utility/FuelGauge.h +++ b/src/Afterburner/src/Utility/FuelGauge.h @@ -34,7 +34,7 @@ public: void init(float fuelUsed = 0); void reset(); void Integrate(float Hz); - float Used_ml(); + float Used_mL(); float Used_strokes(); }; diff --git a/src/Afterburner/src/Utility/NVStorage.cpp b/src/Afterburner/src/Utility/NVStorage.cpp index bc508c6..c3f6925 100644 --- a/src/Afterburner/src/Utility/NVStorage.cpp +++ b/src/Afterburner/src/Utility/NVStorage.cpp @@ -97,6 +97,11 @@ sHeaterTuning::setSysVoltage(float fVal) } } +float +sHeaterTuning::getLVC() const +{ + return lowVolts * 0.1; +} void CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo) @@ -235,7 +240,12 @@ sHeaterTuning::load() validatedLoad("systemVoltage", sysVoltage, 120, u8Match2, 120, 240); validatedLoad("fanSensor", fanSensor, 1, u8inBounds, 1, 2); validatedLoad("glowDrive", glowDrive, 5, u8inBounds, 1, 6); + if(sysVoltage == 120) + validatedLoad("lowVolts", lowVolts, 115, u8inBounds, 100, 125); + else + validatedLoad("lowVolts", lowVolts, 230, u8inBounds, 200, 250); validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1); + validatedLoad("tempOfs", tempOfs, 0.0, -10.0, +10.0); preferences.end(); } @@ -252,7 +262,9 @@ sHeaterTuning::save() preferences.putUChar("systemVoltage", sysVoltage); preferences.putUChar("fanSensor", fanSensor); preferences.putUChar("glowDrive", glowDrive); + preferences.putUChar("lowVolts", lowVolts); preferences.putFloat("pumpCal", pumpCal); + preferences.putFloat("tempOfs", tempOfs); preferences.end(); } diff --git a/src/Afterburner/src/Utility/NVStorage.h b/src/Afterburner/src/Utility/NVStorage.h index 37bd258..b58633f 100644 --- a/src/Afterburner/src/Utility/NVStorage.h +++ b/src/Afterburner/src/Utility/NVStorage.h @@ -37,10 +37,12 @@ struct sHeaterTuning : public CESP32_NVStorage { uint8_t Pmax; uint16_t Fmin; uint16_t Fmax; - uint8_t sysVoltage; + uint8_t sysVoltage; // x10 uint8_t fanSensor; uint8_t glowDrive; + uint8_t lowVolts; // x10 float pumpCal; + float tempOfs; bool valid() { bool retval = true; @@ -52,6 +54,11 @@ struct sHeaterTuning : public CESP32_NVStorage { retval &= fanSensor == 1 || fanSensor == 2; retval &= INBOUNDS(glowDrive, 1, 6); retval &= INBOUNDS(pumpCal, 0.001, 1.0); + if(sysVoltage == 120) + retval &= INBOUNDS(lowVolts, 100, 125); + else + retval &= INBOUNDS(lowVolts, 200, 250); + retval &= INBOUNDS(tempOfs, -10, +10); return retval; }; void init() { @@ -63,6 +70,8 @@ struct sHeaterTuning : public CESP32_NVStorage { fanSensor = 1; glowDrive = 5; pumpCal = 0.02; + lowVolts = 115; + tempOfs = 0; }; void load(); void save(); @@ -75,6 +84,8 @@ struct sHeaterTuning : public CESP32_NVStorage { fanSensor = rhs.fanSensor; glowDrive = rhs.glowDrive; pumpCal = rhs.pumpCal; + lowVolts = rhs.lowVolts; + tempOfs = rhs.tempOfs; return *this; } float getPmin() const; @@ -82,6 +93,7 @@ struct sHeaterTuning : public CESP32_NVStorage { void setPmin(float val); void setPmax(float val); void setSysVoltage(float val); + float getLVC() const; }; struct sHomeMenuActions { diff --git a/src/Afterburner/src/Utility/helpers.h b/src/Afterburner/src/Utility/helpers.h index 95f07a7..11265f7 100644 --- a/src/Afterburner/src/Utility/helpers.h +++ b/src/Afterburner/src/Utility/helpers.h @@ -78,19 +78,12 @@ extern void setUploadSize(long val); extern void getGPIOinfo(sGPIO& info); extern void simulateGPIOin(uint8_t newKey); extern void setDegFMode(bool state); -extern float getBatteryVoltage(); +extern float getBatteryVoltage(bool fast); extern float getGlowVolts(); extern float getGlowCurrent(); extern float getFanSpeed(); extern int sysUptime(); -/* extern void setFuelGauge_RTC(float val); -extern void getFuelGauge_RTC(float& val); -extern void setDesiredTemp_RTC(uint8_t val); -extern void getDesiredTemp_RTC(uint8_t& val); -extern void setDesiredPump_RTC(uint8_t val); -extern void getDesiredPump_RTC(uint8_t& val);*/ - extern void ShowOTAScreen(int percent=0, eOTAmodes updateType=eOTAnormal); diff --git a/src/Afterburner/src/Utility/macros.h b/src/Afterburner/src/Utility/macros.h index 8f1701a..04d9ee8 100644 --- a/src/Afterburner/src/Utility/macros.h +++ b/src/Afterburner/src/Utility/macros.h @@ -2,7 +2,7 @@ * This file is part of the "bluetoothheater" distribution * (https://gitlab.com/mrjones.id.au/bluetoothheater) * - * Copyright (C) 2018 Ray Jones + * Copyright (C) 2019 Ray Jones * Copyright (C) 2018 James Clark * * This program is free software: you can redistribute it and/or modify @@ -23,12 +23,12 @@ #ifndef __MACROS_H__ #define __MACROS_H__ -#define LOWERLIMIT(A, B) if((A) < (B)) (A) = (B) -#define UPPERLIMIT(A, B) if((A) > (B)) (A) = (B) -#define WRAPUPPERLIMIT(A, B, C) if((A) > (B)) (A) = (C) -#define WRAPLOWERLIMIT(A, B, C) if((A) < (B)) (A) = (C) -#define WRAPLIMITS(A, B, C) if((A) < (B)) (A) = (C) ; if((A) > (C)) (A) = (B) +#define LOWERLIMIT(A, B) { if((A) < (B)) (A) = (B); } +#define UPPERLIMIT(A, B) { if((A) > (B)) (A) = (B); } +#define WRAPUPPERLIMIT(A, B, C) { if((A) > (B)) (A) = (C); } +#define WRAPLOWERLIMIT(A, B, C) { if((A) < (B)) (A) = (C); } +#define WRAPLIMITS(A, B, C) { if((A) < (B)) (A) = (C) ; if((A) > (C)) (A) = (B); } #define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX))) -#define BOUNDSLIMIT(A, B, C) if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C) +#define BOUNDSLIMIT(A, B, C) { if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C); } #endif \ No newline at end of file