Compare commits

..

No commits in common. "master" and "V2.2.2" have entirely different histories.

1580 changed files with 27812 additions and 133879 deletions

18
.gitignore vendored
View file

@ -7,21 +7,3 @@
.vs
__vm
/Arduino/BTCDieselHeater/.vscode/*.json
.pio
.pioenvs
.piolibdeps
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
/.vscode/settings.json
/.vscode/extensions.json
Arduino/Afterburner/data/*
Arduino/Afterburner/src/*
/Altium
/Releases
/webdev
/case
/DieselHeaterV2.PcbDoc
/StandardResponse.txt
/HeaterHack-Tested.zip
/OTA_COM.txt

View file

@ -1,67 +0,0 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

View file

@ -1,6 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x1F0000,0x1E0000,
spiffs, data, spiffs, 0x3D0000,0x30000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x1E0000
5 app1 app ota_1 0x1F0000 0x1E0000
6 spiffs data spiffs 0x3D0000 0x30000

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,34 +0,0 @@
/**********************************************************************
* This file is deliberately empty.
*
* It only exists to satisfy the Arduino IDE's perverse requirement that a
* .ino must live directly below a parent directory, with the same name.
*
* In this instance Afterburner\Afterburner.ino
*
* I seriously recommend you use PLatformIO with your favourite editor.
*
* The real source code for the entire project is linked to via a symbolic
* link to the ClonedRepo\src, lib & data directories.
*
* ie ClonedRepo\Arduino\Afterburner\src\src -> ClonedRepo\src (..\..\src)
* ie ClonedRepo\Arduino\Afterburner\src\lib -> ClonedRepo\lib (..\..\lib)
* ie ClonedRepo\Arduino\Afterburner\data -> ClonedRepo\data (..\..\data)
*
* A batch file is in this folder to create these links, please use it first.
*
* Whilst initially alarming that is .ino file is empty, the Arduino IDE
* happily creates the required executable :-)
*
* The REAL host of setup() and loop() resides in ClonedRepo\src\Afterburner.cpp
*
*
*****************************************************************************
*****************************************************************************
** **
** DUMP the Arduino IDE, and use PlatformIO. **
** Load the ClonedRepo path into PlatformIO. **
** Builds much faster and meshes well with decent programming editors :-) **
** **
*****************************************************************************
*****************************************************************************/

View file

@ -1,5 +0,0 @@
#!/bin/sh
mkdir src
ln -s ../../src src/src
ln -s ../../lib src/lib
ln -s ../../data data

View file

@ -1,7 +0,0 @@
rem mklink /H Afterburner.ino ..\..\src\AfterBurner\Afterburner.cpp
mkdir src
mklink /J src\lib ..\..\lib
mklink /J src\src ..\..\src
mklink /J data ..\..\data

View file

@ -1,20 +0,0 @@
TO WORK WITH ARDUINO IDE, EVERYTHING IN THIS FOLDER IS FAKE!
When you pull from gitlab, no symbolic links will be created.
You need to execute MakeSymLinks_Windows.bat from Explorer.
Arduino insists upon .ino for their projects, and the .ino
file name also has to match the parent directory name.
The BIG trick here is Afterburner.ino is empty - zilch, nada, nothing!
All the REAL source code lives via the src symbolic link.
The real core exists as a .cpp file: repo\src\Afterburner.cpp
Arduino\Afterburner\Afterburner.ino is EMPTY
Arduino\Afterburner\src\src links to repo\src\
Arduino\Afterburner\src\lib links to repo\lib\
Arduino\Afterburner\data links to repo\data
Ugggh. I hate Arduino IDE (and it's build environment!)

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,536 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<!-- <link rel="icon" href="data;,"> -->
<script>
var Socket;
function init() {
Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
Socket.onmessage = function(event){
var heater = JSON.parse(event.data);
var key;
for(key in heater) {
console.log("JSON decode:", key, heater[key]);
switch(key) {
case "RunState":
if (heater[key] == 0) {
document.getElementById("myonoffswitch").checked = false;
document.getElementById("myonoffswitch").style = "block";
document.getElementById("onoffswitch").style.visibility = "visible";
} else if(heater[key] >= 7) {
document.getElementById("myonoffswitch").checked = false;
document.getElementById("myonoffswitch").style = "none";
document.getElementById("onoffswitch").style.visibility = "hidden";
} else {
document.getElementById("myonoffswitch").checked = true;
document.getElementById("myonoffswitch").style = "block";
document.getElementById("onoffswitch").style.visibility = "visible";
}
document.getElementById("RunString").style.visibility = (heater[key] == 5 || heater[key] == 0) ? "hidden" : "visible";
break;
case "ErrorString":
case "RunString":
document.getElementById(key).innerHTML = heater[key];
break;
case "PumpFixed":
case "TempCurrent":
document.getElementById(key).innerHTML = parseFloat(heater[key]).toFixed(1);
break;
case "TempDesired":
document.getElementById(key).value = heater[key];
var ValKey = key + 'Val'; // eg 'PumpMinVal'
document.getElementById(ValKey).innerHTML = heater[key];
break;
case "ErrorState":
document.getElementById("ErrorDiv").hidden = heater[key] <= 1;
break;
case "TempBody":
//The threshold levels for each bar to come on are: 21°C, 41°C, 61°C, 81°C, 101°C, 121°C
if(heater[key] > 120){
document.getElementById("TopBar").className = "active121";
}
else if(heater[key] > 100){
document.getElementById("TopBar").className = "active101";
}
else if(heater[key] > 80){
document.getElementById("TopBar").className = "active81";
}
else if(heater[key] > 60){
document.getElementById("TopBar").className = "active61";
}
else if(heater[key] > 40){
document.getElementById("TopBar").className = "active41";
}
else if(heater[key] > 20){
document.getElementById("TopBar").className = "active21";
}
else {
document.getElementById("TopBar").className = "active0";
}
break;
case "PumpMin":
case "PumpMax":
var OneDecimalPlace = parseFloat(heater[key]).toFixed(1);
var ValKey = key + 'Val'; // eg 'PumpMinVal'
document.getElementById(key).value = OneDecimalPlace;
document.getElementById(key).innerHTML = OneDecimalPlace;
document.getElementById(ValKey).innerHTML = OneDecimalPlace;
break;
case "FanMin":
case "FanMax":
var RPM = heater[key];
var ValKey = key + 'Val'; // eg 'FanMinVal'
document.getElementById(key).value = RPM;
document.getElementById(key).innerHTML = RPM;
document.getElementById(ValKey).innerHTML = RPM;
break;
case "Thermostat":
if(heater[key] != 0) {
document.getElementById("FixedDiv").hidden = true;
document.getElementById("ThermoDiv").hidden = false;
}
else {
document.getElementById("FixedDiv").hidden = false;
document.getElementById("ThermoDiv").hidden = true;
}
break;
}
}
}
}
function setSchedule(){
//clearly need to add some code here to send the Json formatted data to the esp
console.log("Set Schedule Button Press")
}
Date.prototype.toDateInputValue = (function() {
var local = new Date(this);
local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
return local.toJSON().slice(0,10);
});
function sendJSONobject(obj){
var str = JSON.stringify(obj);
console.log("JSON Tx:", str);
Socket.send(str);
}
// Scripts for date handling
Date.prototype.today = function () {
return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + (this.getMonth()+1) +"/"+ this.getFullYear();
}
// Scripts for setting date and time
function setcurrenttime(){
var cmd = {};
cmd.Time = document.getElementById("curtime").value;
sendJSONobject(cmd);
}
function setcurrentdate(){
var cmd = {};
cmd.Date = document.getElementById("curdate").value;
sendJSONobject(cmd);
}
function funcNavLinks() {
var x = document.getElementById("myLinks");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
function checkTime(i)
{
if (i<10)
{
i="0" + i;
}
return i;
}
function funcdispSettings() {
document.getElementById("Settings").style.display = "block";
currentTime = new Date();
var h = currentTime.getHours();
var m = currentTime.getMinutes();
var s = currentTime.getSeconds();
// add a zero in front of numbers<10
h = checkTime(h);
m = checkTime(m);
s = checkTime(s);
console.log("Hours",h);
console.log("Minutes",m);
console.log("Seconds",s);
document.getElementById("curtime").value = h + ":" + m + ":" + s;
document.getElementById("curdate").value = currentTime.today()
document.getElementById("Home").style.display = "none";
document.getElementById("Advanced").style.display = "none";
document.getElementById("myLinks").style.display ="none";
document.getElementById('curdate').valueAsDate = new Date();
}
function funcdispHome(){
document.getElementById("Settings").style.display = "none";
document.getElementById("Home").style.display = "block";
document.getElementById("Advanced").style.display = "none";
document.getElementById("myLinks").style.display ="none";
}
function funcdispAdvanced(){
document.getElementById("Settings").style.display = "none";
document.getElementById("Home").style.display = "none";
document.getElementById("Advanced").style.display = "block";
document.getElementById("myLinks").style.display ="none";
}
// Function to check the power on/off slide switch.
function OnOffCheck(){
// Get the checkbox status and place in the checkbox variable
var checkBox = document.getElementById("myonoffswitch");
// Send a message to the Devel console of web browser for debugging
console.log("OnOffCheck:", document.getElementById("myonoffswitch").checked);
// If the checkbox is checked, display the output text
// We also need to send a message back into the esp as we cannot directly run Arduino Functions from within the javascript
var cmd = {};
if (checkBox.checked){
//Insert Code Here To Turn On The Heater
console.log("Turning On Heater");
cmd.RunState = 1;
sendJSONobject(cmd);
}
else{
//Insert Code Here To Turn Off The Heater
console.log("Turning Off Heater");
cmd.RunState = 0;
sendJSONobject(cmd);
}
}
function onSlideDone(newVal, JSONKey) {
//elementid must equal the JSON name for each setting
document.getElementById(JSONKey).innerHTML = newVal;
var cmd = {};
cmd[JSONKey] = newVal; // note: variable name needs []
cmd.NVsave = 8861; // named variable DOESN'T !!
sendJSONobject(cmd);
}
function onSlideUpdate(newVal, JSONKey) {
//elementid must equal the JSON name for each setting
document.getElementById(JSONKey).innerHTML = newVal;
}
function SetPumpMin(){
var cmd = {};
cmd['PumpMin'] = document.getElementById("PumpMin").value;
cmd.NVsave = 8861;
sendJSONobject(cmd);
}
</script>
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1">
<style>
.throb_me {
animation: throbber 1s linear infinite;
}
@keyframes throbber {
50% {
opacity: 0;
}
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
.onoffswitch {
position: relative; width: 90px;
-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block; overflow: hidden; cursor: pointer;
border: 2px solid #999999; border-radius: 20px;
}
.onoffswitch-inner {
display: block; width: 200%; margin-left: -100%;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
box-sizing: border-box;
}
.onoffswitch-inner:before {
content: "ON";
padding-left: 10px;
background-color: #34A7C1; color: #FFFFFF;
}
.onoffswitch-inner:after {
content: "OFF";
padding-right: 10px;
background-color: #EEEEEE; color: #999999;
text-align: right;
}
.onoffswitch-switch {
display: block; width: 18px; margin: 6px;
background: #FFFFFF;
position: absolute; top: 0; bottom: 0;
right: 56px;
border: 2px solid #999999; border-radius: 20px;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 0px;
}
.mobile-container {
margin: auto;
background-color: #555;
height: 500px;
color: white;
border-radius: 10px;
}
.topnav {
overflow: hidden;
background-color: #333;
position: relative;
}
.topnav #myLinks {
display: none;
}
.topnav a {
color: white;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
display: block;
}
.topnav a.icon {
background: black;
display: block;
position: absolute;
left: 0;
top: 0;
}
.topnav a:hover {
background-color: #ddd;
color: black;
}
.active0 {
background-color: #5e4fa2;
color: black;
}
.active21 {
background-color: #427bb1;
color: #ffffff;
}
.active41 {
background-color: #36c0a3;
color: #ffffff;
}
.active61 {
background-color: #29cf38;
color: #000000;
}
.active81 {
background-color: #92df1b;
color: #ffffff;
}
.active101 {
background-color: #efab0e;
color: #ffffff;
}
.active121 {
background-color: #ff0000;
color: #ffffff;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
MainPage {
display: block
}
#Advanced {
display: none
}
#Settings {
display: none
}
}
</style>
<title>Chinese Diesel Heater Web Controller Interface</title>
</head>
<body onload="javascript:init()">
<div class="mobile-container">
<!-- Top Navigation Menu -->
<div class="topnav">
<div id="TopBar" style="padding-left:30px"><a href="javascript:void(0);" onclick="funcdispHome()" >Chinese Diesel Heater Web Control</a></div>
<div id="myLinks">
<a href="javascript:void(0);" onclick="funcdispHome()">Home</a>
<a href="javascript:void(0);" onclick="funcdispSettings()">Settings</a>
<a href="javascript:void(0);" onclick="funcdispAdvanced()">Advanced Settings</a>
</div>
<a href="javascript:void(0);" class="icon" onclick="funcNavLinks()">
</i>=
</a>
</div>
<div style="padding-left:16px">
<span class="MaingPage" id="Home">
<div><H2>Power Control</H2></div>
<div class="onoffswitch" id="onoffswitch">
<input type="checkbox" onclick="OnOffCheck()" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" clicked>
<label class="onoffswitch-label" for="myonoffswitch">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
<span class="throb_me" id="RunString" style="visibility:hidden"></span>
<div>
<h2>Temperature Control</h2>
</div>
<input type="range" id="TempDesired" min="8" max="35" step="1" value="22" oninput="onSlideUpdate(this.value, 'TempDesiredVal')" onchange="onSlideDone(this.value, 'TempDesired')">
<div id="ThermoDiv">
<b>Desired Temp: </b> <span id="TempDesiredVal"></span>
</div>
<div id="FixedDiv">
<b>Fixed Hz: </b>
<span id="PumpFixed"></span>
</div>
<div>
<b>Current Temp: </b><span id="TempCurrent">
</div>
<div id="ErrorDiv" style="color:crimson" hidden>
<b>Error <span id="ErrorString"> </b>
</div>
</span>
<div id="Advanced">
<h2><b>Advanced Settings</b></h2>
<br>
<h3><b>Minimum Fuel Settings</b></h3>
<div>
<b>Pump Min: </b><span id="PumpMinVal"> </span>
<input type="range" id="PumpMin" min="1" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMinVal')" onchange="onSlideDone(this.value, 'PumpMin')">
</div>
<div>
<b>Fan Min: </b><span id="FanMinVal"> </span>
<input type="range" id="FanMin" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMinVal')" onchange="onSlideDone(this.value, 'FanMin')">
</div>
<br>
<h3><b>Maximum Fuel Settings</b></h3>
<div>
<b>Pump Max: </b><span id="PumpMaxVal"> </span>
<input type="range" id="PumpMax" min=".5" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMaxVal')" onchange="onSlideDone(this.value, 'PumpMax')">
</div>
<div>
<b>Fan Max: </b><span id="FanMaxVal"> </span>
<input type="range" id="FanMax" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMaxVal')" onchange="onSlideDone(this.value, 'FanMax')">
</div>
</div>
<Div id="Settings">
Current Date:<br>
<input type="date" id="curdate"><input type="button" Value="Set Date" onclick="setcurrentdate()">
<br>
Current Time (24 Hour Format):<br>
<input type="time" id="curtime"> <input type="button" Value="Set Time" onclick="setcurrenttime()">
<hr></hr>
<br><br>
Timer1: <input type="checkbox" border-radius="4px" name="Timer" id="Timer1onoff"> <input type="text" class="schedule" id="Timer1Start"> <input type="text" id="Timer1End"> <br>
Timer2: <input type="checkbox" border-radius="4px" name="Tue"> <input type="text" class="schedule" id="Timer2Start"> <input type="text" id="Timer2End"><br>
<input type="button" Value="Save Schedule" onclick="setSchedule()">
</Div>
</body>
</html>

View file

@ -0,0 +1,102 @@
1249177ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
+21ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
1250198ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
+23ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
*** SWITCHED INTO VERBOSE MODE ****
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
1251221ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74 :6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
dT{16}:6,RD(8B)
dT{1}:6,RD(1D)
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
dT{1}:6,RD(16)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{2}:6,RD(0)
dT{1}:6,RD(2F)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(8)
dT{1}:6,RD(0)
dT{1}:6,RD(1A)
dT{1}:6,RD(64)
dT{1}:6,RD(0)
:7 +48ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
:8
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
8< (lots of state :0 snipped)
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
:5:5:5:5:5:5:5:5:5:5
1252268ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
dT{16}:6,RD(8B)
dT{1}:6,RD(1D)
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
dT{2}:6,RD(16)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(84)
dT{1}:6,RD(0)
dT{1}:6,RD(2F)
dT{1}:6,RD(0)
dT{2}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(0)
dT{1}:6,RD(8)
dT{1}:6,RD(0)
dT{1}:6,RD(1A)
dT{2}:6,RD(64)
dT{1}:6,RD(0):7
+49ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
Bluetooth data not sent, CRC error
:8
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

View file

@ -0,0 +1,117 @@
Start updating sketch
Progress: 100%
End
*WM: [1] AutoConnect
*WM: [2] ESP32 event handler enabled
*WM: [2] Connecting as wifi client...
*WM: [2] setSTAConfig static ip not set
*WM: [3] WIFI station disconnect
*WM: [1] Connecting to saved AP: WigginsCorner
*WM: [3] WiFi station enable
*WM: [1] connectTimeout not set, ESP waitForConnectResult...
*WM: [2] [EVENT] 4
*WM: [2] [EVENT] 7
*WM: [2] Connection result: WL_CONNECTED
*WM: [3] lastconxresult: WL_CONNECTED
*WM: [1] AutoConnect: SUCCESS
*WM: [1] STA IP Address: 192.168.0.101
connected...yeey :)
Ready
IP address: 192.168.0.101
Attempting to detect HC-05 Bluetooth module...
@ 9600 baud... OK.
HC-05 found
Setting Name to "Diesel Heater"... OK
Setting baud rate to 9600N81...OK
2313ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 08 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 0B DE
3335ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
4357ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
5380ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
6404ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
7427ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
8451ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
9474ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
10498ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
11521ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
12545ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
13568ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
14592ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
15615ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
16639ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
17662ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
18686ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
19709ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
20732ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
21756ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
22780ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
23803ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
24827ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
25850ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
26873ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
27897ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
28920ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 07 6C 2F 66 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
29944ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
30967ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
31991ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
33014ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
34038ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
35061ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
36084ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
37108ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
38131ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
39155ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
40178ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
41202ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
42225ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
43249ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
44272ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
45296ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
46319ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
47342ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
48366ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
49390ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
50413ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
51436ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
52460ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
53484ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
54507ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
55531ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
56555ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
57578ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
58602ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
59625ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
60649ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
61671ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
62695ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
63718ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
64742ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
65765ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
66788ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
67812ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
68836ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
69859ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
70882ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
71906ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
72929ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
73952ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
74976ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
76000ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
77023ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 Timeout collecting BTC heater response data, returning to Idle State
78047ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
79070ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
80093ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+24ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
81117ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
Bluetooth data not sent, CRC error
82140ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A

View file

@ -0,0 +1,46 @@
1174404ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1175426ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1176448ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1177471ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1178493ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1179515ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1180537ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1181559ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1182583ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
1183588ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1184611ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
1185632ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
1186654ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
1187676ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
Bluetooth data not sent, CRC error
1188699ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
Bluetooth data not sent, CRC error
1189721ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 4E 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:27B2 data:9A
Bluetooth data not sent, CRC error
1190743ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
Bluetooth data not sent, CRC error
1191765ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
Bluetooth data not sent, CRC error
1192788ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+21ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
Bluetooth data not sent, CRC error
1193810ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
+23ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
Bluetooth data not sent, CRC error
1194833ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State

View file

