From f2af9c3fda6da54f31f43fa3f6ec82b2e1f3dd6e Mon Sep 17 00:00:00 2001 From: Ray Jones Date: Wed, 30 Oct 2019 21:48:25 +1100 Subject: [PATCH] Added under/over temperature threshold for GPIO outputs --- icons/Thresh.bmp | Bin 0 -> 190 bytes src/Afterburner.cpp | 4 +- src/OLED/GPIOInfoScreen.cpp | 8 + src/OLED/GPIOSetupScreen.cpp | 336 ++++++++++++++++++++++++----------- src/OLED/GPIOSetupScreen.h | 1 + src/OLED/fonts/Icons.cpp | 19 ++ src/OLED/fonts/Icons.h | 1 + src/Utility/BTC_GPIO.cpp | 230 ++++++++++++++++-------- src/Utility/BTC_GPIO.h | 38 ++-- src/Utility/NVStorage.cpp | 8 +- src/Utility/NVStorage.h | 4 + 11 files changed, 462 insertions(+), 187 deletions(-) create mode 100644 icons/Thresh.bmp diff --git a/icons/Thresh.bmp b/icons/Thresh.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d5482b694abea0195c0cece9ef57530fa18b801d GIT binary patch literal 190 zcmZuoyAgm;2#a?%R;=M1RyM9<&14=Uu>l5<&OGt~9>?{danp8k`?z4O#aa3%3b3Hs lMr9-wX2wNSAtDpWmm`W09AyqKcS-jUPajO5m;JAO?q3TDFl7J$ literal 0 HcmV?d00001 diff --git a/src/Afterburner.cpp b/src/Afterburner.cpp index 0dc93d4..de44b5b 100644 --- a/src/Afterburner.cpp +++ b/src/Afterburner.cpp @@ -1585,6 +1585,8 @@ void setupGPIO() GPIOout2_pin, NVstore.getUserSettings().GPIO.out1Mode, NVstore.getUserSettings().GPIO.out2Mode); + GPIOout.setThresh(NVstore.getUserSettings().GPIO.thresh[0], + NVstore.getUserSettings().GPIO.thresh[1]); // ### MAJOR ISSUE WITH ADC INPUTS ### // @@ -1592,7 +1594,7 @@ void setupGPIO() // This is ADC2 channel (#9). // Unfortunately it was subsequently discovered that any ADC2 input cannot be // used if Wifi is enabled. - // THIS ISSUE IS NOT RESOLBVABLE IN SOFTWARE. + // THIS ISSUE IS NOT RESOLVABLE IN SOFTWARE. // *** It is not possible to use ANY of the 10 ADC2 channels if Wifi is enabled :-( *** // // Fix is to cut traces to GPIO33 & GPIO26 and swap the connections. diff --git a/src/OLED/GPIOInfoScreen.cpp b/src/OLED/GPIOInfoScreen.cpp index dedf083..56a2d7e 100644 --- a/src/OLED/GPIOInfoScreen.cpp +++ b/src/OLED/GPIOInfoScreen.cpp @@ -127,6 +127,10 @@ CGPIOInfoScreen::animate() _drawBitmap(99, 15, UserIconInfo); _drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo); break; + case CGPIOout1::Thresh: + _drawBitmap(99, 15, threshIconInfo); + _drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo); + break; } #if USE_JTAG == 0 @@ -138,6 +142,10 @@ CGPIOInfoScreen::animate() _drawBitmap(99, 27, UserIconInfo); _drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo); break; + case CGPIOout2::Thresh: + _drawBitmap(99, 27, threshIconInfo); + _drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo); + break; } diff --git a/src/OLED/GPIOSetupScreen.cpp b/src/OLED/GPIOSetupScreen.cpp index 62ecade..3d54762 100644 --- a/src/OLED/GPIOSetupScreen.cpp +++ b/src/OLED/GPIOSetupScreen.cpp @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ #include "128x64OLED.h" @@ -31,6 +31,14 @@ extern CGPIOout GPIOout; extern CGPIOin GPIOin; extern CGPIOalg GPIOalg; +int8_t s8abs(int8_t val) +{ + if(val >= 0) + return val; + else + return -val; +} + /////////////////////////////////////////////////////////////////////////// // // CGPIOSetupScreen @@ -53,6 +61,8 @@ CGPIOSetupScreen::CGPIOSetupScreen(C128x64_OLED& display, CScreenManager& mgr) : _GPIOparams.out1Mode = CGPIOout1::Disabled; _GPIOparams.out2Mode = CGPIOout2::Disabled; _GPIOparams.algMode = CGPIOalg::Disabled; + _GPIOparams.thresh[0] = 0; + _GPIOparams.thresh[1] = 0; _ExtHold = 0; } @@ -63,6 +73,7 @@ CGPIOSetupScreen::onSelect() _initUI(); _GPIOparams = NVstore.getUserSettings().GPIO; _ExtHold = NVstore.getUserSettings().ExtThermoTimeout; + _repeatCount = -1; } void @@ -75,6 +86,8 @@ CGPIOSetupScreen::_initUI() bool CGPIOSetupScreen::show() { + char msg[16]; + _display.clearDisplay(); static bool animated = false; @@ -138,6 +151,17 @@ CGPIOSetupScreen::show() case CGPIOout1::Disabled: msgText = "---"; break; case CGPIOout1::Status: msgText = "Status"; break; case CGPIOout1::User: msgText = "User"; break; + case CGPIOout1::Thresh: + if(_rowSel == 6) { + sprintf(msg, " %dC", s8abs(_GPIOparams.thresh[0])); + _printMenuText(Column2, Line3, msg, false); + _printMenuText(Column2, Line3, _GPIOparams.thresh[0] >= 0 ? ">" : "<", true); + } + else { + sprintf(msg, "%s %dC", _GPIOparams.thresh[0] >= 0 ? ">" : "<", s8abs(_GPIOparams.thresh[0])); + _printMenuText(Column2, Line3, msg, _rowSel == 8); + } + break; } if(msgText) _printMenuText(Column2, Line3, msgText, _rowSel == 6); @@ -149,6 +173,17 @@ CGPIOSetupScreen::show() switch(_GPIOparams.out2Mode) { case CGPIOout2::Disabled: msgText = "---"; break; case CGPIOout2::User: msgText = "User"; break; + case CGPIOout2::Thresh: + if(_rowSel == 5) { + sprintf(msg, " %d`C", s8abs(_GPIOparams.thresh[1])); + _printMenuText(Column2, Line2, msg, false); + _printMenuText(Column2, Line2, _GPIOparams.thresh[1] >= 0 ? ">" : "<", true); + } + else { + sprintf(msg, "%s %d`C", _GPIOparams.thresh[1] >= 0 ? ">" : "<", s8abs(_GPIOparams.thresh[1])); + _printMenuText(Column2, Line2, msg, _rowSel == 7); + } + break; } if(msgText) _printMenuText(Column2, Line2, msgText, _rowSel == 5); @@ -227,6 +262,12 @@ CGPIOSetupScreen::animate() switch(_GPIOparams.out2Mode) { case CGPIOout2::Disabled: pMsg = " Output 2: DISABLED. "; break; case CGPIOout2::User: pMsg = " Output 2: User controlled. "; break; + case CGPIOout2::Thresh: + if(_GPIOparams.thresh[1] >= 0) + pMsg = " Output 2: Active if over temperature. Hold LEFT to set under. Hold RIGHT to set over. "; + else + pMsg = " Output 2: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. "; + break; } if(pMsg) _scrollMessage(56, pMsg, _scrollChar); @@ -237,10 +278,32 @@ CGPIOSetupScreen::animate() case CGPIOout1::Disabled: pMsg = " Output 1: DISABLED. "; break; case CGPIOout1::Status: pMsg = " Output 1: LED status indicator. "; break; case CGPIOout1::User: pMsg = " Output 1: User controlled. "; break; + case CGPIOout1::Thresh: + if(_GPIOparams.thresh[0] >= 0) + pMsg = " Output 1: Active if over temperature. Hold LEFT to set under. Hold RIGHT to set over. "; + else + pMsg = " Output 1: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. "; + break; } if(pMsg) _scrollMessage(56, pMsg, _scrollChar); break; + case 7: + _display.drawFastHLine(0, 52, 128, WHITE); + if(_GPIOparams.thresh[1] >= 0) + pMsg = " Output 2: Active if over temperature. CENTRE to accept. Hold LEFT to set under. "; + else + pMsg = " Output 2: Active if under temperature. CENTRE to accept. Hold RIGHT to set over. "; + _scrollMessage(56, pMsg, _scrollChar); + break; + case 8: + _display.drawFastHLine(0, 52, 128, WHITE); + if(_GPIOparams.thresh[0] >= 0) + pMsg = " Output 1: Active if over temperature. Centre to accept. Hold LEFT to set under. "; + else + pMsg = " Output 1: Active if under temperature. Centre to accept. Hold RIGHT to set over. "; + _scrollMessage(56, pMsg, _scrollChar); + break; } return true; } @@ -251,109 +314,164 @@ CGPIOSetupScreen::animate() bool CGPIOSetupScreen::keyHandler(uint8_t event) { + sUserSettings us; if(event & keyPressed) { - // press LEFT to select previous screen - if(event & key_Left) { - switch(_rowSel) { - case 0: - _ScreenManager.prevMenu(); - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - _scrollChar = 0; - _adjust(-1); - break; - case 10: - _rowSel = 0; // abort save - break; + _repeatCount = 0; + } + + if(event & keyRepeat) { + if(_repeatCount >= 0) { + _repeatCount++; + // hold LEFT to toggle GPIO output #1 + if(event & key_Left) { + if(_repeatCount > 1) { + _repeatCount = -1; // prevent double handling + if((_rowSel == 6 || _rowSel == 8) && _GPIOparams.out1Mode == CGPIOout1::Thresh) { + _GPIOparams.thresh[0] = -s8abs(_GPIOparams.thresh[0]); + BOUNDSLIMIT(_GPIOparams.thresh[0], -50, -1); + _rowSel = 8; + } + if((_rowSel == 5 || _rowSel == 7) && _GPIOparams.out2Mode == CGPIOout2::Thresh) { + _GPIOparams.thresh[1] = -s8abs(_GPIOparams.thresh[1]); + BOUNDSLIMIT(_GPIOparams.thresh[1], -50, -1); + _rowSel = 7; + } + } + } + if(event & key_Right) { + if(_repeatCount > 1) { + _repeatCount = -1; // prevent double handling + if((_rowSel == 6 || _rowSel == 8) && _GPIOparams.out1Mode == CGPIOout1::Thresh) { + _GPIOparams.thresh[0] = s8abs(_GPIOparams.thresh[0]); + BOUNDSLIMIT(_GPIOparams.thresh[0], 0, 50); + _rowSel = 8; + } + if((_rowSel == 5 || _rowSel == 7) && _GPIOparams.out2Mode == CGPIOout2::Thresh) { + _GPIOparams.thresh[1] = s8abs(_GPIOparams.thresh[1]); + BOUNDSLIMIT(_GPIOparams.thresh[1], 0, 50); + _rowSel = 7; + } + } } } - // press RIGHT to select next screen - if(event & key_Right) { - switch(_rowSel) { - case 0: - _ScreenManager.nextMenu(); - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - _scrollChar = 0; - _adjust(+1); - break; - case 10: - _rowSel = 0; // abort save - break; - } - } - if(event & key_Down) { - if(_rowSel == 10) { - _rowSel = 0; // abort save - } - else { - _scrollChar = 0; - _rowSel--; - if((_rowSel == 3) && (_GPIOparams.in2Mode != CGPIOin2::Thermostat)) - _rowSel--; // force skip if not set to external thermostat - if((_rowSel == 1) && ((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG))) // GPIO but NO analog support - _rowSel--; // force skip if analog input is not supported by PCB - LOWERLIMIT(_rowSel, 0); - } - } - // UP press - if(event & key_Up) { - switch(_rowSel) { - case 0: - if((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG)) // GPIO but NO Analog support - _rowSel++; // force skip if analog input is not supported by PCB - case 1: - case 2: - case 3: - case 4: - case 5: - _scrollChar = 0; - _rowSel++; - if((_rowSel == 3) && (_GPIOparams.in2Mode != CGPIOin2::Thermostat)) - _rowSel++; // force skip if not set to external thermostat - UPPERLIMIT(_rowSel, 6); - break; - case 10: // confirmed save - _enableStoringMessage(); - us = NVstore.getUserSettings(); - us.GPIO = _GPIOparams; - us.ExtThermoTimeout = _ExtHold; - NVstore.setUserSettings(us); - saveNV(); + } - setupGPIO(); - - _rowSel = 0; - break; - } - } - // CENTRE press - if(event & key_Centre) { - switch(_rowSel) { - case 0: - _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - _rowSel = 10; - break; + if(event & keyReleased) { + // press LEFT to select previous screen + if(_repeatCount == 0) { + if(event & key_Left) { + switch(_rowSel) { + case 0: + _ScreenManager.prevMenu(); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + _scrollChar = 0; + _adjust(-1); + break; + case 10: + _rowSel = 0; // abort save + break; + } + } + // press RIGHT to select next screen + if(event & key_Right) { + switch(_rowSel) { + case 0: + _ScreenManager.nextMenu(); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + _scrollChar = 0; + _adjust(+1); + break; + case 10: + _rowSel = 0; // abort save + break; + } + } + if(event & key_Down) { + if(_rowSel == 10) { + _rowSel = 0; // abort save + } + else { + _scrollChar = 0; + _rowSel--; + if((_rowSel == 3) && (_GPIOparams.in2Mode != CGPIOin2::Thermostat)) + _rowSel--; // force skip if not set to external thermostat + if((_rowSel == 1) && ((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG))) // GPIO but NO analog support + _rowSel--; // force skip if analog input is not supported by PCB + LOWERLIMIT(_rowSel, 0); + } + } + // UP press + if(event & key_Up) { + switch(_rowSel) { + case 0: + if((getBoardRevision() == BRD_V2_GPIO_NOALG) || (getBoardRevision() == BRD_V3_GPIO_NOALG)) // GPIO but NO Analog support + _rowSel++; // force skip if analog input is not supported by PCB + case 1: + case 2: + case 3: + case 4: + case 5: + _scrollChar = 0; + _rowSel++; + if((_rowSel == 3) && (_GPIOparams.in2Mode != CGPIOin2::Thermostat)) + _rowSel++; // force skip if not set to external thermostat + UPPERLIMIT(_rowSel, 6); + break; + case 10: // confirmed save + _enableStoringMessage(); + us = NVstore.getUserSettings(); + us.GPIO = _GPIOparams; + us.ExtThermoTimeout = _ExtHold; + NVstore.setUserSettings(us); + saveNV(); + + setupGPIO(); + + _rowSel = 0; + break; + } + } + // CENTRE press + if(event & key_Centre) { + switch(_rowSel) { + case 0: + _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + _rowSel = 10; + break; + case 7: + _rowSel = 5; + break; + case 8: + _rowSel = 6; + break; + } } } + _repeatCount = -1; _ScreenManager.reqUpdate(); } @@ -400,15 +518,35 @@ CGPIOSetupScreen::_adjust(int dir) case 5: // outputs mode tVal = _GPIOparams.out2Mode; tVal += dir; - WRAPLIMITS(tVal, 0, 1); + WRAPLIMITS(tVal, 0, 2); _GPIOparams.out2Mode = (CGPIOout2::Modes)tVal; break; case 6: // outputs mode tVal = _GPIOparams.out1Mode; tVal += dir; - WRAPLIMITS(tVal, 0, 2); + WRAPLIMITS(tVal, 0, 3); _GPIOparams.out1Mode = (CGPIOout1::Modes)tVal; break; + case 7: + if(_GPIOparams.thresh[1] < 0) { + _GPIOparams.thresh[1] += -dir; + BOUNDSLIMIT(_GPIOparams.thresh[1], -50, -1); + } + else { + _GPIOparams.thresh[1] += dir; + BOUNDSLIMIT(_GPIOparams.thresh[1], 0, 50); + } + break; + case 8: + if(_GPIOparams.thresh[0] < 0) { + _GPIOparams.thresh[0] += -dir; + BOUNDSLIMIT(_GPIOparams.thresh[0], -50, -1); + } + else { + _GPIOparams.thresh[0] += dir; + BOUNDSLIMIT(_GPIOparams.thresh[0], 0, 50); + } + break; } } diff --git a/src/OLED/GPIOSetupScreen.h b/src/OLED/GPIOSetupScreen.h index 77ed389..5101a73 100644 --- a/src/OLED/GPIOSetupScreen.h +++ b/src/OLED/GPIOSetupScreen.h @@ -37,6 +37,7 @@ class CGPIOSetupScreen : public CPasswordScreen unsigned long _ExtHold; int _animateCount; int _scrollChar; + int _repeatCount; void _initUI(); public: CGPIOSetupScreen(C128x64_OLED& display, CScreenManager& mgr); diff --git a/src/OLED/fonts/Icons.cpp b/src/OLED/fonts/Icons.cpp index db61ff3..b56774e 100644 --- a/src/OLED/fonts/Icons.cpp +++ b/src/OLED/fonts/Icons.cpp @@ -1373,3 +1373,22 @@ const uint8_t PROGMEM passwordIcon[] = const BITMAP_INFO passwordIconInfo(11, 17, passwordIcon); +// +// Image data for thresh +// + +const uint8_t PROGMEM threshIcon[] = +{ + 0xAA, 0x80, // # # # # # + 0x00, 0x00, // + 0x30, 0x00, // ## + 0x49, 0x00, // # # # + 0xFF, 0x80, // ######### + 0x49, 0x00, // # # # + 0x06, 0x00, // ## + 0x00, 0x00, // + 0xAA, 0x80, // # # # # # +}; + +const BITMAP_INFO threshIconInfo(9, 9, threshIcon); + diff --git a/src/OLED/fonts/Icons.h b/src/OLED/fonts/Icons.h index cb36e00..c55e569 100644 --- a/src/OLED/fonts/Icons.h +++ b/src/OLED/fonts/Icons.h @@ -158,3 +158,4 @@ extern const BITMAP_INFO _2IconInfo; extern const BITMAP_INFO algIconInfo; extern const BITMAP_INFO passwordIconInfo; +extern const BITMAP_INFO threshIconInfo; diff --git a/src/Utility/BTC_GPIO.cpp b/src/Utility/BTC_GPIO.cpp index a99c6a0..9046586 100644 --- a/src/Utility/BTC_GPIO.cpp +++ b/src/Utility/BTC_GPIO.cpp @@ -48,11 +48,13 @@ const char* GPIOin2Names[] = { const char* GPIOout1Names[] = { "Disabled", "Status", - "User" + "User", + "Thresh" }; const char* GPIOout2Names[] = { "Disabled", - "User" + "User", + "Thresh" }; const char* GPIOalgNames[] = { @@ -307,8 +309,105 @@ CGPIOin::simulateKey(uint8_t newKey) _Input2.manage((newKey & 0x02) != 0); } + /********************************************************************************************************* - ** GPIO out root + ** GPIO out base class + *********************************************************************************************************/ +CGPIOoutBase::CGPIOoutBase() +{ + _pin = 0; + _thresh = 0; + _userState = 0; +} + +void +CGPIOoutBase::begin(int pin) +{ + _pin = pin; + if(pin) { + pinMode(pin, OUTPUT); // GPIO output pin #1 + digitalWrite(pin, LOW); + } +} + +void +CGPIOoutBase::setThresh(int thresh) +{ + _thresh = thresh; +} + +void +CGPIOoutBase::setState(bool state) +{ + _userState = state; +} + +bool +CGPIOoutBase::_getUserState() +{ + return _userState; +}; + +void +CGPIOoutBase::_setPinState(int state) +{ + digitalWrite(_pin, state); +} + +int +CGPIOoutBase::_getPinState() +{ + return digitalRead(_pin); +}; + + +void +CGPIOoutBase::_doUser() +{ +// DebugPort.println("GPIOout::_doUser2()"); + if(_pin) { + digitalWrite(_pin, _userState ? HIGH : LOW); + } +} + + +void +CGPIOoutBase::_doThresh() +{ + if(_thresh) { + float tAct = getTemperatureSensor(0); + if(digitalRead(_pin)) { + // output is currently active + if(_thresh > 0) { // active when OVER threshold mode + if((tAct + 0.1) < _thresh) { // test if under threshold +0.1deg hysteresis + digitalWrite(_pin, LOW); // deactivate output when less than threshold + } + } + else { // active if UNDER threshold mode + if(tAct > -_thresh) { // inactive if over threshold + digitalWrite(_pin, LOW); // deactivate output when over threshold + } + } + } + else { + // output is not currently active + if(_thresh > 0) { // active when OVER threshold mode + if(tAct > _thresh) { // test if over threshold + digitalWrite(_pin, HIGH); // activate output when over threshold + } + } + else { // active if UNDER threshold mode + if((tAct + 0.1) < -_thresh) { // test if under threshold +0.1deg hysteresis + digitalWrite(_pin, HIGH); // activate output when under threshold + } + } + } + } +} + + +/********************************************************************************************************* + ** GPIO out manager *********************************************************************************************************/ @@ -330,6 +429,13 @@ CGPIOout::setMode(CGPIOout1::Modes mode1, CGPIOout2::Modes mode2) _Out2.setMode(mode2); }; +void +CGPIOout::setThresh(int op1, int op2) +{ + _Out1.setThresh(op1); + _Out2.setThresh(op2); +} + CGPIOout1::Modes CGPIOout::getMode1() const { @@ -374,26 +480,21 @@ CGPIOout::getState(int channel) *********************************************************************************************************/ -CGPIOout1::CGPIOout1() +CGPIOout1::CGPIOout1() : CGPIOoutBase() { _Mode = Disabled; - _pin = 0; _breatheDelay = 0; _statusState = 0; _statusDelay = 0; - _userState = 0; _prevState = -1; } void -CGPIOout1::begin(int pin, CGPIOout1::Modes mode) +CGPIOout1::begin(int pin, CGPIOout1::Modes mode) { - _pin = pin; - if(pin) { - pinMode(pin, OUTPUT); // GPIO output pin #1 - digitalWrite(pin, LOW); - ledcSetup(0, 500, 8); // create PWM channel for GPIO1: 500Hz, 8 bits - } + CGPIOoutBase::begin(pin); + + ledcSetup(0, 500, 8); // create PWM channel for GPIO1: 500Hz, 8 bits setMode(mode); } @@ -401,10 +502,11 @@ CGPIOout1::begin(int pin, CGPIOout1::Modes mode) void CGPIOout1::setMode(CGPIOout1::Modes mode) { - if(mode >= Disabled && mode <= User) + if(mode >= Disabled && mode <= Thresh) _Mode = mode; _prevState = -1; - ledcDetachPin(_pin); // ensure PWM detached from IO line + if(_getPin()) + ledcDetachPin(_getPin()); // ensure PWM detached from IO line }; CGPIOout1::Modes CGPIOout1::getMode() const @@ -416,16 +518,18 @@ void CGPIOout1::manage() { switch (_Mode) { - case Disabled: break; - case Status: _doStatus(); break; - case User: _doUser(); break; + case CGPIOout1::Disabled: break; + case CGPIOout1::Status: _doStatus(); break; + case CGPIOout1::User: _doUser(); break; + case CGPIOout1::Thresh: _doThresh(); break; } } void CGPIOout1::_doStatus() { - if(_pin == 0) + int pin = _getPin(); + if(pin == 0) return; // DebugPort.println("GPIOout::_doStatus()"); @@ -466,30 +570,30 @@ CGPIOout1::_doStatus() _statusDelay = millis() + BREATHINTERVAL; switch(statusMode) { case 0: - ledcDetachPin(_pin); // detach PWM from IO line - digitalWrite(_pin, LOW); + ledcDetachPin(pin); // detach PWM from IO line + _setPinState(LOW); _ledState = 0; break; case 1: - ledcAttachPin(_pin, 0); // attach PWM to GPIO line + ledcAttachPin(pin, 0); // attach PWM to GPIO line ledcWrite(0, _statusState); _breatheDelay = millis() + BREATHINTERVAL; break; case 2: - ledcDetachPin(_pin); // detach PWM from IO line - digitalWrite(_pin, HIGH); + ledcDetachPin(pin); // detach PWM from IO line + _setPinState(HIGH); _ledState = 1; break; case 3: - ledcAttachPin(_pin, 0); // attach PWM to GPIO line + ledcAttachPin(pin, 0); // attach PWM to GPIO line _statusState = 255; ledcWrite(0, _statusState); _breatheDelay = millis() + BREATHINTERVAL; break; case 4: - ledcDetachPin(_pin); // detach PWM from IO line + ledcDetachPin(pin); // detach PWM from IO line _breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off - digitalWrite(_pin, LOW); + _setPinState(LOW); break; } } @@ -500,14 +604,6 @@ CGPIOout1::_doStatus() } } -void -CGPIOout1::_doUser() -{ -// DebugPort.println("GPIOout::_doUser2()"); - if(_pin) { - digitalWrite(_pin, _userState ? HIGH : LOW); - } -} void CGPIOout1::_doStartMode() // breath up PWM @@ -547,12 +643,12 @@ CGPIOout1::_doSuspendMode() // brief flash _statusState++; if(_statusState & 0x01) { _breatheDelay += ONFLASHINTERVAL; // brief flash on - digitalWrite(_pin, HIGH); + _setPinState(HIGH); stretch = (millis() + 250) | 1; // pulse extend for UI purposes, ensure non zero } else { _breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off - digitalWrite(_pin, LOW); + _setPinState(LOW); } } if(stretch) { @@ -563,41 +659,34 @@ CGPIOout1::_doSuspendMode() // brief flash _ledState = stretch ? 1 : 0; } -void -CGPIOout1::setState(bool state) -{ - _userState = state; -} - uint8_t CGPIOout1::getState() { switch(_Mode) { - case User: return _userState; - case Status: return _ledState; // special pulse extender for suspend mode - default: return 0; - } + case User: + case Thresh: + return _getPinState(); + case Status: + return _ledState; // special pulse extender for suspend mode + default: + return 0; + } } /********************************************************************************************************* ** GPIO2 *********************************************************************************************************/ -CGPIOout2::CGPIOout2() +CGPIOout2::CGPIOout2() : CGPIOoutBase() { _Mode = Disabled; - _pin = 0; - _userState = 0; } void CGPIOout2::begin(int pin, Modes mode) { - _pin = pin; - if(pin) { - pinMode(pin, OUTPUT); // GPIO output pin #2 - digitalWrite(pin, LOW); - ledcSetup(1, 500, 8); // create PWM channel for GPIO2: 500Hz, 8 bits - } + CGPIOoutBase::begin(pin); + + ledcSetup(1, 500, 8); // create PWM channel for GPIO2: 500Hz, 8 bits setMode(mode); } @@ -605,10 +694,11 @@ CGPIOout2::begin(int pin, Modes mode) void CGPIOout2::setMode(CGPIOout2::Modes mode) { - if(mode >= Disabled && mode <= User) + if(mode >= Disabled && mode <= Thresh) _Mode = mode; - if(_pin) - ledcDetachPin(_pin); // ensure PWM detached from IO line + int pin = _getPin(); + if(pin) + ledcDetachPin(pin); // ensure PWM detached from IO line }; CGPIOout2::Modes CGPIOout2::getMode() const @@ -622,27 +712,21 @@ CGPIOout2::manage() switch (_Mode) { case CGPIOout2::Disabled: break; case CGPIOout2::User: _doUser(); break; + case CGPIOout2::Thresh: _doThresh(); break; } } -void -CGPIOout2::_doUser() -{ - if(_pin) { - digitalWrite(_pin, _userState ? HIGH : LOW); - } -} - -void -CGPIOout2::setState(bool state) -{ - _userState = state; -} uint8_t CGPIOout2::getState() { - return _userState; + switch (_Mode) { + case CGPIOout2::User: + case CGPIOout2::Thresh: + return _getPinState(); + default: + return 0; + } } // expected external analogue circuit is a 10k pot. diff --git a/src/Utility/BTC_GPIO.h b/src/Utility/BTC_GPIO.h index bb7a6c9..c5fc756 100644 --- a/src/Utility/BTC_GPIO.h +++ b/src/Utility/BTC_GPIO.h @@ -102,54 +102,66 @@ public: } }; -class CGPIOout1 { +class CGPIOoutBase { + int _thresh; + bool _userState; + int _pin; +protected: + void _doThresh(); + void _doUser(); + bool _getUserState(); + int _getPin() { return _pin; }; + void _setPinState(int state); + int _getPinState(); +public: + CGPIOoutBase(); + void setState(bool state); + void setThresh(int val); + void begin(int pin); +}; + +class CGPIOout1 : public CGPIOoutBase { public: enum Modes { Disabled, Status, - User + User, + Thresh }; CGPIOout1(); void begin(int pin, Modes mode); void setMode(Modes mode); void manage(); - void setState(bool state); uint8_t getState(); Modes getMode() const; private: Modes _Mode; - int _pin; void _doStatus(); - void _doUser(); int _prevState; int _statusState; int _statusDelay; unsigned long _breatheDelay; - bool _userState; uint8_t _ledState; void _doStartMode(); void _doStopMode(); void _doSuspendMode(); }; -class CGPIOout2 { +class CGPIOout2 : public CGPIOoutBase { public: enum Modes { Disabled, - User + User, + Thresh }; CGPIOout2(); void begin(int pin, Modes mode); void setMode(Modes mode); void manage(); - void setState(bool state); uint8_t getState(); Modes getMode() const; private: Modes _Mode; - int _pin; - bool _userState; - void _doUser(); }; class CGPIOout { @@ -161,6 +173,7 @@ public: void begin(int pin1, int pin2, CGPIOout1::Modes mode1, CGPIOout2::Modes mode2); void manage(); void setState(int channel, bool state); + void setThresh(int thr1, int thr2); uint8_t getState(int channel); CGPIOout1::Modes getMode1() const; CGPIOout2::Modes getMode2() const; @@ -190,6 +203,7 @@ struct sGPIOparams { CGPIOout1::Modes out1Mode; CGPIOout2::Modes out2Mode; CGPIOalg::Modes algMode; + int8_t thresh[2]; }; struct sGPIO { diff --git a/src/Utility/NVStorage.cpp b/src/Utility/NVStorage.cpp index 4c419bb..44ac6c9 100644 --- a/src/Utility/NVStorage.cpp +++ b/src/Utility/NVStorage.cpp @@ -414,8 +414,10 @@ sUserSettings::load() preferences.putUChar("GPIOout1Mode", GPIO.out1Mode); // set new preferences.putUChar("GPIOout2Mode", GPIO.out2Mode); // set new } - validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 2); GPIO.out1Mode = (CGPIOout1::Modes)tVal; - validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 1); GPIO.out2Mode = (CGPIOout2::Modes)tVal; + validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 3); GPIO.out1Mode = (CGPIOout1::Modes)tVal; + validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 2); GPIO.out2Mode = (CGPIOout2::Modes)tVal; + validatedLoad("GPIOout1Thresh", GPIO.thresh[0], 0, s8inBounds, -50, 50); + validatedLoad("GPIOout2Thresh", GPIO.thresh[1], 0, s8inBounds, -50, 50); validatedLoad("GPIOalgMode", tVal, 0, u8inBounds, 0, 2); GPIO.algMode = (CGPIOalg::Modes)tVal; validatedLoad("MenuOnTimeout", HomeMenu.onTimeout, 0, u8inBounds, 0, 3); validatedLoad("MenuonStart", HomeMenu.onStart, 0, u8inBounds, 0, 3); @@ -450,6 +452,8 @@ sUserSettings::save() preferences.putUChar("GPIOin2Mode", GPIO.in2Mode); preferences.putUChar("GPIOout1Mode", GPIO.out1Mode); preferences.putUChar("GPIOout2Mode", GPIO.out2Mode); + preferences.putChar("GPIOout1Thresh", GPIO.thresh[0]); + preferences.putChar("GPIOout2Thresh", GPIO.thresh[1]); preferences.putUChar("GPIOalgMode", GPIO.algMode); preferences.putUChar("MenuOnTimeout", HomeMenu.onTimeout); preferences.putUChar("MenuonStart", HomeMenu.onStart); diff --git a/src/Utility/NVStorage.h b/src/Utility/NVStorage.h index 73e46cc..5b6a37d 100644 --- a/src/Utility/NVStorage.h +++ b/src/Utility/NVStorage.h @@ -332,6 +332,8 @@ struct sUserSettings : public CESP32_NVStorage { GPIO.out1Mode = CGPIOout1::Disabled; GPIO.out2Mode = CGPIOout2::Disabled; GPIO.algMode = CGPIOalg::Disabled; + GPIO.thresh[0] = 0; + GPIO.thresh[1] = 0; FrameRate = 1000; cyclic.init(); HomeMenu.init(); @@ -357,6 +359,8 @@ struct sUserSettings : public CESP32_NVStorage { GPIO.out1Mode = rhs.GPIO.out1Mode; GPIO.out2Mode = rhs.GPIO.out2Mode; GPIO.algMode = rhs.GPIO.algMode; + GPIO.thresh[0] = rhs.GPIO.thresh[0]; + GPIO.thresh[1] = rhs.GPIO.thresh[1]; FrameRate = rhs.FrameRate; cyclic = rhs.cyclic; HomeMenu = rhs.HomeMenu;