ESP32_ChinaDieselHeater_Con.../src/OLED/DS18B20Screen.cpp
2019-10-18 12:55:16 +11:00

381 lines
10 KiB
C++

/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 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 "128x64OLED.h"
#include "DS18B20Screen.h"
#include "KeyPad.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
#include "../Utility/TempSense.h"
CDS18B20Screen::CDS18B20Screen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_nNumSensors = 0;
for(int i=0; i<3; i++) {
_sensorRole[i] = -1;
_Offset[i] = 0;
}
_initUI();
}
void
CDS18B20Screen::onSelect()
{
CScreenHeader::onSelect();
_initUI();
_nNumSensors = getTempSensor().getDS18B20().getNumSensors();
_readNV();
}
void
CDS18B20Screen::_initUI()
{
_rowSel = 0;
_colSel = 0;
_keyHold = -1;
_scrollChar = 0;
}
bool
CDS18B20Screen::show()
{
char msg[32];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == SaveConfirm) {
_showConfirmMessage();
}
else {
if(_colSel == 0)
_showTitle("DS18B20 Sensor Role");
else
_showTitle("DS18B20 Sensor Offset");
int baseLine = 16;
switch(_nNumSensors) {
case 2: baseLine = 28; break;
case 3: baseLine = 40; break;
}
for(int sensor = 0; sensor<_nNumSensors; sensor++) {
switch(_sensorRole[sensor]) {
case 0: strcpy(msg, "Pri"); break;
case 1: strcpy(msg, "Sec"); break;
case 2: strcpy(msg, "Ter"); break;
default: strcpy(msg, " ? "); break;
}
_printMenuText(border, baseLine-sensor*12, msg, _rowSel == (sensor+1) && _colSel == 0);
OneWireBus_ROMCode romCode;
if(!getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode)) {
strcpy(msg, "missing?") ;
}
else {
char* buffer = msg;
for (int j = 5; j >= 0; j--) {
sprintf(buffer, "%02X%s", romCode.fields.serial_number[j], j ? ":" : "");
buffer += 3;
}
}
{
CTransientFont AF(_display, &miniFontInfo);
_printMenuText(27, baseLine+2-sensor*12, msg);
}
if(_colSel == 0) {
float temperature;
getTempSensor().getDS18B20().getTemperatureIdx(sensor, temperature, false);
sprintf(msg, "%.01fC", temperature + _Offset[sensor]);
}
else {
sprintf(msg, "%+.01f", _Offset[sensor]);
}
_printMenuText(90, baseLine-sensor*12, msg, _rowSel == (sensor+1) && _colSel == 1);
}
}
}
return true;
}
bool
CDS18B20Screen::animate()
{
if(!CPasswordScreen::_busy() && !CPasswordScreen::isPasswordBusy()) {
if(_rowSel != SaveConfirm) {
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(_display.xCentre(), 52, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
case 2:
case 3:
if(_colSel == 0)
pMsg = " Hold Right to adjust probe offset. ";
else
pMsg = " Hold Left to select probe's role. ";
break;
}
if(pMsg != NULL) {
_display.drawFastHLine(0, 52, 128, WHITE);
_scrollMessage(56, pMsg, _scrollChar);
}
return true;
}
}
return false;
}
bool
CDS18B20Screen::keyHandler(uint8_t event)
{
if(CPasswordScreen::keyHandler(event)) {
if(_isPasswordOK()) {
_rowSel = 1;
_keyHold = -1;
}
}
else {
sUserSettings us;
if(event & keyPressed) {
_keyHold = 0;
// DOWN press
if(event & key_Down) {
_testCancel();
if(_rowSel == SaveConfirm)
_rowSel = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
}
if(event & keyRepeat) {
if(_keyHold >= 0) {
_keyHold++;
if(_keyHold == 2) {
if(event & key_Up) {
// rescan the one wire bus
getTempSensor().getDS18B20().find();
_nNumSensors = getTempSensor().getDS18B20().getNumSensors();
_readNV();
}
if(event & key_Left) {
_colSel = 0;
_scrollChar = 0;
}
if(event & key_Right) {
_testCancel();
_colSel = 1;
_scrollChar = 0;
}
if(event & key_Centre) {
if(_colSel == 0)
_sensorRole[_rowSel-1] = -1;
else
_Offset[_rowSel-1] = 0;
}
_keyHold = -1;
}
}
}
if(event & keyReleased) {
if(_keyHold == 0) {
// UP release
if(event & key_Up) {
if(_rowSel == SaveConfirm) {
_enableStoringMessage();
_saveNV();
NVstore.save();
getTempSensor().getDS18B20().mapSensor(-1); // reset existing mapping
getTempSensor().getDS18B20().mapSensor(0, NVstore.getHeaterTuning().DS18B20probe[0].romCode);
getTempSensor().getDS18B20().mapSensor(1, NVstore.getHeaterTuning().DS18B20probe[1].romCode);
getTempSensor().getDS18B20().mapSensor(2, NVstore.getHeaterTuning().DS18B20probe[2].romCode);
getTempSensor().getDS18B20().mapSensor(-2); // report mapping
_rowSel = 0;
}
else {
if(_rowSel == 0) {
_getPassword();
if(_isPasswordOK()) {
_rowSel = 1;
}
}
else {
_testCancel();
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
}
// LEFT press
if(event & key_Left) {
if(_rowSel == 0)
_ScreenManager.prevMenu();
else
adjust(-1);
}
// RIGHT press
if(event & key_Right) {
if(_rowSel == 0)
_ScreenManager.nextMenu();
else
adjust(+1);
}
// CENTRE press
if(event & key_Centre) {
if(_rowSel == 0) {
// _ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
// _ScreenManager.selectMenu(CScreenManager::SystemSettingsLoop, CScreenManager::TempSensorUI); // force return to user settings menu
if(getTempSensor().getBME280().getCount())
_ScreenManager.returnMenu();
else
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
else {
_rowSel = SaveConfirm;
}
}
}
_keyHold = -1;
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CDS18B20Screen::adjust(int dir)
{
switch(_rowSel) {
case 1:
if(_colSel == 0) {
_sensorRole[0] += dir;
WRAPLIMITS(_sensorRole[0], 0, _nNumSensors-1);
if(_nNumSensors == 2)
_sensorRole[1] = _sensorRole[0] == 0 ? 1 : 0;
}
else {
_Offset[0] += dir * 0.1;
BOUNDSLIMIT(_Offset[0], -10, +10);
}
break;
case 2:
if(_colSel == 0) {
_sensorRole[1] += dir;
WRAPLIMITS(_sensorRole[1], 0, _nNumSensors-1);
if(_nNumSensors == 2)
_sensorRole[0] = _sensorRole[1] == 0 ? 1 : 0;
}
else {
_Offset[1] += dir * 0.1;
BOUNDSLIMIT(_Offset[1], -10, +10);
}
break;
case 3:
if(_colSel == 0) {
_sensorRole[2] += dir;
WRAPLIMITS(_sensorRole[2], 0, _nNumSensors-1);
}
else {
_Offset[2] += dir * 0.1;
BOUNDSLIMIT(_Offset[2], -10, +10);
}
break;
}
}
void
CDS18B20Screen::_testCancel()
{
switch(_rowSel) {
case 1:
if(_sensorRole[1] == _sensorRole[0]) _sensorRole[1] = -1;
if(_sensorRole[2] == _sensorRole[0]) _sensorRole[2] = -1;
break;
case 2:
if(_sensorRole[0] == _sensorRole[1]) _sensorRole[0] = -1;
if(_sensorRole[2] == _sensorRole[1]) _sensorRole[2] = -1;
break;
case 3:
if(_sensorRole[0] == _sensorRole[2]) _sensorRole[0] = -1;
if(_sensorRole[1] == _sensorRole[2]) _sensorRole[1] = -1;
break;
}
}
void
CDS18B20Screen::_readNV()
{
for(int i=0; i< 3; i++)
_sensorRole[i] = -1;
const sHeaterTuning& tuning = NVstore.getHeaterTuning();
for(int sensor = 0; sensor < getTempSensor().getDS18B20().getNumSensors(); sensor++) {
_Offset[sensor] = tuning.DS18B20probe[sensor].offset;
OneWireBus_ROMCode romCode;
getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode); // get rom code of each attached sensor
// NV storage indices are the sensor role
// ie 0 is normal thermostat
// scan the NV store and match the stored romCodes
// if not matched, the sensor remains unmapped
for(int i=0; i< 3; i++) {
if(memcmp(tuning.DS18B20probe[i].romCode.bytes, romCode.bytes, 8) == 0) {
_sensorRole[sensor] = i; // assign role to sensor according to NV placement
break;
}
}
}
DebugPort.printf("Sensor roles: %d, %d, %d\r\n", _sensorRole[0], _sensorRole[1], _sensorRole[2]);
}
void
CDS18B20Screen::_saveNV()
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
for(int i=0; i<3; i++) {
memset(tuning.DS18B20probe[i].romCode.bytes, 0, 8);
tuning.DS18B20probe[i].offset = 0;
}
for(int sensor = 0; sensor < getTempSensor().getDS18B20().getNumSensors(); sensor++) {
tuning.DS18B20probe[sensor].offset = _Offset[sensor];
int role = _sensorRole[sensor]; // role of probe determines placement in NV storage
if(role != -1) {
OneWireBus_ROMCode romCode;
getTempSensor().getDS18B20().getRomCodeIdx(sensor, romCode); // get rom code of indexed sensor
memcpy(tuning.DS18B20probe[role].romCode.bytes, romCode.bytes, 8);
}
}
NVstore.setHeaterTuning(tuning);
}