@ -0,0 +1,786 @@
[Starting] Opening the serial port - COM9
oad:0x3fff0018,len:4
l<EFBFBD><EFBFBD><EFBFBD><EFBFBD>fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
[Info] Opened the serial port - COM9
1046[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
1086[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
2070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
2110[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
3093[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
3133[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
4113[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
4153[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
5132[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
5172[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
6155[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
6195[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
7179[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
7219[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
No Bluetooth client
Free heap 96224
8202[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
8242[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
9222[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
9262[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
No Bluetooth client
Free heap 96224
10245[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
10285[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
No Bluetooth client
Free heap 96224
11265[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
11305[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
12289[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
12329[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
13308[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
13348[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
14331[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
14371[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
15354[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
15394[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
16378[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
16418[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
17401[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
17441[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
18425[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
18465[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
19445[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
19485[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
20468[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
20508[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
No Bluetooth client
Free heap 96224
21488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
21528[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
No Bluetooth client
Free heap 96224
22508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
22558[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
23531[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
23581[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
Free heap 92384
[CMD]degC19
Command decode: degC = 19
[CMD]save
Command decode: NV save
24550[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
24600[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
25573[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
25623[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
26598[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
26648[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
27620[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
27670[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
Free heap 92384
28643[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
28693[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
Free heap 92384
29667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
29717[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
Free heap 92384
[CMD]ON
Command decode: Heater ON
30691[BTC] 76 16 A0 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC E1 57
30741[HTR] 76 16 01 00 00 8B 00 00 00 53 00 11 00 00 00 00 00 00 00 1B 64 00 96 5A
Free heap 92384
31712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
31762[HTR] 76 16 02 01 00 8A 00 00 00 0A 00 10 00 02 00 5F 00 00 00 1B 64 00 C9 1D
Free heap 92384
32733[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
32783[HTR] 76 16 02 01 00 89 00 00 00 0B 00 10 00 04 00 B7 00 00 00 1B 64 00 16 AC
Free heap 92384
33753[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
33803[HTR] 76 16 02 01 00 89 00 00 00 0E 00 10 00 07 01 0E 00 00 00 1B 64 00 E4 5D
Free heap 92384
34777[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
34827[HTR] 76 16 02 01 00 89 00 00 00 11 00 10 00 09 01 62 00 00 00 1B 64 00 1D 97
Free heap 92384
35800[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
35850[HTR] 76 16 02 01 00 89 00 50 00 14 00 10 00 0A 01 86 00 00 00 1B 64 00 DA 7B
Free heap 92384
36822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
36872[HTR] 76 16 02 01 00 89 00 C8 00 17 00 10 00 0B 01 C5 00 00 00 1B 64 00 27 99
Free heap 92384
37845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
37895[HTR] 76 16 02 01 00 89 01 C2 00 1A 00 10 00 0E 02 21 00 00 00 1B 64 00 B6 1A
Free heap 92384
38867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
38917[HTR] 76 16 02 01 00 89 02 80 00 1C 00 10 00 0F 02 41 00 00 00 1B 64 00 26 FC
Free heap 92384
39889[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
39939[HTR] 76 16 02 01 00 88 03 D4 00 1D 00 10 00 12 02 80 00 00 00 1B 64 00 04 7F
Free heap 92384
40912[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
40962[HTR] 76 16 02 01 00 88 04 CE 00 20 00 10 00 14 02 C0 00 00 00 1B 64 00 E4 9F
Free heap 92384
41935[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
41985[HTR] 76 16 02 01 00 88 06 04 00 20 00 10 00 16 02 EC 00 00 00 1B 64 00 70 A0
Free heap 92384
42958[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
43008[HTR] 76 16 02 01 00 88 06 9A 00 20 00 10 00 17 02 F8 00 00 00 1B 64 00 89 E7
Free heap 92384
43981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
44031[HTR] 76 16 02 01 00 88 07 3A 00 20 00 10 00 1A 03 23 00 00 00 1B 64 00 30 74
Free heap 92384
45005[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
45055[HTR] 76 16 02 01 00 88 07 80 00 20 00 10 00 1C 03 43 00 00 00 1B 64 00 E5 05
Free heap 92384
46029[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
46079[HTR] 76 16 02 01 00 88 07 B2 00 1E 00 10 00 1E 03 5F 00 00 00 1B 64 00 2F 24
Free heap 92384
47052[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
47102[HTR] 76 16 02 01 00 87 07 B2 00 1A 00 10 00 1F 03 5F 00 00 00 1B 64 00 C8 12
Free heap 92384
48076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
48126[HTR] 76 16 02 01 00 87 07 80 00 19 00 10 00 21 03 77 00 00 00 1B 64 00 7D 15
Free heap 92384
49100[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
49150[HTR] 76 16 02 01 00 87 07 26 00 18 00 10 00 23 03 8F 00 00 00 1B 64 00 29 51
Free heap 92384
50120[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
50170[HTR] 76 16 02 01 00 87 06 E0 00 18 00 10 00 25 03 9F 00 00 00 1B 64 00 8A EC
Free heap 92384
51144[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
51194[HTR] 76 16 02 01 00 87 06 7C 00 18 00 10 00 28 03 B3 00 00 00 1B 64 00 B1 C5
Free heap 92384
52163[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
52213[HTR] 76 16 02 01 00 87 06 36 00 18 00 10 00 2A 03 C7 00 00 00 1B 64 00 E1 22
Free heap 92384
53185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
53235[HTR] 76 16 02 01 00 87 05 E6 00 19 00 10 00 2C 03 CF 00 00 00 1B 64 00 AD 12
Free heap 92384
54207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
54257[HTR] 76 16 02 01 00 87 05 C8 00 18 00 10 00 2D 03 C3 00 00 00 1B 64 00 A0 7F
Free heap 92384
55229[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
55279[HTR] 76 16 02 01 00 87 05 A0 00 19 00 10 00 2F 03 CF 00 00 00 1B 64 00 6F C0
Free heap 92384
56249[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
56299[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 32 03 D3 00 00 00 1B 64 00 F2 F7
Free heap 92384
57272[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
57322[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 33 03 DF 00 00 00 1B 64 00 62 36
Free heap 92384
58292[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
58342[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 35 03 D3 00 00 00 1B 64 00 C2 D1
Free heap 92384
59315[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
59365[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 37 03 DF 00 00 00 1B 64 00 23 06
Free heap 92384
60335[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
60385[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 39 03 DB 00 00 00 1B 64 00 83 0F
Free heap 92384
61355[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
61405[HTR] 76 16 02 01 00 85 05 8C 00 18 00 10 00 3B 03 E6 00 00 00 1B 64 00 51 08
Free heap 92384
62379[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
62429[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 3D 03 DF 00 00 00 1B 64 00 78 12
Free heap 92384
63398[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
63448[HTR] 76 16 02 01 00 85 05 8C 00 19 00 10 00 3F 03 DF 00 00 00 1B 64 00 13 91
Free heap 92384
64418[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
64468[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 41 03 E6 00 00 00 1B 64 00 B9 8B
Free heap 92384
65441[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
65491[HTR] 76 16 02 01 00 85 05 8C 00 1A 00 10 00 42 03 DF 00 00 00 1B 64 00 82 A9
Free heap 92384
66462[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
66512[HTR] 76 16 02 01 00 85 05 96 00 1A 00 10 00 44 03 E6 00 00 00 1B 64 00 2A B1
Free heap 92384
67485[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
67535[HTR] 76 16 02 01 00 84 05 96 00 19 00 11 00 47 03 EA 00 00 00 1B 64 00 75 39
Free heap 92384
68508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
68558[HTR] 76 16 02 01 00 84 05 A0 00 1A 00 10 00 49 03 F6 00 00 00 1B 64 00 FD 1F
Free heap 92384
69530[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
69580[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 11 00 4A 03 EE 00 00 00 1B 64 00 F7 1D
Free heap 92384
70552[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
70602[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 10 00 4C 03 F2 00 00 00 1B 64 00 6A EF
Free heap 92384
71574[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
71624[HTR] 76 16 02 01 00 83 05 B4 00 19 00 11 00 4F 03 FA 00 00 00 1B 64 00 5C 5F
Free heap 92384
72597[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
72647[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 51 04 06 00 00 00 1B 64 00 2A A2
Free heap 92384
73621[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
73671[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 52 03 FE 00 00 00 1B 64 00 F4 04
Free heap 92384
74644[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
74694[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 54 04 06 00 00 00 1B 64 00 7D 17
Free heap 92384
75667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
75717[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 56 04 06 00 00 00 1B 64 00 60 08
Free heap 92384
76690[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
76740[HTR] 76 16 02 01 00 82 05 BE 00 1A 00 10 00 58 04 12 00 00 00 1B 64 00 EC 47
Free heap 92384
77712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
77762[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 04 06 00 00 00 1B 64 00 CB E5
Free heap 92384
78735[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
78785[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 03 FA 00 00 00 1B 64 00 22 98
Free heap 92384
79756[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
79806[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 F6 00 00 00 1B 64 00 B9 C3
Free heap 92384
80779[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
80829[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 EE 00 00 00 1B 64 00 B8 5B
Free heap 92384
81803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
81853[HTR] 76 16 02 01 00 83 05 D2 00 1C 00 10 00 59 03 E6 00 00 00 1B 64 00 2E 8A
Free heap 92384
82822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
82872[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 11 00 59 03 DF 00 00 00 1B 64 00 83 F1
Free heap 92384
83845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
83895[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 10 00 59 03 DB 00 00 00 1B 64 00 BF B0
Free heap 92384
84867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
84917[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 10 00 59 03 D3 00 00 00 1B 64 00 EF 68
Free heap 92384
85888[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
85938[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 11 00 59 03 D7 00 00 00 1B 64 00 52 2B
Free heap 92384
86910[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
86960[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
Free heap 92384
87933[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
87983[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
Free heap 92384
88956[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
89006[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 CB 00 00 00 1B 64 00 80 4C
Free heap 92384
89979[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
90029[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 C7 00 00 00 1B 64 00 7C 84
Free heap 92384
91002[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
91052[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
Free heap 92384
92024[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
92074[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
Free heap 92384
93047[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
93097[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 15 C0
Free heap 92384
94070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
94120[HTR] 76 16 02 01 00 83 05 DC 00 1D 00 11 00 59 03 BF 00 00 00 1B 64 00 52 CB
Free heap 92384
95094[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
95144[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
Free heap 92384
96117[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
96167[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 11 4E
Free heap 92384
97139[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
97189[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
Free heap 92384
98162[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
98212[HTR] 76 16 02 01 00 83 05 C8 00 1A 00 11 00 59 03 BB 00 00 00 1B 64 00 DA 91
Free heap 92384
99185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
99235[HTR] 76 16 02 01 00 83 05 C8 00 1B 00 11 00 59 03 B7 00 00 00 1B 64 00 5B 5F
Free heap 92384
100207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
100257[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 11 00 59 03 B7 00 00 00 1B 64 00 FC AB
Free heap 92384
101230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
101280[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 59 03 BB 00 00 00 1B 64 00 00 63
Free heap 92384
102252[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
102302[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B7 00 00 00 1B 64 00 81 AD
Free heap 92384
103276[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
103326[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 59 03 B7 00 00 00 1B 64 00 07 25
Free heap 92384
104298[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
104348[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 41 E8
Free heap 92384
105320[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
105370[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 BD EC
Free heap 92384
106344[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
106394[HTR] 76 16 02 01 00 83 05 D2 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 90 80
Free heap 92384
107366[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
107416[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 68 0A
Free heap 92384
108388[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
108438[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 87 B4
Free heap 92384
109411[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
109461[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 89 22
Free heap 92384
110435[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
110485[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
Free heap 92384
111457[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
111507[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
Free heap 92384
112480[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
112530[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 00 00 00 1B 64 00 CE 77
Free heap 92384
113500[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
113550[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 5E 75
Free heap 92384
114523[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
114573[HTR] 76 16 02 01 00 81 05 F0 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 39 5E
Free heap 92384
115546[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
115596[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 10 00 00 1B 64 00 19 20
Free heap 92384
116569[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
116619[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AF 10 00 00 1B 64 00 D8 FD
Free heap 92384
117593[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
117643[HTR] 76 16 02 01 00 82 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 CE 24
Free heap 92384
118616[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
118666[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 18 B8
Free heap 92384
119639[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
119689[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 1F 32
Free heap 92384
120661[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
120711[HTR] 76 16 02 01 00 80 06 04 00 1A 00 11 00 59 03 AB 10 00 00 1B 64 00 DF FE
Free heap 92384
121685[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
121735[HTR] 76 16 02 01 00 83 06 18 00 1C 00 11 00 59 03 AF 10 00 00 1B 64 00 20 5E
Free heap 92384
122708[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
122758[HTR] 76 16 02 01 00 83 06 22 00 1C 00 11 00 59 03 A7 10 00 00 1B 64 00 F3 6D
Free heap 92384
123728[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
123778[HTR] 76 16 02 01 00 83 06 2C 00 1C 00 11 00 59 03 AB 10 00 00 1B 64 00 F7 2F
Free heap 92384
124748[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
124798[HTR] 76 16 02 01 00 83 06 40 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 0B 42
Free heap 92384
125770[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
125820[HTR] 76 16 02 01 00 83 06 54 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 04 56
Free heap 92384
126792[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
126842[HTR] 76 16 02 01 00 83 06 5E 00 1C 00 11 00 59 03 AF 11 00 00 1B 64 00 C3 99
Free heap 92384
127812[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
127862[HTR] 76 16 02 01 00 83 06 68 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 15 6A
Free heap 92384
128833[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
128883[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
Free heap 92384
129853[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
129903[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
Free heap 92384
130874[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
130924[HTR] 76 16 02 01 00 83 06 86 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 D8 06
Free heap 92384
131894[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
131944[HTR] 76 16 02 01 00 83 06 90 00 1D 00 11 00 59 03 AF 11 00 00 1B 64 00 16 D5
Free heap 92384
132915[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
132965[HTR] 76 16 02 01 00 83 06 9A 00 1E 00 11 00 59 03 AB 11 00 00 1B 64 00 12 1F
Free heap 92384
133938[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
133988[HTR] 76 16 02 01 00 83 06 A4 00 1E 00 11 00 59 03 AF 12 00 00 1B 64 00 F1 E4
Free heap 92384
134957[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
135007[HTR] 76 16 02 01 00 83 06 AE 00 21 00 11 00 59 03 AB 12 00 00 1B 64 00 C9 7E
Free heap 92384
135981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
136031[HTR] 76 16 02 01 00 83 06 C2 00 1F 00 11 00 59 03 AB 12 00 00 1B 64 00 9A 45
Free heap 92384
137003[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
137053[HTR] 76 16 02 01 00 82 06 CC 00 1E 00 11 00 59 03 A7 12 00 00 1B 64 00 8F 54
Free heap 92384
ASSERT_PARAM(512 0), in rwbt.c at line 273
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)
Core 0 register dump:
PC : 0x400850c8 PS : 0x00060034 A0 : 0x80088b40 A1 : 0x3ffc05b0
A2 : 0x00000001 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x60008054
A6 : 0x3ffc1030 A7 : 0x60008050 A8 : 0x800850c5 A9 : 0x3ffc0590
A10 : 0x00000004 A11 : 0x00000000 A12 : 0x6000804c A13 : 0xffffffff
A14 : 0x00000000 A15 : 0xfffffffc SAR : 0x00000004 EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x40084ffd LEND : 0x40085004 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x4017d35e EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x400850c8
Backtrace: 0x400850c8:0x3ffc05b0 0x40088b3d:0x3ffc05d0 0x400891cf:0x3ffc05f0 0x400817ad:0x3ffc0610 0x4017d35b:0x00000000
Core 1 register dump:
PC : 0x400d1faa PS : 0x00060334 A0 : 0x800d1258 A1 : 0x3ffd55d0
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000000
A6 : 0x00000000 A7 : 0x3ffd36c0 A8 : 0x3ffc4920 A9 : 0x3ffd55b0
A10 : 0x3ffe7f84 A11 : 0x3ffd0814 A12 : 0xd4000000 A13 : 0x3ffd54d0
A14 : 0x00000002 A15 : 0x3ffd36c0 SAR : 0x0000000a EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0x00000000
Backtrace: 0x400d1faa:0x3ffd55d0 0x400d1255:0x3ffd55f0 0x400d1718:0x3ffd5610 0x401692c4:0x3ffd5630
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
1045[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
1085[HTR] 76 16 02 01 00 81 06 FE 00 1F 00 11 00 59 03 A7 12 00 00 1B 64 00 EB 14
No Bluetooth client
Free heap 96196
2065[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
2105[HTR] 76 16 02 01 00 82 07 26 00 20 00 11 00 59 03 AB 12 00 00 1B 64 00 2E 64
No Bluetooth client
Free heap 96196
3086[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
3126[HTR] 76 16 02 01 00 83 07 3A 00 21 00 11 00 59 03 A7 12 00 00 1B 64 00 36 E7
No Bluetooth client
Free heap 96196
4107[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
4147[HTR] 76 16 02 01 00 82 07 62 00 21 00 11 00 59 03 AF 12 00 00 1B 64 00 5C 67
No Bluetooth client
Free heap 96196
5126[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
5166[HTR] 76 16 02 01 00 82 07 6C 00 20 00 11 00 59 03 AF 13 00 00 1B 64 00 08 EA
No Bluetooth client
Free heap 96196
6146[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
6186[HTR] 76 16 02 01 00 82 07 94 00 22 00 11 00 59 03 AB 13 00 00 1B 64 00 C8 50
No Bluetooth client
Free heap 96196
7167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
7207[HTR] 76 16 02 01 00 82 07 A8 00 22 00 11 00 59 03 AF 13 00 00 1B 64 00 19 29
No Bluetooth client
Free heap 96196
8187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
8227[HTR] 76 16 02 01 00 82 07 BC 00 21 00 11 00 59 03 AB 13 00 00 1B 64 00 15 7D
No Bluetooth client
Free heap 96196
9208[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
9248[HTR] 76 16 02 01 00 82 07 C6 00 23 00 11 00 59 03 AB 13 00 00 1B 64 00 74 80
No Bluetooth client
Free heap 96196
10233[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
10273[HTR] 76 16 02 01 00 82 07 E4 00 23 00 11 00 59 03 AF 13 00 00 1B 64 00 AD 67
No Bluetooth client
Free heap 96196
11253[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
11293[HTR] 76 16 02 01 00 82 07 F8 00 24 00 11 00 58 03 AF 13 00 00 1B 64 00 73 7D
No Bluetooth client
Free heap 96196
12274[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
12314[HTR] 76 16 02 01 00 82 08 0C 00 24 00 11 00 59 03 AF 13 00 00 1B 64 00 50 C1
No Bluetooth client
Free heap 96196
13294[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
13334[HTR] 76 16 02 01 00 82 08 20 00 24 00 11 00 59 03 AF 14 00 00 1B 64 00 FA EC
No Bluetooth client
Free heap 96196
14314[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
14354[HTR] 76 16 02 01 00 82 08 48 00 25 00 11 00 59 03 AF 14 00 00 1B 64 00 55 86
No Bluetooth client
Free heap 96196
15338[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
15378[HTR] 76 16 02 01 00 82 08 66 00 25 00 11 00 59 03 B3 14 00 00 1B 64 00 88 F5
No Bluetooth client
Free heap 96196
16362[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
16402[HTR] 76 16 02 01 00 82 08 84 00 26 00 11 00 59 03 B3 14 00 00 1B 64 00 02 92
No Bluetooth client
Free heap 96196
17382[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
17422[HTR] 76 16 02 01 00 82 08 A2 00 26 00 11 00 59 03 AF 14 00 00 1B 64 00 D9 E9
No Bluetooth client
Free heap 96196
18403[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
18443[HTR] 76 16 02 01 00 80 08 C0 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 D0 75
No Bluetooth client
Free heap 96196
19423[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
19463[HTR] 76 16 02 01 00 82 08 D4 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 BF C0
No Bluetooth client
Free heap 96196
20443[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
20483[HTR] 76 16 02 01 00 82 08 E8 00 27 00 12 00 5A 03 AF 15 00 00 1B 64 00 0A 3B
No Bluetooth client
Free heap 96196
21464[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
21504[HTR] 76 16 02 01 00 82 08 FC 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 7F FD
No Bluetooth client
Free heap 96196
22488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
22528[HTR] 76 16 02 01 00 82 09 10 00 27 00 12 00 59 03 AF 15 00 00 1B 64 00 28 16
No Bluetooth client
Free heap 96196
23508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
23548[HTR] 76 16 02 01 00 82 09 2E 00 28 00 12 00 59 03 B3 15 00 00 1B 64 00 F6 61
No Bluetooth client
Free heap 96196
24529[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
24569[HTR] 76 16 02 01 00 80 09 42 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 FF A3
No Bluetooth client
Free heap 96196
25549[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
25589[HTR] 76 16 02 01 00 82 09 60 00 2A 00 12 00 59 03 AF 15 00 00 1B 64 00 41 75
No Bluetooth client
Free heap 96196
26570[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
26610[HTR] 76 16 02 01 00 82 09 74 00 2A 00 12 00 59 03 B3 16 00 00 1B 64 00 BC BC
No Bluetooth client
Free heap 96196
27591[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
27631[HTR] 76 16 02 01 00 82 09 9C 00 2A 00 12 00 59 03 B7 16 00 00 1B 64 00 32 11
No Bluetooth client
Free heap 96196
28613[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
28653[HTR] 76 16 02 01 00 82 09 B0 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 AE 3F
No Bluetooth client
Free heap 96196
29633[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
29673[HTR] 76 16 02 01 00 82 09 CE 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 8E C1
No Bluetooth client
Free heap 96196
30653[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
30693[HTR] 76 16 02 01 00 82 09 EC 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 97 63
No Bluetooth client
Free heap 96196
31674[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
31714[HTR] 76 16 02 01 00 82 09 F6 00 2C 00 12 00 59 03 B7 16 00 00 1B 64 00 DB F2
No Bluetooth client
Free heap 96196
32694[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
32734[HTR] 76 16 02 01 00 82 0A 14 00 2C 00 12 00 59 03 B7 17 00 00 1B 64 00 B2 D1
No Bluetooth client
Free heap 96196
33718[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
33758[HTR] 76 16 02 01 00 82 0A 1E 00 2D 00 12 00 59 03 B7 17 00 00 1B 64 00 34 59
No Bluetooth client
Free heap 96196
34740[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
34780[HTR] 76 16 02 01 00 82 0A 32 00 2D 00 12 00 58 03 B7 17 00 00 1B 64 00 B9 78
No Bluetooth client
Free heap 96196
35760[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
35800[HTR] 76 16 02 01 00 82 0A 46 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 CD 04
No Bluetooth client
Free heap 96196
36782[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
36822[HTR] 76 16 02 01 00 82 0A 5A 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 C4 18
No Bluetooth client
Free heap 96196
37803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
37843[HTR] 76 16 02 01 00 82 0A 78 00 2F 00 12 00 59 03 B7 17 00 00 1B 64 00 5C B8
No Bluetooth client
Free heap 96196
38823[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
38863[HTR] 76 16 02 01 00 82 0A 8C 00 2F 00 12 00 59 03 B7 18 00 00 1B 64 00 E4 4C
No Bluetooth client
Free heap 96196
39843[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
39883[HTR] 76 16 02 01 00 80 0A AA 00 2F 00 12 00 59 03 B3 18 00 00 1B 64 00 5E 0E
No Bluetooth client
Free heap 96196
40864[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
40904[HTR] 76 16 02 01 00 82 0A D2 00 30 00 12 00 59 03 BB 18 00 00 1B 64 00 43 74
No Bluetooth client
Free heap 96196
41884[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
41924[HTR] 76 16 02 01 00 80 0A E6 00 30 00 12 00 59 03 B7 18 00 00 1B 64 00 34 2D
No Bluetooth client
Free heap 96196
42906[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
42946[HTR] 76 16 02 01 00 82 0B 0E 00 31 00 12 00 59 03 B7 18 00 00 1B 64 00 0B A7
No Bluetooth client
Free heap 96196
43925[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
43965[HTR] 76 16 02 01 00 80 0B 36 00 31 00 12 00 59 03 B7 19 00 00 1B 64 00 A8 3F
No Bluetooth client
Free heap 96196
44946[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
44986[HTR] 76 16 02 01 00 82 0B 54 00 32 00 12 00 59 03 BB 19 00 00 1B 64 00 22 B5
No Bluetooth client
Free heap 96196
45965[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
46005[HTR] 76 16 02 01 00 82 0B 68 00 32 00 13 00 59 03 B7 19 00 00 1B 64 00 CF 41
No Bluetooth client
Free heap 96196
46986[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
47026[HTR] 76 16 02 01 00 82 0B 7C 00 33 00 12 00 59 03 BB 19 00 00 1B 64 00 BD 9F
No Bluetooth client
Free heap 96196
48008[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
48048[HTR] 76 16 02 01 00 82 0B 9A 00 32 00 12 00 59 03 BB 1A 00 00 1B 64 00 45 FB
No Bluetooth client
Free heap 96196
49031[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
49071[HTR] 76 16 02 01 00 82 0B A4 00 33 00 12 00 59 03 BF 1A 00 00 1B 64 00 14 02
No Bluetooth client
Free heap 96196
50053[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
50093[HTR] 76 16 02 01 00 82 0B B8 00 33 00 13 00 59 03 BB 1A 00 00 1B 64 00 21 5F
No Bluetooth client
Free heap 96196
51076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
51116[HTR] 76 16 02 01 00 82 0B C2 00 34 00 13 00 59 03 BB 1A 00 00 1B 64 00 45 AE
No Bluetooth client
Free heap 96196
52099[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
52139[HTR] 76 16 02 01 00 82 0B E0 00 34 00 13 00 59 03 BF 1A 00 00 1B 64 00 9C 49
No Bluetooth client
Free heap 96196
53122[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
53162[HTR] 76 16 02 01 00 7F 0B EA 00 32 00 13 00 59 03 BB 1B 00 00 1B 64 00 EC 5E
No Bluetooth client
Free heap 96196
54145[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
54185[HTR] 76 16 02 01 00 82 0C 08 00 35 00 13 00 59 03 C3 1B 00 00 1B 64 00 77 5D
No Bluetooth client
Free heap 96196
55167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
55207[HTR] 76 16 02 01 00 82 0C 1C 00 36 00 13 00 59 03 BB 1B 00 00 1B 64 00 BC B4
No Bluetooth client
Free heap 96196
56187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
56227[HTR] 76 16 02 01 00 81 0C 3A 00 36 00 13 00 59 03 BF 1B 00 00 1B 64 00 96 A7
No Bluetooth client
Free heap 96196
57207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
57247[HTR] 76 16 02 01 00 82 0C 58 00 36 00 13 00 59 03 BB 1C 00 00 1B 64 00 38 F1
No Bluetooth client
Free heap 96196
58230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
No Bluetooth client
58270[HTR] 76 16 02 01 00 82 0C 6C 00 37 00 13 00 59 03 BB 1C 00 00 1B 64 00 AE C7
No Bluetooth client
Free heap 96196

File diff suppressed because it is too large Load diff

View file

@ -22,8 +22,10 @@
#ifndef __BLUETOOTHABSTRACT_H__
#define __BLUETOOTHABSTRACT_H__
#include <Arduino.h>
#include "../Utility/UtilClasses.h"
#include "../Utility/helpers.h"
#include "../Utility/Debugport.h"
#include "../Protocol/helpers.h"
class CProtocol;
@ -33,7 +35,7 @@ protected:
virtual void foldbackDesiredTemp() {};
public:
virtual void begin() {};
virtual bool send(const char* Str) { return false; };
virtual void send(const char* Str) {};
virtual void check() {};
virtual void collectRxData(char rxVal) {
// provide common behviour for bytes received from a bluetooth client
@ -45,8 +47,6 @@ public:
}
};
virtual bool isConnected() { return false; };
virtual const char* getMAC() { return "unknown"; };
virtual bool test(char) { return false; }; // returns true whilst test mode is active
};
extern CBluetoothAbstract& getBluetoothClient();

View file

@ -21,15 +21,14 @@
#include <Arduino.h>
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../Protocol/Protocol.h"
#include "../Utility/DebugPort.h"
#include "../Utility/debugport.h"
#include "BluetoothESP32.h"
#include "../cfg/BTCConfig.h"
#ifdef ESP32
#if USE_HC05_BLUETOOTH == 1
/////////////////////////////////////////////////////////////////////////////////////////
// HC-05 BLUETOOTH with ESP32
// |
@ -46,19 +45,18 @@ CBluetoothESP32HC05::CBluetoothESP32HC05(int keyPin, int sensePin, int rxPin, in
}
void
CBluetoothESP32HC05::_openSerial(int baudrate)
CBluetoothESP32HC05::openSerial(int baudrate)
{
// Open Serial port on the ESP32
// best to explicitly specify pins for the pin multiplexer!
HC05_SerialPort.begin(baudrate, SERIAL_8N1, _rxPin, _txPin);
pinMode(_rxPin, INPUT_PULLUP); // newer modules seem to be open drian - sort of - need a pullup to work properly anyway
}
// ^
// |
// HC-05 BLUETOOTH with ESP32
/////////////////////////////////////////////////////////////////////////////////////////
#endif
#if USE_CLASSIC_BLUETOOTH == 1
/////////////////////////////////////////////////////////////////////////////////////////
@ -86,7 +84,7 @@ CBluetoothESP32Classic::check()
}
}
bool
void
CBluetoothESP32Classic::send(const char* Str)
{
if(isConnected()) {
@ -96,14 +94,12 @@ CBluetoothESP32Classic::send(const char* Str)
#endif
SerialBT.write((uint8_t*)Str, strlen(Str));
delay(10);
return true;
}
else {
DebugPort.println("No Bluetooth client");
#if BT_LED == 1
digitalWrite(LED_Pin, 0);
#endif
return false;
}
}
@ -264,7 +260,7 @@ CBluetoothESP32BLE::sendFrame(const char* pHdr, const CProtocol& Frame, bool lin
}
}
*/
bool
void
CBluetoothESP32BLE::send(const char* Str)
{
char fullMsg[32];
@ -278,14 +274,12 @@ CBluetoothESP32BLE::send(const char* Str)
BLE_Send(txData);
delay(10);
return true;
}
else {
DebugPort.println("No Bluetooth client");
#if BT_LED == 1
digitalWrite(LED_Pin, 0);
#endif
return false;
}
}

View file

@ -28,24 +28,18 @@ class CBluetoothESP32HC05 : public CBluetoothHC05 {
public:
CBluetoothESP32HC05(int keyPin, int sensePin, int rxPin, int txPin);
protected:
void _openSerial(int baudrate);
void openSerial(int baudrate);
};
#if USE_CLASSIC_BLUETOOTH == 1
class CBluetoothESP32Classic : public CBluetoothAbstract {
BluetoothSerial SerialBT;
public:
virtual void begin();
virtual bool send(const char* Str);
virtual void send(const char* Str);
virtual void check();
virtual bool isConnected();
};
#endif
#if USE_BLE_BLUETOOTH == 1
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
@ -64,10 +58,8 @@ public:
CBluetoothESP32BLE();
virtual ~CBluetoothESP32BLE();
virtual void begin();
virtual bool send(const char* Str);
virtual void send(const char* Str);
virtual void check();
virtual bool isConnected();
};
#endif
};

View file

@ -0,0 +1,262 @@
/*
* 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 "BluetoothHC05.h"
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../Protocol/Protocol.h"
#include "../Protocol/helpers.h"
#include "../Utility/DebugPort.h"
// Bluetooth access via HC-05 Module, using a UART
CBluetoothHC05::CBluetoothHC05(int keyPin, int sensePin)
{
// extra control pins required to fully drive a HC05 module
_keyPin = keyPin; // used to enable AT command mode (ONLY ON SUPPORTED MODULES!!!!)
_sensePin = sensePin; // feedback signal used to sense if a client is connected
pinMode(_keyPin, OUTPUT);
digitalWrite(_keyPin, LOW); // request HC-05 module to enter data mode
// attach to the SENSE line from the HC-05 module
// this line goes high when a BT client is connected :-)
pinMode(_sensePin, INPUT);
}
void
CBluetoothHC05::begin()
{
const int BTRates[] = {
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
};
_rxLine.clear();
digitalWrite(_keyPin, HIGH); // request HC-05 module to enter command mode
delay(50);
openSerial(9600); // virtual function, may call derived class method here
DebugPort.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
DebugPort.print(" @ ");
DebugPort.print(BTRates[BTidx]);
DebugPort.print(" baud... ");
openSerial(BTRates[BTidx]); // open serial port at a std. baud rate
delay(10);
flush();
HC05_SerialPort.print("AT\r\n"); // clear the throat!
delay(100);
HC05_SerialPort.setTimeout(100);
if(ATCommand("AT\r\n")) { // probe with a simple "AT"
DebugPort.println(" OK."); // got a response - woo hoo found the module!
break;
}
if(ATCommand("AT\r\n")) { // sometimes a second try is good...
DebugPort.println(" OK.");
break;
}
// failed, try another baud rate
DebugPort.println("");
HC05_SerialPort.flush();
HC05_SerialPort.end();
delay(100);
}
DebugPort.println("");
if(BTidx == maxTries) {
// we could not get anywhere with the AT commands, but maybe this is the other module
// plough on and assume 9600 baud, but at the mercy of whatever the module name is...
DebugPort.println("FAILED to detect a HC-05 Bluetooth module :-(");
// leave the EN pin high - if other style module keeps it powered!
// assume it is 9600, and just (try to) use it like that...
// we will sense the STATE line to prove a client is hanging off the link...
DebugPort.println("ASSUMING a HC-05 module @ 9600baud (Unknown name)");
openSerial(9600);
}
else {
// found a HC-05 module at one of its supported baud rates.
// now program it's name and force a 9600 baud data interface.
// this is the defacto standard as shipped!
DebugPort.println("HC-05 found");
DebugPort.print(" Setting Name to \"Diesel Heater\"... ");
if(!ATCommand("AT+NAME=\"Diesel Heater\"\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Setting baud rate to 9600N81...");
if(!ATCommand("AT+UART=9600,1,0\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+IPSCAN=1024,1,1024,1\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
/*
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+SNIFF=40,20,1,8\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}
DebugPort.print(" Lowering power consumption...");
if(!ATCommand("AT+ENSNIFF=0002,72,0A3C7F\r\n")) {
DebugPort.println("FAILED");
}
else {
DebugPort.println("OK");
}*/
openSerial(9600);
// leave HC-05 command mode, return to data mode
digitalWrite(_keyPin, LOW);
}
delay(50);
flush(); // ensure any AT command reponse dribbles are cleaned up!
DebugPort.println("");
}
void
CBluetoothHC05::check()
{
// check for data coming back over Bluetooth
if(HC05_SerialPort.available()) { // serial rx data is available
char rxVal = HC05_SerialPort.read();
collectRxData(rxVal);
}
}
bool
CBluetoothHC05::isConnected()
{
return digitalRead(_sensePin);
}
void
CBluetoothHC05::send(const char* Str)
{
if(isConnected()) {
HC05_SerialPort.print(Str);
}
else {
// DebugPort.print("No Bluetooth client");
}
}
/*
void
CBluetoothHC05::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
{
// report to debug port
CBluetoothAbstract::sendFrame(pHdr, Frame, false);
if(isConnected()) {
if(Frame.verifyCRC()) {
// send data frame to HC-05
HC05_SerialPort.print(pHdr);
HC05_SerialPort.write(Frame.Data, 24);
// toggle LED
#if BT_LED == 1
digitalWrite(LED_Pin, !digitalRead(LED_Pin)); // toggle LED
#endif
}
else {
DebugPort.print("Bluetooth data not sent, CRC error ");
}
}
else {
if(lineterm) { // only report no client if this will be at end of line (long line support)
DebugPort.print("No Bluetooth client");
}
// force LED off
#if BT_LED == 1
digitalWrite(LED_Pin, LOW);
#endif
}
if(lineterm)
DebugPort.println("");
}
*/
void
CBluetoothHC05::openSerial(int baudrate)
{
// standard serial port for Due, Mega (ESP32 uses virtual, derived from this class)
HC05_SerialPort.begin(baudrate);
}
// protected function, to perform Hayes commands with HC-05
bool
CBluetoothHC05::ATCommand(const char* cmd)
{
HC05_SerialPort.print(cmd);
char RxBuffer[16];
memset(RxBuffer, 0, 16);
int read = HC05_SerialPort.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
return true;
}
return false;
}
void
CBluetoothHC05::foldbackDesiredTemp()
{
StaticJsonBuffer<32> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
if(foldbackModerator.addJson("TempDesired", getSetTemp(), root)) {
char opStr[32];
root.printTo(opStr);
send(opStr);
}
}
void
CBluetoothHC05::flush()
{
while(HC05_SerialPort.available())
HC05_SerialPort.read();
}

View file

@ -38,26 +38,16 @@ static HardwareSerial& HC05_SerialPort(Serial2);
class CBluetoothHC05 : public CBluetoothAbstract {
bool ATCommand(const char* str);
bool ATResponse(const char* str, const char* respHdr, char* response, int& len);
bool Reset(bool keystate);
int _sensePin, _keyPin;
CModerator foldbackModerator;
char _MAC[32];
bool _bTest;
bool _bGotMAC;
int _BTbaudIdx;
public:
CBluetoothHC05(int keyPin, int sensePin);
void begin();
bool send(const char* Str);
void send(const char* Str);
void check();
virtual bool isConnected();
const char* getMAC();
virtual bool test(char); // returns true whilst test mode is active
protected:
virtual void _openSerial(int baudrate);
virtual void _foldbackDesiredTemp();
void _flush();
void _decodeMACresponse(char* pResponse, int len);
void _setCommandMode(bool commandMode);
virtual void openSerial(int baudrate);
virtual void foldbackDesiredTemp();
void flush();
};

View file

@ -22,7 +22,6 @@
#include "128x64OLED.h"
#include "../Utility/DebugPort.h"
#include "../Utility/UtilClasses.h"
#define DBG DebugPort.print
#define DBGln DebugPort.println
@ -75,7 +74,7 @@ size_t C128x64_OLED::write(uint8_t c)
{
if(m_pFontInfo) {
if (c == '\n') {
cursor_y += textsize_y*8;
cursor_y += textsize*8;
cursor_x = 0;
} else if (c == '\r') {
// skip em
@ -103,7 +102,7 @@ void C128x64_OLED::getTextExtents(const char* str, CRect& rect)
rect.height = 0;
if(m_pFontInfo) {
while(*str) {
uint8_t c = (uint8_t)*str++;
unsigned char c = (unsigned char)*str++;
if(c >= m_pFontInfo->StartChar && c <= m_pFontInfo->EndChar) {
const FONT_CHAR_INFO* pCharInfo = &m_pFontInfo->pCharInfo[c - m_pFontInfo->StartChar];
// and extract info from flash (program) storage
@ -124,13 +123,15 @@ void C128x64_OLED::getTextExtents(const char* str, CRect& rect)
}
void
C128x64_OLED::drawDotFactoryChar(int16_t x, int16_t y, uint8_t c, uint16_t color, uint16_t bg, const FONT_INFO* pFontDescriptor, int& xsize, int& ysize)
C128x64_OLED::drawDotFactoryChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, const FONT_INFO* pFontDescriptor, int& xsize, int& ysize)
{
#ifdef DEBUG_FONT
char pr = c;
DBG(pr); DBG(F(" fg=")); DBG(color); DBG(F(" bg=")); DBGln(bg);
#endif
uint16_t char2print = c;
if(c >= pFontDescriptor->StartChar && c <= pFontDescriptor->EndChar) {
#ifdef DEBUG_FONT
@ -141,7 +142,7 @@ C128x64_OLED::drawDotFactoryChar(int16_t x, int16_t y, uint8_t c, uint16_t color
// point to info for selected character
const FONT_CHAR_INFO* pCharInfo = &pFontDescriptor->pCharInfo[c - pFontDescriptor->StartChar];
// and extract info from flash (program) storage
uint8_t* addr = (uint8_t*)&pCharInfo->Offset;
unsigned char* addr = (unsigned char*)&pCharInfo->Offset;
// uint8_t LSB = pgm_read_byte(&pCharInfo->Offset);
uint8_t LSB = pgm_read_byte(addr++);
uint8_t MSB = pgm_read_byte(addr);

View file

@ -25,7 +25,7 @@
#include "../cfg/BTCConfig.h"
#if USE_ADAFRUIT_SH1106 == 1
#include "../../lib/esp32-sh1106-oled/Adafruit_SH1106.h"
#include <Adafruit_SH1106.h>
#define OLED_BASE_CLASS Adafruit_SH1106
#endif
#if USE_ADAFRUIT_SSD1306 == 1
@ -34,9 +34,7 @@
#endif
#include "fonts/FontTypes.h"
//#include "../Utility/UtilClasses.h"
struct CRect;
#include "../Utility/UtilClasses.h"
class C128x64_OLED : public OLED_BASE_CLASS {
const FONT_INFO* m_pFontInfo;
@ -44,7 +42,7 @@ public:
C128x64_OLED(int8_t DC, int8_t CS, int8_t RST); // Hardware SPI constructor
C128x64_OLED(int8_t SDA, int8_t SCL); // I2C constructor
void drawDotFactoryChar(int16_t x, int16_t y, uint8_t c, uint16_t color, uint16_t bg, const FONT_INFO* pFontDescriptor, int& xsize, int& ysize);
void drawDotFactoryChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, const FONT_INFO* pFontDescriptor, int& xsize, int& ysize);
void setFontInfo(const FONT_INFO* pFontInfo) { m_pFontInfo = pFontInfo; };
void offsetCursor(int16_t x, int16_t y) {
cursor_x += x;

View file

@ -0,0 +1,351 @@
/*
* 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 "128x64OLED.h"
#include "fonts/tahoma16.h"
#include "fonts/tahoma24.h"
#include "fonts/Icons.h"
#include "BasicScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#define MAXIFONT tahoma_24ptFontInfo
//#define MAXIFONT tahoma_16ptFontInfo
///////////////////////////////////////////////////////////////////////////
//
// CBasicScreen
//
// This screen provides a basic control function
//
///////////////////////////////////////////////////////////////////////////
CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_showSetModeTime = 0;
_showModeTime = 0;
_feedbackType = 0;
_nModeSel = 0;
}
bool
CBasicScreen::show()
{
CScreenHeader::show();
char msg[20];
int xPos, yPos;
float fTemp = getTemperatureSensor();
if(fTemp > -80) {
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(msg, "%.1f`F", fTemp);
}
else {
sprintf(msg, "%.1f`C", fTemp);
}
{
CTransientFont AF(_display, &MAXIFONT); // temporarily use a large font
_printMenuText(_display.xCentre(), 23, msg, false, eCentreJustify);
// _printMenuText(_display.xCentre(), 25, msg, false, eCentreJustify);
}
}
else {
_printMenuText(_display.xCentre(), 25, "No Temperature Sensor", false, eCentreJustify);
}
// at bottom of screen show either:
// Selection between Fixed or Thermostat mode
// Current heat demand setting
// Run state of heater
if(_showModeTime) {
const int border = 3;
const int radius = 4;
// Show selection between Fixed or Thermostat mode
long tDelta = millis() - _showModeTime;
if(tDelta < 0) {
yPos = _display.height() - _display.textHeight() - border; // bottom of screen, with room for box
// display "Fixed Hz" at lower right, allowing space for a selection surrounding box
strcpy(msg, "Fixed Hz");
xPos = _display.width() - border; // set X position to finish short of RHS
_printMenuText(xPos, yPos, msg, _nModeSel == 1, eRightJustify);
// display "Thermostat" at lower left, allowing space for a selection surrounding box
strcpy(msg, "Thermostat");
xPos = border;
_printMenuText(xPos, yPos, msg, _nModeSel == 0);
// setThermostatMode(_nModeSel == 0 ? 1 : 0); // set the new mode
}
else {
// cancel selection mode, apply whatever is boxed
_showModeTime = 0;
_showSetModeTime = millis() + 5000; // then make the new mode setting be shown
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
}
if((_showModeTime == 0) && _showSetModeTime) {
long tDelta = millis() - _showSetModeTime;
if(tDelta < 0) {
switch(_feedbackType) {
case 0:
// Show current heat demand setting
if(getThermostatModeActive()) {
float fTemp = getTemperatureDesired();
if(NVstore.getDegFMode()) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(msg, "Setpoint = %.0f`F", fTemp);
}
else {
sprintf(msg, "Setpoint = %.0f`C", fTemp);
}
}
else {
sprintf(msg, "Setpoint = %.1fHz", getHeaterInfo().getPump_Fixed());
}
break;
case 1:
case 2:
sprintf(msg, "GPIO output #%d %s", _feedbackType, getGPIO(_feedbackType-1) ? "ON" : "OFF");
break;
}
// centre message at bottom of screen
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), msg, false, eCentreJustify);
}
else {
_showSetModeTime = 0;
}
}
if((_showModeTime == 0) && (_showSetModeTime == 0)) {
showRunState();
}
return true;
}
bool
CBasicScreen::keyHandler(uint8_t event)
{
static int repeatCount = -1;
if(event & keyPressed) {
repeatCount = 0; // unlock tracking of repeat events
}
//
// use repeat function for key hold detection
//
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
_showSetModeTime = millis() + 2000;
_feedbackType = 1;
_ScreenManager.reqUpdate();
}
}
// 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
_showSetModeTime = millis() + 2000;
_feedbackType = 2;
_ScreenManager.reqUpdate();
}
}
// hold DOWN to enter thermostat / fixed mode selection
if(event & key_Down) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
_showModeTime = millis() + 5000;
_nModeSel = getThermostatModeActive() ? 0 : 1;
}
}
// hold UP to toggle degC/degF mode selection
if(event & key_Up) {
if(repeatCount > 2) {
repeatCount = -1; // prevent double handling
_showModeTime = millis() + 5000;
NVstore.setDegFMode(NVstore.getDegFMode() ? 0 : 1);
}
}
// hold CENTRE to turn ON or OFF
if(event & key_Centre) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(repeatCount > 5) {
repeatCount = -1;
requestOff();
}
}
else { // standard idle state
// standby, request ON
if(repeatCount > 3) {
repeatCount = -1;
requestOn();
}
}
}
}
}
//
// key released handling
//
if(event & keyReleased) {
if(!_showModeTime) {
// release DOWN key to reduce set demand, provided we are not in mode select
if(event & key_Down) {
if(reqTempDelta(-1)) {
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
else
_reqOEMWarning();
}
// release UP key to increase set demand, provided we are not in mode select
if(event & key_Up) {
if(reqTempDelta(+1)) {
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
_ScreenManager.reqUpdate();
}
else
_reqOEMWarning();
}
}
if(event & key_Left) {
if(repeatCount >= 0) {
if(!_showModeTime) {
_ScreenManager.prevMenu();
}
else {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_showModeTime = millis() + 5000;
_nModeSel = 0;
setThermostatMode(1); // set the new mode
NVstore.save();
}
_ScreenManager.reqUpdate();
}
}
}
if(event & key_Right) {
if(repeatCount >= 0) {
if(!_showModeTime)
_ScreenManager.nextMenu();
else {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_showModeTime = 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
if(_showModeTime) {
_showModeTime = millis(); // force immediate cancellation of showmode (via screen update)
}
_showSetModeTime = millis() + 2000;
_feedbackType = 0;
}
_ScreenManager.reqUpdate();
}
repeatCount = -1;
}
return true;
}
void
CBasicScreen::showRunState()
{
int runstate = getHeaterInfo().getRunStateEx();
int errstate = getHeaterInfo().getErrState();
if(errstate) errstate--; // correct for +1 biased return value
static bool toggle = false;
const char* toPrint = NULL;
_display.setTextColor(WHITE, BLACK);
if(errstate && ((runstate == 0) || (runstate > 5))) {
// flash error code
char msg[16];
toggle = !toggle;
if(toggle) {
// create an "E-XX" message to display
sprintf(msg, "E-%02d", errstate);
}
else {
strcpy(msg, " ");
}
int xPos = _display.xCentre();
int yPos = _display.height() - 2*_display.textHeight();
_printMenuText(xPos, yPos, msg, false, eCentreJustify);
toPrint = getHeaterInfo().getErrStateStr();
}
else {
if(runstate) {
toPrint = getHeaterInfo().getRunStateStr();
// simplify starting states
switch(runstate) {
case 1:
case 2:
case 3:
case 4:
toPrint = "Starting";
break;
}
}
}
if(toPrint) {
// locate at bottom centre
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), toPrint, false, eCentreJustify);
}
}

View file

@ -21,7 +21,6 @@
#include <stdint.h>
#include "ScreenHeader.h"
#include "../Utility/DemandManager.h"
class C128x64_OLED;
class CScreenManager;
@ -30,15 +29,13 @@ class CProtocolPackage;
class CBasicScreen : public CScreenHeader
{
unsigned long _showSetModeTime;
unsigned char _feedbackType;
unsigned long _showModeTime;
unsigned long _showAbortTime;
CDemandManager::eStartCode _abortreason;
uint8_t _bShowOtherSensors;
uint8_t _feedbackType;
uint8_t _nModeSel;
unsigned char _nModeSel;
void showRunState();
public:
CBasicScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool keyHandler(uint8_t event);
bool animate() { return CScreen::animate(); };
};

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -19,16 +19,12 @@
*
*/
#include <Arduino.h>
#include "ClockScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Protocol/helpers.h"
#include "fonts/Tahoma16.h"
#include "fonts/Tahoma24.h"
#include "fonts/Arial.h"
#include "../RTC/Clock.h"
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../RTC/RTCStore.h"
///////////////////////////////////////////////////////////////////////////
//
@ -45,52 +41,33 @@ CClockScreen::CClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen
_keyRepeatCount = -1;
}
void
CClockScreen::showTime(int)
{
// override and DO NOTHING!
}
bool
CClockScreen::show()
{
showHeaderDetail(true);
CScreenHeader::show(false);
CScreenHeader::show();
const BTCDateTime& now = Clock.get();
char str[32];
int clockcentre = _display.xCentre();
int hr = now.hour();
if(NVstore.getUserSettings().clock12hr) {
if(hr == 0)
hr = 12;
else if (hr > 12)
hr -= 12;
clockcentre -= 8; // allow space for AM/PM indicators
}
// if(now.second() & 0x01)
if(_colon)
sprintf(str, "%d:%02d", hr, now.minute());
sprintf(str, "%d:%02d", now.hour(), now.minute());
else
sprintf(str, "%d %02d", hr, now.minute());
sprintf(str, "%d %02d", now.hour(), now.minute());
_colon = !_colon;
int yPos = 25;
int timewidth = 0;
{
// CTransientFont AF(_display, &tahoma_16ptFontInfo); // temporarily use a large font
CTransientFont AF(_display, &tahoma_24ptFontInfo); // temporarily use a large font
_printMenuText(clockcentre, yPos, str, false, eCentreJustify);
CRect extents;
extents.xPos = 0;
extents.yPos = 0;
_display.getTextExtents(str, extents);
timewidth = extents.width;
}
if(NVstore.getUserSettings().clock12hr) {
CTransientFont AF(_display, &arial_8ptBoldFontInfo); // temporarily use a large font
if(now.hour() >= 12)
_printMenuText(clockcentre + timewidth/2 + 5, yPos + 14, "PM");
else
_printMenuText(clockcentre + timewidth/2 + 5, yPos, "AM");
_printMenuText(_display.xCentre(), yPos, str, false, eCentreJustify);
}
sprintf(str, "%s %d %s %d", now.dowStr(), now.day(), now.monthStr(), now.year());
_printMenuText(_display.xCentre(), 56, str, false, eCentreJustify);
@ -110,9 +87,7 @@ CClockScreen::keyHandler(uint8_t event)
}
// press DOWN
if(event & key_Down) {
if(NVstore.getUserSettings().menuMode < 2) {
_ScreenManager.selectMenu(CScreenManager::TimerMenuLoop); // switch to timer set screen loop
}
_ScreenManager.selectMenu(CScreenManager::TimerMenuLoop); // switch to timer set screen loop
}
}
if(event & keyRepeat) {
@ -122,32 +97,30 @@ CClockScreen::keyHandler(uint8_t event)
if(event & key_Left) {
if(_keyRepeatCount > 2) {
_keyRepeatCount = -1; // prevent double handling
toggleGPIOout(0); // toggle GPIO output #1
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
toggleGPIOout(1); // toggle GPIO output #2
setGPIO(1, !getGPIO(1)); // toggle GPIO output #2
}
}
// hold CENTRE to toggle On/Off state
if(event & key_Centre) {
if(NVstore.getUserSettings().menuMode < 2) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate && !RTC_Store.getFrostOn()) { // running, including cyclic mode idle
if(_keyRepeatCount > 5) {
_keyRepeatCount = -1;
requestOff();
}
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(_keyRepeatCount > 5) {
_keyRepeatCount = -1;
requestOff();
}
else { // standard idle state
// standby, request ON
if(_keyRepeatCount > 3) {
_keyRepeatCount = -1;
requestOn();
}
}
else { // standard idle state
// standby, request ON
if(_keyRepeatCount > 3) {
_keyRepeatCount = -1;
requestOn();
}
}
}

View file

@ -30,7 +30,7 @@ class CScreenManager;
class CClockScreen : public CScreenHeader {
protected:
virtual void showTime() {}; // override so time does not show in header
virtual void showTime(int numTimers);
bool _colon;
int _keyRepeatCount;
public:

View file

@ -22,33 +22,26 @@
#include "128x64OLED.h"
#include "fonts/MiniFont.h"
#include "fonts/Icons.h"
#include "../Bluetooth/BluetoothAbstract.h"
#include "DetailedScreen.h"
#include "../Wifi/BTCWifi.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Protocol/helpers.h"
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../Utility/FuelGauge.h"
#include "../RTC/RTCStore.h"
#include "../Utility/DemandManager.h"
#define MINIFONT miniFontInfo
//#define X_FAN_ICON 55
#define X_FAN_ICON 49
#define X_FAN_ICON 55
#define Y_FAN_ICON 39
//#define X_FUEL_ICON 81
#define X_FUEL_ICON 74
#define X_FUEL_ICON 81
#define Y_FUEL_ICON 39
//#define X_TARGET_ICON 31
#define X_TARGET_ICON 28
#define X_TARGET_ICON 31
#define Y_TARGET_ICON 39
#define Y_BASELINE 58
//#define X_GLOW_ICON 97
#define X_GLOW_ICON 92
#define X_GLOW_ICON 97
#define Y_GLOW_ICON 38
#define X_BOWSER_ICON 91
#define Y_BOWSER_ICON 43
#define X_BODY_BULB 119
#define X_BULB 1 // >= 1
#define Y_BULB 4
@ -80,13 +73,14 @@ CDetailedScreen::CDetailedScreen(C128x64_OLED& display, CScreenManager& mgr) : C
_showTarget = 0;
}
bool
CDetailedScreen::show()
{
showHeaderDetail(_showTarget != 0);
CScreenHeader::show(false);
CScreenHeader::show();
const char* c = String(getTemperatureSensor()).c_str();
int runstate = getHeaterInfo().getRunStateEx();
int errstate = getHeaterInfo().getErrState();
if(errstate) errstate--; // correct for +1 biased return value
@ -97,33 +91,25 @@ CDetailedScreen::show()
}
float desiredT = 0;
float fPump = 0;
if((runstate && (runstate <= 5)) || (runstate == 9) || _showTarget) { // state 9 = manufactured "heating glow plug"
if(CDemandManager::isThermostat() && !CDemandManager::isExtThermostatMode()) {
desiredT = CDemandManager::getDemand();
}
else {
fPump = getHeaterInfo().getPump_Fixed();
if(NVstore.getUserSettings().cyclic.isEnabled())
desiredT = CDemandManager::getDegC();
}
if((runstate && (runstate <= 5)) || _showTarget) {
if(getThermostatModeActive())
desiredT = getTemperatureDesired();
else
desiredT = -getHeaterInfo().getPump_Fixed();
}
float fTemp = getTemperatureSensor();
showThermometer(desiredT, // read values from most recently sent [BTC] frame
fTemp,
fPump);
fTemp);
_animateRPM = false;
_animatePump = false;
_animateGlow = false;
bool bGlowActive = false;
if(runstate != 0 && runstate != 10) { // not idle modes
float power = getHeaterInfo().getGlowPlug_Power();
if(power > 1) {
showGlowPlug(power);
bGlowActive = true;
}
if(_showTarget)
@ -136,9 +122,6 @@ CDetailedScreen::show()
showBodyThermometer(getHeaterInfo().getTemperature_HeatExchg());
}
if(!bGlowActive) {
showBowser(FuelGauge.Used_mL());
}
showRunState(runstate, errstate);
return true;
}
@ -153,20 +136,20 @@ CDetailedScreen::animate()
if(_animatePump) {
// erase region of fuel icon
_display.fillRect(X_FUEL_ICON, Y_FUEL_ICON, FuelIconInfo.width, FuelIconInfo.height + 4, BLACK);
_drawBitmap(X_FUEL_ICON, Y_FUEL_ICON+(_dripAnimationState/2), FuelIconInfo);
_display.fillRect(X_FUEL_ICON, Y_FUEL_ICON, W_FUEL_ICON, H_FUEL_ICON + 4, BLACK);
_display.drawBitmap(X_FUEL_ICON, Y_FUEL_ICON+(_dripAnimationState/2), FuelIcon, W_FUEL_ICON, H_FUEL_ICON, WHITE);
_dripAnimationState++;
_dripAnimationState &= 0x07;
}
if(_animateRPM) {
// erase region of fuel icon
_display.fillRect(X_FAN_ICON, Y_FAN_ICON, FanIcon1Info.width, FanIcon1Info.height, BLACK);
_display.fillRect(X_FAN_ICON, Y_FAN_ICON, W_FAN_ICON, H_FAN_ICON, BLACK);
switch(_fanAnimationState) {
case 0: _drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon1Info); break;
case 1: _drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon2Info); break;
case 2: _drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon3Info); break;
case 3: _drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon4Info); break;
case 0: _display.drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon1, W_FAN_ICON, H_FAN_ICON, WHITE); break;
case 1: _display.drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon2, W_FAN_ICON, H_FAN_ICON, WHITE); break;
case 2: _display.drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon3, W_FAN_ICON, H_FAN_ICON, WHITE); break;
case 3: _display.drawBitmap(X_FAN_ICON, Y_FAN_ICON, FanIcon4, W_FAN_ICON, H_FAN_ICON, WHITE); break;
}
_fanAnimationState++;
_fanAnimationState &= 0x03;
@ -174,8 +157,8 @@ CDetailedScreen::animate()
if(_animateGlow) {
_display.fillRect(X_GLOW_ICON, Y_GLOW_ICON, 17, 10, BLACK);
_drawBitmap(X_GLOW_ICON, Y_GLOW_ICON, GlowPlugIconInfo);
_drawBitmap(X_GLOW_ICON, Y_GLOW_ICON + 2 + _heatAnimationState, GlowHeatIconInfo);
_display.drawBitmap(X_GLOW_ICON, Y_GLOW_ICON, GlowPlugIcon, 16, 9, WHITE);
_display.drawBitmap(X_GLOW_ICON, Y_GLOW_ICON + 2 + _heatAnimationState, GlowHeatIcon, 17, 2, WHITE);
_heatAnimationState -= 2;
_heatAnimationState &= 0x07;
}
@ -198,28 +181,24 @@ CDetailedScreen::keyHandler(uint8_t event)
if(event & keyRepeat) {
if(_keyRepeatCount >= 0) {
_keyRepeatCount++;
if((event & (key_Left | key_Right)) == (key_Left | key_Right)) {
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::HtrSettingsUI);
return true;
}
// hold LEFT to toggle GPIO output #1
if(event & key_Left) {
if(_keyRepeatCount > 2) {
_keyRepeatCount = -1; // prevent double handling
toggleGPIOout(0); // toggle GPIO output #1
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
toggleGPIOout(1); // toggle GPIO output #2
setGPIO(1, !getGPIO(1)); // toggle GPIO output #2
}
}
if(event & key_Centre) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate && !RTC_Store.getFrostOn()) { // running, including cyclic mode idle
if(runstate) { // running, including cyclic mode idle
if(_keyRepeatCount > 5) {
_keyRepeatCount = -1; // prevent double handling
requestOff();
@ -233,10 +212,11 @@ CDetailedScreen::keyHandler(uint8_t event)
}
}
if(event & key_Down) {
if(_keyRepeatCount > 1) { // held Down - toggle thermo/fixed mode
if(_keyRepeatCount > 1) { // held Down - togle thermo/fixed mode
_keyRepeatCount = -1; // prevent double handling
if(CDemandManager::toggleThermostat()) {
if(reqThermoToggle()) {
_showTarget = millis() + 3500;
NVstore.save();
}
else _reqOEMWarning();
}
@ -244,10 +224,7 @@ CDetailedScreen::keyHandler(uint8_t event)
if(event & key_Up) {
if(_keyRepeatCount > 1) { // held Down - togle thermo/fixed mode
_keyRepeatCount = -1; // prevent double handling
sUserSettings settings = NVstore.getUserSettings();
toggle(settings.degF);
NVstore.setUserSettings(settings);
NVstore.save();
NVstore.setDegFMode(NVstore.getDegFMode() ? 0 : 1);
}
}
}
@ -256,17 +233,11 @@ CDetailedScreen::keyHandler(uint8_t event)
if(event & keyReleased) {
if(_keyRepeatCount == 0) { // short Up press - lower target
if(event & key_Up) {
if(CDemandManager::deltaDemand(+1)) {
_showTarget = millis() + 3500;
_ScreenManager.reqUpdate();
}
if(reqTempDelta(+1)) _showTarget = millis() + 3500;
else _reqOEMWarning();
}
if(event & key_Down) { // short Down press - lower target
if(CDemandManager::deltaDemand(-1)) {
_showTarget = millis() + 3500;
_ScreenManager.reqUpdate();
}
if(reqTempDelta(-1)) _showTarget = millis() + 3500;
else _reqOEMWarning();
}
if(event & key_Centre) { // short Centre press - show target
@ -289,97 +260,60 @@ CDetailedScreen::keyHandler(uint8_t event)
#define TEMP_YPOS(A) ((20 - int(A)) + 27) // 26 is location of 20deg tick
void
CDetailedScreen::showThermometer(float fDesired, float fActual, float fPump)
CDetailedScreen::showThermometer(float desired, float actual)
{
char msg[16];
// draw bulb design
_drawBitmap(X_BULB, Y_BULB, AmbientThermometerIconInfo, WHITE);
_display.drawBitmap(X_BULB, Y_BULB, ambientThermometerIcon, W_BULB_ICON, H_BULB_ICON, WHITE);
if(fActual > 0) {
if(actual > 0) {
// draw mercury
int yPos = Y_BULB + TEMP_YPOS(fActual);
int yPos = Y_BULB + TEMP_YPOS(actual);
_display.drawLine(X_BULB + 3, yPos, X_BULB + 3, Y_BULB + 42, WHITE);
_display.drawLine(X_BULB + 4, yPos, X_BULB + 4, Y_BULB + 42, WHITE);
}
// print actual temperature
if(fActual > -80) {
if(actual > -80) {
#ifdef MINI_TEMPLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
if(NVstore.getUserSettings().degF) {
fActual = fActual * 9 / 5 + 32;
sprintf(msg, "%.1f`F", fActual);
if(NVstore.getDegFMode()) {
actual = actual * 9 / 5 + 32;
sprintf(msg, "%.1f`F", actual);
}
else {
sprintf(msg, "%.1f`C", fActual);
sprintf(msg, "%.1f`C", actual);
}
#else
sprintf(msg, "%.1f", actual);
#endif
_printMenuText(0, Y_BASELINE, msg);
}
else {
_printInverted(1, Y_BASELINE-2, "N/A", true);
}
// draw cyclic bracket (if enabled)
if(NVstore.getUserSettings().cyclic.isEnabled() && (fDesired != 0)) {
int max = fDesired + NVstore.getUserSettings().cyclic.Stop + 1;
int min = fDesired + NVstore.getUserSettings().cyclic.Start; // stored as a negative value!
// convert to screen coordinates
max = Y_BULB + TEMP_YPOS(max);
min = Y_BULB + TEMP_YPOS(min);
int xOfs = 8;
// #
_drawBitmap(X_BULB + xOfs, max-2, ThermoPtrHighIconInfo); // ##
// ####
// ####
_drawBitmap(X_BULB + xOfs, min, ThermoPtrLowIconInfo); // ##
// #
}
// draw target setting
// may be suppressed if not in normal start or run state
if((fDesired != 0) || (fPump != 0)) {
if(CDemandManager::isThermostat() && CDemandManager::isExtThermostatMode()) {
const char* pTimeStr = CDemandManager::getExtThermostatHoldTime();
if(pTimeStr) {
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_drawBitmap(X_TARGET_ICON-1, Y_TARGET_ICON+2, ExtThermo2IconInfo); // draw external input #2 icon
_printMenuText(X_TARGET_ICON+(TargetIconInfo.width/2)-1, Y_TARGET_ICON-4, pTimeStr, false, eCentreJustify);
_drawBitmap(X_TARGET_ICON-8, Y_TARGET_ICON-4, miniStopIconInfo); // draw stop icon
}
else
_drawBitmap(X_TARGET_ICON-1, Y_TARGET_ICON+2, ExtThermo2IconInfo); // draw external input #2 icon
if(CDemandManager::isExtThermostatOn())
_drawBitmap(X_TARGET_ICON-2, Y_TARGET_ICON+10, CloseIconInfo); // draw external input #2 icon
else
_drawBitmap(X_TARGET_ICON-2, Y_TARGET_ICON+10, OpenIconInfo); // draw external input #2 icon
}
else {
_drawBitmap(X_TARGET_ICON, Y_TARGET_ICON, TargetIconInfo); // draw target icon
}
if(desired) {
_display.drawBitmap(X_TARGET_ICON, Y_TARGET_ICON, TargetIcon, W_TARGET_ICON, H_TARGET_ICON, WHITE); // set indicator against bulb
char msg[16];
if(fPump == 0) {
int yPos = Y_BULB + TEMP_YPOS(fDesired) - 2; // 2 offsets mid height of icon
_drawBitmap(X_BULB-1, yPos, ThermoPtrIconInfo); // set closed indicator against bulb
if(NVstore.getUserSettings().degF) {
fDesired = fDesired * 9 / 5 + 32;
sprintf(msg, "%.0f`F", fDesired);
if(desired > 0) {
int yPos = Y_BULB + TEMP_YPOS(desired) - 2;
_display.drawBitmap(X_BULB-1, yPos, thermoPtr, 3, 5, WHITE); // set indicator against bulb
if(NVstore.getDegFMode()) {
desired = desired * 9 / 5 + 32;
sprintf(msg, "%.0f`F", desired);
}
else {
sprintf(msg, "%.0f`C", fDesired);
sprintf(msg, "%.0f`C", desired);
}
}
else {
if(fDesired) {
int yPos = Y_BULB + TEMP_YPOS(fDesired) - 2;
_drawBitmap(X_BULB-1, yPos, ThermoOpenPtrIconInfo); // set open style indicator against bulb
}
sprintf(msg, "%.1fHz", fPump);
sprintf(msg, "%.1fHz", -desired);
}
#ifdef MINI_TARGETLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_TARGET_ICON + (TargetIconInfo.width/2), Y_BASELINE, msg, false, eCentreJustify);
_printMenuText(X_TARGET_ICON + (W_TARGET_ICON/2), Y_BASELINE, msg, false, eCentreJustify);
}
}
@ -388,7 +322,7 @@ void
CDetailedScreen::showBodyThermometer(int actual)
{
// draw bulb design
_drawBitmap(X_BODY_BULB, Y_BULB, BodyThermometerIconInfo);
_display.drawBitmap(X_BODY_BULB, Y_BULB, bodyThermometerIcon, 8, 50, WHITE);
// draw mercury
int yPos = Y_BULB + BODY_YPOS(actual);
_display.drawLine(X_BODY_BULB + 3, yPos, X_BODY_BULB + 3, Y_BULB + 42, WHITE);
@ -399,7 +333,7 @@ CDetailedScreen::showBodyThermometer(int actual)
// determine width and position right justified
#ifdef MINI_BODYLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
if(NVstore.getUserSettings().degF) {
if(NVstore.getDegFMode()) {
actual = actual * 9 / 5 + 32;
sprintf(label, "%d`F", actual);
}
@ -416,15 +350,15 @@ CDetailedScreen::showBodyThermometer(int actual)
void
CDetailedScreen::showGlowPlug(float power)
{
_drawBitmap(X_GLOW_ICON, Y_GLOW_ICON, GlowPlugIconInfo);
_display.drawBitmap(X_GLOW_ICON, Y_GLOW_ICON, GlowPlugIcon, W_GLOW_ICON, H_GLOW_ICON, WHITE);
// _animateGlow = true;
char msg[16];
sprintf(msg, "%.0fW", power);
#ifdef MINI_GLOWLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_GLOW_ICON + (GlowPlugIconInfo.width/2),
Y_GLOW_ICON + GlowPlugIconInfo.height + 3,
_printMenuText(X_GLOW_ICON + (W_GLOW_ICON/2),
Y_GLOW_ICON + H_GLOW_ICON + 3,
msg, false, eCentreJustify);
}
@ -440,7 +374,7 @@ CDetailedScreen::showFan(int RPM)
#ifdef MINI_FANLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_FAN_ICON + (FanIcon1Info.width/2), Y_BASELINE, msg, false, eCentreJustify);
_printMenuText(X_FAN_ICON + (W_FAN_ICON/2), Y_BASELINE, msg, false, eCentreJustify);
}
void
@ -455,7 +389,7 @@ CDetailedScreen::showFanV(float volts)
#ifdef MINI_FANLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_FAN_ICON + (FanIcon1Info.width/2), Y_BASELINE, msg, false, eCentreJustify);
_printMenuText(X_FAN_ICON + (W_FAN_ICON/2), Y_BASELINE, msg, false, eCentreJustify);
}
void
@ -469,24 +403,10 @@ CDetailedScreen::showFuel(float rate)
#ifdef MINI_FUELLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_FUEL_ICON + (FuelIconInfo.width/2), Y_BASELINE, msg, false, eCentreJustify);
_printMenuText(X_FUEL_ICON + (W_FUEL_ICON/2), Y_BASELINE, msg, false, eCentreJustify);
}
}
void
CDetailedScreen::showBowser(float used)
{
_display.setTextColor(WHITE);
_drawBitmap(X_BOWSER_ICON, Y_BOWSER_ICON, BowserIconInfo);
char msg[16];
sprintf(msg, "%.02fL", used * 0.001);
#ifdef MINI_FANLABEL
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
#endif
_printMenuText(X_BOWSER_ICON + (BowserIconInfo.width/2), Y_BASELINE, msg, false, eCentreJustify);
}
void
CDetailedScreen::showRunState(int runstate, int errstate)
{

View file

@ -41,14 +41,13 @@ class CDetailedScreen : public CScreenHeader
unsigned long _showTarget;
void showRunState();
void showThermometer(float desired, float actual, float pump);
void showThermometer(float desired, float actual);
void showBodyThermometer(int actual);
void showGlowPlug(float power);
void showFan(int RPM);
void showFanV(float volts);
void showFuel(float rate);
void showRunState(int state, int errstate);
void showBowser(float used);
public:
CDetailedScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();

View file

@ -0,0 +1,107 @@
/*
* 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 "128x64OLED.h"
#include "FontDumpScreen.h"
#include "KeyPad.h"
///////////////////////////////////////////////////////////////////////////
//
// CFontDumpScreen
//
// This screen provides control over experimental features
//
///////////////////////////////////////////////////////////////////////////
static const int Lines[4] = { 24, 34, 44, 54 };
CFontDumpScreen::CFontDumpScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen(display, mgr)
{
_initUI();
}
void
CFontDumpScreen::onSelect()
{
CScreen::onSelect();
}
void
CFontDumpScreen::_initUI()
{
_startChar = 0;
}
bool
CFontDumpScreen::show()
{
_display.clearDisplay();
char msg[8];
_printInverted(_display.xCentre(), 0, " Adafruit Font ", true, eCentreJustify);
int column = 15;
for(int i=0; i<16; i++) {
sprintf(msg, "%X", i);
_printMenuText(column, 12, msg);
column += 7;
}
for(int row = 0; row < 4; row++) {
int currentChar = row * 16 + _startChar;
sprintf(msg, "%02X", currentChar);
_printMenuText(0, Lines[row], msg);
column = 15;
for(int i=0; i<16; i++) {
msg[0] = currentChar++;
msg[1] = 0;
_printMenuText(column, Lines[row], msg);
column += 7;
}
}
_display.drawFastVLine(13, 12, 61, WHITE);
_display.drawFastHLine(0, 21, 128, WHITE);
return true;
}
bool
CFontDumpScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press LEFT or UP to show prior 64 characters
if(event & (key_Left | key_Up)) {
_startChar -= 64;
}
// press RIGHT or DOWN to show next 64 characters
if(event & (key_Right | key_Down)) {
_startChar += 64;
}
// CENTRE press
if(event & key_Centre) {
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI); // force return to prior menu
}
_ScreenManager.reqUpdate();
}
return true;
}

View file

@ -19,8 +19,8 @@
*
*/
#ifndef __HOURMETERSCREEN_H__
#define __HOURMETERSCREEN_H__
#ifndef __FONTDUMPSCREEN_H__
#define __FONTDUMPSCREEN_H__
#include <stdint.h>
#include "Screen.h"
@ -28,13 +28,15 @@
class C128x64_OLED;
class CScreenManager;
class CHourMeterScreen : public CScreen
class CFontDumpScreen : public CScreen
{
unsigned char _startChar;
void _initUI();
public:
CHourMeterScreen(C128x64_OLED& display, CScreenManager& mgr);
CFontDumpScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool keyHandler(uint8_t event);
void onSelect();
};
#endif

View file

@ -0,0 +1,281 @@
/*
* 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/>.
*
*/
///////////////////////////////////////////////////////////////////////////
//
// CFuelMixtureScreen
//
// This screen allows the fuel mixture endpoints to be adjusted
//
///////////////////////////////////////////////////////////////////////////
#include "FuelMixtureScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "../utility/debugPort.h"
CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
}
void
CFuelMixtureScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min();
adjFan[1] = getHeaterInfo().getFan_Max();
}
void
CFuelMixtureScreen::_initUI()
{
_rowSel = 0;
_colSel = 0;
}
bool
CFuelMixtureScreen::show()
{
char str[16];
int xPos, yPos;
const int col2 = 90;
const int col3 = _display.width() - border;
_display.clearDisplay();
if(!CPasswordScreen::show()) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
case 4:
// Pump Minimum adjustment
yPos = border + 36;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%.1f", 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(col3, yPos, str, _rowSel == 2, eRightJustify);
// Fan Minimum adjustment
yPos = border + 12;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%d", 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(col3, yPos, str, _rowSel == 4, eRightJustify);
// navigation line
yPos = 53;
xPos = _display.xCentre();
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 Exit \020 ", _rowSel == 0, eCentreJustify); // " < Exit > "
break;
case 1:
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \3600.1", false, eCentreJustify); // "^vSel Save <> +-0.1"
break;
case 3:
case 4:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \36010", false, eCentreJustify); // "^vSel Save <> +-10"
break;
}
break;
case 5:
_printInverted(_display.xCentre(), 0, " Save Fuel Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
break;
}
}
return true;
}
bool
CFuelMixtureScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press CENTRE
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
break;
case 1:
case 2:
case 3:
case 4:
_rowSel = 5; // enter save confirm mode
break;
case 5:
_rowSel = 0;
break;
}
}
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
case 2:
case 3:
case 4:
_adjustSetting(-1);
break;
case 5:
_rowSel = 0;
break;
}
}
// press RIGHT
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
case 2:
case 3:
case 4:
_adjustSetting(+1);
break;
case 5:
_rowSel = 0;
break;
}
}
// press UP
if(event & key_Up) {
if(hasOEMcontroller())
_reqOEMWarning();
else {
switch(_rowSel) {
case 0:
// grab current settings upon entry to edit mode
adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min();
adjFan[1] = getHeaterInfo().getFan_Max();
case 1:
case 2:
case 3:
_rowSel++;
_colSel = 0;
UPPERLIMIT(_rowSel, 4);
break;
case 5:
_showStoringMessage();
setPumpMin(adjPump[0]);
setPumpMax(adjPump[1]);
setFanMin(adjFan[0]);
setFanMax(adjFan[1]);
saveNV();
_rowSel = 0;
break;
}
}
}
// press DOWN
if(event & key_Down) {
switch(_rowSel) {
case 1:
case 2:
case 3:
case 4:
_rowSel--;
_colSel = 0;
break;
case 5:
_rowSel = 0;
break;
}
}
_ScreenManager.reqUpdate();
}
if(event & keyRepeat) {
switch(_rowSel) {
case 1:
case 2:
case 3:
case 4:
int adj = 0;
if(event & key_Right) adj = +1;
if(event & key_Left) adj = -1;
if(adj) {
_adjustSetting(adj);
}
break;
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CFuelMixtureScreen::_adjustSetting(int dir)
{
switch(_rowSel) {
case 1:
adjPump[0] += (float(dir) * 0.1f);
break;
case 2:
adjPump[1] += (float(dir) * 0.1f);
break;
case 3:
adjFan[0] += dir * 10;
break;
case 4:
adjFan[1] += dir * 10;
break;
}
LOWERLIMIT(adjPump[0], 0.5f);
UPPERLIMIT(adjPump[0], 10.f);
LOWERLIMIT(adjPump[1], 0.5f);
UPPERLIMIT(adjPump[1], 10.f);
LOWERLIMIT(adjFan[0], 1000);
UPPERLIMIT(adjFan[0], 5000);
LOWERLIMIT(adjFan[1], 1000);
UPPERLIMIT(adjFan[1], 5000);
}

View file

@ -30,15 +30,15 @@ class CScreenManager;
class CFuelMixtureScreen : public CPasswordScreen {
float adjPump[2];
uint16_t adjFan[2];
short adjFan[2];
int _rowSel;
int _colSel;
void _adjustSetting(int dir);
void _load();
protected:
void _saveNV();
void _initUI();
public:
CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};

View file

@ -0,0 +1,386 @@
/*
* 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 "128x64OLED.h"
#include "GPIOScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
extern CGPIOout GPIOout;
extern CGPIOin GPIOin;
extern CGPIOalg GPIOalg;
///////////////////////////////////////////////////////////////////////////
//
// CGPIOScreen
//
// This screen provides control over GPIO features
//
///////////////////////////////////////////////////////////////////////////
static const int Line3 = 14;
static const int Line2 = 27;
static const int Line1 = 40;
//static const int Column = 58;
static const int Column = 38;
CGPIOScreen::CGPIOScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_GPIOinMode = 0;
_GPIOoutMode = 0;
_GPIOalgMode = 0;
}
void
CGPIOScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_GPIOinMode = NVstore.getGPIOinMode();
_GPIOoutMode = NVstore.getGPIOoutMode();
_GPIOalgMode = NVstore.getGPIOalgMode();
}
void
CGPIOScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
}
bool
CGPIOScreen::show()
{
_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, " GPIO Settings ", true, eCentreJustify);
_display.drawBitmap(10, 14, GPIOIcon, GPIOWidth, GPIOHeight, WHITE);
// _printMenuText(55, Line3, "Inputs:", false, eRightJustify);
// _printMenuText(55, Line2, "Outputs:", false, eRightJustify);
// _printMenuText(55, Line1, "Analogue:", false, eRightJustify);
{
const char* msgText = NULL;
switch(_GPIOinMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "1-On 2-Off"; break;
case 2: msgText = "1-On 2-\352T"; break;
case 3: msgText = "1-On/Off"; break;
}
if(msgText)
_printMenuText(Column, Line3, msgText, _rowSel == 3);
}
{
const char* msgText = NULL;
switch(_GPIOoutMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "1: Status LED"; break;
case 2: msgText = "1&2 User"; break;
}
if(msgText)
_printMenuText(Column, Line2, msgText, _rowSel == 2);
}
{
const char* msgText = NULL;
switch(_GPIOalgMode) {
case 0: msgText = "Disabled"; break;
case 1: msgText = "Ip1 allows"; break;
}
if(msgText)
_printMenuText(Column, Line1, msgText, _rowSel == 1);
}
}
}
return true;
}
bool
CGPIOScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOalgMode) {
case 0: pMsg = " Analogue input is ignored. "; break;
case 1: pMsg = " Input 1 enables reading of analogue input to set temperature. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOoutMode) {
case 0: pMsg = " Digital outputs are disabled. "; break;
case 1: pMsg = " Output1: LED status indicator. "; break;
case 2: pMsg = " Output 1&2: User controlled. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_GPIOinMode) {
case 0: pMsg = " Digital inputs are disabled. "; break;
case 1: pMsg = " Input 1: Starts upon closure. Input 2: Stops upon closure. "; break;
case 2: pMsg = " Input 1: Starts when held closed, stops when opened. Input2: Max fuel when closed, min fuel when open. "; break;
case 3: pMsg = " Input 1: Starts or Stops upon closure. "; break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CGPIOScreen::keyHandler(uint8_t event)
{
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:
_scrollChar = 0;
_adjust(-1);
break;
case 4:
_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:
_scrollChar = 0;
_adjust(+1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
break;
case 4: // confirmed save
_showStoringMessage();
NVstore.setGPIOinMode(_GPIOinMode);
NVstore.setGPIOoutMode(_GPIOoutMode);
NVstore.setGPIOalgMode(_GPIOalgMode);
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:
_rowSel = 4;
break;
}
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CGPIOScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1: // analogue mode
_GPIOalgMode += dir;
UPPERLIMIT(_GPIOalgMode, 1);
LOWERLIMIT(_GPIOalgMode, 0);
break;
case 2: // outputs mode
_GPIOoutMode += dir;
ROLLLOWERLIMIT(_GPIOoutMode, 0, 2);
ROLLUPPERLIMIT(_GPIOoutMode, 2, 0);
break;
case 3:
_GPIOinMode += dir;
ROLLUPPERLIMIT(_GPIOinMode, 3, 0);
ROLLLOWERLIMIT(_GPIOinMode, 0, 3);
break;
}
}
CGPIOInfoScreen::CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_keyRepeatCount = -1;
}
void
CGPIOInfoScreen::onSelect()
{
CScreenHeader::onSelect();
}
void
CGPIOInfoScreen::_initUI()
{
}
bool
CGPIOInfoScreen::show()
{
CScreenHeader::show();
char msg[16];
_display.writeFillRect(49, 18, 30, 12, WHITE);
_printInverted(64, 20, "GPIO", true, eCentreJustify);
_printMenuText(22, 18, "In", false, eCentreJustify);
_printMenuText(104, 18, "Out", false, eCentreJustify);
_printMenuText(11, 20, "1", false, eCentreJustify);
_printMenuText(34, 20, "2", false, eCentreJustify);
_printMenuText(91, 20, "1", false, eCentreJustify);
_printMenuText(118, 20, "2", false, eCentreJustify);
_printMenuText(55, Line1, "Analogue:", false, eRightJustify);
_display.drawBitmap(4, 29, GPIOin.getState(0) ? CloseIcon : OpenIcon, CloseIconWidth, CloseIconHeight, WHITE);
_display.drawBitmap(27, 29, GPIOin.getState(1) ? CloseIcon : OpenIcon, CloseIconWidth, CloseIconHeight, WHITE);
_display.drawBitmap(86, 29, GPIOout.getState(0) ? BulbOnIcon : BulbOffIcon, BulbOnIconWidth, BulbOnIconHeight, WHITE);
_display.drawBitmap(113, 29, GPIOout.getState(1) ? BulbOnIcon : BulbOffIcon, BulbOnIconWidth, BulbOnIconHeight, WHITE);
sprintf(msg, "%d", GPIOalg.getValue());
_printMenuText(58, Line1, msg);
_printMenuText(_display.xCentre(), 53, " \021 \020 ", true, eCentreJustify);
return true;
}
bool
CGPIOInfoScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_keyRepeatCount = 0; // unlock tracking of repeat events
// UP press
if(event & key_Up) {
}
// CENTRE press
if(event & key_Centre) {
}
}
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
// press LEFT to select previous screen
if(event & key_Left) {
_ScreenManager.prevMenu();
}
// press RIGHT to select next screen
if(event & key_Right) {
_ScreenManager.nextMenu();
}
}
_keyRepeatCount = -1;
}
_ScreenManager.reqUpdate();
return true;
}

View file

@ -19,25 +19,42 @@
*
*/
#ifndef __GPIOINFOSCREEN_H__
#define __GPIOINFOSCREEN_H__
#ifndef __GPIOSCREEN_H__
#define __GPIOSCREEN_H__
#include <stdint.h>
#include "PasswordScreen.h"
#include "../Utility/BTC_GPIO.h"
class C128x64_OLED;
class CScreenManager;
class CGPIOInfoScreen : public CScreen
class CGPIOScreen : public CPasswordScreen
{
int _rowSel;
void _adjust(int dir);
int _GPIOinMode;
int _GPIOoutMode;
int _GPIOalgMode;
int _animateCount;
int _scrollChar;
void _initUI();
public:
CGPIOScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};
class CGPIOInfoScreen : public CScreenHeader
{
int _keyRepeatCount;
void _initUI();
public:
CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};
#endif

View file

@ -21,12 +21,9 @@
#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 "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
///////////////////////////////////////////////////////////////////////////
//
@ -56,9 +53,16 @@ CHeaterSettingsScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_fanSensor = NVstore.getHeaterTuning().fanSensor;
_glowDrive = NVstore.getHeaterTuning().glowDrive;
_sysVoltage = NVstore.getHeaterTuning().sysVoltage / 10;
_fanSensor = getHeaterInfo().getFan_Sensor();
_glowDrive = getHeaterInfo().getGlow_Drive();
_sysVoltage = int(getHeaterInfo().getSystemVoltage());
}
void
CHeaterSettingsScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
}
bool
@ -69,25 +73,32 @@ CHeaterSettingsScreen::show()
if(!CPasswordScreen::show()) { // for showing "saving settings"
_showTitle("Heater Settings");
_printMenuText(97, Line3, "System voltage:", false, eRightJustify);
_printMenuText(97, Line2, "Fan sensor:", false, eRightJustify);
_printMenuText(97, Line1, "Glowplug power:", false, eRightJustify);
sprintf(msg, "%dV", _sysVoltage);
_printMenuText(Column, Line3, msg, _rowSel == 3);
// navigation line
int yPos = 53;
int xPos = _display.xCentre();
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, " Heater Settings ", true, eCentreJustify);
_printMenuText(97, Line3, "System voltage:", false, eRightJustify);
_printMenuText(97, Line2, "Fan sensor:", false, eRightJustify);
_printMenuText(97, Line1, "Glowplug power:", false, eRightJustify);
sprintf(msg, "%dV", _sysVoltage);
_printMenuText(Column, Line3, msg, _rowSel == 3);
// navigation line
int yPos = 53;
int xPos = _display.xCentre();
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 Exit \020 ", true, eCentreJustify);
break;
default:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
break;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 Exit \020 ", true, eCentreJustify);
break;
default:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
break;
}
}
}
@ -98,40 +109,45 @@ CHeaterSettingsScreen::show()
bool
CHeaterSettingsScreen::animate()
{
if(isPasswordBusy() || _saveBusy()) { // Password screen activity
return false;
}
char msg[16];
_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);
CPasswordScreen::animate();
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 {
_printMenuText(Column, Line1, " ");
}
_animateCount++;
ROLLUPPERLIMIT(_animateCount, 9, 0);
if(_animateCount < 4)
sprintf(msg, "PF-%d ", _glowDrive);
else
sprintf(msg, "(%dW)", plugPowers[_glowDrive-1]);
_printMenuText(Column, Line1, msg);
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, " ");
}
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);
}
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;
}
@ -139,15 +155,6 @@ CHeaterSettingsScreen::animate()
bool
CHeaterSettingsScreen::keyHandler(uint8_t event)
{
if(CPasswordScreen::keyHandler(event)) { // handle confirm save
return true;
}
if(CUIEditScreen::keyHandler(event)) { // handle save confirm
return true;
}
if(event & keyPressed) {
// press LEFT to select previous screen
if(event & key_Left) {
@ -160,6 +167,9 @@ CHeaterSettingsScreen::keyHandler(uint8_t event)
case 3:
_adjust(-1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
// press RIGHT to select next screen
@ -173,6 +183,9 @@ CHeaterSettingsScreen::keyHandler(uint8_t event)
case 3:
_adjust(+1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
@ -189,6 +202,14 @@ CHeaterSettingsScreen::keyHandler(uint8_t event)
_rowSel++;
UPPERLIMIT(_rowSel, 3);
break;
case 4: // confirmed save
_showStoringMessage();
setSystemVoltage(float(_sysVoltage));
setFanSensor(_fanSensor);
setGlowDrive(_glowDrive);
saveNV();
_rowSel = 0;
break;
}
}
// CENTRE press
@ -200,8 +221,7 @@ CHeaterSettingsScreen::keyHandler(uint8_t event)
case 1:
case 2:
case 3:
_confirmSave(); // enter save confirm mode
_rowSel = 0;
_rowSel = 4;
break;
}
}
@ -217,7 +237,8 @@ CHeaterSettingsScreen::_adjust(int dir)
switch(_rowSel) {
case 1: // glow power
_glowDrive += dir;
BOUNDSLIMIT(_glowDrive, 1, 6);
UPPERLIMIT(_glowDrive, 6);
LOWERLIMIT(_glowDrive, 1);
break;
case 2: // fan sensor
_fanSensor = (_fanSensor == 1) ? 2 : 1;
@ -227,14 +248,3 @@ CHeaterSettingsScreen::_adjust(int dir)
break;
}
}
void
CHeaterSettingsScreen::_saveNV()
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.setSysVoltage(float(_sysVoltage));
tuning.setFanSensor(_fanSensor);
tuning.setGlowDrive(_glowDrive);
NVstore.setHeaterTuning(tuning);
NVstore.save();
}

View file

@ -30,12 +30,13 @@ class CScreenManager;
class CHeaterSettingsScreen : public CPasswordScreen
{
int _rowSel;
void _adjust(int dir);
int _sysVoltage;
int _fanSensor;
int _glowDrive;
protected:
void _saveNV();
int _animateCount;
void _initUI();
public:
CHeaterSettingsScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();

View file

@ -0,0 +1,216 @@
/*
* 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 "128x64OLED.h"
#include "HomeMenuSelScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
CHomeMenuSelScreen::CHomeMenuSelScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
}
void
CHomeMenuSelScreen::onSelect()
{
CScreenHeader::onSelect();
_rowSel = 0;
_action = NVstore.getHomeMenu();
}
void
CHomeMenuSelScreen::_initUI()
{
}
bool
CHomeMenuSelScreen::show()
{
char msg[16];
_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, " Home Menu Actions ", true, eCentreJustify);
// _printMenuText(66, 14, "On timeout:", false, eRightJustify);
_display.drawBitmap(30, 14, timeoutIcon, timeoutWidth, timeoutHeight, WHITE);
switch(_action.onTimeout) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 14, msg, _rowSel == 3);
// _printMenuText(66, 26, "On start:", false, eRightJustify);
_display.drawBitmap(32, 26, startIcon, startWidth, startHeight, WHITE);
switch(_action.onStart) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 26, msg, _rowSel == 2);
// _printMenuText(66, 38, "On stop:", false, eRightJustify);
_display.drawBitmap(31, 38, stopIcon, stopWidth, stopHeight, WHITE);
switch(_action.onStop) {
case 0: strcpy(msg, "Default"); break;
case 1: strcpy(msg, "Detailed"); break;
case 2: strcpy(msg, "Basic"); break;
case 3: strcpy(msg, "Clock"); break;
}
_printMenuText(50, 38, msg, _rowSel == 1);
/* if(_rowSel == 0)
_printMenuText(_display.xCentre(), 53, " \021 \030Edit Exit \020 ", true, eCentreJustify);
else {
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
}*/
}
}
return true;
}
bool
CHomeMenuSelScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to switch to when the heater stops. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to switch to when the heater starts. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Menu to return to after no keypad activity. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CHomeMenuSelScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// UP press
if(event & key_Up) {
if(_rowSel == 4) {
_showStoringMessage();
NVstore.setHomeMenu(_action);
saveNV();
_rowSel = 0;
}
else {
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
// UP press
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// CENTRE press
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
else {
_rowSel = 4;
}
}
// 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);
}
}
_ScreenManager.reqUpdate();
return true;
}
void
CHomeMenuSelScreen::adjust(int dir)
{
switch(_rowSel) {
case 1:
_action.onStop += dir;
ROLLLOWERLIMIT(_action.onStop, 0, 3);
ROLLUPPERLIMIT(_action.onStop, 3, 0);
break;
case 2:
_action.onStart += dir;
ROLLLOWERLIMIT(_action.onStart, 0, 3);
ROLLUPPERLIMIT(_action.onStart, 3, 0);
break;
case 3:
_action.onTimeout += dir;
ROLLLOWERLIMIT(_action.onTimeout, 0, 3);
ROLLUPPERLIMIT(_action.onTimeout, 3, 0);
break;
}
}

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -19,8 +19,8 @@
*
*/
#ifndef __MENUSELSCREEN_H__
#define __MENUSELSCREEN_H__
#ifndef __HOMEMENUSELSCREEN_H__
#define __HOMEMENUSELSCREEN_H__
#include <stdint.h>
#include "PasswordScreen.h"
@ -29,16 +29,15 @@
class C128x64_OLED;
class CScreenManager;
class CMenuSelScreen : public CPasswordScreen
class CHomeMenuSelScreen : public CPasswordScreen
{
int _rowSel;
int _scrollChar;
int _menuMode;
uint8_t _holdPW;
bool _bReload;
protected:
void _saveNV();
sHomeMenuActions _action;
void _initUI();
public:
CMenuSelScreen(C128x64_OLED& display, CScreenManager& mgr);
CHomeMenuSelScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);

View file

@ -30,9 +30,8 @@
#include "InheritSettingsScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/helpers.h"
// #include "../Wifi/BTCWifi.h"
CInheritSettingsScreen::CInheritSettingsScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
@ -58,6 +57,8 @@ CInheritSettingsScreen::_initUI()
bool
CInheritSettingsScreen::show()
{
CScreenHeader::show();
_display.writeFillRect(0, 16, 96, 12, WHITE);
_printInverted(3, 18, "Inherit Settings", true);
@ -97,41 +98,32 @@ CInheritSettingsScreen::keyHandler(uint8_t event)
{
if(CPasswordScreen::keyHandler(event)) {
if(_isPasswordOK()) {
_copySettings();
setPumpMin(getHeaterInfo().getPump_Min());
setPumpMax(getHeaterInfo().getPump_Max());
setFanMin(getHeaterInfo().getFan_Min());
setFanMax(getHeaterInfo().getFan_Max());
setFanSensor(getHeaterInfo().getFan_Sensor());
setSystemVoltage(getHeaterInfo().getSystemVoltage());
saveNV();
_showStoringMessage();
_nAdoptSettings = 0; // will cause return to main menu after storing message expires
}
return true;
}
if(event & keyPressed) {
// press RIGHT
if(event & key_Right) {
if(hasOEMLCDcontroller()) { // inheritance only valid for LCD controllers
_getPassword();
if(_isPasswordOK()) {
_copySettings();
else {
if(event & keyPressed) {
// press RIGHT
if(event & key_Right) {
if(hasOEMLCDcontroller()) { // inheritance only valid for LCD controllers
_getPassword();
_ScreenManager.reqUpdate();
return true;
}
_ScreenManager.reqUpdate();
return true;
}
_nAdoptSettings = 0; // will cause return to main menu
}
_nAdoptSettings = 0; // will cause return to main menu
}
_ScreenManager.reqUpdate();
return true;
}
void
CInheritSettingsScreen::_copySettings()
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.setPmin(getHeaterInfo().getPump_Min());
tuning.setPmax(getHeaterInfo().getPump_Max());
tuning.setFmin(getHeaterInfo().getFan_Min());
tuning.setFmax(getHeaterInfo().getFan_Max());
tuning.fanSensor = getHeaterInfo().getFan_Sensor();
tuning.setSysVoltage(getHeaterInfo().getSystemVoltage());
NVstore.setHeaterTuning(tuning);
NVstore.save();
_enableStoringMessage();
_nAdoptSettings = 0; // will cause return to main menu after storing message expires
}

View file

@ -31,7 +31,6 @@ class CScreenManager;
class CInheritSettingsScreen : public CPasswordScreen {
int _nAdoptSettings;
void _initUI();
void _copySettings();
public:
CInheritSettingsScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();

View file

@ -0,0 +1,235 @@
/*
* 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 "128x64OLED.h"
#include "OtherOptionsScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
COtherOptionsScreen::COtherOptionsScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
}
void
COtherOptionsScreen::onSelect()
{
CScreenHeader::onSelect();
_rowSel = 0;
_repeatCount = -1;
_frameRate = NVstore.getFrameRate();
_dispTimeout = NVstore.getDimTime();
_menuTimeout = 60000;
}
void
COtherOptionsScreen::_initUI()
{
}
bool
COtherOptionsScreen::show()
{
char msg[16];
_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, " Time Intervals ", true, eCentreJustify);
// data frame refresh rate
_display.drawBitmap(15, 13, refreshIcon, refreshWidth, refreshHeight, WHITE);
sprintf(msg, "%dms", _frameRate);
_printMenuText(40, 14, msg, _rowSel == 3);
// display timeout
_display.drawBitmap(10, 26, displayTimeoutIcon, displayTimeoutWidth, displayTimeoutHeight, WHITE);
if(_dispTimeout) {
float mins = float(abs(_dispTimeout)) / 60000.f;
sprintf(msg, "%s %0.1f min%s", (_dispTimeout < 0) ? "Blank" : "Dim", mins, mins < 2 ? "" : "s");
_printMenuText(40, 26, msg, _rowSel == 2);
}
else
_printMenuText(40, 26, "Always on", _rowSel == 2);
// menu timeout
_display.drawBitmap(10, 38, menuTimeoutIcon, menuTimeoutWidth, menuTimeoutHeight, WHITE);
if(_menuTimeout) {
float mins = float(abs(_menuTimeout)) / 60000.f;
sprintf(msg, "Home %0.1f min%s", mins, mins < 2 ? "" : "s");
_printMenuText(40, 38, msg, _rowSel == 1);
}
else
_printMenuText(40, 38, "Disabled", _rowSel == 1);
/* if(_rowSel == 0)
_printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", _rowSel == 0, eCentreJustify);
else {
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
}*/
}
}
return true;
}
bool
COtherOptionsScreen::animate()
{
if(_rowSel != 4) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " No keypad activity returns to the home menu. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " No keypad activity either dims or blanks the display. Hold Left or Right to toggle Dim/Blank mode. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Define the polling rate of the bluewire communications. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
COtherOptionsScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_repeatCount = 0;
// UP press
if(event & key_Up) {
if(_rowSel == 4) {
_showStoringMessage();
NVstore.setFrameRate(_frameRate);
NVstore.setDimTime(_dispTimeout);
saveNV();
_rowSel = 0;
}
else {
_scrollChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 3);
}
}
// UP press
if(event & key_Down) {
_scrollChar = 0;
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// CENTRE press
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
else {
_rowSel = 4;
}
}
}
if(event & keyRepeat) {
if(keyRepeat >= 0) {
_repeatCount++;
if(_repeatCount > 4) {
// LEFT or RIGHT hold
if(event & (key_Right | key_Left)) {
if(_rowSel == 2) {
_repeatCount = -1;
_dispTimeout = -_dispTimeout;
}
}
}
}
}
if(event & keyReleased) {
if(_repeatCount == 0) {
// LEFT short press
if(event & key_Left) {
if(_rowSel == 0)
_ScreenManager.prevMenu();
else
adjust(-1);
}
// RIGHT short press
if(event & key_Right) {
if(_rowSel == 0)
_ScreenManager.nextMenu();
else
adjust(+1);
}
}
}
_ScreenManager.reqUpdate();
return true;
}
void
COtherOptionsScreen::adjust(int dir)
{
switch(_rowSel) {
case 1:
_menuTimeout += dir * 30000;
LOWERLIMIT(_menuTimeout, 0);
UPPERLIMIT(_menuTimeout, 300000);
break;
case 2:
_dispTimeout += dir * 30000;
LOWERLIMIT(_dispTimeout, -600000);
UPPERLIMIT(_dispTimeout, 600000);
break;
case 3:
_frameRate += dir * 50;
LOWERLIMIT(_frameRate, 300);
UPPERLIMIT(_frameRate, 1500);
break;
}
}

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -23,23 +23,23 @@
#define __OTHEROPTIONSCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "PasswordScreen.h"
class C128x64_OLED;
class CScreenManager;
class CTimeoutsScreen : public CUIEditScreen
class COtherOptionsScreen : public CPasswordScreen
{
int _rowSel;
uint16_t _frameRate;
long _dispTimeout;
long _menuTimeout;
int _repeatCount;
int _scrollChar;
protected:
void _saveNV();
void _initUI();
public:
CTimeoutsScreen(C128x64_OLED& display, CScreenManager& mgr);
COtherOptionsScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);

View file

@ -30,91 +30,71 @@
#include "PasswordScreen.h"
#include "KeyPad.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "fonts/Arial.h"
long CPasswordScreen::__Expiry = 0;
CPasswordScreen::CPasswordScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditScreen(display, mgr)
CPasswordScreen::CPasswordScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_initUI();
}
void
CPasswordScreen::__initPassword(bool get)
CPasswordScreen::onSelect()
{
_bGetPassword = get && (__Expiry == 0);
_bPasswordOK = false;
_bPasswordOK |= __Expiry != 0;
_PWcol = 0;
// reset PW digits
for(int i= 0; i < 4; i++)
_PWdig[i] = -1;
_initUI();
}
void
CPasswordScreen::_initUI()
{
CUIEditScreen::_initUI();
__initPassword(false);
}
void
CPasswordScreen::_getPassword()
{
__initPassword(true);
_ScreenManager.reqUpdate();
_bGetPassword = false;
_bPasswordOK = false;
_PWcol = 0;
for(int i= 0; i < 4; i++)
_PWdig[i] = -1;
_SaveTime = 0;
}
bool
CPasswordScreen::show()
{
CPasswordScreen::animate(); // precautionary, in case derived class forgets to call
if(CUIEditScreen::show())
if(_SaveTime) {
_printInverted(_display.xCentre(), 28, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 39, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 34, " STORING ", true, eCentreJustify);
return true;
if(_bGetPassword) {
if(!_bPasswordOK) {
_display.clearDisplay();
_showPassword();
return true;
}
}
return false;
}
void
CPasswordScreen::_holdPassword()
{
if(NVstore.getUserSettings().holdPassword)
__Expiry = millis() + 24 * 60 * 60 * 1000; // 24 hours
else
__Expiry = 0;
else if(_bGetPassword) {
_printMenuText(_display.xCentre(), 34, "Enter password...", false, eCentreJustify);
_showPassword();
return true;
}
else {
return false;
}
}
bool
CPasswordScreen::isPasswordBusy()
{
if(__Expiry)
return false;
return _bGetPassword;
CPasswordScreen::animate()
{
if(_SaveTime) {
long tDelta = millis() - _SaveTime;
if(tDelta > 0) {
_SaveTime = 0;
_ScreenManager.reqUpdate();
}
}
return false;
}
bool
CPasswordScreen::keyHandler(uint8_t event)
{
if(_bGetPassword) {
if(_bPasswordOK) {
_bGetPassword = false;
return true;
}
if(event & keyPressed) {
// press CENTRE
@ -125,7 +105,6 @@ CPasswordScreen::keyHandler(uint8_t event)
(_PWdig[2] == 8) &&
(_PWdig[3] == 8)) {
_bPasswordOK = true;
_holdPassword();
}
_bGetPassword = false;
@ -138,31 +117,30 @@ CPasswordScreen::keyHandler(uint8_t event)
// press LEFT
if(event & key_Left) {
_PWcol--;
WRAPLOWERLIMIT(_PWcol, 0, 3);
LOWERLIMIT(_PWcol, 0);
}
// press RIGHT
if(event & key_Right) {
_PWcol++;
WRAPUPPERLIMIT(_PWcol, 3, 0);
UPPERLIMIT(_PWcol, 5);
}
// press UP
if(event & key_Up) {
_PWdig[_PWcol]++;
WRAPUPPERLIMIT(_PWdig[_PWcol], 9, 0);
ROLLUPPERLIMIT(_PWdig[_PWcol], 9, 0);
}
// press DOWN
if(event & key_Down) {
_PWdig[_PWcol]--;
WRAPLOWERLIMIT(_PWdig[_PWcol], 0, 9);
ROLLLOWERLIMIT(_PWdig[_PWcol], 0, 9);
}
_ScreenManager.reqUpdate();
}
return true;
}
return false;
}
@ -170,20 +148,19 @@ bool
CPasswordScreen::_showPassword()
{
if(_bGetPassword) {
_showTitle("Enter password");
_printMenuText(_display.xCentre(), 34, "Enter password...", false, eCentreJustify);
// determine metrics of character sizing
CTransientFont AF(_display, &arialBlack_12ptFontInfo);
CRect extents;
_display.getTextExtents("8", extents);
_display.getTextExtents("X", extents);
int charWidth = extents.width;
_display.getTextExtents(" ", extents);
int spaceWidth = extents.width;
for(int idx =0 ; idx < 4; idx++) {
extents.xPos = _display.xCentre() - (2 - idx) * (charWidth * 1.5);
extents.yPos = 30;
extents.yPos = 50;
char str[8];
@ -199,15 +176,22 @@ CPasswordScreen::_showPassword()
return _bGetPassword;
}
void
CPasswordScreen::_getPassword()
{
_bGetPassword = true;
_bPasswordOK = false;
_PWcol = 0;
// reset PW digits
for(int i= 0; i < 4; i++)
_PWdig[i] = -1;
_ScreenManager.reqUpdate();
}
bool CPasswordScreen::_isPasswordOK()
{
if(__Expiry) {
long tDelta = millis() - __Expiry;
if(tDelta > 0) {
__Expiry = 0;
_bPasswordOK = false;
}
}
return __Expiry != 0 || _bPasswordOK;
};
void
CPasswordScreen::_showStoringMessage()
{
_SaveTime = millis() + 1500;
_ScreenManager.reqUpdate();
}

View file

@ -22,33 +22,30 @@
#define __PASSWORDSCREEN_H__
#include <stdint.h>
//#include "ScreenHeader.h"
#include "UIEditScreen.h"
#include "ScreenHeader.h"
class C128x64_OLED;
class CScreenManager;
class CPasswordScreen : public CUIEditScreen {
class CPasswordScreen : public CScreenHeader {
int _PWdig[4];
bool _bGetPassword;
bool _bPasswordOK;
int _PWcol;
unsigned long _SaveTime;
static long __Expiry;
void __initPassword(bool get);
protected:
bool _showPassword();
void _holdPassword();
void _getPassword();
bool _isPasswordOK();
bool _isPasswordOK() { return _bPasswordOK; };
void _showStoringMessage();
void _initUI();
virtual void _saveNV() {};
// int _rowSel;
public:
CPasswordScreen(C128x64_OLED& display, CScreenManager& mgr);
void onSelect();
bool show();
bool keyHandler(uint8_t event);
bool isPasswordBusy();
bool animate();
bool isPasswordBusy() { return (_SaveTime != 0) || _bGetPassword; };
};
#endif

View file

@ -0,0 +1,252 @@
/*
* 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 "PrimingScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/NVStorage.h"
///////////////////////////////////////////////////////////////////////////
//
// CPrimingScreen
//
// This screen allows the temperature control mode to be selected and
// allows pump priming
//
///////////////////////////////////////////////////////////////////////////
CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_initUI();
}
void
CPrimingScreen::onSelect()
{
_stopPump();
_initUI();
}
void
CPrimingScreen::onExit()
{
_stopPump();
}
void
CPrimingScreen::_initUI()
{
_PrimeStop = 0;
_PrimeCheck = 0;
_rowSel = 0;
_colSel = 0;
}
bool
CPrimingScreen::show()
{
CScreenHeader::show();
CRect extents;
int yPos = 53;
// show next/prev menu navigation line
switch(_rowSel) {
case 0:
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _rowSel == 0, eCentreJustify);
break;
case 1:
case 2:
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\030\031 Sel \033\032 Adj", false, eCentreJustify);
break;
case 3:
_display.drawFastHLine(0, 53, 128, WHITE);
if(_colSel == 2) {
_printMenuText(_display.xCentre(), 57, "\033\030\031 Stop", false, eCentreJustify);
}
else {
_printMenuText(_display.xCentre(), 57, "\032 Start \031 Sel", false, eCentreJustify);
}
break;
}
yPos = 40;
if(_rowSel == 1) {
// follow user desired setting, heater info is laggy
_printMenuText(border, yPos, "Thermostat", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "Fixed Hz", _colSel == 1, eRightJustify);
}
else {
// follow actual heater settings
// int col = getHeaterInfo().isThermostat() ? 0 : 1;
int col = getThermostatModeActive() ? 0 : 1;
_printInverted(border, yPos, "Thermostat", col == 0);
_printInverted(_display.width()-border, yPos, "Fixed Hz", col == 1, eRightJustify);
}
yPos = 28;
if(_rowSel == 2) {
_printMenuText(border, yPos, "degC", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "degF", _colSel == 1, eRightJustify);
}
else {
int col = NVstore.getDegFMode();
_printInverted(border, yPos, "degC", col == 0);
_printInverted(_display.width()-border, yPos, "degF", col == 1, eRightJustify);
}
// fuel pump priming menu
yPos = 16;
_printMenuText(border, yPos, "Pump");
if(_rowSel == 3) {
_printMenuText(40, yPos, "OFF", _colSel == 1);
if(_colSel != 2) {
if(!getHeaterInfo().getRunState()) { // prevent option if heater is running
_printMenuText(70, yPos, "ON"); // becomes Hz when actually priming
}
}
else {
float pumpHz = getHeaterInfo().getPump_Actual();
// recognise if heater has stopped pump, after an initial holdoff upon first starting
long tDelta = millis() - _PrimeCheck;
if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) {
_stopPump();
}
// test if time is up, stop priming if so
tDelta = millis() - _PrimeStop;
if(_PrimeStop && tDelta > 0) {
_stopPump();
}
if(_PrimeStop) {
char msg[16];
sprintf(msg, "%.1fHz", pumpHz);
_printMenuText(70, yPos, msg, true);
}
}
}
return true;
}
bool
CPrimingScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
_colSel = 0;
setThermostatMode(1);
saveNV();
break;
case 2:
_colSel = 0;
NVstore.setDegFMode(0);
break;
case 3:
_colSel = 1;
break;
case 4: break;
}
}
// press RIGHT
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
_colSel = 1;
setThermostatMode(0);
saveNV();
break;
case 2:
_colSel = 1;
NVstore.setDegFMode(1);
break;
case 3:
if(!getHeaterInfo().getRunState())
_colSel = 2;
break;
case 4: break;
}
}
// press UP
if(event & key_Up) {
if(hasOEMcontroller())
_reqOEMWarning();
else {
_rowSel++;
UPPERLIMIT(_rowSel, 3);
if(_rowSel == 3)
_colSel = 1; // select OFF upon entry to priming menu
if(_rowSel == 2)
_colSel = NVstore.getDegFMode();
if(_rowSel == 1)
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
_colSel = getThermostatModeActive() ? 0 : 1;
}
}
// press DOWN
if(event & key_Down) {
_rowSel--;
LOWERLIMIT(_rowSel, 0);
_colSel = 0;
if(_rowSel == 1)
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
_colSel = getThermostatModeActive() ? 0 : 1;
if(_rowSel == 2)
_colSel = NVstore.getDegFMode();
}
// check if fuel priming was selected
if(_rowSel == 3 && _colSel == 2) {
reqPumpPrime(true);
_PrimeStop = millis() + 150000; // allow 2.5 minutes - much the same as the heater itself cuts out at
_PrimeCheck = millis() + 3000; // holdoff upon start before testing for heater shutting off pump
}
else {
_stopPump();
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CPrimingScreen::_stopPump()
{
reqPumpPrime(false);
_PrimeCheck = 0;
_PrimeStop = 0;
if(_colSel == 2)
_colSel = 1;
}

View file

@ -31,9 +31,8 @@ class CScreenManager;
class CPrimingScreen : public CScreenHeader {
unsigned long _PrimeStop;
unsigned long _PrimeCheck;
int _paramSel;
int _rowSel;
int _colSel;
bool _resetConfirm;
void _stopPump();
void _initUI();
public:
@ -42,6 +41,7 @@ public:
void onExit();
bool show();
bool keyHandler(uint8_t event);
bool animate() { return CScreen::animate(); };
};
#endif

View file

@ -20,7 +20,7 @@
*/
#include "RebootScreen.h"
#include "../Utility/NVStorage.h"
#include "../Utility/NVstorage.h"
///////////////////////////////////////////////////////////////////////////
//
@ -53,7 +53,7 @@ CRebootScreen::show()
char msg[20];
char fillmsg[20];
memset(fillmsg, ' ', 20);
sprintf(msg, " REBOOT %ld ", tDelta);
sprintf(msg, " REBOOT %d ", tDelta);
fillmsg[strlen(msg)] = 0;
_printInverted(_display.xCentre(), yPos, fillmsg, true, eCentreJustify);

View file

@ -21,7 +21,6 @@
#include <Arduino.h>
#include "Screen.h"
#include "fonts/Arial.h"
// base class functionality for screens
@ -64,7 +63,6 @@ CScreen::show()
void
CScreen::onSelect()
{
_display.clearDisplay();
}
void
@ -93,19 +91,9 @@ CScreen::_printMenuText(int x, int y, const char* str, bool selected, eJUSTIFY j
void
CScreen::_drawMenuSelection(CRect extents, const char* str, int border, int radius)
{
CRect resize(extents);
_display.getTextExtents(str, resize);
// resize.Expand(border);
// _display.drawRoundRect(resize.xPos, resize.yPos, resize.width, resize.height, radius, WHITE);
_drawMenuSelection(resize, border, radius);
}
void
CScreen::_drawMenuSelection(const CRect& extents, int border, int radius)
{
CRect resize(extents);
resize.Expand(border);
_display.drawRoundRect(resize.xPos, resize.yPos, resize.width, resize.height, radius, WHITE);
_display.getTextExtents(str, extents);
extents.Expand(border);
_display.drawRoundRect(extents.xPos, extents.yPos, extents.width, extents.height, radius, WHITE);
}
void
@ -129,16 +117,16 @@ CScreen::_printInverted(int x, int y, const char* str, bool selected, eJUSTIFY j
}
void
CScreen::_scrollMessage(int y, const char* str, int& charOffset, bool centred)
CScreen::_scrollMessage(int y, const char* str, int& charOffset)
{
char msg[22];
int maxIndex = strlen(str) - 21;
strncpy(msg, &str[charOffset], 21);
msg[21] = 0;
_printMenuText(centred ? _display.xCentre() : 0, y, msg, false, centred ? eCentreJustify : eLeftJustify);
char msg[20];
int maxIndex = strlen(str) - 20;
strncpy(msg, &str[charOffset], 19);
msg[19] = 0;
_printMenuText(_display.xCentre(), y, msg, false, eCentreJustify);
charOffset++;
if(charOffset > maxIndex) {
if(charOffset >= maxIndex) {
charOffset = 0;
}
}
@ -148,8 +136,6 @@ CScreen::_adjustExtents(CRect& extents, eJUSTIFY justify, const char* str)
{
_display.getTextExtents(str, extents);
switch(justify) {
case eLeftJustify:
break;
case eCentreJustify:
extents.xPos -= extents.width/2;
break;
@ -165,45 +151,6 @@ CScreen::_reqOEMWarning()
_showOEMerror = 10;
}
void
CScreen::_drawBitmap(int x, int y, const BITMAP_INFO& info, uint16_t colour, uint16_t bg)
{
if(bg == 0xffff) {
// normal mode - does not erase background
_display.drawBitmap(x, y, info.pBitmap, info.width, info.height, colour);
}
else {
// overwrite mode - erases background
_display.drawBitmap(x, y, info.pBitmap, info.width, info.height, colour, bg);
}
}
void
CScreen::_showTitle(const char* title)
{
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
_printMenuText(_display.xCentre(), -1, title, false, eCentreJustify);
_display.drawFastHLine(0, 10, 128, WHITE);
}
void
CScreen::_showConfirmMessage()
{
_showTitle("Saving Settings");
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
void
CScreen::_showStoringMessage()
{
_display.writeFillRect(34, 19, 60, 26, WHITE);
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
_printInverted(_display.xCentre(), 27, " STORING ", true, eCentreJustify);
}
// a class used for temporary alternate fonts usage
// Reverts to standard inbuilt font when the instance falls out of scope
CTransientFont::CTransientFont(C128x64_OLED& disp, const FONT_INFO* pFont) :

View file

@ -22,19 +22,11 @@
#ifndef __SCREEN_H__
#define __SCREEN_H__
#include <Arduino.h>
#include "128x64OLED.h"
#include "ScreenManager.h"
struct BITMAP_INFO {
uint8_t width;
uint8_t height;
const uint8_t* pBitmap;
BITMAP_INFO(uint8_t w, uint8_t h, const uint8_t* pBmp) {
width = w;
height = h;
pBitmap = pBmp;
};
};
#include "fonts/FontTypes.h"
#include "../Utility/UtilClasses.h"
enum eJUSTIFY {
eLeftJustify, eCentreJustify, eRightJustify
@ -42,7 +34,6 @@ enum eJUSTIFY {
const int border = 3;
const int radius = 4;
const int SaveConfirm = 10;
class CScreen {
protected:
@ -53,13 +44,8 @@ protected:
void _printInverted(int x, int y, const char* str, bool selected, eJUSTIFY justify = eLeftJustify);
void _adjustExtents(CRect& rect, eJUSTIFY justify, const char* str);
void _drawMenuSelection(CRect extents, const char* str, int border = 3, int radius = 4);
void _drawMenuSelection(const CRect& extents, int border, int radius);
void _scrollMessage(int y, const char* str, int& charOffset, bool centred=true);
void _scrollMessage(int y, const char* str, int& charOffset);
void _reqOEMWarning();
void _drawBitmap(int x, int y, const BITMAP_INFO& info, uint16_t color = WHITE, uint16_t bg = 0xffff);
void _showTitle(const char* title);
void _showConfirmMessage();
void _showStoringMessage();
public:
CScreen(C128x64_OLED& disp, CScreenManager& mgr);
virtual ~CScreen();

View file

@ -0,0 +1,292 @@
/*
* 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 <Arduino.h>
#include "ScreenHeader.h"
#include "../Protocol/Protocol.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "../Bluetooth/BluetoothAbstract.h"
#include "../Utility/NVStorage.h"
#include "../RTC/Clock.h"
#include "fonts/Arial.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
#include "../RTC/TimerManager.h"
#define MINIFONT miniFontInfo
#define X_BT_ICON 10
#define Y_BT_ICON 0
#define X_WIFI_ICON 19
#define Y_WIFI_ICON 0
#define X_CLOCK 50
#define Y_CLOCK 0
#define X_TIMER_ICON 83
#define Y_TIMER_ICON 0
#define X_BATT_ICON 103
#define Y_BATT_ICON 0
/*#define X_BT_ICON 20
#define Y_BT_ICON 0
#define X_WIFI_ICON 29
#define Y_WIFI_ICON 0
#define X_GPIO_ICON 9
#define X_CLOCK 56
#define Y_CLOCK 0
#define X_TIMER_ICON 84
#define Y_TIMER_ICON 0
#define X_BATT_ICON 103
#define Y_BATT_ICON 0*/
CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(disp, mgr)
{
_clearUpAnimation = false;
_clearDnAnimation = false;
_colon = false;
}
bool
CScreenHeader::show()
{
_display.clearDisplay();
// standard header items
// Bluetooth
showBTicon();
// WiFi
showWifiIcon();
// battery
showBatteryIcon(getHeaterInfo().getBattVoltage());
// timers
int numTimers = showTimers();
// // GPIO
// showGPIO();
// clock
showTime(numTimers);
return true;
}
// Animate IN/OUT arrows against the WiFi icon, according to actual web server traffic:
// an IN (down) arrow is drawn if incoming data has been detected.
// an OUT (up) arrow is drawn if outgoing data has been sent.
//
// Each arrow is drawn for one animation interval with a minimum of one clear interval
// creating a clean flash on the display.
// Both arrows may appear in the same interval.
// The following is a typical sequence, relative to animation ticks, note the gap
// that always appears in the animation interval between either arrow shown:
//
// | | | | | | | | | | | | | | | | |
// _________^^^^^________________________________________^^^^^_________________________
// ______________vvvvv_____vvvvv_______________vvvvv_____vvvvv_____vvvvv_______________
bool
CScreenHeader::animate()
{
bool retval = false;
if((isWifiConnected() || isWifiAP()) && isWebClientConnected()) {
int xPos = X_WIFI_ICON + W_WIFI_ICON;
if(isWifiAP()) {
xPos += 4;
}
// UP arrow animation
//
int yPos = 0;
if(_clearUpAnimation) {
// arrow was drawn in the prior iteration, now erase it
_display.fillRect(xPos, yPos, W_WIFIIN_ICON, H_WIFIIN_ICON, BLACK);
retval = true;
_clearUpAnimation = false;
}
else if(hasWebServerSpoken(true)) {
// we have emitted data to the web client, show an UP arrow
_display.drawBitmap(xPos, yPos, wifiOutIcon, W_WIFIIN_ICON, H_WIFIIN_ICON, WHITE);
_clearUpAnimation = true; // clear arrow upon next iteration
retval = true;
}
// DOWN arrow animation
//
yPos = H_WIFI_ICON - H_WIFIIN_ICON + 1;
if(_clearDnAnimation) {
// arrow was drawn in the prior iteration, now erase it
_display.fillRect(xPos, yPos, W_WIFIOUT_ICON, H_WIFIOUT_ICON, BLACK);
retval = true;
_clearDnAnimation = false;
}
else if(hasWebClientSpoken(true)) {
// we have receievd data from the web client, show an DOWN arrow
_display.drawBitmap(xPos, yPos, wifiInIcon, W_WIFIOUT_ICON, H_WIFIOUT_ICON, WHITE);
_clearDnAnimation = true; // clear arrow upon next iteration
retval = true;
}
}
return retval; // true if we need to update the physical display
}
void
CScreenHeader::showBTicon()
{
if(getBluetoothClient().isConnected()) {
_display.drawBitmap(X_BT_ICON, Y_BT_ICON, BTicon, W_BT_ICON, H_BT_ICON, WHITE);
}
}
void
CScreenHeader::showWifiIcon()
{
if(isWifiConnected() || isWifiAP()) {
_display.drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, wifiIcon, W_WIFI_ICON, H_WIFI_ICON, WHITE);
if(isWifiButton()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 15, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
switch(isWifiButton()) {
case 1: _display.print("CFG"); break;
case 2: _display.print("HTR"); break;
case 3: _display.print("ERS"); break;
}
}
else if(isWifiConfigPortal()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 15, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
// _display.print("PTL");
_display.print("CFG");
}
else if(isWifiAP()) {
_display.fillRect(X_WIFI_ICON + 11, Y_WIFI_ICON + 5, 10, 7, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
_display.print("AP");
}
if(NVstore.getOTAEnabled()) {
_display.fillRect(X_WIFI_ICON +11, Y_WIFI_ICON, 14, 6, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON);
_display.print("OTA");
}
}
}
void
CScreenHeader::showBatteryIcon(float voltage)
{
_display.drawBitmap(X_BATT_ICON, Y_BATT_ICON, BatteryIcon, W_BATT_ICON, H_BATT_ICON, WHITE);
char msg[16];
sprintf(msg, "%.1fV", voltage);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_BATT_ICON + W_BATT_ICON/2,
Y_BATT_ICON + H_BATT_ICON + 2);
_display.printCentreJustified(msg);
// nominal 10.5 -> 13.5V bargraph
int Capacity = (voltage - 10.7) * 4;
if(Capacity < 0) Capacity = 0;
if(Capacity > 11) Capacity = 11;
_display.fillRect(X_BATT_ICON+2 + Capacity, Y_BATT_ICON+2, W_BATT_ICON-4-Capacity, 6, BLACK);
}
int
CScreenHeader::showTimers()
{
int nextTimer = CTimerManager::getNextTimer();
if(nextTimer) {
int xPos = X_TIMER_ICON;
_display.drawBitmap(xPos, Y_TIMER_ICON, largeTimerIcon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
if(nextTimer & 0x80)
_display.drawBitmap(xPos-3, Y_TIMER_ICON, verticalRepeatIcon, verticalRepeatWidthPixels, verticalRepeatHeightPixels, WHITE);
CTransientFont AF(_display, &miniFontInfo); // temporarily use a mini font
if((nextTimer & 0x0f) >= 10)
_display.setCursor(xPos+4, Y_TIMER_ICON+8);
else
_display.setCursor(xPos+6, Y_TIMER_ICON+8);
_display.print(nextTimer & 0x0f);
return 1;
}
return 0;
}
void
CScreenHeader::showTime(int numTimers)
{
const BTCDateTime& now = Clock.get();
char msg[16];
if(now.day() == 0xA5) {
sprintf(msg, "No RTC");
}
else {
if(_colon)
sprintf(msg, "%02d:%02d", now.hour(), now.minute());
else
sprintf(msg, "%02d %02d", now.hour(), now.minute());
_colon = !_colon;
}
{
CTransientFont AF(_display, &arial_8ptFontInfo);
// determine centre position of remaining real estate
int xPos = X_WIFI_ICON + W_WIFI_ICON + W_WIFIIN_ICON; // rhs of wifi conglomeration
if(isWifiAP()) xPos += 4; // add more if an Access Point
/* switch(numTimers) {
case 0: xPos = _display.xCentre(); break;
case 1: xPos += (X_TIMER_ICON - xPos) / 2; break;
}
_printMenuText(xPos, Y_CLOCK, msg, false, eCentreJustify);*/
_printMenuText(X_CLOCK, Y_CLOCK, msg);
}
}
void
CScreenHeader::showGPIO()
{
/* int xPos = X_GPIO_ICON; // both are enabled - draw icon 1 to the left, otherwise leave to the right
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(xPos, 0);
_display.print("1");
_display.drawBitmap(xPos + 4, 0, getGPIO(0) ? TickIcon : CrossIcon, TickIconWidth, TickIconHeight, WHITE);
_display.setCursor(xPos, 6);
_display.print("2");
_display.drawBitmap(xPos + 4, 6, getGPIO(1) ? TickIcon : CrossIcon, TickIconWidth, TickIconHeight, WHITE);*/
}
/*void
CScreenHeader::showGPIO()
{
int xPos = X_GPIO_ICON; // both are enabled - draw icon 1 to the left, otherwise leave to the right
_display.drawBitmap(xPos, 0, getGPIO(0) ? GPIO1ONIcon : GPIO1OFFIcon, GPIOIconWidthPixels, GPIOIconHeightPixels, WHITE);
_display.drawBitmap(xPos, 8, getGPIO(1) ? GPIO2ONIcon : GPIO2OFFIcon, GPIOIconWidthPixels, GPIOIconHeightPixels, WHITE);
}*/

View file

@ -22,45 +22,27 @@
#ifndef __SCREEN_HEADER_H__
#define __SCREEN_HEADER_H__
#include <Arduino.h>
#include "Screen.h"
#include "../Utility/UtilClasses.h"
#include "fonts/FontTypes.h"
struct sScreenholdoff {
int holdon;
int holdoff;
sScreenholdoff() {
reset();
}
void reset() {
holdon = 0;
holdoff = 0;
}
void set(int hldon = 2, int hldoff = 8) {
holdon = hldon;
holdoff = hldoff;
}
};
class CScreenHeader : public CScreen {
sScreenholdoff _UpAnnotation;
sScreenholdoff _DnAnnotation;
bool _clearUpAnimation;
bool _clearDnAnimation;
bool _colon;
bool _hdrDetail;
uint8_t _animateCount;
uint8_t _batteryCount;
uint8_t _batteryWarn;
protected:
void showBTicon();
void showWifiIcon();
void showBatteryIcon(float voltage);
int showTimers();
virtual void showTime(); // x location depends upon how many timers are active
bool showFrost();
void showHeaderDetail(bool state) { _hdrDetail = state; };
virtual void showTime(int numTimers); // x location depends upon how many timers are active
void showGPIO();
public:
CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr);
bool show(bool erase);
bool show();
bool animate();
void onSelect();
};
#endif // __SCREEN_HEADER_H__

View file

@ -0,0 +1,498 @@
/*
* 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 "ScreenManager.h"
#include "DetailedScreen.h"
#include "BasicScreen.h"
#include "PrimingScreen.h"
#include "WiFiScreen.h"
#include "FuelMixtureScreen.h"
#include "SetClockScreen.h"
#include "SetTimerScreen.h"
#include "ClockScreen.h"
#include "RebootScreen.h"
#include "HeaterSettingsScreen.h"
#include "SettingsScreen.h"
#include "ThermostatModeScreen.h"
#include "FontDumpScreen.h"
#include "TimerChartScreen.h"
#include "InheritSettingsScreen.h"
#include "GPIOScreen.h"
#include "VersionInfoScreen.h"
#include "HomeMenuSelScreen.h"
#include "OtherOptionsScreen.h"
#include <Wire.h>
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../protocol/helpers.h"
#include "keypad.h"
#include "fonts/Icons.h"
#include "fonts/MiniFont.h"
////////////////////////////////////////////////////////////////////////////////////////////////
// splash creen created using image2cpp http://javl.github.io/image2cpp/
// Settings:
// Black background
// Invert [X]
// Arduino code, single bitmap
// Identifier: DieselSplash
// Draw Mode: Horizontal
//
const unsigned char DieselSplash [] PROGMEM = {
// 'Splash3, 128x64px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00,
0x02, 0x3e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x01, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x88, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x20, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x84, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x20, 0x40, 0x00, 0x20, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x84, 0x00, 0x00,
0x00, 0x14, 0x00, 0x00, 0x40, 0x40, 0x00, 0x10, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x84, 0x00, 0x00,
0x00, 0x52, 0x00, 0x00, 0x40, 0x20, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00,
0x00, 0x34, 0x00, 0x00, 0x40, 0x10, 0x00, 0x04, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x18, 0x00, 0x00, 0x80, 0x10, 0x00, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x34, 0x00, 0x00, 0x80, 0x08, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x52, 0x00, 0x00, 0x80, 0x08, 0x01, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x14, 0x00, 0x01, 0x00, 0x04, 0x3e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x18, 0x00, 0x01, 0x00, 0x07, 0xc0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
0x00, 0x10, 0x00, 0x06, 0x80, 0x1c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0xc4, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x40, 0x64, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x40, 0x84, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0xc0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x26, 0x23, 0x04, 0x00, 0x00, 0x00, 0x60, 0x00, 0x1e, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x43, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x19, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0xf8, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x1f, 0x20, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0xe8, 0x20, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7c, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x46, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
0x00, 0x02, 0x28, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
0x00, 0x02, 0x28, 0x73, 0x2d, 0xc9, 0x5a, 0x8c, 0xb0, 0x20, 0x31, 0xdd, 0x66, 0x53, 0x2c, 0x00,
0x00, 0x03, 0xee, 0x44, 0xb1, 0x29, 0x63, 0x52, 0xc0, 0x20, 0x4a, 0x51, 0x89, 0x54, 0xb0, 0x00,
0x00, 0x02, 0x28, 0x47, 0xa1, 0x29, 0x42, 0x5e, 0x80, 0x20, 0x4a, 0x51, 0x09, 0x57, 0xa0, 0x00,
0x00, 0x02, 0x28, 0x44, 0x21, 0x2b, 0x42, 0x50, 0x80, 0x21, 0x4a, 0x51, 0x09, 0x54, 0x20, 0x00,
0x00, 0x02, 0x28, 0x33, 0x21, 0xc5, 0x42, 0x4c, 0x80, 0x1e, 0x32, 0x4d, 0x06, 0x53, 0x20, 0x00
};
CScreenManager::CScreenManager()
{
_pDisplay = NULL;
_menu = -1;
_subMenu = 0;
_rootMenu = -1;
_bReqUpdate = false;
_DimTime_ms = millis() + 60000;
_MenuTimeout = millis() + 60000;
_pRebootScreen = NULL;
_bDimmed = false;
}
CScreenManager::~CScreenManager()
{
for(int i=0; i < _Screens.size(); i++) {
for(int j=0; j < _Screens[i].size(); j++) {
if(_Screens[i][j]) {
delete _Screens[i][j];
_Screens[i][j] = NULL;
}
}
}
if(_pDisplay) {
delete _pDisplay; _pDisplay = NULL;
}
}
void
CScreenManager::begin(bool bNoClock)
{
// 128 x 64 OLED support (I2C)
// xxxx_SWITCHCAPVCC = generate display voltage from 3.3V internally
_pDisplay = new C128x64_OLED(OLED_SDA_pin, OLED_SCL_pin);
#if USE_ADAFRUIT_SH1106 == 1
_pDisplay->begin(SH1106_SWITCHCAPVCC);
Wire.begin(OLED_SDA_pin, OLED_SCL_pin, 800000); // speed up I2C from the default crappy 100kHz set via the adafruit begin!
#elif USE_ADAFRUIT_SSD1306 == 1
_pDisplay->begin(SSD1306_SWITCHCAPVCC, 0x3c);
_pDisplay->ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
_pDisplay->ssd1306_command(0x1F); // correct lame reversal of OLED current phases
#endif
// replace adafruit splash screen
_pDisplay->clearDisplay();
_pDisplay->drawBitmap(0, 0, DieselSplash, 128, 64, WHITE);
_pDisplay->setCursor(90, 50);
CTransientFont AF(*_pDisplay, &miniFontInfo); // temporarily use a mini font
_pDisplay->setTextColor(WHITE);
_pDisplay->print(getVersionStr());
// Show initial display buffer contents on the screen --
_pDisplay->display();
DebugPort.println("Creating Screens");
std::vector<CScreen*> menuloop;
// create root menu loop
menuloop.push_back(new CDetailedScreen(*_pDisplay, *this)); // detail control
menuloop.push_back(new CBasicScreen(*_pDisplay, *this)); // basic control
if(!bNoClock)
menuloop.push_back(new CClockScreen(*_pDisplay, *this)); // clock
menuloop.push_back(new CPrimingScreen(*_pDisplay, *this)); // mode / priming
menuloop.push_back(new CWiFiScreen(*_pDisplay, *this)); // comms info
menuloop.push_back(new CGPIOInfoScreen(*_pDisplay, *this)); // GPIO info
menuloop.push_back(new CSettingsScreen(*_pDisplay, *this)); // Tuning info
_Screens.push_back(menuloop);
// create timer screens loop
menuloop.clear();
menuloop.push_back(new CTimerChartScreen(*_pDisplay, *this, 0)); // timer chart
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 0)); // set timer 1
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 1)); // set timer 2
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 2)); // set timer 3
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 3)); // set timer 4
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 4)); // set timer 5
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 5)); // set timer 6
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 6)); // set timer 7
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 7)); // set timer 8
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 8)); // set timer 9
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 9)); // set timer 10
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 10)); // set timer 11
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 11)); // set timer 12
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 12)); // set timer 13
menuloop.push_back(new CSetTimerScreen(*_pDisplay, *this, 13)); // set timer 14
_Screens.push_back(menuloop);
// create heater tuning screens loop - password protected
menuloop.clear();
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
menuloop.push_back(new CVersionInfoScreen(*_pDisplay, *this)); // GPIO settings screen
menuloop.push_back(new CHomeMenuSelScreen(*_pDisplay, *this)); // Home menu settings screen
menuloop.push_back(new COtherOptionsScreen(*_pDisplay, *this)); // Other options 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 CFontDumpScreen(*_pDisplay, *this)); // font dump branch screen
_Screens.push_back(menuloop);
_menu = 0;
#if RTC_USE_DS3231==0 && RTC_USE_DS1307==0 && RTC_USE_PCF8523==0
_rootMenu = 2; // bring up clock set screen first if using millis based RTC!
_subMenu = 2;
#else
_rootMenu = 1; // basic control screen
_subMenu = 1;
#endif
_enterScreen();
}
bool
CScreenManager::checkUpdate()
{
long dimTimeout = NVstore.getDimTime();
// manage dimming or blanking the display, according to user defined inactivity interval
if(dimTimeout && _DimTime_ms) {
long tDelta = millis() - _DimTime_ms;
if(tDelta > 0) {
// time to dim the display
_dim(true);
_DimTime_ms = 0;
if(dimTimeout < 0) {
_pDisplay->clearDisplay();
_pDisplay->display(); // blank screen
}
}
}
if(NVstore.getMenuTimeout() && _MenuTimeout) {
long tDelta = millis() - _MenuTimeout;
if(tDelta > 0) {
_MenuTimeout = 0;
// we will be blanking the display, transit through a dim stage first
if(dimTimeout < 0)
_dim(true);
_leaveScreen();
// fall back to main menu
selectMenu(RootMenuLoop);
// upon dim timeout - sticky root menu screens are the first 3 in the list:
// Detailed Control
// Basic Control
// Clock
// return to those upon timeout, otherwise return to Basic Control screen
if(_rootMenu > 2) {
uint8_t userHomeMenu = NVstore.getHomeMenu().onTimeout;
if(userHomeMenu) { // allow user to override defualt screen
userHomeMenu--;
DebugPort.print("Screen Manager: Menu timeout, falling back to user preferred screen: ");
switch(userHomeMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userHomeMenu;
}
else {
_rootMenu = _subMenu = 1;
DebugPort.print("Screen Manager: Menu timeout, falling back to Basic control screen");
}
}
_enterScreen();
}
}
static int prevRunState = -1;
int runState = getHeaterInfo().getRunStateEx();
if(runState != prevRunState) {
if(runState > 0 && prevRunState == 0) {
// heater has started
uint8_t userStartMenu = NVstore.getHomeMenu().onStart;
if(userStartMenu && userStartMenu <= 3) { // allow user to override defualt screen
userStartMenu--;
DebugPort.print("Screen Manager: Heater start detected, switching to user preferred screen: ");
switch(userStartMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userStartMenu;
_enterScreen();
}
}
if(runState == 0 && prevRunState != 0) {
// heater has stopped
uint8_t userStopMenu = NVstore.getHomeMenu().onStop;
if(userStopMenu && userStopMenu <= 3) { // allow user to override defualt screen
userStopMenu--;
DebugPort.print("Screen Manager: Heater stop detected, switching to user preferred screen: ");
switch(userStopMenu) {
case 0: DebugPort.println("Detailed control menu"); break;
case 1: DebugPort.println("Basic control menu"); break;
case 2: DebugPort.println("Clock menu"); break;
}
_rootMenu = _subMenu = userStopMenu;
_enterScreen();
}
}
prevRunState = runState;
}
if(_bReqUpdate) {
if((dimTimeout < 0) && (_DimTime_ms == 0)) {
// no screen updates, we should be blanked!
}
else {
if(_pRebootScreen) {
_pRebootScreen->show();
_bReqUpdate = false;
return true;
}
else {
if(_menu >= 0) {
_Screens[_menu][_subMenu]->show();
_bReqUpdate = false;
return true;
}
}
}
}
return false;
}
void
CScreenManager::reqUpdate()
{
_bReqUpdate = true;
}
bool
CScreenManager::animate()
{
if((NVstore.getDimTime() < 0) && (_DimTime_ms == 0)) {
// no screen updates, we should be blanked!
return false;
}
if(_menu >= 0)
return _Screens[_menu][_subMenu]->animate();
return false;
}
void
CScreenManager::refresh()
{
if(_pDisplay)
_pDisplay->display();
}
void
CScreenManager::_enterScreen()
{
if(_menu >= 0)
_Screens[_menu][_subMenu]->onSelect();
reqUpdate();
}
void
CScreenManager::_leaveScreen()
{
if(_menu >= 0)
_Screens[_menu][_subMenu]->onExit();
}
void
CScreenManager::_changeSubMenu(int dir)
{
_leaveScreen();
_subMenu += dir;
int bounds = _Screens[_menu].size() - 1;
ROLLUPPERLIMIT(_subMenu, bounds, 0);
ROLLLOWERLIMIT(_subMenu, 0, bounds);
if(_menu == 0)
_rootMenu = _subMenu; // track the root menu for when we branch then return
_enterScreen();
}
void
CScreenManager::nextMenu()
{
if(_menu >= 0 && _menu != BranchMenu) {
_changeSubMenu(+1);
}
}
void
CScreenManager::prevMenu()
{
if(_menu >= 0 && _menu != BranchMenu) {
_changeSubMenu(-1);
}
}
void
CScreenManager::keyHandler(uint8_t event)
{
long dimTime = NVstore.getDimTime();
if(_bDimmed) {
if(event & keyReleased) {
_dim(false);
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = millis() + NVstore.getMenuTimeout();
}
return; // initial press when dimmed is always thrown away
}
// _dim(false);
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = millis() + NVstore.getMenuTimeout();
// call key handler for active screen
if(_menu >= 0)
_Screens[_menu][_subMenu]->keyHandler(event);
}
void
CScreenManager::selectMenu(eUIMenuSets menuSet, int specific)
{
_leaveScreen();
if(_menu >= 0) { // only true once we have created the screens
_menu = menuSet;
if(specific >= 0) {
// targetting a specific menu
_subMenu = specific;
UPPERLIMIT(_subMenu, _Screens[_menu].size()-1); // check bounds!
}
else {
// default sub menu behaviour
if(_menu == 0)
_subMenu = _rootMenu; // return to last used root menu
else
_subMenu = 0; // branches always go to first sub menu
}
}
_enterScreen();
}
void
CScreenManager::showRebootMsg(const char* content[2], long delayTime)
{
if(_pRebootScreen == NULL)
_pRebootScreen = new CRebootScreen(*_pDisplay, *this);
_pRebootScreen->setMessage(content, delayTime);
_bReqUpdate = true;
_dim(false);
}
void
CScreenManager::_dim(bool state)
{
_bDimmed = state;
_pDisplay->dim(state);
}

View file

@ -22,9 +22,10 @@
#ifndef __SCREEN_MANAGER_H__
#define __SCREEN_MANAGER_H__
#include <Arduino.h>
#include <vector>
#include "../Utility/UtilClasses.h"
class CProtocol;
class C128x64_OLED;
class CScreen;
class CRebootScreen;
@ -33,14 +34,10 @@ class CScreenManager {
std::vector<std::vector<CScreen*>> _Screens;
CRebootScreen* _pRebootScreen;
C128x64_OLED* _pDisplay;
unsigned long _OTAholdoff;
int _menu;
int _subMenu;
int _rootMenu;
int _returnMenu;
int _returnSubMenu;
bool _bDimmed;
bool _bReload;
unsigned long _DimTime_ms;
unsigned long _MenuTimeout;
bool _bReqUpdate;
@ -48,22 +45,18 @@ class CScreenManager {
void _leaveScreen();
void _changeSubMenu(int dir);
void _dim(bool state);
void _loadScreens();
void _unloadScreens();
bool _checkOTAholdoff();
public:
enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, UserSettingsLoop, SystemSettingsLoop, TuningMenuLoop, BranchMenu };
enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, GPIOInfoUI, TrunkUI };
enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, TuningMenuLoop, UserSettingsLoop, BranchMenu };
enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, CommsUI, GPIOInfoUI, SettingsUI };
enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI,
Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI };
enum eUIUserSettingsMenus { ExThermostatUI, FrostUI, HomeMenuUI, TimeIntervalsUI, TempSensorUI, GPIOUI };
enum eUIBranchMenus { SetClockUI, InheritSettingsUI, HtrSettingsUI, DS18B20UI };
enum eUISystemSettingsMenus { SysVerUI, SysHoursUI, SysWifiUI, SysBTUI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI };
enum eUIUserSettingsMenus { ExThermostatUI, GPIOUI };
enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI };
public:
CScreenManager();
~CScreenManager();
void begin();
void begin(bool bNoClock);
bool checkUpdate();
bool animate();
void keyHandler(uint8_t event);
@ -71,17 +64,8 @@ public:
void nextMenu();
void prevMenu();
void reqUpdate();
void selectHomeMenu();
void selectMenu(eUIMenuSets menuset, int specific = -1); // use to select loop menus, including the root or branches
void returnMenu(); // use to select loop menus, including the root or branches
void showRebootMsg(const char* content[2], long delayTime);
void showBootMsg(const char* msg);
void showBootWait(int show);
void showOTAMessage(int percent, eOTAmodes updateType);
void clearDisplay();
void bumpTimeout();
void showSplash();
void reqReload() { _bReload = true; };
};
#endif // __SCREEN_MANAGER_H__

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -30,13 +30,12 @@
#include "SetClockScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "fonts/Arial.h"
#include "../RTC/Clock.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
CSetClockScreen::CSetClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditScreen(display, mgr)
CSetClockScreen::CSetClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_initUI();
}
@ -44,16 +43,15 @@ CSetClockScreen::CSetClockScreen(C128x64_OLED& display, CScreenManager& mgr) : C
void
CSetClockScreen::onSelect()
{
CScreen::onSelect();
_initUI();
}
void
CSetClockScreen::_initUI()
{
CUIEditScreen::_initUI();
_rowSel = 0;
_nextT = millis();
_12hr = NVstore.getUserSettings().clock12hr;
_SaveTime = 0;
}
void
@ -65,85 +63,69 @@ CSetClockScreen::showTime(int)
bool
CSetClockScreen::show()
{
if(CUIEditScreen::show()) {
return true;
}
long deltaT = millis() - _nextT;
if(deltaT >= 0) {
_nextT += 1000;
CScreen::show();
_display.clearDisplay();
CScreenHeader::show();
char str[16];
int xPos, yPos;
const int col2 = 90;
const int col3 = _display.width() - border;
_showTitle("Set Clock");
_printInverted(0, 15, " Set Clock ", true);
const BTCDateTime& now = Clock.get();
if(_rowSel == 0) {
// update printable values
_working = now;
if(_12hr) {
if(_working.hour() < 12)
_12hr = 1;
else
_12hr = 2;
}
working = now;
// DELIBERATE DROP THROUGH HERE
}
yPos = 20;
xPos = 6;
// date
if(_rowSel==0) {
xPos = 18;
_printMenuText(xPos, yPos, _working.dowStr());
xPos = 20;
}
sprintf(str, "%d", _working.day());
xPos += 20 + 12;
_printMenuText(xPos, yPos, str, _rowSel==1, eRightJustify);
xPos += 4;
_printMenuText(xPos, yPos, _working.monthStr(), _rowSel==2);
xPos += 22;
sprintf(str, "%d", _working.year());
_printMenuText(xPos, yPos, str, _rowSel==3);
// time
yPos = 32;
xPos = 8;
int hr = _working.hour();
if(_12hr) {
if(hr == 0)
hr = 12;
if(hr > 12)
hr -= 12;
if(_SaveTime) {
long tDelta = millis() - _SaveTime;
if(tDelta > 0)
_SaveTime = 0;
_printInverted(_display.xCentre(), 28, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 39, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 34, " STORING ", true, eCentreJustify);
}
sprintf(str, "%02d", hr);
_printMenuText(xPos, yPos, str, _rowSel==4);
xPos += 16;
_printMenuText(xPos, yPos, ":");
xPos += 8;
sprintf(str, "%02d", _working.minute());
_printMenuText(xPos, yPos, str, _rowSel==5);
xPos += 16;
_printMenuText(xPos, yPos, ":");
sprintf(str, "%02d", _working.second());
xPos += 8;
_printMenuText(xPos, yPos, str, _rowSel==6);
xPos += 20;
const char* annuc = "24hr";
switch(_12hr) {
case 1: annuc = "AM"; break;
case 2: annuc = "PM"; break;
}
_printMenuText(xPos, yPos, annuc, _rowSel == 7);
xPos += 28;
if(_rowSel>=1)
_printMenuText(_display.width()-border, yPos, "SET", _rowSel==8, eRightJustify);
else {
yPos = 28;
xPos = 6;
// date
if(_rowSel==0) {
xPos = 20;
_printMenuText(xPos, yPos, working.dowStr());
}
sprintf(str, "%d", working.day());
xPos += 20 + 12;
_printMenuText(xPos, yPos, str, _rowSel==1, eRightJustify);
xPos += 4;
_printMenuText(xPos, yPos, working.monthStr(), _rowSel==2);
xPos += 22;
sprintf(str, "%d", working.year());
_printMenuText(xPos, yPos, str, _rowSel==3);
// time
yPos = 40;
xPos = 26;
sprintf(str, "%02d", working.hour());
_printMenuText(xPos, yPos, str, _rowSel==4);
xPos += 16;
_printMenuText(xPos, yPos, ":");
xPos += 8;
sprintf(str, "%02d", working.minute());
_printMenuText(xPos, yPos, str, _rowSel==5);
xPos += 16;
_printMenuText(xPos, yPos, ":");
sprintf(str, "%02d", working.second());
xPos += 8;
_printMenuText(xPos, yPos, str, _rowSel==6);
if(_rowSel>=1)
_printMenuText(_display.width()-border, yPos, "SET", _rowSel==7, eRightJustify);
}
// navigation line
xPos = _display.xCentre();
if(_rowSel == 0) {
@ -154,7 +136,7 @@ CSetClockScreen::show()
else {
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\033\032 Sel \030\031 Adj", false, eCentreJustify);
if(_rowSel == 8) {
if(_rowSel == 7) {
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
}
else {
@ -177,15 +159,10 @@ CSetClockScreen::keyHandler(uint8_t event)
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // exit, return to clock screen
}
else {
if(_rowSel == 8) { // set the RTC!
Clock.set(_working);
_enableStoringMessage();
if(_rowSel == 7) { // set the RTC!
Clock.set(working);
_SaveTime = millis() + 1500;
}
// always save the 12/24hr selection on any OK
sUserSettings us = NVstore.getUserSettings();
us.clock12hr = _12hr ? 1 : 0;
NVstore.setUserSettings(us);
NVstore.save();
_rowSel = 0;
}
}
@ -196,7 +173,7 @@ CSetClockScreen::keyHandler(uint8_t event)
}
else {
_rowSel--;
WRAPLOWERLIMIT(_rowSel, 1, 8);
ROLLLOWERLIMIT(_rowSel, 1, 7);
}
}
// press RIGHT
@ -206,13 +183,13 @@ CSetClockScreen::keyHandler(uint8_t event)
}
else {
_rowSel++;
WRAPUPPERLIMIT(_rowSel, 8, 1);
ROLLUPPERLIMIT(_rowSel, 7, 1);
}
}
// press UP
if(event & key_Up) {
if(_rowSel == 0) {
_rowSel = 7;
_rowSel = 1;
}
else {
_adjTimeDate(+1);
@ -249,39 +226,25 @@ CSetClockScreen::keyHandler(uint8_t event)
void
CSetClockScreen::_adjTimeDate(int dir)
{
int days;
switch(_rowSel) {
case 1:
_working.adjustDay(dir);
working.adjustDay(dir);
break;
case 2:
_working.adjustMonth(dir);
working.adjustMonth(dir);
break;
case 3:
_working.adjustYear(dir);
working.adjustYear(dir);
break;
case 4:
_working.adjustHour(dir);
if(_12hr == 1 && _working.hour() >= 12)
_12hr = 2;
if(_12hr == 2 && _working.hour() < 12)
_12hr = 1;
working.adjustHour(dir);
break;
case 5:
_working.adjustMinute(dir);
working.adjustMinute(dir);
break;
case 6:
_working.adjustSecond(dir);
break;
case 7:
DebugPort.printf("hr1=%d ", _working.hour());
_12hr += dir;
WRAPLIMITS(_12hr, 0, 2);
if(_12hr == 1 && _working.hour() >= 12)
_working.adjustHour12();
if(_12hr == 2 && _working.hour() < 12)
_working.adjustHour12();
DebugPort.printf("hr2=%d ", _working.hour());
DebugPort.printf("_12hr=%d\r\n", _12hr);
working.adjustSecond(dir);
break;
}
}

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -23,17 +23,18 @@
#define __SETCLOCKSCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "ScreenHeader.h"
#include "../RTC/BTCDateTime.h"
class C128x64_OLED;
class CScreenManager;
class CProtocol;
class CSetClockScreen : public CUIEditScreen {
class CSetClockScreen : public CScreenHeader {
int _rowSel;
unsigned long _nextT;
BTCDateTime _working;
int _12hr;
BTCDateTime working;
unsigned long _SaveTime;
void _adjTimeDate(int dir);
void _initUI();

View file

@ -30,24 +30,14 @@
#include "SetTimerScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../../lib/RTClib/RTClib.h"
#include "../RTC/TimerManager.h"
#include "fonts/Arial.h"
#include "../Protocol/helpers.h"
#include "../Utility/NVStorage.h"
#include <RTClib.h>
#include "../RTC/TimerManager.h"
const char* briefDOW[] = { "S", "M", "T", "W", "T", "F", "S" };
float calcPumpHz(int desired) {
const sHeaterTuning& tuning = NVstore.getHeaterTuning();
float ratio = float(desired - tuning.Tmin) / float(tuning.Tmax - tuning.Tmin);
float offset = ratio * float(tuning.Pmax - tuning.Pmin);
float PumpHz = tuning.Pmin + offset;
return PumpHz / 10.f; // tuning is saved as Hz x10
}
CSetTimerScreen::CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int instance) : CUIEditScreen(display, mgr)
CSetTimerScreen::CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int instance) : CScreenHeader(display, mgr)
{
_initUI();
_ConflictTime = 0;
@ -58,44 +48,65 @@ CSetTimerScreen::CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int
void
CSetTimerScreen::onSelect()
{
CUIEditScreen::onSelect();
_initUI();
NVstore.getTimerInfo(_timerID, _timerInfo);
}
void
CSetTimerScreen::_initUI()
{
_rowSel = 0;
_colSel = 0;
_SaveTime = 0;
}
bool
CSetTimerScreen::show()
{
if(CUIEditScreen::show()) {
return true;
}
CScreen::show();
_display.clearDisplay();
CScreenHeader::show();
char str[20];
int xPos, yPos;
if(_rowSel == 0) {
NVstore.getTimerInfo(_timerID, _timerInfo); // ensure actual data when on base menu bar
NVstore.getTimerInfo(_timerID, _timerInfo);
}
sprintf(str, "Set Timer #%d", _timerID + 1);
_showTitle(str);
sprintf(str, " Set Timer %d ", _timerID + 1);
_printInverted(0, 15, str, true);
if(_ConflictTime) {
if(_SaveTime) {
long tDelta = millis() - _SaveTime;
if(tDelta > 0)
_SaveTime = 0;
_printInverted(_display.xCentre(), 28, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 39, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 34, " STORING ", true, eCentreJustify);
}
else if(_ConflictTime) {
long tDelta = millis() - _ConflictTime;
if(tDelta > 0)
_ConflictTime = 0;
sprintf(str, " with Timer %d ", _conflictID);
_showConflict(str);
if(_conflictID >= 10) {
// extra space
_printInverted(_display.xCentre(), 26, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 45, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 30, " Conflicts ", true, eCentreJustify);
_printInverted(_display.xCentre(), 38, str, true, eCentreJustify);
}
else {
_printInverted(_display.xCentre(), 26, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 45, " ", true, eCentreJustify);
_printInverted(_display.xCentre(), 30, " Conflicts ", true, eCentreJustify);
_printInverted(_display.xCentre(), 38, str, true, eCentreJustify);
}
}
else {
// start
xPos = 18;
yPos = 15;
yPos = 28;
_printMenuText(xPos, yPos, "On", false, eRightJustify);
_printMenuText(xPos+17, yPos, ":");
_printMenuText(xPos+18, yPos, ":");
xPos += 6;
sprintf(str, "%02d", _timerInfo.start.hour);
_printMenuText(xPos, yPos, str, _rowSel==1 && _colSel==0);
@ -104,10 +115,10 @@ CSetTimerScreen::show()
_printMenuText(xPos, yPos, str, _rowSel==1 && _colSel==1);
// stop
xPos = 82;
yPos = 15;
xPos = 18;
yPos = 41;
_printMenuText(xPos, yPos, "Off", false, eRightJustify);
_printMenuText(xPos+17, yPos, ":");
_printMenuText(xPos+18, yPos, ":");
xPos += 6;
sprintf(str, "%02d", _timerInfo.stop.hour);
_printMenuText(xPos, yPos, str, _rowSel==1 && _colSel==2);
@ -115,64 +126,36 @@ CSetTimerScreen::show()
sprintf(str, "%02d", _timerInfo.stop.min);
_printMenuText(xPos, yPos, str, _rowSel==1 && _colSel==3);
yPos = 39;
{
if(_timerInfo.temperature) {
CTransientFont AF(_display, &arialItalic_7ptFontInfo);
sprintf(str, "( %.1fHz )", calcPumpHz(_timerInfo.temperature));
_printMenuText(64, yPos, str, false, eLeftJustify);
}
}
// control
const char* msg;
xPos = _display.width() - border;
_printEnabledTimers();
xPos = _display.width() - border;
yPos = 28;
yPos = 41;
if(_timerInfo.repeat)
msg = "Repeat";
else
msg = "Once";
_printMenuText(xPos, yPos, msg, _rowSel==1 && _colSel==5, eRightJustify);
xPos = 18;
yPos = 41;
float fTemp = _timerInfo.temperature;
if(fTemp == 0) {
strcpy(str, "Current set ");
strcat(str, NVstore.getUserSettings().degF ? "`F" : "`C");
_printMenuText(_display.xCentre(), yPos, str, _rowSel==1 && _colSel==6, eCentreJustify);
}
else {
if(NVstore.getUserSettings().degF) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(str, "%.0f`F", fTemp);
}
else {
sprintf(str, "%.0f`C", fTemp);
}
_printMenuText(59, yPos, str, _rowSel==1 && _colSel==6, eRightJustify);
}
// navigation line
yPos = 53;
xPos = _display.xCentre();
if(_rowSel == 2) {
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\033\032 Sel \030\031 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 57, "Done", false, eCentreJustify);
}
else if(_rowSel == 1) {
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\033\032 Sel \030\031 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 57, "Save", false, eCentreJustify);
}
else {
_printMenuText(xPos, yPos, " \021 Exit \020 ", _rowSel==0, eCentreJustify);
}
if(_rowSel == 1)
_printMenuText(xPos, yPos, msg, _colSel==5, eRightJustify);
else
_printInverted(xPos, yPos, msg, _timerInfo.repeat, eRightJustify);
}
// navigation line
yPos = 53;
xPos = _display.xCentre();
if(_rowSel == 2) {
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\033\032 Sel \030\031 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 57, "Done", false, eCentreJustify);
}
else if(_rowSel == 1) {
_display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\033\032 Sel \030\031 Adj", false, eCentreJustify);
_printMenuText(_display.xCentre(), 57, "Save", false, eCentreJustify);
}
else {
_printMenuText(xPos, yPos, " \021 Exit \020 ", _rowSel==0, eCentreJustify);
}
return true;
@ -185,11 +168,34 @@ CSetTimerScreen::keyHandler(uint8_t event)
static bool bHeld = false;
// handle initial key press
if(event & keyPressed) {
_repeatCount = 0;
bHeld = false;
// press CENTRE
if(event & key_Centre) {
// ON KEY RELEASE
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // exit: return to clock screen
}
else if(_rowSel == 2) { // exit from per day settings
_rowSel = 1;
_colSel = 4;
}
else { // in config fields, save new settings
// test if the setting conflict with an already defined timer
_conflictID = CTimerManager::conflictTest(_timerInfo);
if(_conflictID) {
_timerInfo.enabled = 0; // cancel enabled status
_ConflictTime = millis() + 1500;
_ScreenManager.reqUpdate();
_rowSel = 1;
_colSel = 4; // select enable/disable
}
else {
_SaveTime = millis() + 1500;
_ScreenManager.reqUpdate();
_rowSel = 0;
_colSel = 0;
}
CTimerManager::setTimer(_timerInfo);
}
}
// press LEFT - navigate fields, or screens
if(event & key_Left) {
@ -200,12 +206,12 @@ CSetTimerScreen::keyHandler(uint8_t event)
case 1:
// select previous field
_colSel--;
WRAPLOWERLIMIT(_colSel, 0, 6);
ROLLLOWERLIMIT(_colSel, 0, 5);
break;
case 2:
// select previous day
_colSel--;
WRAPLOWERLIMIT(_colSel, 0, 6);
ROLLLOWERLIMIT(_colSel, 0, 6);
break;
}
}
@ -218,12 +224,12 @@ CSetTimerScreen::keyHandler(uint8_t event)
case 1:
// select next field
_colSel++;
WRAPUPPERLIMIT(_colSel, 6, 0);
ROLLUPPERLIMIT(_colSel, 5, 0);
break;
case 2:
// select next day
_colSel++;
WRAPUPPERLIMIT(_colSel, 6, 0);
ROLLUPPERLIMIT(_colSel, 6, 0);
break;
}
}
@ -231,14 +237,8 @@ CSetTimerScreen::keyHandler(uint8_t event)
// handle held down keys
if(event & keyRepeat) {
_repeatCount++;
bHeld = true;
if(_rowSel == 1) {
if(event & key_Centre) {
_ScreenManager.reqUpdate();
_rowSel = 0;
_colSel = 0;
}
if(_colSel < 4) {
// fast repeat of hour/minute adjustments by holding up or down keys
if(event & key_Down) _adjust(-1);
@ -256,36 +256,9 @@ CSetTimerScreen::keyHandler(uint8_t event)
}
if(event & keyReleased) {
if(!bHeld) {
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // exit: return to clock screen
}
else if(_rowSel == 2) { // exit from per day settings
_rowSel = 1;
_colSel = 4;
}
else { // in config fields, save new settings
// test if the setting conflict with an already defined timer
_conflictID = CTimerManager::conflictTest(_timerInfo);
if(_conflictID) {
_timerInfo.enabled = 0; // cancel enabled status
_ConflictTime = millis() + 1500;
_ScreenManager.reqUpdate();
_rowSel = 1;
_colSel = 4; // select enable/disable
}
else {
_enableStoringMessage();
_rowSel = 0;
_colSel = 0;
}
CTimerManager::setTimer(_timerInfo);
}
}
int maskDOW = 0x01 << _colSel;
// released DOWN - can only leave adjustment by using OK (centre button)
if(event & key_Down) {
// adjust selected item
@ -343,24 +316,29 @@ CSetTimerScreen::keyHandler(uint8_t event)
void
CSetTimerScreen::_adjust(int dir)
{
int days;
int maskDOW = 0x01 << _colSel; // if doing Day of Week - (_rowSel == 2)
switch(_colSel) {
case 0:
_timerInfo.start.hour += dir;
WRAPLIMITS(_timerInfo.start.hour, 0, 23);
ROLLUPPERLIMIT(_timerInfo.start.hour, 23, 0);
ROLLLOWERLIMIT(_timerInfo.start.hour, 0, 23);
break;
case 1:
_timerInfo.start.min += dir;
WRAPLIMITS(_timerInfo.start.min, 0, 59);
ROLLUPPERLIMIT(_timerInfo.start.min, 59, 0);
ROLLLOWERLIMIT(_timerInfo.start.min, 0, 59);
break;
case 2:
_timerInfo.stop.hour += dir;
WRAPLIMITS(_timerInfo.stop.hour, 0, 23);
ROLLUPPERLIMIT(_timerInfo.stop.hour, 23, 0);
ROLLLOWERLIMIT(_timerInfo.stop.hour, 0, 23);
break;
case 3:
_timerInfo.stop.min += dir;
WRAPLIMITS(_timerInfo.stop.min, 0, 59);
ROLLUPPERLIMIT(_timerInfo.stop.min, 59, 0);
ROLLLOWERLIMIT(_timerInfo.stop.min, 0, 59);
break;
case 4:
if(_rowSel == 1) {
@ -375,77 +353,50 @@ CSetTimerScreen::_adjust(int dir)
case 5:
_timerInfo.repeat = !_timerInfo.repeat;
break;
case 6:
if(_timerInfo.temperature <= 8 && dir < 0)
_timerInfo.temperature = 0;
else {
_timerInfo.temperature += dir;
BOUNDSLIMIT(_timerInfo.temperature, 8, 35);
}
break;
}
}
void
CSetTimerScreen::_printEnabledTimers()
{
const int dayWidth = 10;
int xPos = border;
const int dayWidth = 8;
int xPos = _display.width() - border;
int yPos = 28;
if(_timerInfo.enabled == 0x00 && _rowSel != 2) {
_printMenuText(xPos, yPos, "Disabled", _colSel==4);
_printMenuText(xPos, yPos, "Disabled", _colSel==4, eRightJustify);
}
else if(_timerInfo.enabled & 0x80) {
if(_rowSel==1 && _colSel==4)
_printMenuText(xPos, yPos, "Enabled", true);
_printMenuText(xPos, yPos, "Enabled", true, eRightJustify);
else
_printInverted(xPos, yPos, "Enabled", true);
_printInverted(xPos, yPos, "Enabled", true, eRightJustify);
}
else {
if(_rowSel==1 && _colSel==4) {
CRect extents;
extents.width = 7 * dayWidth + 2;
extents.height = 11;
extents.xPos = border;
extents.yPos = yPos-2;
extents.height = 8;
extents.xPos = xPos - extents.width;
extents.yPos = yPos;
extents.Expand(border);
_display.drawRoundRect(extents.xPos, extents.yPos, extents.width, extents.height, radius, WHITE);
}
xPos = border+3; // back step 7 day entries
xPos -= 7 * dayWidth; // back step 7 day entries
int xSel = xPos + _colSel * dayWidth; // note location of selection now (xPos gets changed)
// print days, inverse if enabled
for(int i=0; i<7; i++) {
int dayMask = 0x01 << i;
if(_timerInfo.enabled & dayMask) {
_display.fillRect(xPos-2, yPos-2, 9, 11, WHITE);
}
_printInverted(xPos, yPos, briefDOW[i], _timerInfo.enabled & dayMask);
_display.drawPixel(xPos-2, yPos-2, BLACK);
_display.drawPixel(xPos-2, yPos+8, BLACK);
_display.drawPixel(xPos+6, yPos-2, BLACK);
_display.drawPixel(xPos+6, yPos+8, BLACK);
xPos += dayWidth;
}
// draw selection loop afterwards - writing text otherwise obliterates it
if(_rowSel==2) {
CRect extents;
extents.xPos = xSel-1-border;
extents.yPos = yPos-1-border;
extents.width = 13;
extents.height = 15;
_display.drawRoundRect(extents.xPos, extents.yPos, extents.width, extents.height, 3, WHITE);
extents.xPos = xSel;
extents.yPos = yPos;
_drawMenuSelection(extents, briefDOW[_colSel]);
}
}
}
void
CSetTimerScreen::_showConflict(const char* str)
{
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
_display.fillRect(19, 22, 90, 36, WHITE);
_printInverted(_display.xCentre(), 39, str, true, eCentreJustify);
_printInverted(_display.xCentre(), 28, "Conflicts", true, eCentreJustify);
}

View file

@ -23,22 +23,25 @@
#define __SETTIMERSCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "ScreenHeader.h"
#include "../Utility/NVStorage.h"
class C128x64_OLED;
class CScreenManager;
class CProtocol;
class CSetTimerScreen : public CUIEditScreen {
int _repeatCount;
class CSetTimerScreen : public CScreenHeader {
int _rowSel;
int _colSel;
int _timerID;
unsigned long _SaveTime;
unsigned long _ConflictTime;
int _conflictID;
sTimer _timerInfo;
void _adjust(int dir);
void _printEnabledTimers();
void _showConflict(const char* str);
void _initUI();
public:
CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int instance);
void onSelect();

View file

@ -30,10 +30,8 @@
#include "SettingsScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Utility/macros.h"
#include "../Protocol/Protocol.h"
#include "fonts/Arial.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
static const int Line3 = 20; // system voltage
static const int Line2 = 30; // fan sensor
@ -55,19 +53,22 @@ CSettingsScreen::onSelect()
_initUI();
}
void
CSettingsScreen::_initUI()
{
// ensure standard entry to screen - especially after a dimming timeout
_animateCount = 0;
}
bool
CSettingsScreen::show()
{
char str[16];
// CScreenHeader::show(false);
//
// _display.writeFillRect(0, 16, 84, 12, WHITE);
// _printInverted(3, 18, "Heater Tuning", true);
CScreen::show();
_display.clearDisplay();
CScreenHeader::show();
_showTitle("Heater Tuning");
_display.writeFillRect(0, 16, 96, 12, WHITE);
_printInverted(3, 18, "Heater Settings", true);
if(!CPasswordScreen::show()) {
@ -75,15 +76,14 @@ CSettingsScreen::show()
_printMenuText(_display.width(), Line3, str, false, eRightJustify);
sprintf(str, "Min: %.1f/%d", getHeaterInfo().getPump_Min(), getHeaterInfo().getFan_Min());
_printMenuText(0, Line3, str);
_printMenuText(0, Line2, str);
sprintf(str, "Max: %.1f/%d", getHeaterInfo().getPump_Max(), getHeaterInfo().getFan_Max());
_printMenuText(0, Line2, str);
_printMenuText(0, Line1, str);
int yPos = 53;
int xPos = _display.xCentre();
_printMenuText(_display.xCentre(), 53, " ", true, eCentreJustify);
_printMenuText(xPos, yPos, "\030Edit Exit", false, eCentreJustify);
_printMenuText(xPos, yPos, " \021 \030Edit \031\352T \020 ", true, eCentreJustify);
}
return true;
@ -103,7 +103,7 @@ CSettingsScreen::animate()
}
else {
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0);
ROLLUPPERLIMIT(_animateCount, 9, 0);
int glowDrive = getHeaterInfo().getGlow_Drive();
_printMenuText(Column, Line1, " ");
@ -135,53 +135,43 @@ CSettingsScreen::animate()
bool
CSettingsScreen::keyHandler(uint8_t event)
{
if(CPasswordScreen::keyHandler(event)) { // handles password collection
if(CPasswordScreen::keyHandler(event)) {
if(_isPasswordOK()) {
_ScreenManager.selectMenu(CScreenManager::TuningMenuLoop);
}
return true;
}
if(event & keyPressed) {
// press LEFT
if(event & key_Left) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
}
// press RIGHT
if(event & key_Right) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
}
// press UP
if(event & key_Up) {
if(hasOEMcontroller()) {
if(event & key_Centre)
_reqOEMWarning();
else {
if(event & keyPressed) {
// press LEFT
if(event & key_Left) {
_ScreenManager.prevMenu();
}
// press RIGHT
if(event & key_Right) {
_ScreenManager.nextMenu();
}
// press UP
if(event & (key_Up | key_Centre)) {
if(hasOEMcontroller()) {
if(event & key_Centre)
_reqOEMWarning();
else {
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::InheritSettingsUI);
}
}
else {
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::InheritSettingsUI);
_getPassword();
}
}
else {
_getPassword();
if(_isPasswordOK()) {
_ScreenManager.selectMenu(CScreenManager::TuningMenuLoop);
}
}
}
if(event & key_Centre) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
}
// press DOWN
if(event & key_Down) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
// press DOWN
if(event & key_Down) {
// _ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::ExperimentalUI);
// _ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI);
}
// THREE FINGER SALUTE!
if((event & (key_Left|key_Right|key_Centre)) == (key_Left|key_Right|key_Centre)) {
for(;;); // force watchdog reboot!
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI);
}
}
}
_ScreenManager.reqUpdate();
return true;
}

View file

@ -29,6 +29,8 @@ class C128x64_OLED;
class CScreenManager;
class CSettingsScreen : public CPasswordScreen {
int _animateCount;
void _initUI();
public:
CSettingsScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();

View file

@ -0,0 +1,296 @@
/*
* 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 "128x64OLED.h"
#include "ThermostatModeScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "fonts/Icons.h"
///////////////////////////////////////////////////////////////////////////
//
// CThermostatModeScreen
//
// 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 = 50;
CThermostatModeScreen::CThermostatModeScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_window = 10;
_thermoMode = 0;
_cyclicMode.init();
}
void
CThermostatModeScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_window = NVstore.getThermostatMethodWindow();
_thermoMode = NVstore.getThermostatMethodMode();
_cyclicMode = NVstore.getCyclicMode();
}
void
CThermostatModeScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
_keyRepeat = -1;
}
bool
CThermostatModeScreen::show()
{
char msg[20];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 10) {
_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, " Thermostat Mode ", true, eCentreJustify);
_display.drawBitmap(10, 14, thermostatIcon, thermostatWidth, thermostatHeight, WHITE);
sprintf(msg, "%.1f\367C", _window); // \367 is octal for Adafruit degree symbol
_printMenuText(Column, Line2, msg, _rowSel == 3);
switch(_thermoMode) {
case 1:
_printMenuText(Column, Line3, "Deadband", _rowSel == 4);
break;
case 2:
_printMenuText(Column, Line3, "Linear Hz", _rowSel == 4);
break;
default:
_printMenuText(Column, Line3, "Standard", _rowSel == 4);
break;
}
if(_cyclicMode.isEnabled()) {
sprintf(msg, "> %d\367C", _cyclicMode.Stop+1); // \367 is octal for Adafruit degree symbol
}
else {
strcpy(msg, "OFF");
}
_printMenuText(Column, Line1, msg, _rowSel == 1);
if(_cyclicMode.isEnabled()) {
sprintf(msg, "< %d\367C", _cyclicMode.Start); // \367 is octal for Adafruit degree symbol
}
else {
strcpy(msg, "");
}
_printMenuText(Column + 37, Line1, msg, _rowSel == 2);
}
}
return true;
}
bool
CThermostatModeScreen::animate()
{
if(_rowSel != 10) {
int yPos = 53;
int xPos = _display.xCentre();
const char* pMsg = NULL;
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
break;
case 1:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Heater shuts down over set point. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 2:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Heater restarts below setpoint. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " User defined window for custom thermostat modes. ";
_scrollMessage(56, pMsg, _scrollChar);
break;
case 4:
_display.drawFastHLine(0, 52, 128, WHITE);
switch(_thermoMode) {
case 1:
pMsg = " The user defined window sets the thermostat's hysteresis. ";
break;
case 2:
pMsg = " The pump rate is adjusted linearly across the set point window. ";
break;
default:
pMsg = " Use heater's standard thermostat control. ";
break;
}
if(pMsg)
_scrollMessage(56, pMsg, _scrollChar);
break;
}
return true;
}
return false;
}
bool
CThermostatModeScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_keyRepeat = 0; // unlock hold function
// press LEFT to select previous screen
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 4:
_scrollChar = 0;
case 1:
case 2:
case 3:
_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 4:
_scrollChar = 0;
case 1:
case 2:
case 3:
_adjust(+1);
break;
case 10:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
if(_rowSel != 0) {
_scrollChar = 0;
_rowSel--;
if(_rowSel == 2 && !_cyclicMode.isEnabled())
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
_scrollChar = 0;
_rowSel++;
if(_rowSel == 2 && !_cyclicMode.isEnabled())
_rowSel++;
UPPERLIMIT(_rowSel, 4);
break;
case 10: // 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:
case 4:
_rowSel = 10;
break;
}
}
_ScreenManager.reqUpdate();
}
if(event & keyRepeat) {
_keyRepeat++;
if((event & key_Down) && (keyRepeat >= 4)) {
_keyRepeat = -1;
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::FontDumpUI);
}
}
}
if(event & keyReleased) {
_keyRepeat = -1;
}
return true;
}
void
CThermostatModeScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1:
_cyclicMode.Stop += dir;
LOWERLIMIT(_cyclicMode.Stop, 0);
UPPERLIMIT(_cyclicMode.Stop, 10);
break;
case 2:
_cyclicMode.Start += dir;
LOWERLIMIT(_cyclicMode.Start, -10);
UPPERLIMIT(_cyclicMode.Start, 0);
break;
case 3: // window
_window += (dir * 0.1);
UPPERLIMIT(_window, 6.3);
LOWERLIMIT(_window, 0.2);
break;
case 4: // thermostat mode
_thermoMode += dir;
ROLLLOWERLIMIT(_thermoMode, 0, 2);
ROLLUPPERLIMIT(_thermoMode, 2, 0);
break;
}
}

View file

@ -23,23 +23,23 @@
#define __THERMOSTATMODESCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "PasswordScreen.h"
#include "../Utility/NVStorage.h"
class C128x64_OLED;
class CScreenManager;
class CThermostatModeScreen : public CUIEditScreen
class CThermostatModeScreen : public CPasswordScreen
{
int _rowSel;
int _keyRepeat;
void _adjust(int dir);
float _window;
int _thermoMode;
sCyclicThermostat _cyclicMode;
int _animateCount;
int _scrollChar;
protected:
void _initUI();
void _saveNV();
public:
CThermostatModeScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();

View file

@ -30,24 +30,27 @@
#include "TimerChartScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Protocol/helpers.h"
#include "../Utility/NVStorage.h"
#include "../../lib/RTClib/RTClib.h"
#include <RTClib.h>
#include "fonts/MiniFont.h"
#include "../RTC/TimerManager.h"
#include "../RTC/Clock.h"
static uint8_t condensed[7][120];
CTimerChartScreen::CTimerChartScreen(C128x64_OLED& display, CScreenManager& mgr, int instance) : CUIEditScreen(display, mgr)
CTimerChartScreen::CTimerChartScreen(C128x64_OLED& display, CScreenManager& mgr, int instance) : CScreenHeader(display, mgr)
{
_rowSel = 0;
_colSel = 0;
_SaveTime = 0;
_instance = instance;
}
void
CTimerChartScreen::onSelect()
{
CTimerManager::createMap();
CTimerManager::condenseMap(condensed);
}
@ -84,6 +87,7 @@ CTimerChartScreen::show()
for(int dow = 0; dow < 7; dow++) {
int day = 0x01 << dow;
int ypos = dow*linespacing + 7; // top of first line
int pixel = 0;
int subpixel = 0;
@ -118,7 +122,7 @@ CTimerChartScreen::show()
if(pixel > 4) {
pixel = 0;
subpixel++;
WRAPUPPERLIMIT(subpixel, 2, 0);
ROLLUPPERLIMIT(subpixel, 2, 0);
}
if((interval == 119) && blockStart >=0) { // timer ran up until midnight
IDcentre = hour0 + (blockStart + 120) / 2;
@ -142,27 +146,10 @@ CTimerChartScreen::show()
}
}
}
cursor();
return true;
}
void
CTimerChartScreen::cursor()
{
static bool bShowWhite = true;
// create masking based upon TODAY
const BTCDateTime tNow = Clock.get();
int dow = tNow.dayOfTheWeek();
int todayTime = tNow.hour() * 60 + tNow.minute();
int yPos = 6 + 7*dow;
int xPos = 9 + int(todayTime * 0.0833333); // 1/12
_display.drawFastVLine(xPos, yPos, 8, bShowWhite ? WHITE : BLACK);
bShowWhite = !bShowWhite;
}
bool
CTimerChartScreen::keyHandler(uint8_t event)
@ -171,8 +158,8 @@ CTimerChartScreen::keyHandler(uint8_t event)
// handle initial key press
if(event & keyPressed) {
bHeld = false;
// press CENTRE, UP or DOWN
if(event & (key_Centre | key_Down | key_Up)) {
// press CENTRE
if(event & key_Centre) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // exit: return to clock screen
}
// press LEFT - navigate fields, or screens
@ -183,6 +170,12 @@ CTimerChartScreen::keyHandler(uint8_t event)
if(event & key_Right) {
_ScreenManager.nextMenu();
}
// press UP
if(event & key_Up) {
}
// press DOWN
if(event & key_Down) {
}
}
// handle held down keys

View file

@ -23,15 +23,18 @@
#define __TIMERCHARTSCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "ScreenHeader.h"
#include "../Utility/NVStorage.h"
class C128x64_OLED;
class CScreenManager;
class CProtocol;
class CTimerChartScreen : public CUIEditScreen {
class CTimerChartScreen : public CScreenHeader {
int _rowSel;
int _colSel;
int _instance;
void cursor();
unsigned long _SaveTime;
public:
CTimerChartScreen(C128x64_OLED& display, CScreenManager& mgr, int instance);

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* 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
@ -20,64 +20,69 @@
*/
#include "128x64OLED.h"
#include "BME280Screen.h"
#include "VersionInfoScreen.h"
#include "KeyPad.h"
#include "../Protocol/helpers.h"
#include "../Utility/UtilClasses.h"
#include "../Utility/NVStorage.h"
#include "../Utility/GPIO.h"
#include "fonts/Icons.h"
#include "../Utility/TempSense.h"
CBME280Screen::CBME280Screen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
CVersionInfoScreen::CVersionInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
}
void
CVersionInfoScreen::onSelect()
{
CScreenHeader::onSelect();
}
void
CVersionInfoScreen::_initUI()
{
_initUI();
}
bool
CBME280Screen::show()
CVersionInfoScreen::show()
{
char msg[32];
char msg[16];
_display.clearDisplay();
if(!CPasswordScreen::show()) { // for showing "saving settings"
_printInverted(_display.xCentre(), 0, " Version Information ", true, eCentreJustify);
_display.drawBitmap(10, 11, firmwareIcon, firmwareWidth, firmwareHeight, WHITE);
sprintf(msg, "V%.3f", getVersion());
_printMenuText(43, 14, msg);
_printMenuText(43, 25, getVersionDate());
_showTitle("BME280 status");
if(getTempSensor().getBME280().getCount()) {
float temperature;
float humidity;
float altitude;
_printMenuText(76, 16, "Temperature:", false, eRightJustify);
_printMenuText(76, 26, "Humidity:", false, eRightJustify);
_printMenuText(76, 36, "Altitude:", false, eRightJustify);
getTempSensor().getTemperatureBME280(temperature);
getTempSensor().getHumidity(humidity);
getTempSensor().getAltitude(altitude);
sprintf(msg, "%.01f`C", temperature);
_printMenuText(80, 16, msg, false);
sprintf(msg, "%.01f%%", humidity);
_printMenuText(80, 26, msg, false);
sprintf(msg, "%.0fm", altitude);
_printMenuText(80, 36, msg, false);
}
else {
_printMenuText(64, 16, "Sensor not found", false, eCentreJustify);
}
_printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", true, eCentreJustify);
_display.drawBitmap(20, 34, hardwareIcon, hardwareWidth, hardwareHeight, WHITE);
int PCB = getBoardRevision();
sprintf(msg, "V%.1f", float(PCB)*0.1f);
_printMenuText(43, 38, msg);
if(PCB == 20) {
_printMenuText(108, 38, "Analog", false, eCentreJustify);
_display.drawLine(88, 42, 127, 42, WHITE);
}
_printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", true, eCentreJustify);
return true;
}
bool
CBME280Screen::keyHandler(uint8_t event)
CVersionInfoScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
// UP press
if(event & key_Up) {
}
// CENTRE press
if(event & key_Centre) {
}
// LEFT press
if(event & key_Left) {
_ScreenManager.prevMenu();
@ -86,7 +91,6 @@ CBME280Screen::keyHandler(uint8_t event)
if(event & key_Right) {
_ScreenManager.nextMenu();
}
// CENTRE press
if(event & key_Centre) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}

View file

@ -23,22 +23,20 @@
#define __VERSIONINFOSCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "PasswordScreen.h"
class C128x64_OLED;
class CScreenManager;
class CVersionInfoScreen : public CUIEditScreen
class CVersionInfoScreen : public CScreenHeader
{
protected:
void _saveNV();
void _initUI();
public:
CVersionInfoScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool keyHandler(uint8_t event);
void onSelect();
bool animate();
};
#endif

View file

@ -21,10 +21,9 @@
#include "WiFiScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../WiFi/BTCWifi.h"
#include "../Utility/NVStorage.h"
#include "fonts/Arial.h"
#include "../Protocol/helpers.h"
#include "../Wifi/BTCWifi.h"
#include "../Utility/NVstorage.h"
///////////////////////////////////////////////////////////////////////////
//
@ -41,7 +40,7 @@ static const int LIMIT_AWAY = 0;
static const int LIMIT_LEFT = 1;
static const int LIMIT_RIGHT = 2;
CWiFiScreen::CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditScreen(display, mgr)
CWiFiScreen::CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
{
_initUI();
}
@ -49,43 +48,37 @@ CWiFiScreen::CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditSc
void
CWiFiScreen::onSelect()
{
CScreen::onSelect();
_initUI();
}
void
CWiFiScreen::_initUI()
{
CUIEditScreen::_initUI();
_OTAsel = NVstore.getUserSettings().enableOTA;
_rowSel = 0;
_colSel = 0;
_OTAsel = NVstore.getOTAEnabled();
_colLimit = LIMIT_LEFT; // left most selection
_bShowMAC = false;
if(NVstore.getUserSettings().wifiMode) { // non zero => enabled wifi, maybe AP only or STA+AP or STA only
if(isWifiAPonly()) {
if(NVstore.getWifiEnabled()) {
if(isWifiAP()) {
if(isWifiConfigPortal()) {
_colSel = 1; // " WiFi: CFG AP only "
_colLimit = LIMIT_AWAY; // inner selection
}
else {
_colSel = 2; // " WiFi: AP only ";
_colLimit = LIMIT_RIGHT; // right most selection
}
}
else {
if(NVstore.getUserSettings().wifiMode & 0x02) { // 0x02 set => STA only preferred
if(isWifiConfigPortal()) {
_colSel = 5; // " WiFi: CFG STA only "
}
else {
_colSel = 6; // " WiFi: STA only ";
}
if(isWifiConfigPortal()) {
_colSel = 3; // " WiFi: CFG STA+AP "
_colLimit = LIMIT_AWAY; // away from menu limits
}
else {
if(isWifiConfigPortal()) {
_colSel = 3; // " WiFi: CFG STA+AP "
}
else {
_colSel = 4; // " WiFi: STA+AP ";
}
_colSel = 4; // " WiFi: STA+AP ";
_colLimit = LIMIT_RIGHT; // right most selection
}
}
}
@ -94,44 +87,39 @@ CWiFiScreen::_initUI()
bool
CWiFiScreen::show()
{
// CScreenHeader::show(false);
CScreen::show();
CScreenHeader::show();
_display.clearDisplay();
_showTitle("WiFi settings");
int yPos = 18;
const char* pTitle = NULL;
switch(_colSel) {
case 0:
pTitle = "DISABLED";
pTitle = " WiFi: DISABLED ";
break;
case 1:
pTitle = "CFG AP only";
pTitle = " WiFi: CFG AP only ";
break;
case 2:
pTitle = "AP only";
pTitle = " WiFi: AP only ";
break;
case 3:
pTitle = "CFG STA+AP";
pTitle = " WiFi: CFG STA+AP ";
break;
case 4:
pTitle = "STA+AP";
break;
case 5:
pTitle = "CFG STA only";
break;
case 6:
pTitle = "STA only";
pTitle = " WiFi: STA+AP ";
break;
}
_printMenuText(border, yPos, pTitle, _rowSel==1); // selection box
if(_OTAsel == 0)
_printMenuText(128-border, yPos, "OTA: OFF", _rowSel==2, eRightJustify); // selection box
else
_printMenuText(128-border, yPos, "OTA: ON ", _rowSel==2, eRightJustify); // selection box
if(_rowSel == 0)
_printInverted(3, yPos, pTitle, true); // inverted title bar
if(_rowSel == 1)
_printMenuText(3, yPos, pTitle, true); // selection box
if(_rowSel == 2) {
if(_OTAsel == 0)
_printMenuText(3, yPos, " OTA: DISABLED ", true); // selection box
else
_printMenuText(3, yPos, " OTA: ENABLED ", true); // selection box
}
yPos += 3;
if(_colSel) {
@ -159,30 +147,45 @@ CWiFiScreen::show()
bool
CWiFiScreen::animate()
{
bool retval = false;
// show next/prev menu navigation line
if(_rowSel == 0) {
// _printMenuText(_display.xCentre(), 53, " ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 53, "\021 \020", true, eCentreJustify);
if(_bShowMAC) {
_printMenuText(_display.xCentre(), 53, "\030Mode \031IP", false, eCentreJustify);
_printMenuText(_display.xCentre(), 53, " Exit", false, eCentreJustify);
}
else {
_printMenuText(_display.xCentre(), 53, "\030Mode \031MAC", false, eCentreJustify);
_printMenuText(_display.xCentre(), 53, " Exit", false, eCentreJustify);
}
_printMenuText(_display.xCentre(), 53, " \021 \020 ", true, eCentreJustify);
if(_bShowMAC)
_printMenuText(_display.xCentre(), 53, "\030Sel \031IP", false, eCentreJustify);
else
_printMenuText(_display.xCentre(), 53, "\030Sel \031MAC", false, eCentreJustify);
}
if(_rowSel == 1) {
_display.drawFastHLine(0, 52, 128, WHITE);
const char* pMsg = NULL;
pMsg = "\031ESC \030OTA Set \033\032Adj"; // both Sel arrows
_printMenuText(_display.xCentre(), 56, pMsg, false, eCentreJustify);
switch(_colLimit) {
case LIMIT_AWAY:
pMsg = "\031 ESC Set \033\032 Sel"; // both Sel arrows
break;
case LIMIT_LEFT:
pMsg = "\031 ESC Set \032 Sel"; // only right Sel arrow
break;
case LIMIT_RIGHT:
pMsg = "\031 ESC Set \033 Sel"; // only left Sel arrow
break;
}
if(pMsg)
_printMenuText(_display.xCentre(), 56, pMsg, false, eCentreJustify);
}
if(_rowSel == 2) {
_display.drawFastHLine(0, 52, 128, WHITE);
const char* pMsg = NULL;
pMsg = "\031Mode Set \033\032Adj";
_printMenuText(_display.xCentre(), 56, pMsg, false, eCentreJustify);
switch(_OTAsel) {
case 0:
pMsg = "\031 ESC Set \032 Enable"; // only right Sel arrow
break;
case 1:
pMsg = "\031 ESC Set \033 Disable"; // only left Sel arrow
break;
}
if(pMsg)
_printMenuText(_display.xCentre(), 56, pMsg, false, eCentreJustify);
}
CScreen::animate();
return true;
@ -193,6 +196,9 @@ CWiFiScreen::keyHandler(uint8_t event)
{
if(event & keyPressed) {
_repeatCount = 0;
// press CENTRE
if(event & key_Centre) {
}
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
@ -200,18 +206,21 @@ CWiFiScreen::keyHandler(uint8_t event)
_ScreenManager.prevMenu();
break;
case 1:
if(isWifiAPonly()) {
if(isWifiAP()) {
// _colSel = 0;
// _colLimit = LIMIT_LEFT;
_colSel--;
WRAPLOWERLIMIT(_colSel, 0, 2);
LOWERLIMIT(_colSel, 0);
_colLimit = (_colSel == 0) ? LIMIT_LEFT : LIMIT_AWAY;
}
else {
_colSel--;
WRAPLOWERLIMIT(_colSel, 0, 6);
LOWERLIMIT(_colSel, 0);
_colLimit = (_colSel == 0) ? LIMIT_LEFT : LIMIT_AWAY;
}
break;
case 2:
_OTAsel--;
WRAPLOWERLIMIT(_OTAsel, 0, 1);
_OTAsel = 0;
break;
}
}
@ -222,18 +231,23 @@ CWiFiScreen::keyHandler(uint8_t event)
_ScreenManager.nextMenu();
break;
case 1:
if(isWifiAPonly()) {
if(isWifiAP()) {
// _colSel = 1;
// _colLimit = LIMIT_RIGHT;
_colSel++;
WRAPUPPERLIMIT(_colSel, 2, 0);
UPPERLIMIT(_colSel, 2);
_colLimit = (_colSel == 3) ? LIMIT_RIGHT : LIMIT_AWAY;
}
else {
_colSel++;
WRAPUPPERLIMIT(_colSel, 6, 0);
UPPERLIMIT(_colSel, 4);
_colLimit = (_colSel == 4) ? LIMIT_RIGHT : LIMIT_AWAY;
// UPPERLIMIT(_colSel, 3);
// _colLimit = (_colSel == 3) ? LIMIT_RIGHT : LIMIT_AWAY;
}
break;
case 2:
_OTAsel++;
WRAPUPPERLIMIT(_OTAsel, 1, 0);
_OTAsel = 1;
break;
}
}
@ -261,9 +275,6 @@ CWiFiScreen::keyHandler(uint8_t event)
if(event & keyReleased) {
if(event & key_Centre) {
if(_rowSel == 0) {
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
}
if(_rowSel == 1) {
switch(_colSel) {
@ -282,19 +293,11 @@ CWiFiScreen::keyHandler(uint8_t event)
case 4:
wifiEnterConfigPortal(false, false, 5000); // STA+AP: keep credentials, reboot into webserver
break;
case 5:
wifiEnterConfigPortal(true, false, 5000, true); // CFG STA only: keep credentials, reboot into portal
break;
case 6:
wifiEnterConfigPortal(false, false, 5000, true); // STA only: keep credentials, reboot into webserver
break;
}
_rowSel = 3; // stop ticker display
}
if(_rowSel == 2) {
sUserSettings settings = NVstore.getUserSettings();
settings.enableOTA = _OTAsel;
NVstore.setUserSettings(settings);
NVstore.setOTAEnabled(_OTAsel);
NVstore.save();
const char* content[2];
if(_OTAsel)

View file

@ -23,12 +23,12 @@
#define __WIFISCREEN_H__
#include <stdint.h>
#include "UIEditScreen.h"
#include "ScreenHeader.h"
class C128x64_OLED;
class CScreenManager;
class CWiFiScreen : public CUIEditScreen {
class CWiFiScreen : public CScreenHeader {
public:
CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr);
void onSelect();
@ -36,7 +36,8 @@ public:
bool animate();
bool keyHandler(uint8_t event);
private:
int _OTAsel;
int _colLimit;
int _rowSel, _colSel, _OTAsel;
int _repeatCount;
bool _bShowMAC;
void _initUI();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
#include "FontTypes.h"
// Font data for Arial 8pt
extern const uint8_t PROGMEM arial_8ptBitmaps [];
extern const FONT_INFO arial_8ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM arial_8ptDescriptors[];
// Font data for Arial 7pt
extern const uint8_t PROGMEM arial_7ptBitmaps [];
extern const FONT_INFO arial_7ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM arial_7ptDescriptors[];

View file

@ -44,7 +44,7 @@ typedef struct {
uint8_t EndChar; // End character
uint8_t SpaceWidth;
const FONT_CHAR_INFO* pCharInfo; // Character descriptor array
const uint8_t* pBitmaps; // Character bitmap array
const unsigned char* pBitmaps; // Character bitmap array
} FONT_INFO;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
#include "FontTypes.h"
// Font data for Franklin Gothic Medium Cond 8pt
extern const uint8_t PROGMEM franklinGothicMediumCond_8ptBitmaps [] ;
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_8ptDescriptors[] ;
extern const FONT_INFO franklinGothicMediumCond_8ptFontInfo;
// Font data for Franklin Gothic Medium Cond 7pt
extern const uint8_t PROGMEM franklinGothicMediumCond_7ptBitmaps [];
extern const FONT_INFO franklinGothicMediumCond_7ptFontInfo;
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_7ptDescriptors[];

View file

@ -0,0 +1,539 @@
/*
* 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 <Arduino.h>
#include "Icons.h"
// 'Thermometer', 8x50px
const unsigned char bodyThermometerIcon [] PROGMEM = {
0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff,
0x7e, 0x3c
};
// 'ThermometerActual', 8x50px
const unsigned char ambientThermometerIcon [] PROGMEM = {
0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24,
0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x24, 0x24, 0x24, 0x24, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff,
0x7e, 0x3c
};
// 'ThermoPtr', 3x5px
const unsigned char thermoPtr [] PROGMEM = {
0x80, 0xc0, 0xe0, 0xc0, 0x80
};
// 'Bluetooth icon', 6x11px
const unsigned char BTicon [] PROGMEM = {
0x20, 0x30, 0x28, 0xa4, 0x68, 0x30, 0x68, 0xa4, 0x28, 0x30, 0x20,
};
// 'wifiIcon', 13x10px
const unsigned char wifiIcon [] PROGMEM = {
0x1f, 0xc0, 0x20, 0x20, 0x40, 0x10, 0x8f, 0x88, 0x10, 0x40, 0x20, 0x20,
0x07, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x00
};
// 'wifiInIcon, 5x5px
const unsigned char wifiInIcon [] PROGMEM = {
0x70, 0x70, 0xf8, 0x70, 0x20
};
// 'wifiOutIcon, 5x5px
const unsigned char wifiOutIcon [] PROGMEM = {
0x20, 0x70, 0xf8, 0x70, 0x70
};
// 'BatteryIcon', 15x10px
const unsigned char BatteryIcon [] PROGMEM = {
0x30, 0x18, 0xff, 0xfe, 0x80, 0x02, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda, 0xb6, 0xda,
0x80, 0x02, 0xff, 0xfe
};
// 'GlowPlugIcon', 16x9px
const unsigned char GlowPlugIcon [] PROGMEM = {
0x71, 0xc7, 0x0e, 0x38, 0x14, 0x14, 0x12, 0x24, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x0a, 0x28,
0x0e, 0x38
};
// 'HeatRise', 17x2px
const unsigned char GlowHeatIcon [] PROGMEM = {
0x80, 0x00, 0x80, 0x40, 0x01, 0x00
};
// 'Fan3_1a', 16x16px
const unsigned char FanIcon1 [] PROGMEM = {
0x03, 0xc0, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x03, 0xc0, 0x07, 0xe0, 0x06, 0x60,
0x7e, 0x7e, 0x87, 0xe1, 0x87, 0xe1, 0x84, 0x21, 0x84, 0x21, 0x78, 0x1e, 0x00, 0x00, 0x00, 0x00
};
// 'Fan3_2a', 16x16px
const unsigned char FanIcon2 [] PROGMEM = {
0x00, 0x78, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x7b, 0xf8, 0x87, 0xe0, 0x86, 0x60,
0x86, 0x60, 0x87, 0xe0, 0x7b, 0xf8, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x78
};
// 'Fan3_3a', 16x16px
const unsigned char FanIcon3 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x78, 0x1e, 0x84, 0x21, 0x84, 0x21, 0x87, 0xe1, 0x87, 0xe1, 0x7e, 0x7e,
0x06, 0x60, 0x07, 0xe0, 0x03, 0xc0, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x03, 0xc0
};
// 'Fan3_4a', 16x16px
const unsigned char FanIcon4 [] PROGMEM = {
0x1e, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1f, 0xde, 0x07, 0xe1, 0x06, 0x61,
0x06, 0x61, 0x07, 0xe1, 0x1f, 0xde, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1e, 0x00
};
// 'FuelIcon', 7x12px
const unsigned char FuelIcon [] PROGMEM = {
0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38
};
// 'Target', 13x13px
const unsigned char TargetIcon [] PROGMEM = {
0x0f, 0x80, 0x10, 0x40, 0x20, 0x20, 0x47, 0x10, 0x88, 0x88, 0x92, 0x48, 0x97, 0x48, 0x92, 0x48,
0x88, 0x88, 0x47, 0x10, 0x20, 0x20, 0x10, 0x40, 0x0f, 0x80
};
// 'repeat', 15x15px
const unsigned char repeatIcon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x02, 0xf0, 0x04, 0xe0, 0x04, 0xe0, 0x08, 0x98, 0x30, 0x07, 0xc0
};
// 'timerID1', 15x15px
const unsigned char timerID1Icon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x2d, 0x08, 0x25, 0xe8,
0x24, 0x08, 0x24, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'timerID2', 15x15px
const unsigned char timerID2Icon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x2d, 0x08, 0x25, 0xe8,
0x28, 0x08, 0x2c, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'timer', 15x15px
const unsigned char timerIcon [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x09, 0x20, 0x11, 0x10, 0x21, 0x08, 0x21, 0x08, 0x21, 0xe8,
0x20, 0x08, 0x20, 0x08, 0x10, 0x10, 0x08, 0x20, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00
};
// 'large timer', 15x15px
const unsigned char largeTimerIcon[] PROGMEM =
{
0x07, 0xC0, // #####
0x19, 0x30, // ## # ##
0x21, 0x08, // # # #
0x41, 0x04, // # # #
0x41, 0x04, // # # #
0x81, 0x02, // # # #
0x81, 0xF2, // # ##### #
0x80, 0x02, // # #
0x80, 0x02, // # #
0x80, 0x02, // # #
0x40, 0x04, // # #
0x40, 0x04, // # #
0x20, 0x08, // # #
0x18, 0x30, // ## ##
0x0F, 0xE0, // #######
};
const uint8_t PROGMEM verticalRepeatIcon [] =
{
0x78, // ####
0x38, // ###
0x38, // ###
0x48, // # #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x80, // #
0x40, // #
0x40, // #
0x20, // #
0x20, // #
};
const uint8_t PROGMEM GPIO1OFFIcon[] =
{
0x3E, 0x00, // #####
0x41, 0x00, // # #
0x88, 0x80, // # # #
0x98, 0x80, // # ## #
0x88, 0x80, // # # #
0x88, 0x80, // # # #
0x9C, 0x80, // # ### #
0x41, 0x00, // # #
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO1ONIcon[] =
{
0x3E, 0x00, // #####
0x7F, 0x00, // #######
0xF7, 0x80, // #### ####
0xE7, 0x80, // ### ####
0xF7, 0x80, // #### ####
0xF7, 0x80, // #### ####
0xE3, 0x80, // ### ###
0x7F, 0x00, // #######
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO2OFFIcon[] =
{
0x3E, 0x00, // #####
0x41, 0x00, // # #
0x9C, 0x80, // # ### #
0x84, 0x80, // # # #
0x9C, 0x80, // # ### #
0x90, 0x80, // # # #
0x9C, 0x80, // # ### #
0x41, 0x00, // # #
0x3E, 0x00, // #####
};
const uint8_t PROGMEM GPIO2ONIcon[] =
{
0x3E, 0x00, // #####
0x7F, 0x00, // #######
0xE3, 0x80, // ### ###
0xFB, 0x80, // ##### ###
0xE3, 0x80, // ### ###
0xEF, 0x80, // ### #####
0xE3, 0x80, // ### ###
0x7F, 0x00, // #######
0x3E, 0x00, // #####
};
const uint8_t PROGMEM CrossIcon[] =
{
0x88, // # #
0x50, // # #
0x20, // #
0x50, // # #
0x88, // # #
};
const uint8_t PROGMEM TickIcon[] =
{
0x00, //
0x08, // #
0x10, // #
0xa0, // # #
0x40, // #
};
const uint8_t PROGMEM OpenIcon[] =
{
0x1F, 0xC0, // #######
0x02, 0x00, // #
0x02, 0x00, // #
0x3A, 0xE0, // ### # ###
0xEA, 0xB8, // ### # # # ###
0x3A, 0xE0, // ### # ###
0x00, 0x00, //
};
const uint8_t PROGMEM CloseIcon[] =
{
0x00, 0x00, //
0x00, 0x00, //
0x3F, 0xE0, // #########
0x3A, 0xE0, // ### # ###
0xFA, 0xF8, // ##### # #####
0x3A, 0xE0, // ### # ###
0x02, 0x00, // #
};
const uint8_t PROGMEM BulbOnIcon[] =
{
0x08, 0x00, // #
0x41, 0x00, // # #
0x1C, 0x00, // ###
0x22, 0x00, // # #
0xA2, 0x80, // # # # #
0x1C, 0x00, // ###
0x14, 0x00, // # #
0x1C, 0x00, // ###
};
const uint8_t PROGMEM BulbOffIcon[] =
{
0x00, 0x00, //
0x00, 0x00, //
0x1C, 0x00, // ###
0x22, 0x00, // # #
0x22, 0x00, // # #
0x1C, 0x00, // ###
0x14, 0x00, // # #
0x1C, 0x00, // ###
};
const uint8_t PROGMEM startIcon[] =
{
0x80, // #
0xC0, // ##
0xE0, // ###
0xF0, // ####
0xF8, // #####
0xF0, // ####
0xE0, // ###
0xC0, // ##
0x80, // #
};
const uint8_t PROGMEM stopIcon[] =
{
0x00, //
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0xFC, // ######
0x00, //
};
const uint8_t PROGMEM displayTimeoutIcon[] =
{
0xFF, 0xE1, 0xFF, // ########### #########
0x80, 0x20, 0x82, // # # # #
0x80, 0x20, 0x82, // # # # #
0x80, 0x20, 0x44, // # # # #
0x80, 0x20, 0x28, // # # # #
0x80, 0x20, 0x44, // # # # #
0xFF, 0xE0, 0x92, // ########### # # #
0x0E, 0x00, 0xBA, // ### # ### #
0x3F, 0x80, 0xFE, // ####### #######
0x00, 0x01, 0xFF, // #########
};
const uint8_t PROGMEM menuTimeoutIcon[] =
{
0x00, 0x01, 0xFF, // #########
0xFF, 0xC0, 0x82, // ########## # #
0x00, 0x00, 0x82, // # #
0xFF, 0x00, 0x44, // ######## # #
0x00, 0x00, 0x28, // # #
0xFC, 0x00, 0x44, // ###### # #
0x00, 0x00, 0x92, // # # #
0xFF, 0x80, 0xBA, // ######### # ### #
0x00, 0x00, 0xFE, // #######
0x00, 0x01, 0xFF, // #########
};
const uint8_t PROGMEM timeoutIcon[] =
{
0xFF, 0x80, // #########
0x41, 0x00, // # #
0x41, 0x00, // # #
0x22, 0x00, // # #
0x14, 0x00, // # #
0x22, 0x00, // # #
0x49, 0x00, // # # #
0x5D, 0x00, // # ### #
0x7F, 0x00, // #######
0xFF, 0x80, // #########
};
const uint8_t PROGMEM refreshIcon[] =
{
0x01, 0x00, // #
0x00, 0x80, // #
0x7F, 0xC8, // ######### #
0x80, 0x88, // # # #
0x81, 0x08, // # # #
0x80, 0x08, // # #
0x84, 0x08, // # # #
0x88, 0x08, // # # #
0x9F, 0xF0, // # #########
0x08, 0x00, // #
0x04, 0x00, // #
};
const uint8_t PROGMEM thermostatIcon[] =
{
0x00, 0x00, 0x07, 0x00, // ###
0x00, 0x00, 0x0E, 0x00, // ###
0x00, 0x00, 0x0C, 0x40, // ## #
0x00, 0x00, 0x0C, 0xC0, // ## ##
0x00, 0x00, 0x1F, 0xC0, // #######
0x00, 0x00, 0x3F, 0x80, // #######
0x00, 0x00, 0x7C, 0x00, // #####
0x00, 0x00, 0xF8, 0x00, // #####
0x38, 0x01, 0xF0, 0x00, // ### #####
0x44, 0x01, 0xE0, 0x00, // # # ####
0x44, 0x00, 0xC0, 0x00, // # # ##
0x45, 0xC0, 0x00, 0x00, // # # ###
0x44, 0x00, 0x00, 0x00, // # #
0x55, 0xC0, 0x08, 0x00, // # # # ### #
0x54, 0x00, 0x1C, 0x00, // # # # ###
0x55, 0xC0, 0x2A, 0x00, // # # # ### # # #
0x54, 0x00, 0x08, 0x00, // # # # #
0x54, 0x00, 0x00, 0x00, // # # #
0x54, 0x00, 0x08, 0x00, // # # # #
0x54, 0x00, 0x2A, 0x00, // # # # # # #
0x54, 0x00, 0x1C, 0x00, // # # # ###
0x54, 0x00, 0x08, 0x00, // # # # #
0x92, 0x00, 0x00, 0x00, // # # #
0xBA, 0x00, 0x00, 0x00, // # ### #
0xBA, 0x00, 0x00, 0x00, // # ### #
0xBA, 0x00, 0x00, 0x00, // # ### #
0x82, 0x00, 0x00, 0x00, // # #
0x7C, 0x00, 0x00, 0x80, // ##### #
0x00, 0x01, 0xB0, 0xC0, // ## ## ##
0x00, 0x01, 0xB0, 0xE0, // ## ## ###
0x00, 0x01, 0xB0, 0xF0, // ## ## ####
0x00, 0x01, 0xB0, 0xE0, // ## ## ###
0x00, 0x01, 0xB0, 0xC0, // ## ## ##
0x00, 0x00, 0x00, 0x80, // #
};
const uint8_t PROGMEM GPIOIcon[] =
{
0x00, 0x00, 0x00, //
0x00, 0x20, 0x00, // #
0x01, 0x20, 0x00, // # #
0x00, 0xA0, 0x70, // # # ###
0x3F, 0xE0, 0x10, // ######### #
0x00, 0xA5, 0x70, // # # # # ###
0x01, 0x22, 0x40, // # # # #
0x00, 0x25, 0x70, // # # # ###
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x20, 0x00, 0x00, // #
0x20, 0x80, 0x00, // # #
0x20, 0x40, 0x70, // # # ###
0x3F, 0xE0, 0x10, // ######### #
0x20, 0x45, 0x70, // # # # # ###
0x20, 0x82, 0x40, // # # # #
0x20, 0x05, 0x70, // # # # ###
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, //
0x08, 0x00, 0x00, // #
0x09, 0x00, 0x00, // # #
0x05, 0x00, 0x00, // # #
0x24, 0x08, 0x00, // # # #
0x02, 0x00, 0x00, // #
0x02, 0x00, 0x00, // #
0x01, 0x00, 0x00, // #
0xC3, 0x86, 0x00, // ## ### ##
0x01, 0x80, 0x00, // ##
/*
0x00, 0x00, //
0x00, 0x08, // #
0x00, 0x48, // # #
0x00, 0x28, // # #
0x0F, 0xF8, // #########
0x00, 0x28, // # #
0x00, 0x48, // # #
0x00, 0x08, // #
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x08, 0x00, // #
0x08, 0x20, // # #
0x08, 0x10, // # #
0x0F, 0xF8, // #########
0x08, 0x10, // # #
0x08, 0x20, // # #
0x08, 0x00, // #
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x08, 0x00, // #
0x09, 0x00, // # #
0x05, 0x00, // # #
0x24, 0x08, // # # #
0x02, 0x00, // #
0x02, 0x00, // #
0x01, 0x00, // #
0xC3, 0x86, // ## ### ##
0x01, 0x80, // ## */
};
const uint8_t PROGMEM firmwareIcon[] =
{
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
0x80, 0x00, 0x00, 0x40, // # #
0x9F, 0xFF, 0x2A, 0x40, // # ############# # # # #
0x80, 0x00, 0x00, 0x40, // # #
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x7F, 0x00, 0x40, // # ####### #
0x80, 0x08, 0x00, 0x40, // # # #
0x80, 0x08, 0x00, 0x40, // # # #
0x83, 0xFF, 0xE0, 0x40, // # ############# #
0x82, 0x08, 0x20, 0x40, // # # # # #
0x82, 0x08, 0x20, 0x40, // # # # # #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x8F, 0xBE, 0xF8, 0x40, // # ##### ##### ##### #
0x80, 0x00, 0x00, 0x40, // # #
0x80, 0x00, 0x00, 0x40, // # #
0xFF, 0xFF, 0xFF, 0xC0, // ##########################
};
const uint8_t PROGMEM hardwareIcon[] =
{
0xFF, 0xFF, // ################
0x80, 0x01, // # #
0x95, 0x09, // # # # # # #
0x95, 0x09, // # # # # # #
0xBF, 0x89, // # ####### # #
0xA0, 0x89, // # # # # #
0xA0, 0x81, // # # # #
0xA0, 0x81, // # # # #
0xA0, 0x81, // # # # #
0xA0, 0x89, // # # # # #
0xBF, 0x89, // # ####### # #
0x95, 0x09, // # # # # # #
0x95, 0x09, // # # # # # #
0x80, 0x01, // # #
0xFF, 0xFF, // ################
};

View file

@ -0,0 +1,185 @@
/*
* 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/>.
*
*/
// 'Thermometer', 8x50px
#define W_BULB_ICON 8
#define H_BULB_ICON 50
extern const unsigned char ambientThermometerIcon [];
extern const unsigned char bodyThermometerIcon [];
// 'ThermoPtr', 3x5px
#define W_PTR_ICON 3
#define H_PTR_ICON 5
extern const unsigned char thermoPtr [];
// 'Bluetooth icon', 6x11px
#define W_BT_ICON 6
#define H_BT_ICON 11
extern const unsigned char BTicon [];
// 'wifiIcon', 13x10px
#define W_WIFI_ICON 13
#define H_WIFI_ICON 10
extern const unsigned char wifiIcon [];
// 'wifiInIcon', 5x5px
#define W_WIFIIN_ICON 5
#define H_WIFIIN_ICON 5
extern const unsigned char wifiInIcon [];
// 'wifiOutIcon', 5x5px
#define W_WIFIOUT_ICON 5
#define H_WIFIOUT_ICON 5
extern const unsigned char wifiOutIcon [];
// 'BatteryIcon', 15x10px
#define W_BATT_ICON 15
#define H_BATT_ICON 10
extern const unsigned char BatteryIcon [];
// 'GlowPlugIcon', 16x9px
#define W_GLOW_ICON 16
#define H_GLOW_ICON 9
extern const unsigned char GlowPlugIcon [];
// 'HeatRise', 17x2px
#define W_HEAT_ICON 17
#define H_HEAT_ICON 2
extern const unsigned char GlowHeatIcon [];
#define W_FAN_ICON 16
#define H_FAN_ICON 16
// 'Fan3_1a', 16x16px
extern const unsigned char FanIcon1 [];
// 'Fan3_2a', 16x16px
extern const unsigned char FanIcon2 [];
// 'Fan3_3a', 16x16px
extern const unsigned char FanIcon3 [];
// 'Fan3_4a', 16x16px
extern const unsigned char FanIcon4 [];
// 'FuelIcon', 7x12px
#define W_FUEL_ICON 7
#define H_FUEL_ICON 12
extern const unsigned char FuelIcon [];
// 'Target', 13x13px
#define W_TARGET_ICON 13
#define H_TARGET_ICON 13
extern const unsigned char TargetIcon [];
#define W_TIMER_ICON 15
#define H_TIMER_ICON 15
extern const unsigned char repeatIcon [];
extern const unsigned char timerID1Icon [];
extern const unsigned char timerID2Icon [];
extern const unsigned char timerIcon [];
extern const unsigned char largeTimerIcon [];
extern const uint8_t verticalRepeatIcon [];
extern const uint8_t GPIO1OFFIcon[];
extern const uint8_t GPIO1ONIcon[];
extern const uint8_t GPIO2OFFIcon[];
extern const uint8_t GPIO2ONIcon[];
extern const uint8_t CrossIcon[];
extern const uint8_t TickIcon[];
// Bitmap sizes for verticalRepeat
const uint8_t verticalRepeatWidthPixels = 6;
const uint8_t verticalRepeatHeightPixels = 15;
// Bitmap sizes for GPIOIcons
const uint8_t GPIOIconWidthPixels = 9;
const uint8_t GPIOIconHeightPixels = 9;
// Bitmap sizes for TickIcons
const uint8_t TickIconWidth = 5;
const uint8_t TickIconHeight = 5;
// Bitmap for open
extern const uint8_t OpenIcon[];
const uint8_t OpenIconWidth = 13;
const uint8_t OpenIconHeight = 7;
// Bitmap for close
extern const uint8_t CloseIcon[];
const uint8_t CloseIconWidth = 13;
const uint8_t CloseIconHeight = 7;
// Bitmap for BulbOn
extern const uint8_t BulbOnIcon[];
const uint8_t BulbOnIconWidth = 9;
const uint8_t BulbOnIconHeight = 8;
// Bitmap for BulbOff
extern const uint8_t BulbOffIcon[];
const uint8_t BulbOffIconWidth = 9;
const uint8_t BulbOffIconHeight = 8;
// Bitmap for start
extern const uint8_t startIcon[];
const uint8_t startWidth = 5;
const uint8_t startHeight = 9;
// Bitmap sizes for stop
extern const uint8_t stopIcon[];
const uint8_t stopWidth = 6;
const uint8_t stopHeight = 8;
// Bitmap for displayTimeout
extern const uint8_t displayTimeoutIcon[];
const uint8_t displayTimeoutWidth = 24;
const uint8_t displayTimeoutHeight = 10;
// Bitmap for menuTimeout
extern const uint8_t menuTimeoutIcon[];
const uint8_t menuTimeoutWidth = 24;
const uint8_t menuTimeoutHeight = 10;
// Bitmap for timeout
extern const uint8_t timeoutIcon[];
const uint8_t timeoutWidth = 9;
const uint8_t timeoutHeight = 10;
// Bitmap for refresh
extern const uint8_t refreshIcon[];
const uint8_t refreshWidth = 13;
const uint8_t refreshHeight = 11;
// Bitmap for thermostat modes
extern const uint8_t thermostatIcon[];
const uint8_t thermostatWidth = 28;
const uint8_t thermostatHeight = 34;
// Bitmap for gPIO
extern const uint8_t GPIOIcon[];
const uint8_t GPIOWidth = 20;
const uint8_t GPIOHeight = 33;
// Bitmap for firmware
extern const uint8_t firmwareIcon[];
const uint8_t firmwareWidth = 26;
const uint8_t firmwareHeight = 21;
// Bitmap for hardware
extern const uint8_t hardwareIcon[];
const uint8_t hardwareWidth = 16;
const uint8_t hardwareHeight = 15;

View file

@ -160,65 +160,17 @@ const uint8_t miniFontBitmaps[] PROGMEM =
0x40, // #
0xf8, // #####
// @78 'o' (3 pixels wide)
// @78 'O' (3 pixels wide)
0x70, // ###
0x88, // # #
0x70, // ###
// @81 ':' (1 pixel wide)
0x50, // # #
// @82 'b' (3 pixels wide)
0xf8, // #####
0x28, // # #
0x38, // ###
// @85 'd' (3 pixels wide)
0x38, // ###
0x28, // # #
0xf8, // #####
// @88 '-' (3 pixels wide)
0x20, // #
0x20, // #
0x20, // #
// @91 'N' (3 pixels wide)
0xf8, // #####
0x20, // #
0xf8, // #####
// @94 'Y' (3 pixels wide)
0xc0, // ##
0x38, // ###
0xc0, // ##
// @97 'a' (3 pixels wide)
0x10, // #
0x28, // # #
0x38, // ###
// @100 'n' (3 pixels wide)
0x38, // ###
0x20, // #
0x38, // ###
// @103 'O' (3 pixels wide)
0xF8, // #####
0x88, // # #
0xF8, // #####
// @106 'r' (3 pixels wide)
0x38, // ###
0x20, // #
0x20, // #
};
// Character descriptors for a 3x5 font
// { [Char width in bits], [Char height in bits], [Offset into tahoma_16ptCharBitmaps in bytes] }
const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{
{3, 5, 88}, // '-'
{1, 5, 0}, // '.'
{0, 0, 0}, // '/'
{3, 5, 1}, // '0'
@ -231,7 +183,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{3, 5, 22}, // '7'
{3, 5, 25}, // '8'
{3, 5, 28}, // '9'
{1, 5, 81}, // ':'
{0, 0, 0}, // ':'
{0, 0, 0}, // ';'
{0, 0, 0}, // '<'
{0, 0, 0}, // '='
@ -239,9 +191,9 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // '?'
{0, 0, 0}, // '@'
{3, 5, 33}, // 'A'
{3, 5, 82}, // 'B'
{0, 0, 0}, // 'B'
{3, 5, 36}, // 'C'
{3, 5, 85}, // 'D'
{0, 0, 0}, // 'D'
{3, 5, 72}, // 'E'
{3, 5, 39}, // 'F'
{3, 5, 42}, // 'G'
@ -251,8 +203,8 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // 'K'
{3, 5, 48}, // 'L'
{3, 5, 75}, // 'M'
{3, 5, 91}, // 'N'
{3, 5, 103}, // 'O'
{0, 0, 0}, // 'N'
{3, 5, 78}, // 'O'
{3, 5, 51}, // 'P'
{0, 0, 0}, // 'Q'
{3, 5, 66}, // 'R'
@ -262,7 +214,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{3, 5, 57}, // 'V'
{3, 5, 60}, // 'W'
{0, 0, 0}, // 'X'
{3, 5, 94}, // 'Y'
{0, 0, 0}, // 'Y'
{0, 0, 0}, // 'Z'
{0, 0, 0}, // '['
{0, 0, 0}, // '\'
@ -270,7 +222,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // '^'
{0, 0, 0}, // '_'
{2, 5, 31}, // '`' use for degree symbol
{3, 5, 97}, // 'a'
{0, 0, 0}, // 'a'
{0, 0, 0}, // 'b'
{0, 0, 0}, // 'c'
{0, 0, 0}, // 'd'
@ -283,11 +235,11 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // 'k'
{0, 0, 0}, // 'l'
{0, 0, 0}, // 'm'
{3, 5, 100}, // 'n'
{3, 5, 78}, // 'O'
{0, 0, 0}, // 'n'
{0, 0, 0}, // 'o'
{0, 0, 0}, // 'p'
{0, 0, 0}, // 'q'
{3, 5, 106}, // 'r'
{0, 0, 0}, // 'r'
{0, 0, 0}, // 's'
{0, 0, 0}, // 't'
{0, 0, 0}, // 'u'
@ -303,7 +255,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
const FONT_INFO miniFontInfo =
{
5, // Character height
'-', // Start character
'.', // Start character
'z', // End character
1, // Width, in pixels, of space character
miniFontDescriptors, // Character descriptor array

View file

@ -0,0 +1,314 @@
//
// Font data for Tahoma 16pt
//
// Generated by The Dot Factory:
// http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Dot Factory Settings
//
// Flip/Rotate Padding Removal Line Wrap Descriptors
// [X] Flip X Height(Y): Tightest (O) At column [X] Generate descriptor array
// [ ] Flip Y Width(X): Tightest ( ) At bitmap Char Width: In Bits
// 90deg Char Height: In Bits
// Font Height: In Bits
// Comments Byte [ ] Multiple descriptor arrays
// [X] Variable Name Bit layout: RowMajor
// [X] BMP visualise [#] Order: MSBfirst Create new when exceeds [80]
// [X] Char descriptor Format: Hex
// Style: Cpp Leading: 0x Image width: In Bits
// Image height: In Bits
// Variable name format
// Bitmaps: const uint8_t PROGMEM {0}Bitmaps Space char generation
// Char Info: const FONT_CHAR_INFO PROGMEM {0}Descriptors [ ] Generate space bitmap
// Font Info: const FONT_INFO {0}FontInfo [2] pixels for space char
// Width: const uint8_t {0}Width
// Height: const uint8_t {0}Height
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
#include "tahoma16.h"
// Character bitmaps for Tahoma 16pt
const uint8_t tahoma_16ptBitmaps[] PROGMEM =
{
// @0 '.' (4 pixels wide)
0x00, 0x0F, // ####
0x00, 0x0F, // ####
0x00, 0x0F, // ####
0x00, 0x0F, // ####
// @8 '0' (11 pixels wide)
0x0F, 0xF0, // ########
0x3F, 0xFC, // ############
0x7F, 0xFE, // ##############
0xFF, 0xFF, // ################
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xF0, 0x0F, // #### ####
0xFF, 0xFF, // ################
0x7F, 0xFE, // ##############
0x3F, 0xFC, // ############
0x0F, 0xF0, // ########
// @30 '1' (10 pixels wide)
0x38, 0x07, // ### ###
0x38, 0x07, // ### ###
0x38, 0x07, // ### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x07, // ###
0x00, 0x07, // ###
0x00, 0x07, // ###
// @50 '2' (11 pixels wide)
0x70, 0x07, // ### ###
0xE0, 0x0F, // ### ####
0xE0, 0x1F, // ### #####
0xE0, 0x3F, // ### ######
0xE0, 0x7F, // ### #######
0xF1, 0xF7, // #### ##### ###
0xFF, 0xE7, // ########### ###
0x7F, 0xC7, // ######### ###
0x7F, 0x87, // ######## ###
0x3E, 0x07, // ##### ###
0x00, 0x07, // ###
// @72 '3' (11 pixels wide)
0x70, 0x0E, // ### ###
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xE3, 0x87, // ### ### ###
0xE3, 0x87, // ### ### ###
0xE3, 0x87, // ### ### ###
0xE7, 0xCF, // ### ##### ####
0xFF, 0xFF, // ################
0x7E, 0xFE, // ###### #######
0x7E, 0xFE, // ###### #######
0x3C, 0x78, // #### ####
// @94 '4' (12 pixels wide)
0x00, 0xF0, // ####
0x01, 0xF0, // #####
0x07, 0x70, // ### ###
0x0E, 0x70, // ### ###
0x38, 0x70, // ### ###
0x70, 0x70, // ### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x70, // ###
0x00, 0x70, // ###
// @118 '5' (11 pixels wide)
0x00, 0x0E, // ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xFF, 0x87, // ######### ###
0xE3, 0x87, // ### ### ###
0xE3, 0xCF, // ### #### ####
0xE3, 0xFF, // ### ##########
0xE3, 0xFE, // ### #########
0xE1, 0xFC, // ### #######
0xE0, 0xF8, // ### #####
// @140 '6' (11 pixels wide)
0x07, 0xF0, // #######
0x1F, 0xFC, // ###########
0x3F, 0xFE, // #############
0x7F, 0xFF, // ###############
0xFB, 0x0F, // ##### ## ####
0xF7, 0x07, // #### ### ###
0xE7, 0x8F, // ### #### ####
0xE7, 0xFF, // ### ###########
0xE7, 0xFE, // ### ##########
0xE3, 0xFC, // ### ########
0x01, 0xF8, // ######
// @162 '7' (11 pixels wide)
0xE0, 0x01, // ### #
0xE0, 0x07, // ### ###
0xE0, 0x1F, // ### #####
0xE0, 0x7F, // ### #######
0xE1, 0xFF, // ### #########
0xE7, 0xFC, // ### #########
0xFF, 0xF0, // ############
0xFF, 0xC0, // ##########
0xFF, 0x00, // ########
0xFC, 0x00, // ######
0xF0, 0x00, // ####
// @184 '8' (11 pixels wide)
0x3C, 0x3C, // #### ####
0x7E, 0xFE, // ###### #######
0x7F, 0xFE, // ##############
0xFF, 0xFF, // ################
0xE7, 0x8F, // ### #### ####
0xE3, 0x87, // ### ### ###
0xE3, 0xC7, // ### #### ###
0xFF, 0xFF, // ################
0x7F, 0xFE, // ##############
0x7E, 0xFE, // ###### #######
0x3C, 0x7C, // #### #####
// @206 '9' (11 pixels wide)
0x1F, 0x80, // ######
0x3F, 0xC7, // ######## ###
0x7F, 0xE7, // ########## ###
0xFF, 0xE7, // ########### ###
0xF1, 0xE7, // #### #### ###
0xE0, 0xEF, // ### ### ####
0xF0, 0xDF, // #### ## #####
0xFF, 0xFE, // ###############
0x7F, 0xFC, // #############
0x3F, 0xF8, // ###########
0x0F, 0xE0, // #######
// @228 '`' (8 pixels wide)
0x3C, 0x00, // ####
0x7E, 0x00, // ######
0xE7, 0x00, // ### ###
0xC3, 0x00, // ## ##
0xC3, 0x00, // ## ##
0xE7, 0x00, // ### ###
0x7E, 0x00, // ######
0x3C, 0x00, // ####
// @244 'C' (12 pixels wide)
0x07, 0xE0, // ######
0x1F, 0xF8, // ##########
0x3F, 0xFC, // ############
0x7F, 0xFE, // ##############
0xF8, 0x1F, // ##### #####
0xF0, 0x0F, // #### ####
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0xE0, 0x07, // ### ###
0x70, 0x0E, // ### ###
0x78, 0x1E, // #### ####
// @268 ':' (4 pixels wide)
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
0x3C, 0x3C, // #### ####
// @276 ' ' (4 pixels wide)
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
0x00, 0x00, //
// @284 '-' (4 pixels wide)
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
0x03, 0xC0, // ####
// @300 'F' (9 pixels wide)
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
0xE3, 0x80, // ### ###
};
// Character descriptors for Tahoma 16pt
// { [Char width in bits], [Char height in bits], [Offset into tahoma_16ptCharBitmaps in bytes] }
const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM =
{
{4, 16, 276}, // ' '
{0, 0, 0}, // '!'
{0, 0, 0}, // '"'
{0, 0, 0}, // '#'
{0, 0, 0}, // '$'
{0, 0, 0}, // '%'
{0, 0, 0}, // '&'
{0, 0, 0}, // '''
{0, 0, 0}, // '('
{0, 0, 0}, // ')'
{0, 0, 0}, // '*'
{0, 0, 0}, // '+'
{0, 0, 0}, // ,
{8, 16, 284}, // -
{4, 16, 0}, // '.'
{0, 0, 0}, // '/'
{11, 16, 8}, // '0'
{10, 16, 30}, // '1'
{11, 16, 50}, // '2'
{11, 16, 72}, // '3'
{12, 16, 94}, // '4'
{11, 16, 118}, // '5'
{11, 16, 140}, // '6'
{11, 16, 162}, // '7'
{11, 16, 184}, // '8'
{11, 16, 206}, // '9'
{4, 16, 268}, // ':'
{0, 0, 0}, // ';'
{0, 0, 0}, // '<'
{0, 0, 0}, // '='
{0, 0, 0}, // '>'
{0, 0, 0}, // '?'
{0, 0, 0}, // '@'
{0, 0, 0}, // 'A'
{0, 0, 0}, // 'B'
{12, 16, 244}, // 'C'
{0, 0, 0}, // 'D'
{0, 0, 0}, // 'E'
{10, 16, 300}, // 'F'
{0, 0, 0}, // 'G'
{0, 0, 0}, // 'H'
{0, 0, 0}, // 'I'
{0, 0, 0}, // 'J'
{0, 0, 0}, // 'K'
{0, 0, 0}, // 'L'
{0, 0, 0}, // 'M'
{0, 0, 0}, // 'N'
{0, 0, 0}, // 'O'
{0, 0, 0}, // 'P'
{0, 0, 0}, // 'Q'
{0, 0, 0}, // 'R'
{0, 0, 0}, // 'S'
{0, 0, 0}, // 'T'
{0, 0, 0}, // 'U'
{0, 0, 0}, // 'V'
{0, 0, 0}, // 'W'
{0, 0, 0}, // 'X'
{0, 0, 0}, // 'Y'
{0, 0, 0}, // 'Z'
{0, 0, 0}, // '['
{0, 0, 0}, // '\'
{0, 0, 0}, // ']'
{0, 0, 0}, // '^'
{0, 0, 0}, // '_'
{8, 16, 228}, // '`' use for degree symbol
};
// Font information for Tahoma 16pt
// easier to leave in RAM, not that big anyway
const FONT_INFO tahoma_16ptFontInfo =
{
16, // Character height
' ', // Start character
'`', // End character
2, // Width, in pixels, of space character
tahoma_16ptDescriptors, // Character descriptor array
tahoma_16ptBitmaps, // Character bitmap array
};

View file

@ -0,0 +1,7 @@
#include "FontTypes.h"
// Font data for Tahoma 16pt
extern const uint8_t tahoma_16ptBitmaps[] PROGMEM; // stored in program flash memory
extern const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM; // stored in program flash memory
extern const FONT_INFO tahoma_16ptFontInfo;

View file

@ -29,7 +29,7 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////
#include "Tahoma24.h"
#include "tahoma24.h"
// Character bitmaps for Tahoma 24pt
const uint8_t tahoma_24ptBitmaps [] PROGMEM =

View file

@ -20,7 +20,7 @@
*/
#include <Arduino.h>
#include "KeyPad.h"
#include "keypad.h"
#include "../cfg/pins.h"
CKeyPad::CKeyPad()

View file

@ -22,30 +22,46 @@
#include <Arduino.h>
#include "Protocol.h"
#include "../Utility/DebugPort.h"
#include "../Utility/helpers.h"
#include "helpers.h"
#include "../cfg/BTCConfig.h"
#include "../Utility/macros.h"
unsigned short
CProtocol::CalcCRC(int len) const
{
// calculate a CRC-16/MODBUS checksum using the first 22 bytes of the data array
unsigned short wCRCWord = 0xFFFF;
int wLength = len;
const unsigned char* pData = Data;
while (wLength--)
{
unsigned char nTemp = *pData++ ^ wCRCWord;
wCRCWord >>= 8;
wCRCWord ^= wCRCTable[nTemp];
}
return wCRCWord;
}
void
CProtocol::setCRC()
{
CModBusCRC16 CRCengine;
setCRC(CRCengine.process(22, Data));
setCRC(CalcCRC(22));
}
void
CProtocol::setCRC(uint16_t CRC)
CProtocol::setCRC(unsigned short CRC)
{
Data[22] = (CRC >> 8) & 0xff; // MSB of CRC in Data[22]
Data[23] = (CRC >> 0) & 0xff; // LSB of CRC in Data[23]
}
uint16_t
unsigned short
CProtocol::getCRC() const
{
uint16_t CRC;
unsigned short CRC;
CRC = Data[22]; // MSB of CRC in Data[22]
CRC <<= 8;
CRC |= Data[23]; // LSB of CRC in Data[23]
@ -54,17 +70,16 @@ CProtocol::getCRC() const
// return true for CRC match
bool
CProtocol::verifyCRC(std::function<void(const char*)> pushMsg) const
CProtocol::verifyCRC(bool bSilent) const
{
char errmsg[32];
CModBusCRC16 CRCengine;
uint16_t CRC = CRCengine.process(22, Data); // calculate CRC based on first 22 bytes of our data buffer
uint16_t FrameCRC = getCRC();
unsigned short CRC = CalcCRC(22); // calculate CRC based on first 22 bytes
unsigned short FrameCRC = getCRC();
bool bOK = (FrameCRC == CRC);
if(!bOK) {
sprintf(errmsg, "verifyCRC FAILED: calc: %04X data: %04X\r\n", CRC, FrameCRC);
pushMsg(errmsg);
if(!bOK && !bSilent) {
DebugPort.print("verifyCRC FAILED: calc:");
DebugPort.print(CRC, HEX);
DebugPort.print(" data:");
DebugPort.println(FrameCRC, HEX);
}
return bOK; // does it match the stored values?
}
@ -78,7 +93,7 @@ CProtocol::operator=(const CProtocol& rhs)
void
CProtocol::setFan_Min(uint16_t Speed)
CProtocol::setFan_Min(short Speed)
{
// Minimum speed set
Controller.MinFanRPM_MSB = (Speed >> 8) & 0xff;
@ -86,17 +101,17 @@ CProtocol::setFan_Min(uint16_t Speed)
}
void
CProtocol::setFan_Max(uint16_t Speed)
CProtocol::setFan_Max(short Speed)
{
// Minimum speed set
Controller.MaxFanRPM_MSB = (Speed >> 8) & 0xff;
Controller.MaxFanRPM_LSB = (Speed >> 0) & 0xff;
}
uint16_t
short
CProtocol::getFan_Min() const
{
uint16_t retval;
short retval;
// Minimum speed get
retval = Controller.MinFanRPM_MSB;
retval <<= 8;
@ -104,10 +119,10 @@ CProtocol::getFan_Min() const
return retval;
}
uint16_t
short
CProtocol::getFan_Max() const
{
uint16_t retval;
short retval;
// Maximum speed get
retval = Controller.MaxFanRPM_MSB;
retval <<= 8;
@ -115,11 +130,11 @@ CProtocol::getFan_Max() const
return retval;
}
uint16_t
short
CProtocol::getFan_Actual() const
{
// Rx side, actual
uint16_t retval;
short retval;
retval = Heater.FanRPM_MSB;
retval <<= 8;
retval |= Heater.FanRPM_LSB;
@ -127,7 +142,7 @@ CProtocol::getFan_Actual() const
}
void
CProtocol::setFan_Actual(uint16_t Speed) // Heater side, actual
CProtocol::setFan_Actual(short Speed) // Heater side, actual
{
// actual speed set
Heater.FanRPM_MSB = (Speed >> 8) & 0xff;
@ -137,7 +152,7 @@ CProtocol::setFan_Actual(uint16_t Speed) // Heater side, actual
float
CProtocol::getGlowPlug_Current() const // glow plug current
{
uint16_t val;
short val;
val = Heater.GlowPlugCurrent_MSB;
val <<= 8;
val |= Heater.GlowPlugCurrent_LSB;
@ -145,7 +160,7 @@ CProtocol::getGlowPlug_Current() const // glow plug current
}
void
CProtocol::setGlowPlug_Current(uint16_t ampsx100) // glow plug current
CProtocol::setGlowPlug_Current(short ampsx100) // glow plug current
{
Heater.GlowPlugCurrent_MSB = (ampsx100 >> 8) & 0xff;
Heater.GlowPlugCurrent_LSB = (ampsx100 >> 0) & 0xff;
@ -154,7 +169,7 @@ CProtocol::setGlowPlug_Current(uint16_t ampsx100) // glow plug current
float
CProtocol::getGlowPlug_Voltage() const // glow plug voltage
{
uint16_t val;
short val;
val = Heater.GlowPlugVoltage_MSB;
val <<= 8;
val |= Heater.GlowPlugVoltage_LSB;
@ -163,16 +178,16 @@ CProtocol::getGlowPlug_Voltage() const // glow plug voltage
void
CProtocol::setGlowPlug_Voltage(uint16_t voltsx10) // glow plug voltage
CProtocol::setGlowPlug_Voltage(short voltsx10) // glow plug voltage
{
Heater.GlowPlugVoltage_MSB = (voltsx10 >> 8) & 0xff;
Heater.GlowPlugVoltage_LSB = (voltsx10 >> 0) & 0xff;
}
int16_t
short
CProtocol::getTemperature_HeatExchg() const // temperature of heat exchanger
{
int16_t retval;
short retval;
retval = Heater.HeatExchgTemp_MSB;
retval <<= 8;
retval |= Heater.HeatExchgTemp_LSB;
@ -180,7 +195,7 @@ CProtocol::getTemperature_HeatExchg() const // temperature of heat exchanger
}
void
CProtocol::setTemperature_HeatExchg(uint16_t degC) // temperature of heat exchanger
CProtocol::setTemperature_HeatExchg(short degC) // temperature of heat exchanger
{
Heater.HeatExchgTemp_MSB = (degC >> 8) & 0xff;
Heater.HeatExchgTemp_LSB = (degC >> 0) & 0xff;
@ -190,7 +205,7 @@ float
CProtocol::getFan_Voltage() const // fan voltage
{
if(getRunState()) { // fan volatge sensing goes stupid when main heater relay turns off!
uint16_t val;
short val;
val = Heater.FanVoltage_MSB;
val <<= 8;
val |= Heater.FanVoltage_LSB;
@ -202,7 +217,7 @@ CProtocol::getFan_Voltage() const // fan voltage
void
CProtocol::setFan_Voltage(float volts) // fan voltage
{
uint16_t val = uint16_t(volts * 10);
short val = short(volts * 10);
Heater.FanVoltage_MSB = (val >> 8) & 0xff;
Heater.FanVoltage_LSB = (val >> 0) & 0xff;
}
@ -210,7 +225,7 @@ CProtocol::setFan_Voltage(float volts) // fan voltage
void
CProtocol::setVoltage_Supply(float volts)
{
uint16_t val = uint16_t(volts * 10);
short val = short(volts * 10);
Heater.SupplyV_MSB = (val >> 8) & 0xff;
Heater.SupplyV_LSB = (val >> 0) & 0xff;
}
@ -218,7 +233,7 @@ CProtocol::setVoltage_Supply(float volts)
float
CProtocol::getVoltage_SupplyRaw() const
{
uint16_t val = 0;
short val = 0;
val = Heater.SupplyV_MSB & 0xff;
val <<= 8;
val |= Heater.SupplyV_LSB & 0xff;
@ -232,30 +247,6 @@ CProtocol::getVoltage_Supply() const
return getVoltage_SupplyRaw() + 0.6; // compensate for series protection diode
}
void
CProtocol::setAltitude(float altitude, bool valid)
{
int16_t alt = (int16_t)altitude;
Controller.Altitude_MSB = (alt >> 8) & 0xff;
Controller.Altitude_LSB = (alt >> 0) & 0xff;
if(valid) {
Controller.Unknown1_MSB = 0xeb;
Controller.Unknown1_LSB = 0x47;
}
else {
Controller.Unknown1_MSB = 0x01; // always 0x01
Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
}
}
int
CProtocol::getAltitude() const
{
int16_t alt = (Controller.Altitude_MSB << 8) | Controller.Altitude_LSB;
return alt;
}
void
CProtocol::Init(int FrameMode)
{
@ -264,7 +255,7 @@ CProtocol::Init(int FrameMode)
Controller.Len = 22;
Controller.Command = 0; // NOP
setTemperature_Actual(18); // 1degC / digit
setHeaterDemand(20); // 1degC / digit
setTemperature_Desired(20); // 1degC / digit
setPump_Min(1.4f); // Hz
setPump_Max(4.3f); // Hz
setFan_Min(1450); // 1RPM / digit
@ -278,8 +269,8 @@ CProtocol::Init(int FrameMode)
Controller.Prime = 0; // 00: normal, 0x5A: fuel prime
Controller.Unknown1_MSB = 0x01; // always 0x01
Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
Controller.Altitude_MSB = 0x0d; // basic controllers always 0x0d
Controller.Altitude_LSB = 0xac; // basic controllers always 0xac 16bit: "3500"
Controller.Unknown2_MSB = 0x0d; // always 0x0d
Controller.Unknown2_LSB = 0xac; // always 0xac 16bit: "3500" ?? Ignition fan max RPM????
setCRC();
}
else if(FrameMode == HeatMode){
@ -336,7 +327,7 @@ CProtocol::setSystemVoltage(float fVal)
int CProtocolPackage::getRunStateEx() const
{
int runstate = getRunState();
if(isCyclicStopStartActive()) {
if(isCyclicActive()) {
// special states for cyclic suspended
switch(runstate) {
case 0: runstate = 10; break; // standby, awaiting temperature drop
@ -382,38 +373,36 @@ CProtocolPackage::getRunStateStr() const
const char* Errstates [] PROGMEM = {
"", // [0]
"", // [1]
"Low voltage", // [2] E-01
"High voltage", // [3] E-02
"Glow plug fault", // [4] E-03
"Pump fault", // [5] E-04
"Overheat", // [6] E-05
"Motor fault", // [7] E-06
"Comms fault", // [8] E-07
"Flame out", // [9] E-08
"Temp sense", // [10] E-09
"Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5
"Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Excess fuel usage", // [13] E-12 SmartError manufactured state - excess fuel consumed
"",
"",
"Low voltage", // E-01
"High voltage", // E-02
"Glow plug fault", // E-03
"Pump fault", // E-04
"Overheat", // E-05
"Motor fault", // E-06
"Comms fault", // E-07
"Flame out", // E-08
"Temp sense", // E-09
"Ignition fail", // E-10 SmartError manufactured state - sensing runstate 2 -> >5
"Failed 1st ignition attempt", // E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Unknown error?" // mystery code!
};
const char* ErrstatesEx [] PROGMEM = {
"E-00: OK", // [0]
"E-00: OK", // [1]
"E-01: Low voltage", // [2] E-01
"E-02: High voltage", // [3] E-02
"E-03: Glow plug fault", // [4] E-03
"E-04: Pump fault", // [5] E-04
"E-05: Overheat", // [6] E-05
"E-06: Motor fault", // [7] E-06
"E-07: No heater comms", // [8] E-07
"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 ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"E-12: Excess fuel shutdown", // [13] E-12 SmartError manufactured state - excess fuel consumed
"E-00: OK",
"E-00: OK",
"E-01: Low voltage", // E-01
"E-02: High voltage", // E-02
"E-03: Glow plug fault", // E-03
"E-04: Pump fault", // E-04
"E-05: Overheat", // E-05
"E-06: Motor fault", // E-06
"E-07: No heater comms", // E-07
"E-08: Flame out", // E-08
"E-09: Temp sense", // E-09
"E-10: Ignition fail", // E-10 SmartError manufactured state - sensing runstate 2 -> >5
"E-11: Failed 1st ignition attempt", // E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Unknown error?" // mystery code!
};
@ -439,43 +428,31 @@ CProtocolPackage::setRefTime()
_timeStamp.setRefTime();
}*/
char dbgFrameMsg[192];
void
CProtocolPackage::reportFrames(bool isOEM, std::function<void(const char*)> pushMsg)
CProtocolPackage::reportFrames(bool isOEM)
{
dbgFrameMsg[0] = 0;
_timeStamp.report(dbgFrameMsg); // absolute time
_timeStamp.report(); // absolute time
if(isOEM) {
DebugReportFrame("OEM:", Controller, TERMINATE_OEM_LINE ? "\r\n" : " ", dbgFrameMsg);
DebugReportFrame("OEM:", Controller, TERMINATE_OEM_LINE ? "\r\n" : " ");
}
else {
DebugReportFrame("BTC:", Controller, TERMINATE_BTC_LINE ? "\r\n" : " ", dbgFrameMsg);
DebugReportFrame("BTC:", Controller, TERMINATE_BTC_LINE ? "\r\n" : " ");
}
DebugReportFrame("HTR:", Heater, "\r\n", dbgFrameMsg);
pushMsg(dbgFrameMsg);
DebugReportFrame("HTR:", Heater, "\r\n");
}
int
CProtocolPackage::getErrState() const
CProtocolPackage::getErrState() const
{
static int CommsErrHoldoff = 5;
if(getBlueWireStat() & 0x01) {
if(CommsErrHoldoff)
CommsErrHoldoff--; // expire holdoff events, don't be too trigger happy on comms error
else
return 8; // persistently not seeing heater data - force E-07
return 8; // force E-07 - we're not seeing heater data
}
else {
CommsErrHoldoff = 5;
int smartErr = getSmartError();
if(smartErr)
return smartErr;
else
return Heater.getErrState();
}
int smartErr = getSmartError();
if(smartErr)
return smartErr;
else
return Heater.getErrState();
}

View file

@ -0,0 +1,251 @@
/*
* 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/>.
*
*/
#ifndef _CPROTOCOL_H_
#define _CPROTOCOL_H_
#include <Arduino.h>
#include "../Utility/UtilClasses.h"
class CProtocol {
public:
union {
unsigned char Data[24];
struct {
unsigned char Byte0; // [0] always 0x76
unsigned char Len; // [1] always 0x16 == 22
unsigned char Command; // [2] transient commands: 00: NOP, 0xa0 START, 0x05: STOP
unsigned char ActualTemperature; // [3] 1degC / digit
unsigned char DesiredTemperature; // [4] 1degC / digit
unsigned char MinPumpFreq; // [5] 0.1Hz/digit
unsigned char MaxPumpFreq; // [6] 0.1Hz/digit
unsigned char MinFanRPM_MSB; // [7] 16 bit - big endian MSB
unsigned char MinFanRPM_LSB; // [8] 16 bit - big endian LSB : 1 RPM / digit
unsigned char MaxFanRPM_MSB; // [9] 16 bit - big endian MSB
unsigned char MaxFanRPM_LSB; // [10] 16 bit - big endian LSB : 1 RPM / digit
unsigned char OperatingVoltage; // [11] 120, 240 : 0.1V/digit
unsigned char FanSensor; // [12] SN-1 or SN-2
unsigned char OperatingMode; // [13] 0x32:Thermostat, 0xCD:Fixed
unsigned char MinTemperature; // [14] Minimum settable temperature
unsigned char MaxTemperature; // [15] Maximum settable temperature
unsigned char GlowDrive; // [16] power to supply to glow plug
unsigned char Prime; // [17] 00: normal, 0x5A: fuel prime
unsigned char Unknown1_MSB; // [18] always 0x01
unsigned char Unknown1_LSB; // [19] always 0x2c "300 secs = max run without burn detected"?
unsigned char Unknown2_MSB; // [20] always 0x0d
unsigned char Unknown2_LSB; // [21] always 0xac "3500 ?"
unsigned char CRC_MSB; // [22]
unsigned char CRC_LSB; // [23]
} Controller;
struct {
unsigned char Byte0; // always 0x76
unsigned char Len; // always 0x16 == 22 bytes
unsigned char RunState; // operating state
unsigned char ErrState; // 0: OFF, 1: ON, 2+ (E-0n + 1)
unsigned char SupplyV_MSB; // 16 bit - big endian MSB
unsigned char SupplyV_LSB; // 16 bit - big endian MSB : 0.1V / digit
unsigned char FanRPM_MSB; // 16 bit - big endian MSB
unsigned char FanRPM_LSB; // 16 bit - big endian LSB : 1 RPM / digit
unsigned char FanVoltage_MSB; // 16 bit - big endian MSB
unsigned char FanVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
unsigned char HeatExchgTemp_MSB; // 16 bit - big endian MSB
unsigned char HeatExchgTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
unsigned char GlowPlugVoltage_MSB; // 16 bit - big endian MSB
unsigned char GlowPlugVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
unsigned char GlowPlugCurrent_MSB; // 16 bit - big endian MSB
unsigned char GlowPlugCurrent_LSB; // 16 bit - big endian LSB : 10mA / digit
unsigned char ActualPumpFreq; // fuel pump freq.: 0.1Hz / digit
unsigned char StoredErrorCode; //
unsigned char Unknown1; // always 0x00
unsigned char FixedPumpFreq; // fixed mode frequency set point: 0.1Hz / digit
unsigned char Unknown2; // always 0x64 "100 ?"
unsigned char Unknown3; // always 0x00
unsigned char CRC_MSB;
unsigned char CRC_LSB;
} Heater;
};
static const int CtrlMode = 1;
static const int HeatMode = 2;
const unsigned short wCRCTable[256] = {
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040
};
public:
CProtocol() { Init(0); };
CProtocol(int TxMode) { Init(TxMode); };
void Init(int Txmode);
// CRC handlers
unsigned short CalcCRC(int len) const; // calculate the CRC upon len bytes
void setCRC(); // calculate and set the CRC in the buffer
void setCRC(unsigned short CRC); // set the CRC in the buffer
unsigned short getCRC() const; // extract CRC value from buffer
bool verifyCRC(bool silent=false) const; // return true for CRC match
void setActiveMode() { Controller.Byte0 = 0x76; }; // this allows heater to save tuning params to EEPROM
void setPassiveMode() { Controller.Byte0 = 0x78; }; // this prevents heater saving tuning params to EEPROM
// command helpers
void resetCommand() { setRawCommand(0x00); };
void onCommand() { setRawCommand(0xA0); };
void offCommand() { setRawCommand(0x05); };
// raw command
int getRawCommand() const { return Controller.Command; };
void setRawCommand(int mode) { Controller.Command = mode; };
// Run state
unsigned char getRunState() const { return Heater.RunState; };
void setRunState(unsigned char state) { Heater.RunState = state; };
unsigned char getErrState() const { return Heater.ErrState; };
void setErrState(unsigned char state) { Heater.ErrState = state; };
unsigned char getStoredErrCode() const { return Heater.StoredErrorCode; };
void setStoredErrCode(unsigned char state) { Heater.StoredErrorCode = state; };
//
float getVoltage_Supply() const;
float getVoltage_SupplyRaw() const;
void setVoltage_Supply(float volts);
float getSystemVoltage() const { return float(Controller.OperatingVoltage) * 0.1; };
void setSystemVoltage(float val);
// fan set/get
short getFan_Actual() const; // Heater side, actual
short getFan_Min() const; // Controller side, define min fan speed
short getFan_Max() const; // Controller side, define max fan speed
void setFan_Actual(short speed); // Heater side, actual
void setFan_Min(short speed); // Controller side, define min fan speed
void setFan_Max(short speed); // Controller side, define max fan speed
float getFan_Voltage() const; // fan voltage
void setFan_Voltage(float volts); // fan voltage
// pump set/get
void setPump_Min(float Freq) { Controller.MinPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Max(float Freq) { Controller.MaxPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Actual(float Freq) { Heater.ActualPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
void setPump_Fixed(float Freq) { Heater.FixedPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
float getPump_Min() const { return float(Controller.MinPumpFreq) * 0.1f; }; // Tx side, min pump freq
float getPump_Max() const { return float(Controller.MaxPumpFreq) * 0.1f; }; // Tx side, max pump freq
float getPump_Actual() const { return float(Heater.ActualPumpFreq) * 0.1f; }; // Rx style, actual
float getPump_Fixed() const { return float(Heater.FixedPumpFreq) * 0.1f; }; // Fixed mode pump frequency
void setPump_Prime(bool on) { Controller.Prime = on ? 0x5A : 0; };
// temperature set/get
void setTemperature_Desired(unsigned char degC) { Controller.DesiredTemperature = degC; };
void setTemperature_Min(unsigned char degC) { Controller.MinTemperature = degC; };
void setTemperature_Max(unsigned char degC) { Controller.MaxTemperature = degC; };
void setTemperature_Actual(unsigned char degC) { Controller.ActualTemperature = degC; };
unsigned char getTemperature_Desired() const { return Controller.DesiredTemperature; };
unsigned char getTemperature_Min() const { return Controller.MinTemperature; };
unsigned char getTemperature_Max() const { return Controller.MaxTemperature; };
unsigned char getTemperature_Actual() const { return Controller.ActualTemperature; };
void setThermostatModeProtocol(unsigned on);
bool isThermostat() const { return Controller.OperatingMode == 0x32; };
// glow plug
float getGlowPlug_Current() const; // glow plug current
float getGlowPlug_Voltage() const; // glow plug voltage
void setGlowPlug_Current(short ampsx100); // glow plug current
void setGlowPlug_Voltage(short voltsx10); // glow plug voltage
void setGlowDrive(unsigned char val) { Controller.GlowDrive = val; };
unsigned char getGlowDrive() const { return Controller.GlowDrive; };
// heat exchanger
short getTemperature_HeatExchg() const; // temperature of heat exchanger
void setTemperature_HeatExchg(short degC); // temperature of heat exchanger
void DebugReport(const char* hdr, const char* ftr);
CProtocol& operator=(const CProtocol& rhs);
};
class CModeratedFrame : public CProtocol {
unsigned long lastTime;
public:
CModeratedFrame() { lastTime = 0; };
void setTime() { lastTime = millis(); };
long elapsedTime() { return millis() - lastTime; };
};
class CProtocolPackage {
CProtocol Heater;
CProtocol Controller;
CContextTimeStamp _timeStamp;
public:
void set(const CProtocol& htr, const CProtocol& ctl) { Heater = htr; Controller = ctl; };
int getRunState() const { return Heater.getRunState(); };
int getRunStateEx() const; // extra support for cyclic thermostat mode
const char* getRunStateStr() const;
int getErrState() const;
const char* getErrStateStr() const;
const char* getErrStateStrEx() const;
float getBattVoltage() const { return Heater.getVoltage_Supply(); };
bool isThermostat() const { return Controller.isThermostat(); };
float getTemperature_Desired() const { return float(Controller.getTemperature_Desired()); };
float getTemperature_HeatExchg() const { return float(Heater.getTemperature_HeatExchg()); };
float getTemperature_Min() const { return float(Controller.getTemperature_Min()); };
float getTemperature_Max() const { return float(Controller.getTemperature_Max()); };
float getPump_Fixed() const { return Heater.getPump_Fixed(); };
float getPump_Actual() const { return Heater.getPump_Actual(); };
float getPump_Min() const { return Controller.getPump_Min(); };
float getPump_Max() const { return Controller.getPump_Max(); };
float getFan_Actual() const { return Heater.getFan_Actual(); };
short getFan_Min() const { return Controller.getFan_Min(); };
short getFan_Max() const { return Controller.getFan_Max(); };
float getFan_Voltage() const { return Heater.getFan_Voltage(); };
int getFan_Sensor() const { return Controller.Controller.FanSensor; };
float getGlowPlug_Power() const { return Heater.getGlowPlug_Current() * Heater.getGlowPlug_Voltage(); };
float getGlow_Voltage() const { return Heater.getGlowPlug_Voltage(); };
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
int getGlow_Drive() const { return Controller.getGlowDrive(); };
// void setRefTime();
void reportFrames(bool isOEM);
};
#endif

View file

@ -0,0 +1,120 @@
/*
* 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 "SmartError.h"
#include "TxManage.h"
CSmartError::CSmartError()
{
reset();
}
void
CSmartError::reset()
{
m_prevRunState = 0;
m_Error = 0;
m_bInhibit = false;
}
// we use inhibit when we manually command the heater off during preheat
// otherwise we'll register an ignition fail event
void
CSmartError::inhibit()
{
m_bInhibit = true;
m_Error = 0;
}
// accept a fresh heater frame
// inpsect the advertised run state, tracking when and how it transitions out
// of preheat especially.
// abnormal transitions are registered and becoem our smart m_Error
// In addition, the hetaer frame has the ErrState updated to track the
// smart error, providing no heater error exists!
void
CSmartError::monitor(const CProtocol& heaterFrame)
{
bool bSilent = true;
if(heaterFrame.verifyCRC(bSilent)) { // check but don't report dodgy frames to debug
// only accept valid heater frames!
monitor(heaterFrame.getRunState());
}
}
// test the new run state value, comparing to previous
// detect abnormal transitions
void
CSmartError::monitor(unsigned char newRunState)
{
// check if moving away from heater Idle state (S0)
// especially useful if an OEM controller exists
if((m_prevRunState == 0) && newRunState) {
// reset the smart error
m_Error = 0;
m_bInhibit = false;
}
if(!m_bInhibit) {
if(m_prevRunState == 2) { // preheat state (S2)
if(newRunState == 4) {
// transitioned from preheat to ignited
// - all good!
m_Error = 0;
}
else if(newRunState > 5) {
// transitioned from preheat to post glow
// - second ignition attempt failed, heater is shutting down
m_Error = 11;
}
else if(newRunState == 3) {
// transitioned from preheat to retry
// - first ignition attempt failed, heater will retry
m_Error = 12;
}
}
}
if(m_prevRunState != newRunState) {
// check for transition to startup
// - force cancellation of an on request if we generated it
if(newRunState >= 2) {
TxManage.queueOnRequest(false); // ensure ON request is cancelled
}
// check for transition to shutdown
// - force cancellation of an off request if we generated it
if(newRunState >= 7 || newRunState == 0) {
TxManage.queueOffRequest(false); // ensure OFF request is cancelled
}
}
m_prevRunState = newRunState;
}
// return our smart error, if it exists, as the registered code
unsigned char
CSmartError::getError()
{
if(m_Error) {
return m_Error;
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show more