ESP32_ChinaDieselHeater_Con.../Arduino/BTCDieselHeater/src/Utility/GPIO.cpp
Ray Jones de6226ad12 User settings loop now uses graphic symbology.
Added adjustable -ve threshold for Jess mode (cyclic shutdown if over temp).
Added user selectable display blank, dim or do nothing option on keypad inactivity.
Added user selectable menu timeout on keypad inactivity.
2019-04-27 20:41:47 +10:00

374 lines
7.9 KiB
C++

/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
#include "GPIO.h"
#include "../Protocol/helpers.h"
#include <driver/adc.h>
#include "DebugPort.h"
const int BREATHINTERVAL = 45;
const int FADEAMOUNT = 3;
const int FLASHPERIOD = 2000;
const int ONFLASHINTERVAL = 50;
CGPIOin::CGPIOin()
{
_Mode = GPIOinNone;
_lastKey = 0;
}
void
CGPIOin::begin(int pin1, int pin2, GPIOinModes mode, int activeState)
{
_Debounce.addPin(pin1);
_Debounce.addPin(pin2);
_Debounce.setActiveState(activeState);
setMode(mode);
}
uint8_t
CGPIOin::getState(int channel)
{
int mask = 0x01 << (channel & 0x01);
return (_Debounce.getState() & mask) != 0;
}
void
CGPIOin::manage()
{
switch (_Mode) {
case GPIOinNone:
break;
case GPIOinOn1Off2:
_doOn1Off2();
break;
case GPIOinOnHold1:
_doOnHold1();
break;
case GPIOinOn1Off1:
_doOn1Off1();
break;
}
}
void
CGPIOin::_doOn1Off2()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
requestOn();
}
if(newKey & 0x02) {
requestOff();
}
}
}
// mode where heater runs if input 1 is shorted
// stops when open
void
CGPIOin::_doOnHold1()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
requestOn();
}
else {
requestOff();
}
}
}
// mode where heater runs if input 1 is shorted
// stops when open
void
CGPIOin::_doOn1Off1()
{
uint8_t newKey = _Debounce.manage();
// determine edge events
uint8_t keyChange = newKey ^ _lastKey;
_lastKey = newKey;
if(keyChange) {
if(newKey & 0x01) {
if(getHeaterInfo().getRunStateEx())
requestOff();
else
requestOn();
}
}
}
CGPIOout::CGPIOout()
{
_Mode = GPIOoutNone;
_pins[0] = 0;
_pins[1] = 0;
_breatheDelay = 0;
_statusState = 0;
_statusDelay = 0;
_userState = 0;
_prevState = -1;
}
void
CGPIOout::begin(int pin1, int pin2, GPIOoutModes mode)
{
_pins[0] = pin1;
_pins[1] = pin2;
if(pin1) {
pinMode(pin1, OUTPUT); // GPIO output pin #1
digitalWrite(pin1, LOW);
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: 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;
}
}
void
CGPIOout::_doStatus()
{
if(_pins[0] == 0)
return;
// DebugPort.println("GPIOout::_doStatus()");
int runstate = getHeaterInfo().getRunStateEx();
int statusMode = 0;
switch(runstate) {
case 1:
case 2:
case 3:
case 4:
case 9:
// starting modes
statusMode = 1;
break;
case 5:
// run mode
statusMode = 2;
break;
case 6:
case 7:
case 8:
case 11:
case 12:
// cooldown modes
statusMode = 3;
break;
case 10:
// suspend mode
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;
_statusDelay = millis() + BREATHINTERVAL;
switch(statusMode) {
case 0:
ledcDetachPin(_pins[0]); // detach PWM from IO line
digitalWrite(_pins[0], LOW);
break;
case 1:
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
ledcWrite(0, _statusState);
_breatheDelay = millis() + BREATHINTERVAL;
break;
case 2:
ledcDetachPin(_pins[0]); // detach PWM from IO line
digitalWrite(_pins[0], HIGH);
break;
case 3:
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
_statusState = 255;
ledcWrite(0, _statusState);
_breatheDelay = millis() + BREATHINTERVAL;
break;
case 4:
ledcDetachPin(_pins[0]); // detach PWM from IO line
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
digitalWrite(_pins[0], LOW);
break;
}
}
switch(statusMode) {
case 1: _doStartMode(); break;
case 3: _doStopMode(); break;
case 4: _doSuspendMode(); break;
}
}
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
CGPIOout::_doStartMode() // breath up PWM
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_breatheDelay += BREATHINTERVAL;
int expo = ((_statusState >> 5) + 1);
_statusState += expo;
_statusState &= 0xff;
ledcWrite(0, _statusState);
}
}
void
CGPIOout::_doStopMode() // breath down PWM
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_breatheDelay += BREATHINTERVAL;
int expo = ((_statusState >> 5) + 1);
_statusState -= expo;
_statusState &= 0xff;
ledcWrite(0, _statusState);
}
}
void
CGPIOout::_doSuspendMode() // brief flash
{
long tDelta = millis() - _breatheDelay;
if(tDelta >= 0) {
_statusState++;
if(_statusState & 0x01) {
_breatheDelay += ONFLASHINTERVAL; // brief flash on
digitalWrite(_pins[0], HIGH);
}
else {
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
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;
}
// expected external analogue circuit is a 10k pot.
// Top end of pot is connected to GPIO Vcc (red wire) via 5k6 fixed resistor. (GPIO Vcc is 5V via schottky diode)
// Bottom end of pot is connected to GND (black wire) via 1k fixed resistor.
// Wiper is into Pin 6 of GPIO (white wire) - analogue input
CGPIOalg::CGPIOalg()
{
_expMean = 0;
}
void
CGPIOalg::begin(adc1_channel_t pin, GPIOalgModes mode)
{
_pin = pin;
_Mode = mode;
if(_Mode != GPIOalgNone) {
adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_5);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_11db);
}
}
void CGPIOalg::manage()
{
const float fAlpha = 0.95; // exponential mean alpha
if(_Mode != GPIOalgNone) {
int read_raw;
char msg[32];
read_raw = adc1_get_raw( ADC1_CHANNEL_5);
sprintf(msg, "ADC: %d", read_raw );
_expMean = _expMean * fAlpha + (1-fAlpha) * float(read_raw);
// DebugPort.println(msg);
}
}
int
CGPIOalg::getValue()
{
return _expMean;
}