diff --git a/Arduino/BTCDieselHeater/BTCDieselHeater.ino b/Arduino/BTCDieselHeater/BTCDieselHeater.ino index d091453..b16e447 100644 --- a/Arduino/BTCDieselHeater/BTCDieselHeater.ino +++ b/Arduino/BTCDieselHeater/BTCDieselHeater.ino @@ -410,9 +410,8 @@ void setup() { bBTconnected = false; Bluetooth.begin(); - - GPIOin.begin(GPIOin1_pin, GPIOin2_pin, GPIOinOn1Off1); - GPIOout.begin(GPIOout1_pin, GPIOout2_pin, GPIOoutStatus); + + setupGPIO(); } @@ -1231,3 +1230,21 @@ bool isCyclicActive() return bUserON && (NVstore.getCyclicMode() != 0); } +void setupGPIO() +{ + GPIOin.begin(GPIOin1_pin, GPIOin2_pin, NVstore.getGPIOinMode()); + GPIOout.begin(GPIOout1_pin, GPIOout2_pin, NVstore.getGPIOoutMode()); +} + +void setGPIO(int channel, bool state) +{ + DebugPort.print("setGPIO: Output #"); DebugPort.print(channel+1); DebugPort.print(" = "); DebugPort.println(state); + GPIOout.setState(channel, state); +} + +bool getGPIO(int channel) +{ + bool retval = GPIOout.getState(channel); + DebugPort.print("getGPIO: Output #"); DebugPort.print(channel+1); DebugPort.print(" = "); DebugPort.println(retval); + return retval; +} diff --git a/Arduino/BTCDieselHeater/src/OLED/BasicScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/BasicScreen.cpp index 88fb7c3..a7459f3 100644 --- a/Arduino/BTCDieselHeater/src/OLED/BasicScreen.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/BasicScreen.cpp @@ -144,7 +144,7 @@ CBasicScreen::keyHandler(uint8_t event) if(event & keyPressed) { repeatCount = 0; // unlock tracking of repeat events - // press LEFT to select previous screen, or Fixed Hz mode when in mode select +/* // press LEFT to select previous screen, or Fixed Hz mode when in mode select if(event & key_Left) { if(!_showMode) _ScreenManager.prevMenu(); @@ -159,8 +159,8 @@ CBasicScreen::keyHandler(uint8_t event) } _ScreenManager.reqUpdate(); } - } - // press RIGHT to select next screen, or Thermostat mode when in mode select + }**/ +/* // press RIGHT to select next screen, or Thermostat mode when in mode select if(event & key_Right) { if(!_showMode) _ScreenManager.nextMenu(); @@ -175,7 +175,7 @@ CBasicScreen::keyHandler(uint8_t event) } _ScreenManager.reqUpdate(); } - } + }*/ // press UP & DOWN to toggle thermostat / fixed Hz mode // impossible with 5 way switch! uint8_t doubleKey = key_Down | key_Up; @@ -192,6 +192,20 @@ CBasicScreen::keyHandler(uint8_t event) if(event & keyRepeat) { if(repeatCount >= 0) { repeatCount++; + // hold LEFT to toggle GPIO output #1 + if(event & key_Left) { + if(repeatCount > 2) { + repeatCount = -1; // prevent double handling + setGPIO(0, !getGPIO(0)); // toggle GPIO output #1 + } + } + // hold RIGHT to toggle GPIO output #2 + if(event & key_Right) { + if(repeatCount > 2) { + repeatCount = -1; // prevent double handling + setGPIO(1, !getGPIO(1)); // toggle GPIO output #2 + } + } // hold DOWN to enter thermostat / fixed mode selection if(event & key_Down) { if(repeatCount > 2) { @@ -244,6 +258,41 @@ CBasicScreen::keyHandler(uint8_t event) _reqOEMWarning(); } } + if(event & key_Left) { + if(repeatCount >= 0) { + if(!_showMode) { + _ScreenManager.prevMenu(); + } + else { + if(hasOEMcontroller()) + _reqOEMWarning(); + else { + _showMode = millis() + 5000; + _nModeSel = 0; + setThermostatMode(1); // set the new mode + NVstore.save(); + } + _ScreenManager.reqUpdate(); + } + } + } + if(event & key_Right) { + if(repeatCount >= 0) { + if(!_showMode) + _ScreenManager.nextMenu(); + else { + if(hasOEMcontroller()) + _reqOEMWarning(); + else { + _showMode = millis() + 5000; + _nModeSel = 1; + setThermostatMode(0); // set the new mode + NVstore.save(); + } + _ScreenManager.reqUpdate(); + } + } + } // release CENTRE to accept new mode, and/or show current setting if(event & key_Centre) { if(repeatCount != -2) { // prevent after off commands diff --git a/Arduino/BTCDieselHeater/src/OLED/ClockScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/ClockScreen.cpp index b7f4d63..eda3196 100644 --- a/Arduino/BTCDieselHeater/src/OLED/ClockScreen.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/ClockScreen.cpp @@ -37,6 +37,7 @@ CClockScreen::CClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr) { _colon = false; + _keyRepeatCount = -1; } void @@ -77,14 +78,15 @@ bool CClockScreen::keyHandler(uint8_t event) { if(event & keyPressed) { + _keyRepeatCount = 0; // unlock tracking of repeat events // press LEFT - if(event & key_Left) { +/* if(event & key_Left) { _ScreenManager.prevMenu(); } // press RIGHT if(event & key_Right) { _ScreenManager.nextMenu(); - } + }*/ // press UP if(event & key_Up) { _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::SetClockUI); // switch to clock set screen @@ -94,6 +96,37 @@ CClockScreen::keyHandler(uint8_t event) _ScreenManager.selectMenu(CScreenManager::TimerMenuLoop); // switch to timer set screen loop } } + if(event & keyRepeat) { + if(_keyRepeatCount >= 0) { + _keyRepeatCount++; + // hold LEFT to toggle GPIO output #1 + if(event & key_Left) { + if(_keyRepeatCount > 2) { + _keyRepeatCount = -1; // prevent double handling + setGPIO(0, !getGPIO(0)); // toggle GPIO output #1 + } + } + // hold RIGHT to toggle GPIO output #2 + if(event & key_Right) { + if(_keyRepeatCount > 2) { + _keyRepeatCount = -1; // prevent double handling + setGPIO(1, !getGPIO(1)); // toggle GPIO output #2 + } + } + } + } + // release event + if(event & keyReleased) { + if(_keyRepeatCount == 0) { // short Up press - lower target + if(event & key_Left) { + _ScreenManager.prevMenu(); + } + if(event & key_Right) { + _ScreenManager.nextMenu(); + } + } + _keyRepeatCount = -1; + } return true; } diff --git a/Arduino/BTCDieselHeater/src/OLED/ClockScreen.h b/Arduino/BTCDieselHeater/src/OLED/ClockScreen.h index b0420f2..8120b16 100644 --- a/Arduino/BTCDieselHeater/src/OLED/ClockScreen.h +++ b/Arduino/BTCDieselHeater/src/OLED/ClockScreen.h @@ -32,6 +32,7 @@ class CClockScreen : public CScreenHeader { protected: virtual void showTime(int numTimers); bool _colon; + int _keyRepeatCount; public: CClockScreen(C128x64_OLED& display, CScreenManager& mgr); bool show(); diff --git a/Arduino/BTCDieselHeater/src/OLED/DetailedScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/DetailedScreen.cpp index c5bffc8..676e5f9 100644 --- a/Arduino/BTCDieselHeater/src/OLED/DetailedScreen.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/DetailedScreen.cpp @@ -176,17 +176,32 @@ CDetailedScreen::keyHandler(uint8_t event) if(event & keyPressed) { _keyRepeatCount = 0; // unlock tracking of repeat events - if(event & key_Left) { +/* if(event & key_Left) { _ScreenManager.prevMenu(); } if(event & key_Right) { _ScreenManager.nextMenu(); - } + }*/ } // require hold to turn ON or OFF if(event & keyRepeat) { if(_keyRepeatCount >= 0) { _keyRepeatCount++; + // hold LEFT to toggle GPIO output #1 + if(event & key_Left) { + if(_keyRepeatCount > 2) { + _keyRepeatCount = -1; // prevent double handling + setGPIO(0, !getGPIO(0)); // toggle GPIO output #1 + } + } + // hold RIGHT to toggle GPIO output #2 + if(event & key_Right) { + if(_keyRepeatCount > 2) { + _keyRepeatCount = -1; // prevent double handling + setGPIO(1, !getGPIO(1)); // toggle GPIO output #2 + } + } + if(event & key_Centre) { int runstate = getHeaterInfo().getRunStateEx(); if(runstate) { // running, including cyclic mode idle @@ -235,6 +250,12 @@ CDetailedScreen::keyHandler(uint8_t event) _showTarget = millis() + 3500; } _ScreenManager.reqUpdate(); + if(event & key_Left) { + _ScreenManager.prevMenu(); + } + if(event & key_Right) { + _ScreenManager.nextMenu(); + } } _keyRepeatCount = -1; } diff --git a/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.cpp deleted file mode 100644 index 258b6ae..0000000 --- a/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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 . - * - */ - -#include "128x64OLED.h" -#include "ExperimentalSettingsScreen.h" -#include "KeyPad.h" -#include "../Protocol/helpers.h" -#include "../Utility/UtilClasses.h" -#include "../Utility/NVStorage.h" - - -/////////////////////////////////////////////////////////////////////////// -// -// CExperimentalSettingsScreen -// -// This screen provides control over experimental features -// -/////////////////////////////////////////////////////////////////////////// - -static const int Line3 = 14; -static const int Line2 = 27; -static const int Line1 = 40; -static const int Column = 70; - -CExperimentalSettingsScreen::CExperimentalSettingsScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr) -{ - _initUI(); - _window = 10; - _thermoMode = 0; - _cyclicMode = 0; -} - -void -CExperimentalSettingsScreen::onSelect() -{ - CPasswordScreen::onSelect(); - _initUI(); - _window = NVstore.getThermostatMethodWindow(); - _thermoMode = NVstore.getThermostatMethodMode(); - _cyclicMode = NVstore.getCyclicMode(); -} - -void -CExperimentalSettingsScreen::_initUI() -{ - _rowSel = 0; - _animateCount = 0; -} - -bool -CExperimentalSettingsScreen::show() -{ - char msg[20]; - _display.clearDisplay(); - - if(!CPasswordScreen::show()) { // for showing "saving settings" - - if(_rowSel == 4) { - _printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify); - _printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify); - _printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify); - } - else { - _printInverted(_display.xCentre(), 0, " Experimental ", true, eCentreJustify); - _printMenuText(65, Line3, "Suspend:", false, eRightJustify); - _printMenuText(65, Line2, "Thermostat:", false, eRightJustify); - _printMenuText(65, Line1, "Window:", false, eRightJustify); - sprintf(msg, "%.1f\367C", _window); // \367 is octal for Adafruit degree symbol - _printMenuText(Column, Line1, msg, _rowSel == 1); - switch(_thermoMode) { - case 1: - _printMenuText(Column, Line2, "Deadband", _rowSel == 2); - break; - case 2: - _printMenuText(Column, Line2, "Linear Hz", _rowSel == 2); - break; - default: - _printMenuText(Column, Line2, "Standard", _rowSel == 2); - break; - } - if(_cyclicMode) { - sprintf(msg, "> %d\367C", _cyclicMode+1); // \367 is octal for Adafruit degree symbol - } - else { - strcpy(msg, "OFF"); - } - _printMenuText(Column, Line3, msg, _rowSel == 3); - } - } - - return true; -} - -bool -CExperimentalSettingsScreen::animate() -{ - if(_rowSel != 4) { - int yPos = 53; - int xPos = _display.xCentre(); - const char* pMsg = NULL; - switch(_rowSel) { - case 0: - _printMenuText(xPos, yPos, " Exit ", true, eCentreJustify); - _printMenuText(_display.width(), yPos, "\030Edit", false, eRightJustify); - break; - case 1: - _display.drawFastHLine(0, 52, 128, WHITE); - pMsg = " User defined window for custom thermostat modes. "; - _scrollMessage(56, pMsg, _startChar); - break; - case 2: - _display.drawFastHLine(0, 52, 128, WHITE); - switch(_thermoMode) { - case 1: - pMsg = " Controller holds measured temperature at the set point whilst within the window. "; - break; - case 2: - pMsg = " Controller uses Fixed Hz mode, adjusting pump rate linearly across the set point window. "; - break; - default: - pMsg = " Use heater's standard thermostat control. "; - break; - } - if(pMsg) - _scrollMessage(56, pMsg, _startChar); - break; - case 3: - _display.drawFastHLine(0, 52, 128, WHITE); - pMsg = " Controller auto cycles heater if over temperature occurs. "; - _scrollMessage(56, pMsg, _startChar); - break; - } - return true; - } - return false; -} - -bool -CExperimentalSettingsScreen::keyHandler(uint8_t event) -{ - if(event & keyPressed) { - // press LEFT to select previous screen - if(event & key_Left) { - switch(_rowSel) { - case 2: - _startChar = 0; - case 1: - case 3: - _adjust(-1); - break; - case 4: - _rowSel = 0; // abort save - break; - } - } - // press RIGHT to select next screen - if(event & key_Right) { - switch(_rowSel) { - case 2: - _startChar = 0; - case 1: - case 3: - _adjust(+1); - break; - case 4: - _rowSel = 0; // abort save - break; - } - } - if(event & key_Down) { - if(_rowSel == 0) { - _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::FontDumpUI); - } - else { - _rowSel--; - LOWERLIMIT(_rowSel, 0); - } - } - // UP press - if(event & key_Up) { - switch(_rowSel) { - case 0: - case 1: - case 2: - case 3: - _startChar = 0; - _rowSel++; - UPPERLIMIT(_rowSel, 3); - break; - case 4: // confirmed save - _showStoringMessage(); - NVstore.setThermostatMethodMode(_thermoMode); - NVstore.setThermostatMethodWindow(_window); - NVstore.setCyclicMode(_cyclicMode); - saveNV(); - _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: - _rowSel = 4; - break; - } - } - _ScreenManager.reqUpdate(); - } - - return true; -} - -void -CExperimentalSettingsScreen::_adjust(int dir) -{ - switch(_rowSel) { - case 1: // window - _window += (dir * 0.1); - UPPERLIMIT(_window, 6.3); - LOWERLIMIT(_window, 0.2); - break; - case 2: // thermostat mode - _thermoMode += dir; - ROLLLOWERLIMIT(_thermoMode, 0, 2); - ROLLUPPERLIMIT(_thermoMode, 2, 0); - break; - case 3: - _cyclicMode += dir; - UPPERLIMIT(_cyclicMode, 10); - LOWERLIMIT(_cyclicMode, 0); - break; - } -} diff --git a/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.h b/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.h deleted file mode 100644 index 5ea1fe1..0000000 --- a/Arduino/BTCDieselHeater/src/OLED/ExperimentalSettingsScreen.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 __EXPERIMENTALSETTINGSSCREEN_H__ -#define __EXPERIMENTALSETTINGSSCREEN_H__ - -#include -#include "PasswordScreen.h" - -class C128x64_OLED; -class CScreenManager; - -class CExperimentalSettingsScreen : public CPasswordScreen -{ - int _rowSel; - void _adjust(int dir); - float _window; - int _thermoMode; - int _cyclicMode; - int _animateCount; - int _startChar; - void _initUI(); -public: - CExperimentalSettingsScreen(C128x64_OLED& display, CScreenManager& mgr); - bool show(); - bool animate(); - bool keyHandler(uint8_t event); - void onSelect(); -}; - -#endif diff --git a/Arduino/BTCDieselHeater/src/OLED/FontDumpScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/FontDumpScreen.cpp index 39eb04e..b6ee55d 100644 --- a/Arduino/BTCDieselHeater/src/OLED/FontDumpScreen.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/FontDumpScreen.cpp @@ -97,7 +97,7 @@ CFontDumpScreen::keyHandler(uint8_t event) } // CENTRE press if(event & key_Centre) { - _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::ExperimentalUI); // force return to prior menu + _ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI); // force return to prior menu } _ScreenManager.reqUpdate(); } diff --git a/Arduino/BTCDieselHeater/src/OLED/ScreenManager.cpp b/Arduino/BTCDieselHeater/src/OLED/ScreenManager.cpp index aa3e536..bf14c20 100644 --- a/Arduino/BTCDieselHeater/src/OLED/ScreenManager.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/ScreenManager.cpp @@ -31,10 +31,11 @@ #include "RebootScreen.h" #include "HeaterSettingsScreen.h" #include "SettingsScreen.h" -#include "ExperimentalSettingsScreen.h" +#include "ThermostatModeScreen.h" #include "FontDumpScreen.h" #include "TimerChartScreen.h" #include "InheritSettingsScreen.h" +#include "GPIOScreen.h" #include #include "../cfg/pins.h" #include "../cfg/BTCConfig.h" @@ -204,11 +205,15 @@ CScreenManager::begin(bool bNoClock) menuloop.push_back(new CFuelMixtureScreen(*_pDisplay, *this)); // tuning menuloop.push_back(new CHeaterSettingsScreen(*_pDisplay, *this)); // tuning _Screens.push_back(menuloop); + // create User Settings screens loop + menuloop.clear(); + menuloop.push_back(new CThermostatModeScreen(*_pDisplay, *this)); // experimental settings screen + menuloop.push_back(new CGPIOScreen(*_pDisplay, *this)); // GPIO settings screen + _Screens.push_back(menuloop); // create branch screens menuloop.clear(); menuloop.push_back(new CSetClockScreen(*_pDisplay, *this)); // clock set branch screen menuloop.push_back(new CInheritSettingsScreen(*_pDisplay, *this)); // inherit OEM settings branch screen - menuloop.push_back(new CExperimentalSettingsScreen(*_pDisplay, *this)); // experimental settings branch screen menuloop.push_back(new CFontDumpScreen(*_pDisplay, *this)); // font dump branch screen _Screens.push_back(menuloop); diff --git a/Arduino/BTCDieselHeater/src/OLED/ScreenManager.h b/Arduino/BTCDieselHeater/src/OLED/ScreenManager.h index 7f2c8f5..b5c835d 100644 --- a/Arduino/BTCDieselHeater/src/OLED/ScreenManager.h +++ b/Arduino/BTCDieselHeater/src/OLED/ScreenManager.h @@ -43,12 +43,13 @@ class CScreenManager { void _leaveScreen(); void _changeSubMenu(int dir); public: - enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, TuningMenuLoop, BranchMenu }; + enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, TuningMenuLoop, UserSettingsLoop, BranchMenu }; enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, CommsUI, SettingsUI }; enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI, Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI }; enum eUITuningMenus { MixtureUI, HeaterSettingsUI }; - enum eUIBranchMenus { SetClockUI, InheritSettingsUI, ExperimentalUI, FontDumpUI }; + enum eUIUserSettingsMenus { ExThermostatUI, GPIOUI }; + enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI }; public: CScreenManager(); ~CScreenManager(); diff --git a/Arduino/BTCDieselHeater/src/OLED/SettingsScreen.cpp b/Arduino/BTCDieselHeater/src/OLED/SettingsScreen.cpp index 84f6772..5cda6c9 100644 --- a/Arduino/BTCDieselHeater/src/OLED/SettingsScreen.cpp +++ b/Arduino/BTCDieselHeater/src/OLED/SettingsScreen.cpp @@ -167,7 +167,8 @@ CSettingsScreen::keyHandler(uint8_t event) } // press DOWN if(event & key_Down) { - _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::ExperimentalUI); +// _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::ExperimentalUI); + _ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI); } } } diff --git a/Arduino/BTCDieselHeater/src/Protocol/helpers.h b/Arduino/BTCDieselHeater/src/Protocol/helpers.h index 8d519c7..6228ad1 100644 --- a/Arduino/BTCDieselHeater/src/Protocol/helpers.h +++ b/Arduino/BTCDieselHeater/src/Protocol/helpers.h @@ -56,6 +56,9 @@ extern bool hasOEMLCDcontroller(); extern int getBlueWireStat(); extern int getSmartError(); extern bool isCyclicActive(); +extern void setupGPIO(); +extern void setGPIO(int channel, bool state); +extern bool getGPIO(int channel); diff --git a/Arduino/BTCDieselHeater/src/Utility/GPIO.cpp b/Arduino/BTCDieselHeater/src/Utility/GPIO.cpp index 27fcdca..3aedf4b 100644 --- a/Arduino/BTCDieselHeater/src/Utility/GPIO.cpp +++ b/Arduino/BTCDieselHeater/src/Utility/GPIO.cpp @@ -22,7 +22,7 @@ #include "GPIO.h" #include "../Protocol/helpers.h" -const int BREATHINTERVAL = 30; +const int BREATHINTERVAL = 45; const int FADEAMOUNT = 3; const int FLASHPERIOD = 2000; const int ONFLASHINTERVAL = 50; @@ -156,6 +156,8 @@ CGPIOout::CGPIOout() _breatheDelay = 0; _statusState = 0; _statusDelay = 0; + _userState = 0; + _prevState = -1; } void @@ -166,32 +168,33 @@ CGPIOout::begin(int pin1, int pin2, GPIOoutModes mode) if(pin1) { pinMode(pin1, OUTPUT); // GPIO output pin #1 digitalWrite(pin1, LOW); - ledcSetup(0, 500, 8); // create PWM channel for GPIO1 + ledcSetup(0, 500, 8); // create PWM channel for GPIO1: 500Hz, 8 bits } if(pin2) { pinMode(pin2, OUTPUT); // GPIO output pin #2 digitalWrite(pin2, LOW); - ledcSetup(1, 500, 8); // create PWM channel for GPIO2 - ledcAttachPin(pin2, 1); // attach PWM to GPIO line + ledcSetup(1, 500, 8); // create PWM channel for GPIO2: 500Hz, 8 bits } - - setMode(mode); } +void +CGPIOout::setMode(GPIOoutModes mode) +{ + _Mode = mode; + _prevState = -1; + ledcDetachPin(_pins[0]); // ensure PWM detached from IO line + ledcDetachPin(_pins[1]); // ensure PWM detached from IO line +}; + void CGPIOout::manage() { switch (_Mode) { - case GPIOoutNone: - break; - case GPIOoutStatus: - _doStatus(); - break; - case GPIOoutUser: - _doUser(); - break; + case GPIOoutNone: break; + case GPIOoutStatus: _doStatus(); break; + case GPIOoutUser: _doUser(); break; } } @@ -201,12 +204,10 @@ CGPIOout::_doStatus() if(_pins[0] == 0) return; +// DebugPort.println("GPIOout::_doStatus()"); int runstate = getHeaterInfo().getRunStateEx(); int statusMode = 0; switch(runstate) { - case 0: - statusMode = 0; - break; case 1: case 2: case 3: @@ -232,6 +233,9 @@ CGPIOout::_doStatus() statusMode = 4; break; } + + // change of mode typically requires changing from simple digital out + // to PWM or vice versa if(_prevState != statusMode) { _prevState = statusMode; _statusState = 0; @@ -244,7 +248,7 @@ CGPIOout::_doStatus() case 1: ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line ledcWrite(0, _statusState); - _breatheDelay = millis() + BREATHINTERVAL; + _breatheDelay = millis() + BREATHINTERVAL; break; case 2: ledcDetachPin(_pins[0]); // detach PWM from IO line @@ -254,7 +258,7 @@ CGPIOout::_doStatus() ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line _statusState = 255; ledcWrite(0, _statusState); - _breatheDelay = millis() + BREATHINTERVAL; + _breatheDelay = millis() + BREATHINTERVAL; break; case 4: ledcDetachPin(_pins[0]); // detach PWM from IO line @@ -273,7 +277,13 @@ CGPIOout::_doStatus() void CGPIOout::_doUser() { - +// DebugPort.println("GPIOout::_doUser()"); + if(_pins[0]) { + digitalWrite(_pins[0], (_userState & 0x01) ? HIGH : LOW); + } + if(_pins[1]) { + digitalWrite(_pins[1], (_userState & 0x02) ? HIGH : LOW); + } } void @@ -282,8 +292,10 @@ CGPIOout::_doStartMode() // breath up PWM long tDelta = millis() - _breatheDelay; if(tDelta >= 0) { _breatheDelay += BREATHINTERVAL; - _statusState += FADEAMOUNT; - ledcWrite(0, _statusState & 0xff); + int expo = ((_statusState >> 5) + 1); + _statusState += expo; + _statusState &= 0xff; + ledcWrite(0, _statusState); } } @@ -293,8 +305,11 @@ CGPIOout::_doStopMode() // breath down PWM long tDelta = millis() - _breatheDelay; if(tDelta >= 0) { _breatheDelay += BREATHINTERVAL; - _statusState -= FADEAMOUNT; - ledcWrite(0, _statusState & 0xff); + int expo = ((_statusState >> 5) + 1); + _statusState -= expo; + _statusState &= 0xff; + ledcWrite(0, _statusState); + } } @@ -313,4 +328,21 @@ CGPIOout::_doSuspendMode() // brief flash digitalWrite(_pins[0], LOW); } } +} + +void +CGPIOout::setState(int channel, bool state) +{ + int mask = 0x01 << (channel & 0x01); + if(state) + _userState |= mask; + else + _userState &= ~mask; +} + +bool +CGPIOout::getState(int channel) +{ + int mask = 0x01 << (channel & 0x01); + return (_userState & mask) != 0; } \ No newline at end of file diff --git a/Arduino/BTCDieselHeater/src/Utility/GPIO.h b/Arduino/BTCDieselHeater/src/Utility/GPIO.h index 68fa7e1..ca47559 100644 --- a/Arduino/BTCDieselHeater/src/Utility/GPIO.h +++ b/Arduino/BTCDieselHeater/src/Utility/GPIO.h @@ -19,6 +19,9 @@ * */ +#ifndef __BTCGPIO_H__ +#define __BTCGPIO_H__ + #include enum GPIOinModes { @@ -63,12 +66,17 @@ class CGPIOout { int _statusState; int _statusDelay; unsigned long _breatheDelay; + uint8_t _userState; void _doStartMode(); void _doStopMode(); void _doSuspendMode(); public: CGPIOout(); - void setMode(GPIOoutModes mode) { _Mode = mode; }; + void setMode(GPIOoutModes mode); void begin(int pin1, int pin2, GPIOoutModes mode); void manage(); + void setState(int channel, bool state); + bool getState(int channel); }; + +#endif // __BTCGPIO_H__ diff --git a/Arduino/BTCDieselHeater/src/Utility/NVStorage.cpp b/Arduino/BTCDieselHeater/src/Utility/NVStorage.cpp index 71f8d7e..c4977c8 100644 --- a/Arduino/BTCDieselHeater/src/Utility/NVStorage.cpp +++ b/Arduino/BTCDieselHeater/src/Utility/NVStorage.cpp @@ -284,6 +284,55 @@ CHeaterStorage::setCyclicMode(unsigned char val) save(); } +GPIOinModes +CHeaterStorage::getGPIOinMode() +{ + GPIOinModes inMode = GPIOinNone; + switch(_calValues.Options.GPIOinMode) { + case 0: inMode = GPIOinNone; break; + case 1: inMode = GPIOinOn1Off2; break; + case 2: inMode = GPIOinOnHold1; break; + case 3: inMode = GPIOinOn1Off1; break; + } + return inMode; +} + +void +CHeaterStorage::setGPIOinMode(unsigned char val) +{ + _calValues.Options.GPIOinMode = val; +} + +GPIOoutModes +CHeaterStorage::getGPIOoutMode() +{ + GPIOoutModes outMode = GPIOoutNone; + switch(_calValues.Options.GPIOoutMode) { + case 0: outMode = GPIOoutNone; break; + case 1: outMode = GPIOoutStatus; break; + case 2: outMode = GPIOoutUser; break; + } + return outMode; +} + +void +CHeaterStorage::setGPIOoutMode(unsigned char val) +{ + _calValues.Options.GPIOoutMode = val; +} + +unsigned char +CHeaterStorage::getGPIOalgMode() +{ + return _calValues.Options.GPIOalgMode; +} + +void +CHeaterStorage::setGPIOalgMode(unsigned char val) +{ + _calValues.Options.GPIOalgMode = val; +} + /////////////////////////////////////////////////////////////////////////////////////// // ESP32 // @@ -403,6 +452,9 @@ CESP32HeaterStorage::loadUI() validatedLoad("enableWifi", _calValues.Options.enableWifi, 1, u8inBounds, 0, 1); validatedLoad("enableOTA", _calValues.Options.enableOTA, 1, u8inBounds, 0, 1); validatedLoad("cyclicMode", _calValues.Options.cyclicMode, 0, u8inBounds, 0, 10); + validatedLoad("GPIOinMode", _calValues.Options.GPIOinMode, 0, u8inBounds, 0, 3); + validatedLoad("GPIOoutMode", _calValues.Options.GPIOoutMode, 0, u8inBounds, 0, 2); + validatedLoad("GPIOalgMode", _calValues.Options.GPIOalgMode, 0, u8inBounds, 0, 2); preferences.end(); } @@ -416,6 +468,9 @@ CESP32HeaterStorage::saveUI() preferences.putUChar("enableWifi", _calValues.Options.enableWifi); preferences.putUChar("enableOTA", _calValues.Options.enableOTA); preferences.putUChar("cyclicMode", _calValues.Options.cyclicMode); + preferences.putUChar("GPIOinMode", _calValues.Options.GPIOinMode); + preferences.putUChar("GPIOoutMode", _calValues.Options.GPIOoutMode); + preferences.putUChar("GPIOalgMode", _calValues.Options.GPIOalgMode); preferences.end(); } diff --git a/Arduino/BTCDieselHeater/src/Utility/NVStorage.h b/Arduino/BTCDieselHeater/src/Utility/NVStorage.h index 3daf5cf..f97ff5f 100644 --- a/Arduino/BTCDieselHeater/src/Utility/NVStorage.h +++ b/Arduino/BTCDieselHeater/src/Utility/NVStorage.h @@ -23,6 +23,7 @@ #define __BTC_NV_STORAGE_H__ #include "../RTC/Timers.h" // for sTimer +#include "GPIO.h" struct sHeater { uint8_t Pmin; @@ -68,6 +69,10 @@ struct sBTCoptions { uint8_t enableWifi; uint8_t enableOTA; uint8_t cyclicMode; + uint8_t GPIOinMode; + uint8_t GPIOoutMode; + uint8_t GPIOalgMode; + bool valid() { bool retval = true; retval &= (DimTime >= 0) && (DimTime < 300000); // 5 mins @@ -76,6 +81,8 @@ struct sBTCoptions { retval &= (enableWifi == 0) || (enableWifi == 1); retval &= (enableOTA == 0) || (enableOTA == 1); retval &= cyclicMode < 10; + retval &= GPIOinMode < 4; + retval &= GPIOoutMode < 3; return retval; } void init() { @@ -85,6 +92,9 @@ struct sBTCoptions { enableWifi = 1; enableOTA = 1; cyclicMode = 0; + GPIOinMode = 0; + GPIOoutMode = 0; + GPIOalgMode = 0; }; }; @@ -139,6 +149,9 @@ public: unsigned char getWifiEnabled(); unsigned char getOTAEnabled(); unsigned char getCyclicMode(); + GPIOinModes getGPIOinMode(); + GPIOoutModes getGPIOoutMode(); + unsigned char getGPIOalgMode(); void setPmin(float); void setPmax(float); @@ -156,12 +169,16 @@ public: void setWifiEnabled(unsigned char val); void setOTAEnabled(unsigned char val); void setCyclicMode(unsigned char val); + void setGPIOinMode(unsigned char val); + void setGPIOoutMode(unsigned char val); + void setGPIOalgMode(unsigned char val); void getTimerInfo(int idx, sTimer& timerInfo); void setTimerInfo(int idx, const sTimer& timerInfo); }; + #ifdef ESP32 #include