/* portableReadout.ino using Teensy 3.6 and 3.2" color TfT touchscreen Display
Controller ILL9341 320x240, with touchscreen XPT2046
Using the Teensy 3.6 and BME 680 sensor
Implements the Teensy built-in RTC and the built-in SD.
A receiver gets RF sensor messages from six transmitters on the 433 MHz band.
There is 2-way communications with a Picaxe 08M2 which control power.
This has a 'standby' mode which records one of each message on a 15-minute cycle.
It also records and displays the sensor outputs of the BME680
The contents of any day file can be read out and sent to the USB.
Provides for Daily Saving Time and minutes adjustment
It is powered by a Li Ion battey and has a charger.
New version John Saunders 9/18/2023
*/
#include "ILI9341_t3.h"
#include "SPI.h"
#define BUILTIN_SDCARD 254
#include "SD.h"
#include "XPT2046_Touchscreen.h"
#include "EEPROM.h"
#include <font_Arial.h> // from ILI9341_t3
#define blueLED 6
#define intPort 33
#define chargePort 23
#define blPort 35 //positive turns on backlight, 56 to 91 MA at 48MHz
#define PIN_T_CS 4
#define PIN_IRQ 5
#define PIN_TFT_CS 10
#define PIN_DC 9
#define PIN_RST 24
#define picIRQ 7
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
#define TFT_NAVY 0x000F /* 0, 0, 128 */
#define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */
#define TFT_MAROON 0x7800 /* 128, 0, 0 */
#define TFT_PURPLE 0x780F /* 128, 0, 128 */
#define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */
#define TFT_LIGHTGREY 0xD69A /* 211, 211, 211 */
#define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */
#define TFT_BLUE 0x001F /* 0, 0, 255 */
#define TFT_GREEN 0x07E0 /* 0, 255, 0 */
#define TFT_CYAN 0x07FF /* 0, 255, 255 */
#define TFT_RED 0xF800 /* 255, 0, 0 */
#define TFT_MAGENTA 0xF81F /* 255, 0, 255 */
#define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */
#define TFT_WHITE 0xFFFF /* 255, 255, 255 */
#define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */
#define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */
#define TFT_PINK 0xFE19 /* 255, 192, 203 */ //Lighter pink, was 0xFC9F
#define TFT_BROWN 0x9A60 /* 150, 75, 0 */
#define TFT_GOLD 0xFEA0 /* 255, 215, 0 */
#define TFT_SILVER 0xC618 /* 192, 192, 192 */
#define TFT_SKYBLUE 0x867D /* 135, 206, 235 */
#define TFT_VIOLET 0x915C /* 180, 46, 226 */
// Touchscreen Button values for sensing.
// Button indices are 0 - 3 CW from top left P, N, B, Y + C in center
// X increases left to right
#define YP_X_MIN 620
#define YP_X_MAX 1800
#define BN_X_MIN 2400
#define BN_X_MAX 3300
// Y increases top to bottom
#define PN_Y_MIN 2220
#define PN_Y_MAX 2830
#define YB_Y_MIN 3300
#define YB_Y_MAX 3600
#define C_X_MIN 870
#define C_X_MAX 3120
#define C_Y_MIN 1400
#define C_Y_MAX 1900
// P N B Y C
const int buttXmin[5] = {YP_X_MIN, BN_X_MIN, BN_X_MIN, YP_X_MIN, C_X_MIN};
const int buttXmax[5] = {YP_X_MAX, BN_X_MAX, BN_X_MAX, YP_X_MAX, C_X_MAX};
const int buttYmin[5] = {PN_Y_MIN, PN_Y_MIN, YB_Y_MIN, YB_Y_MIN, C_Y_MIN};
const int buttYmax[5] = {PN_Y_MAX, PN_Y_MAX, YB_Y_MAX, YB_Y_MAX, C_Y_MAX};
// P N B Y C
const int buttXmin[5] = {YP_X_MIN, BN_X_MIN, BN_X_MIN, YP_X_MIN, C_X_MIN};
const int buttXmax[5] = {YP_X_MAX, BN_X_MAX, BN_X_MAX, YP_X_MAX, C_X_MAX};
const int buttYmin[5] = {PN_Y_MIN, PN_Y_MIN, YB_Y_MIN, YB_Y_MIN, C_Y_MIN};
const int buttYmax[5] = {PN_Y_MAX, PN_Y_MAX, YB_Y_MAX, YB_Y_MAX, C_Y_MAX};
// Touchscreen button size and placeement. These correspond to the index in buttInx
// C
// P N
// Y B
// P N B Y C
const int buttXpos[5] = { 20, 170, 170, 20, 40};
const int buttYpos[5] = {140, 140, 200, 200, 70};
const int buttWidth[5] = {130, 130, 130, 130, 250};
const int buttDepth[5] = { 40, 40, 40, 40, 50};
const char *navButtons[] = { // Navigation button labels2)
// 0 1 2 3 4 5 6 7
"Messages", " Temps", "Humidity", "Voltages", " Gas Qual", " Garage", "Activity", "Year Set",
// 8 9 10 11 12 13 14
"Month Set", "Date Set" , "Adj Year", "Adj Month", "Adj Date", "Adj Hours", "Adj Minutes",
// 15 16 17 18 19
"ST/DST", " Home", "Settings", "Rec Time", "View Time",
};
const char *actionButtons[] = { //Action button labels
// A = 0 B = 1 C = 2 D = 3
"Edit Clock", "Playback", "Standard", "Day Sav",
// E = 4 F = 5 G = 6
"increase", "decrease", "Store Changes",
// H = 7 I = 8 J = 9 K = 10 L = 11
" Read File", "Next Date", "Prev Date", "Next Month", "Prev Month",
// M N O P Q
"Store Changes", "decrease", "increase", "decrease", "increase"
};
const char *headers[] = { // Goes at the top of most pages
// 0 1 2 3 4
"Temperatures", "Humidities", "Charge and Battery Voltage", "Gas Quality", "Garage State",
// 5 6 7 8 9
"Read Year Set", "Read Month Set", "Read Date Set", "Adjust Year", "Adjust Month",
// 10 11 12 13
"Adjust Date", "Adjust Hour", "Adjust Minutes", "Daylight Saving",
// 14 15 16
"John Saunders' contraption", "Activity Monitor", "Settings Menu" ,
// 17 18
"Record Period = ", "Activity View Time = "
};
struct page_t {
uint8_t hdrInx; //index into headers, 21 for no header
uint8_t tdDisp; // 0 = dispBigTime(), 1 = dispTimeDate(), 2 = dispReadDate(), 3 dispTimeDate
uint8_t buttInx[5]; // Index to navButtons if numeric,jumps to next sysMode
// Index to actionButtons if alpha, index denotes action
};
page_t Pages[] = {
// messages - 0 temperatures - 1 humidities - 2
{ 21, 21, 21, 21, 1, 16, 21}, {0, 3, 21, 21, 2, 0, 21}, {1, 3, 21, 21, 3, 1, 21},
// voltages - 3 Gas quality -4 Garage - 5
{2, 3, 21, 21, 4, 2, 21}, {3, 3, 21, 21, 5, 3, 21}, {4, 3, 21, 21, 0, 4, 21},
// activity- 6 Year set - 7 month set - 8
{15, 3, 21, 21, 0, 16, 21}, {5, 2, 'F', 'E', 8, 9, 'H'}, {6, 2, 'L', 'K', 9, 7, 'H'},
// Date set - 9 Adjust Year - 10 Adjust Month - 11
{7, 2, 'J', 'I', 7, 8, 'H'}, {8, 1, 'F', 'E', 11, 16, 'G'}, {9, 1, 'F', 'E', 12, 10, 'G'},
// Adjust Date - 12 Adjust Hours = 13 // Adjust Minutes - 14
{10, 1, 'F', 'E', 13, 11, 'G'}, {11, 1, 'F', 'E', 14, 12, 'G'}, {12, 1, 'F', 'E', 15, 13, 'G'},
// Adjust Daylight Savings -15 main - 16 settings - 17
{13, 3, 'C', 'D', 16, 21, 'M'}, {14, 0, 17, 'B', 6, 0, 21}, {16, 3, 'A', 15, 19, 18, 21},
// Record Interval - 18 Activity Time - 19
{17, 4, 21, 21, 'N', 'O', 'M'}, {18, 5, 21, 21, 'P', 'Q', 'M'}
};
// Objects:
ILI9341_t3 TFTscreen = ILI9341_t3(PIN_TFT_CS, PIN_DC, PIN_RST, 11, 13, 12);
//XPT2046_Touchscreen ts = XPT2046_Touchscreen(PIN_T_CS, PIN_IRQ);
XPT2046_Touchscreen ts = XPT2046_Touchscreen(PIN_T_CS); // Interrupt disabled
// --------------- DME688 includes, etc ---------------
// I2C interface address = 0x77, SCL (yellow pin 19), SDA (blue pin 18)
#include "Zanshin_BME680.h"
BME680_Class BME680;
// Several other SD libraries did not recognize BUILTIN_SDCARD and the SD needed updating
File file; //The SD object is in the SD library.
/*********************************************************************
Timekeeping functions
**********************************************************************
*/
#include "teensyTimeLib.h"
// RTC object is pre-instantiated in the library:
tmElements_t locTm, editTm;
utime_t locTt, untTt, editTt;
uint8_t tzHours; //Hours fro GMT
uint8_t clockList[7];
uint8_t editList[7];
const char *dayName[8] = {
"Sunday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};
const char *monthName[13] = {
"January", "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
void timeDateGet(void) {
locTt = untTt - (tzHours * SECS_PER_HOUR);
breakTime(locTt, &locTm);
clockList[0] = locTm.Second; // Not adjustable 0 - 59
clockList[1] = locTm.Minute; // 0 - 59
clockList[2] = locTm.Hour; // 0 - 23
clockList[5] = locTm.Year; // - 2000
clockList[6] = locTm.Wday; // Not adjustable 1 (Sun) - 7
clockList[4] = locTm.Day;
clockList[3] = locTm.Month;
}
char chargeFlag;
/*********************************************************************
Display functions
**********************************************************************
*/
int sysMode;
const int hdrPos = 40;
void displayTimeDate(void) {
char timeDateBuf[30];
static uint8_t oldHour, oldMin, oldSec;
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", oldHour, oldMin, oldSec, clockList[3], clockList[4], clockList[5]);
TFTscreen.setCursor(0, 13);
TFTscreen.print(timeDateBuf);
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", clockList[2], clockList[1], clockList[0], clockList[3], clockList[4], clockList[5]);
TFTscreen.setTextColor(TFT_GOLD); // prints orange lettrs to TFT display
TFTscreen.setCursor(0, 13);
TFTscreen.setFont(Arial_16);
TFTscreen.print(timeDateBuf);
oldHour = clockList[2];
oldMin = clockList[1];
oldSec = clockList[0];
}
void displayEditDate(void) {
char timeDateBuf[30];
static uint8_t oldHour, oldMin, oldSec;
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", oldHour, oldMin, oldSec, editList[3], editList[4], editList[5]);
TFTscreen.setCursor(0, 13);
TFTscreen.print(timeDateBuf);
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", editList[2], editList[1], editList[0], editList[3], editList[4], editList[5]);
TFTscreen.setTextColor(TFT_WHITE); // prints orange lettrs to TFT display
TFTscreen.setCursor(0, 13);
TFTscreen.setFont(Arial_16);
TFTscreen.print(timeDateBuf);
oldHour = editList[2];
oldMin = editList[1];
oldSec = editList[0];
}
void displayPeriod(int pVal) {
TFTscreen.fillRect(260, hdrPos, 60, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(260, hdrPos);
TFTscreen.print(pVal, DEC);
}
void displayBigTime(int dpos, int tpos) {
char timeBuf[25];
static uint8_t oldHour, oldMin, oldSec;
sprintf(timeBuf, " %s,%s %02u,20%02u", dayName[clockList[6]], monthName[clockList[3]], clockList[4], clockList[5]);
TFTscreen.setFont(Arial_16);
TFTscreen.fillRect(0, dpos, 320, 25, TFT_BLACK);
TFTscreen.setTextColor(TFT_GREEN);
TFTscreen.setCursor(0, dpos);
TFTscreen.print(timeBuf);
sprintf(timeBuf, "%02u:%02u:%02u", oldHour, oldMin, oldSec);
TFTscreen.setFont(Arial_40);
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
TFTscreen.setCursor(0, tpos);
TFTscreen.print(timeBuf);
sprintf(timeBuf, "%02u:%02u:%02u", clockList[2], clockList[1], clockList[0]);
TFTscreen.setTextColor(TFT_ORANGE);
TFTscreen.setCursor(0, tpos);
TFTscreen.print(timeBuf);
TFTscreen.setFont(Arial_16);
TFTscreen.setCursor(235, (tpos + 15));
if (tzHours == 7) {
TFTscreen.print(" PDST");
}
if (tzHours == 8) {
TFTscreen.print(" PST");
}
oldHour = clockList[2];
oldMin = clockList[1];
oldSec = clockList[0];
}
uint8_t readDateVal;
uint8_t readMonthVal;
uint8_t readYearVal;
void displayReadDate(int pos) {
char readDateBuf[20];
TFTscreen.fillRect(10, (pos - 12), 230, 20, TFT_BLACK);
TFTscreen.setCursor(10, pos);
TFTscreen.setFont(Arial_16);
sprintf(readDateBuf, "%02u/%02u/20%02u", readMonthVal, readDateVal, readYearVal);
TFTscreen.setTextColor(TFT_YELLOW); // prints orange lettrs to TFT display
TFTscreen.print(readDateBuf);
}
void dispHourMin(uint8_t inx) {
TFTscreen.fillRect(100, 140, 98, 30, TFT_BLACK);
TFTscreen.setCursor((buttXpos[4] + 180), (buttYpos[4] + 10));
TFTscreen.setFont(Arial_20);
TFTscreen.setTextColor(TFT_ORANGE);
TFTscreen.print(editList[inx]);
}
void dispHeader(void) {
uint8_t index;
TFTscreen.fillRect(0, hdrPos, 339, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(5, hdrPos);
index = Pages[sysMode].hdrInx;
if (index != 21) {
TFTscreen.print(headers[index]);
}
if (sysMode == 6) {
displayBattVolt(255, hdrPos);
}
}
void displayBattVolt(uint8_t xPos, uint8_t yPos) {
TFTscreen.setCursor(xPos, yPos);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_GREEN);
if (msgs[11].msgData[6] > '3') {
TFTscreen.setTextColor(TFT_BLUE);
}
else {
if (msgs[11].msgData[8] < '5') {
TFTscreen.setTextColor(TFT_RED);
}
}
for (int i = 6; i < 10; i++) {
TFTscreen.write(msgs[11].msgData[i]);
}
}
void displayMsgNames(uint8_t index, int pos) {
TFTscreen.fillRect(0, pos, 339, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(15, pos);
TFTscreen.print(msgNames[index]);
TFTscreen.setCursor(150, pos);
TFTscreen.print(msgs[index].ageing);
}
void displayButtons(void) { // Displays the buttons for the current sysMode
uint8_t buttVal;
for (int buttID = 0; buttID < 5; buttID++) {
buttVal = Pages[sysMode].buttInx[buttID];
if (((buttVal != 0) && (buttVal != 21)) || ((buttVal == 0) && (buttID < 4) )) { // erase old button
TFTscreen.fillRect(buttXpos[buttID], buttYpos[buttID], buttWidth[buttID], buttDepth[buttID], TFT_BLACK);
delay(10);
TFTscreen.drawRect(buttXpos[buttID], buttYpos[buttID], buttWidth[buttID], buttDepth[buttID], TFT_WHITE);
delay(10);
}
TFTscreen.setCursor((buttXpos[buttID] + 10), (buttYpos[buttID] + 10));
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
if (((buttVal > 0) && (buttVal < 20)) || ((buttVal == 0) && (buttID < 4) )) {
TFTscreen.print(navButtons[buttVal]);
}
if ((buttVal >= 'A') && (buttVal < 'Z')) {
TFTscreen.print(actionButtons[(buttVal - 'A')]);
}
delay(20);
}
}
/*********************************************************************
RF Message functions for parsing and display of individual fields
**********************************************************************
*/
// index into mesgs table from keyCode - 'n', the ID which starts each message
// n o p q r s t u v w x y z
const int msgInx[13] = {3, 15, 15, 11, 2, 1, 0, 5, 15, 15, 6, 15, 4};
const int msgSize = 35;
const int nameSize = 14;
struct msg_t {
char code;
uint8_t len;
uint8_t hours;
uint8_t mins;
uint16_t ageing; //0 initially, 1 if a message has been received
char msgData[msgSize];
};
const char *msgNames[] = { // Goes at the top of most pages
// 0 1 2 3 4
"Time", "Solar", "Barometer", "Gas Quality", "Gas Utility",
// 5 6 7 8 9
"Garage Fan", "NIXIE Clock", "Test", "Measurement", "Power",
// 10 11 12
"Event", "Battery", "Environmental"
};
const int numMsgs = 13;
msg_t msgs[numMsgs] = { //Includes both RF and BME680 fields. These values are meaningless placeholders
{'t', 10, 14, 23, 0, ",04,24,11,04, " }, // 0
{'s', 17, 24, 11, 0, ",068, 057, 070, 557, " }, // 1
{'r', 19, 14, 23, 0, ",987,176,0187,0444, " }, // 2
{'n', 17, 14, 23, 0, ",A, 14.173, 24.309, " }, // 3
{'z', 14, 14, 23, 0, ",0083.8,00479, " }, // 4
{'u', 11, 14, 23, 0, ",077, D, C, S, " }, // 5
{'x', 16, 14, 23, 0, ",1,P,D,11,08,526, " }, // 6
{'p', 8, 14, 23, 0, ",38.562, " }, // 7
{'v', 6, 14, 23, 0, ",29.87, " }, // 8
{'w', 11, 14, 23, 0, ",-27888.71, " }, // 9
{'o', 8, 14, 23, 0, ",077.21, " }, // 10
{'q', 13, 14, 23, 0, ",4.98,3.28,S, " }, // 11
{'e', 8, 14, 23, 0, ",42.8,29.93,-2056,4.48 " }, // 12
};
struct fld_t { //Defines how to select a field from a message and display it
uint8_t fldLabel; //Index into labels
uint8_t msgInx; //Index into msgs
uint8_t fldUnit; //count of commas to begining of field
uint8_t dp; //Decimal Point: 0 = none, 1 = after 1 digit , 2 = after 2 digits, etc
uint8_t unitInx; //Index into units
};
// Each entry corresponds to a page and each item to a row.
fld_t flds_1[] = { //sysMode 1, Rows 1 - 5, etc
{0, 12, 0, 0, 6}, {1, 1, 0, 0, 6}, {2, 4, 0, 0, 6}, {3, 5, 0, 0, 6}, {14, 2, 0, 0, 7} //0
};
fld_t flds_2[] = {
{0, 12, 1, 0, 3}, {1, 1, 1, 0, 3}, {4, 1, 2, 0, 4}, {7, 2, 2, 0, 8}, {8, 2, 3, 0, 8}
};
fld_t flds_3[] = {
{18, 11, 0, 0, 5}, {6, 2, 1, 2, 5}, {17, 11, 1, 0, 5}, {16, 1, 3, 1, 5}, {5, 4, 1, 0, 0}
};
fld_t flds_4[] = {
{0, 12, 3, 0, 9}, {11, 3, 1, 0, 9}, {12, 3, 2, 0, 9}, {13, 3, 0, 0, 0}
};
fld_t flds_5[] = {
{9, 5, 1, 0, 0}, {10, 5, 2, 0, 0}, {15, 5, 3, 0, 0}
};
fld_t *fields[] = {flds_1, flds_2, flds_3, flds_4, flds_5};
const char*labels[] = {
// 0 1 2 3 4
"Local", "Outside", "Den", "Garage", "Solar Current",
// 5 6 7 8
"Den Light", "Solar Charging", "Today Charge", "Yesterday Charge",
// 9 10 11 12 13
"Garage Door", "Garage Fan", "Gas Hot", "Gas Cold", "Gas Alarm",
// 14 15 16 17 18
"Barometer", "Garage Temperature", "Solar Battery", "Battery", "Charging"
};
const char*units[] = {
//0 1 2 3 4 5 6 7 8 9
" ", ": ", " / ", " % ", "MA", "V", "*F", "inHg", "MAH", "Kohm",
//10 11 12 13 14 15
"up", "dowm", "running", "stopped", "hot", "cold"
};
int getMsgIndex(char keyCode) { //Reverse lookup
return msgInx[(int)keyCode - 110];
};
char picState;
void displayField(int pageInx, int row, int pos) {
int commaLoc[8];
int commaIndex = 0;
int startIndex, endIndex;
int labelIndex;
char recChar;
int dpInx;
fld_t selFld = fields[pageInx][row];
for (int i = 0; i < msgSize; i++) {
recChar = msgs[selFld.msgInx].msgData[i];
if (recChar == ',') {
commaLoc[commaIndex++] = i;
}
}
labelIndex = selFld.fldLabel;
TFTscreen.setCursor(0, pos);
TFTscreen.fillRect(0, pos, 319, 25, TFT_BLACK); // Erase previous display
TFTscreen.setCursor(0, pos);
TFTscreen.setTextColor(TFT_GREEN);
TFTscreen.print(labels[labelIndex]);
TFTscreen.print('=');
TFTscreen.setTextColor(TFT_WHITE);
startIndex = commaLoc[selFld.fldUnit] + 1;
endIndex = commaLoc[(selFld.fldUnit + 1)];
recChar = msgs[selFld.msgInx].msgData[1];
switch (labelIndex) { //Some sensor values need tweeking for display
case 9: //Up/Down
if (recChar == 'U') {
TFTscreen.print(units[10]);
}
else {
TFTscreen.print(units[11]);
}
break;
case 10: //Run/Stop
if (recChar == 'R') {
TFTscreen.print(units[12]);
}
else {
TFTscreen.print(units[13]);
}
break;
case 15: //Hot/Cold
if (recChar == 'H') {
TFTscreen.print(units[14]);
}
else {
TFTscreen.print(units[15]);
}
break;
case 14: //Barometer
if (recChar > (int)'5') {
TFTscreen.print("29.");
}
else {
TFTscreen.print("30.");
}
default:
dpInx = selFld.dp + startIndex;
for (int i = startIndex; i < endIndex; i++) {
if (i > msgSize) {
break;
}
if ((dpInx > startIndex) && (i == dpInx)) {
TFTscreen.print('.');
}
TFTscreen.print(msgs[selFld.msgInx].msgData[i]);
}
TFTscreen.setTextColor(TFT_GREEN);
TFTscreen.print(' ');
TFTscreen.print(units[selFld.unitInx]);
break;
}
}
const float chargeRatio = 0.436; //Vref * dividerMult / 2048
const float vRef = 3.264; //For charging voltage measurement
const float dividerMult = 2.93;
/*********************************************************************
Receiver functions
**********************************************************************
*/
const int maxCols = 33;
unsigned pulseLength;
const int pwMin = 145;
char rxBuf[maxCols]; //Passed from getPicaxeData() to loop()
bool newMsg = false; //Passed from getPicaxeData() to loop()
void getRecMsg(void) { // Input from Receiver, invoked by interrupt
byte colCount = 0;
char recChar;
unsigned pwLen = 0;
pulseLength = 0;
int hdrChkSum = 0;
while (digitalRead(intPort) > 0) { // 16.8 ms, threshold = 1.2V
pwLen++;
delayMicroseconds(100);
}
// digitalWrite(blueLED,HIGH);
if (pwLen > pwMin) { //Fisrst check on the mssage integrity
pulseLength = pwLen;
while ((Serial5.available() > 0) && (colCount < maxCols)) {
recChar = Serial5.read();
if ( !newMsg && (recChar >= ' ') && (recChar <= 'z')) {
//if ((recChar >= ' ') && (recChar <= 'z')) {
// Don't overwrite undisplayed message
rxBuf[colCount++] = recChar;
}
}
// Second check is on the unlock code by gettig the checksum
// of the fixed unlock code at the beginnng of the message
for (int i = 0; i < 7; i++) {
hdrChkSum += rxBuf[i];
}
if ((hdrChkSum == 390) && (newMsg == false)) { //Known value, now check the message checksum
newMsg = true;
}
}
//digitalWrite(blueLED,LOW);
}
/*
I originally put the EEPROM.write() code in here but it crashed the Teensy
However the EEPROM code executes normally in loop()!
Only the minimum checks are done in the nterrupt function
The fourth check is to get the checksum of the data part of the message,
and comparing it to the last 2 characters of the message
*/
uint8_t verifyRecMsg(void) { //Checking rxBuf:
uint8_t lastCharPos, chkHex, testVal, chkSum = 0;
char keyCode, chkChar, msgLenChar;
keyCode = rxBuf[7];
int msgIndex = getMsgIndex(keyCode);
delay(10);
if (msgIndex < 0 || msgIndex > 10) { // Checking for valid message type
return 15;
}
msgLenChar = rxBuf[9];
if (msgLenChar < 61 || msgLenChar > 110) { //Checking for reasonable message length
return 15;
}
lastCharPos = msgLenChar - 49;
/*
if (keyCode == 'x') {
Serial.print("Received NIXIE message:");
Serial.println(rxBuf);
}
*/
for (int i = 11; i < lastCharPos; i++) { // Sum active message characters
chkSum += (uint8_t )rxBuf[i];
}
chkHex = chkSum / 16;
chkChar = rxBuf[(lastCharPos + 1)];
if (isAlpha(chkChar)) {
testVal = (uint8_t)(chkChar - 55);
}
else {
testVal = (uint8_t)(chkChar - 48);
}
if (testVal != chkHex) {
Serial.println(rxBuf);
Serial.print("Failed message ");
Serial.print(keyCode);
Serial.print(" checksum 1 characters ");
Serial.print(chkHex, HEX);
Serial.print(':');
Serial.println((char)chkChar);
return 15;
}
chkHex = chkSum & 0x0F;
chkChar = rxBuf[(lastCharPos + 2)];
if (isAlpha(chkChar)) {
testVal = (uint8_t)(chkChar - 55);
}
else {
testVal = (uint8_t)(chkChar - 48);
}
if (testVal != chkHex) {
Serial.println(rxBuf);
Serial.print("Failed message ");
Serial.print(keyCode);
Serial.print(" checksum 2 characters ");
Serial.print(chkHex, HEX);
Serial.print(':');
Serial.println((char)chkChar);
return 15;
}
/*
if (keyCode == 'x') {
Serial.println("Passed NIXIE message checksum 1");
}
*/
if ((lastCharPos > 10) && (lastCharPos <= maxCols)) {
msgs[msgIndex].ageing = (60 * clockList[2]) + clockList[1] - (60 * msgs[msgIndex].hours) - msgs[msgIndex].mins;
digitalWrite(blueLED, HIGH);
msgs[msgIndex].len = lastCharPos - 10;;
msgs[msgIndex].code = keyCode;
msgs[msgIndex].mins = clockList[1];
msgs[msgIndex].hours = clockList[2];
for (int i = 10; i <= lastCharPos; i++) {
msgs[msgIndex].msgData[(i - 10)] = rxBuf[i];
}
msgs[msgIndex].msgData[++lastCharPos] = 0;
delay(300);
digitalWrite(blueLED, LOW);
}
return msgIndex;
}
char chargeFlag;
/*********************************************************************
Display functions
**********************************************************************
*/
int sysMode;
const int hdrPos = 40;
void displayTimeDate(void) {
char timeDateBuf[30];
static uint8_t oldHour, oldMin, oldSec;
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", oldHour, oldMin, oldSec, clockList[3], clockList[4], clockList[5]);
TFTscreen.setCursor(0, 13);
TFTscreen.print(timeDateBuf);
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", clockList[2], clockList[1], clockList[0], clockList[3], clockList[4], clockList[5]);
TFTscreen.setTextColor(TFT_GOLD); // prints orange lettrs to TFT display
TFTscreen.setCursor(0, 13);
TFTscreen.setFont(Arial_16);
TFTscreen.print(timeDateBuf);
oldHour = clockList[2];
oldMin = clockList[1];
oldSec = clockList[0];
}
void displayEditDate(void) {
char timeDateBuf[30];
static uint8_t oldHour, oldMin, oldSec;
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", oldHour, oldMin, oldSec, editList[3], editList[4], editList[5]);
TFTscreen.setCursor(0, 13);
TFTscreen.print(timeDateBuf);
sprintf(timeDateBuf, " %02u:%02u:%02u %02u/%02u/%02u", editList[2], editList[1], editList[0], editList[3], editList[4], editList[5]);
TFTscreen.setTextColor(TFT_WHITE); // prints orange lettrs to TFT display
TFTscreen.setCursor(0, 13);
TFTscreen.setFont(Arial_16);
TFTscreen.print(timeDateBuf);
oldHour = editList[2];
oldMin = editList[1];
oldSec = editList[0];
}
void displayPeriod(int pVal) {
TFTscreen.fillRect(260, hdrPos, 60, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(260, hdrPos);
TFTscreen.print(pVal, DEC);
}
void displayBigTime(int dpos, int tpos) {
char timeBuf[25];
static uint8_t oldHour, oldMin, oldSec;
sprintf(timeBuf, " %s,%s %02u,20%02u", dayName[clockList[6]], monthName[clockList[3]], clockList[4], clockList[5]);
TFTscreen.setFont(Arial_16);
TFTscreen.fillRect(0, dpos, 320, 25, TFT_BLACK);
TFTscreen.setTextColor(TFT_GREEN);
TFTscreen.setCursor(0, dpos);
TFTscreen.print(timeBuf);
sprintf(timeBuf, "%02u:%02u:%02u", oldHour, oldMin, oldSec);
TFTscreen.setFont(Arial_40);
TFTscreen.setTextColor(TFT_BLACK); // erase previous time
TFTscreen.setCursor(0, tpos);
TFTscreen.print(timeBuf);
sprintf(timeBuf, "%02u:%02u:%02u", clockList[2], clockList[1], clockList[0]);
TFTscreen.setTextColor(TFT_ORANGE);
TFTscreen.setCursor(0, tpos);
TFTscreen.print(timeBuf);
TFTscreen.setFont(Arial_16);
TFTscreen.setCursor(235, (tpos + 15));
if (tzHours == 7) {
TFTscreen.print(" PDST");
}
if (tzHours == 8) {
TFTscreen.print(" PST");
}
oldHour = clockList[2];
oldMin = clockList[1];
oldSec = clockList[0];
}
uint8_t readDateVal;
uint8_t readMonthVal;
uint8_t readYearVal;
void displayReadDate(int pos) {
char readDateBuf[20];
TFTscreen.fillRect(10, (pos - 12), 230, 20, TFT_BLACK);
TFTscreen.setCursor(10, pos);
TFTscreen.setFont(Arial_16);
sprintf(readDateBuf, "%02u/%02u/20%02u", readMonthVal, readDateVal, readYearVal);
TFTscreen.setTextColor(TFT_YELLOW); // prints orange lettrs to TFT display
TFTscreen.print(readDateBuf);
}
void dispHourMin(uint8_t inx) {
TFTscreen.fillRect(100, 140, 98, 30, TFT_BLACK);
TFTscreen.setCursor((buttXpos[4] + 180), (buttYpos[4] + 10));
TFTscreen.setFont(Arial_20);
TFTscreen.setTextColor(TFT_ORANGE);
TFTscreen.print(editList[inx]);
}
void dispHeader(void) {
uint8_t index;
TFTscreen.fillRect(0, hdrPos, 339, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(5, hdrPos);
index = Pages[sysMode].hdrInx;
if (index != 21) {
TFTscreen.print(headers[index]);
}
if (sysMode == 6) {
displayBattVolt(255, hdrPos);
}
}
void displayBattVolt(uint8_t xPos, uint8_t yPos) {
TFTscreen.setCursor(xPos, yPos);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_GREEN);
if (msgs[11].msgData[6] > '3') {
TFTscreen.setTextColor(TFT_BLUE);
}
else {
if (msgs[11].msgData[8] < '5') {
TFTscreen.setTextColor(TFT_RED);
}
}
for (int i = 6; i < 10; i++) {
TFTscreen.write(msgs[11].msgData[i]);
}
}
void displayMsgNames(uint8_t index, int pos) {
TFTscreen.fillRect(0, pos, 339, 20, TFT_BLACK);
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
TFTscreen.setCursor(15, pos);
TFTscreen.print(msgNames[index]);
TFTscreen.setCursor(150, pos);
TFTscreen.print(msgs[index].ageing);
}
void displayButtons(void) { // Displays the buttons for the current sysMode
uint8_t buttVal;
for (int buttID = 0; buttID < 5; buttID++) {
buttVal = Pages[sysMode].buttInx[buttID];
if (((buttVal != 0) && (buttVal != 21)) || ((buttVal == 0) && (buttID < 4) )) { // erase old button
TFTscreen.fillRect(buttXpos[buttID], buttYpos[buttID], buttWidth[buttID], buttDepth[buttID], TFT_BLACK);
delay(10);
TFTscreen.drawRect(buttXpos[buttID], buttYpos[buttID], buttWidth[buttID], buttDepth[buttID], TFT_WHITE);
delay(10);
}
TFTscreen.setCursor((buttXpos[buttID] + 10), (buttYpos[buttID] + 10));
TFTscreen.setFont(Arial_16);
TFTscreen.setTextColor(TFT_WHITE);
if (((buttVal > 0) && (buttVal < 20)) || ((buttVal == 0) && (buttID < 4) )) {
TFTscreen.print(navButtons[buttVal]);
}
if ((buttVal >= 'A') && (buttVal < 'Z')) {
TFTscreen.print(actionButtons[(buttVal - 'A')]);
}
delay(20);
}
}
/*********************************************************************
File functions
**********************************************************************
*/
void recordMsg(int index) {
/* Records on one line the contents of rxBuf
The filename is /yy/mm/dd
The file format is hh:mm:ss,r,(data) r is keycode
*/
File recFile;
char filename[20];
char recMsg[45];
transmit('B');
for (int i = 0; i < msgSize; i++) {
recMsg[i] = 0;
}
sprintf(recMsg, "%c,%02u:%02u%s\r\n", msgs[index].code, msgs[index].hours, msgs[index].mins, msgs[index].msgData);
sprintf(filename, "/%02u/%02u/%02u.csv", clockList[5], clockList[3], clockList[4]);
recFile = SD.open(filename, FILE_WRITE);
if (recFile) {
// Serial.print("Writing ");
// Serial.println(filename);
recFile.write(recMsg);
recFile.close();
}
else {
Serial.print("Failed to write to ");
Serial.println(filename);
}
Serial.print(recMsg);
transmit('N');
}
void displaySdFile() {
File file;
char picChar;
uint8_t bufPos;
char filename[20];
char buf[35];
int lineCount = 0;
transmit('B');
sprintf(filename, "/%02u/%02u/%02u.csv", readYearVal, readMonthVal, readDateVal);
file = SD.open(filename, FILE_READ);
if (file) {
Serial.print(filename);
Serial.println(" is opened for reading");
bufPos = 0;
while (file.available()) {
do {
picChar = file.read();
if (bufPos < 35) {
buf[bufPos++] = picChar;
}
if (picChar == 10) {
++lineCount;
}
} while ((picChar > 31) && (picChar < 128));
buf[bufPos] = 0;
Serial.print(buf);
bufPos = 0;
}
}
else {
Serial.print("Unable to open file ");
Serial.println(filename);
}
file.close();
TFTscreen.setCursor(0, 67);
TFTscreen.print(lineCount);
TFTscreen.print(" records read");
TFTscreen.setCursor(0, 90);
TFTscreen.print("File ");
TFTscreen.print(filename);
TFTscreen.println(" is closed");
Serial.print("File ");
Serial.print(filename);
Serial.println(" is closed");
transmit('N');
}
/*********************************************************************
BME680 and input functions
**********************************************************************
*/
void getEnvironmental() {
int32_t temp, humidity, pressure, gas;
int32_t altVal, pVal;
BME680.getSensorData(temp, humidity, pressure, gas);
altVal = (temp * 9.0) / 5.0;
altVal += 3200;
pVal = pressure * 0.02983;
sprintf(msgs[12].msgData, ",%03d.%01d,%03d,%02d.%02d,%5d ",
(int8_t)(altVal / 100), (uint8_t)(altVal % 100), // Temperature in decidegrees
(int8_t)(humidity / 1000), // Humidity in milli-percent
(int16_t)(pVal / 100), (uint8_t)(pVal % 100), // Pressure in hepa Pascals or in Hg
(int16_t)(gas / 100)); // Gas Quality
temp = analogRead(chargePort) * chargeRatio;
sprintf(msgs[8].msgData, ",%01d.%02d,", (int16_t)(temp / 100), (uint8_t)(temp % 100));
chargeFlag = (temp / 100) + '0';
}
void transmit(char busyFlag) {
// Transmit the status message
Serial3.write('~');
delay(5);
Serial3.write('<');
Serial3.write(chargeFlag);
Serial3.write(',');
Serial3.write(busyFlag);
Serial3.println('>');
}
/*********************************************************************
Touchscreen function
**********************************************************************
*/
bool is_pressed(int index) { // button 0-4
bool pressed = false;
TS_Point p = ts.getPoint();
if ((p.y < buttYmax[index]) && (p.y > buttYmin[index]) && (p.x < buttXmax[index]) && (p.x > buttXmin[index])) {
TFTscreen.fillRect(buttXpos[index], buttYpos[index], buttWidth[index], buttDepth[index], TFT_SKYBLUE);
delay(300);
TFTscreen.fillRect(buttXpos[index], buttYpos[index], buttWidth[index], buttDepth[index], TFT_BLACK);
delay(300);
pressed = true;
}
return pressed;
}
uint16_t secCount = 0;
uint8_t oldSec = 10;
char picCmd = '1'; //1 = black button on, 0 = black button off
const uint16_t maxSecCount = 900;
uint8_t blTurnoffCountMax = 20;
uint8_t ticInterval = 200;
void setup() {
int EEPROMaddr;
Serial.begin(9600); //USB
Serial5.begin(2400); //Receiver
Serial3.begin(9600); //Picaxe
Serial4.begin(9600); //Monitor
Wire.begin();
pinMode(blueLED, OUTPUT);
pinMode(PIN_IRQ, INPUT_PULLUP);
pinMode(intPort, INPUT_PULLUP);
pinMode(PIN_RST, OUTPUT);
pinMode(blPort, OUTPUT);
digitalWrite(blPort, HIGH);
initRTC(); // set the Time library to use Teensy 3.5's RTC to keep time
//tmElements_t nowTime = {0, 31, 18, 4, 21, 9, 23};
//setRTCtm(&nowTime);
// BME688
BME680.begin(I2C_STANDARD_MODE); // Start BME680 using I2C protocol
BME680.setOversampling(TemperatureSensor, Oversample16); // Use enumerated type values
BME680.setOversampling(HumiditySensor, Oversample16); // Use enumerated type values
BME680.setOversampling(PressureSensor, Oversample16); // Use enumerated type values
BME680.setIIRFilter(IIR4); // Use enumerated type values
BME680.setGas(320, 150); // 320�c for 150 milliseconds
digitalWrite(PIN_RST, LOW);
delay(1);
digitalWrite(PIN_RST, HIGH);
delay(100);
TFTscreen.begin();
TFTscreen.setRotation(3);
TFTscreen.fillScreen(TFT_BLACK); // prints black screen to TFT display
TFTscreen.setTextColor(TFT_GREEN);
TFTscreen.setFont(Arial_14);
delay(5);
Serial.println("Colorscreen started.");
if (!ts.begin()) {
Serial.println("Unable to start touchscreen.");
}
else {
Serial.println("Touchscreen started.");
ts.setRotation(1); //Was 0 before upgrade
}
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("SD not present");
}
else {
Serial.println("SD initialized");
}
tzHours = EEPROM.read(0);
blTurnoffCountMax = EEPROM.read(1);
// EEPROM.write(2, 12);
ticInterval = EEPROM.read(2);
for (int i = 0; i < 7; i++) {
EEPROMaddr = 40 * i;
msgs[i].len = EEPROM.read(EEPROMaddr);
msgs[i].code = EEPROM.read(EEPROMaddr + 1);
msgs[i].mins = EEPROM.read(EEPROMaddr + 2);
msgs[i].hours = EEPROM.read(EEPROMaddr + 3);
for (int j = 0; j < msgSize; j++) {
msgs[i].msgData[j] = EEPROM.read(EEPROMaddr + 4 + j);
}
}
picState = 'B';
newMsg = false;
secCount = 0;
sysMode = 16;
attachInterrupt(digitalPinToInterrupt(intPort), getRecMsg, RISING);
}
void loop() {
int gotIndex = 15;
int row;
static int prevMode = 34;
uint8_t EEPROMaddr;
static bool tic = false;
static uint16_t count, envCount;
static uint16_t blTurnoffCount;
static char oldPicState = 'B';
bool battFlag = false;
bool eepromFlag = false;
const uint8_t activePos = 65;
tic = false;
if (Serial3.available() > 7) { //First measure the charge voltage
delay(10);
// Receive the battery voltage message
msgs[11].msgData[0] = ',';
Serial3.read(); //'<';
msgs[11].msgData[5] = ',';
for (int i = 6; i < 10; i++) {
picCmd = Serial3.read();
if ((i == 6) && (picCmd < '5')) {
battFlag = true;
}
if (battFlag) {
msgs[11].msgData[i] = picCmd;
}
}
msgs[11].msgData[10] = ',';
picCmd = Serial3.read(); //'>';
if (picCmd == '>') {
msgs[11].hours = clockList[2]; //To time-tag BME680 file entries
msgs[11].mins = clockList[1];
msgs[11].msgData[12] = 0;
picState = Serial3.read();
if (battFlag) {
msgs[11].msgData[11] = picState; //Picaxe ststus: S, B, R or O
}
if (oldPicState != picState) {
Serial.print("Picaxe State change:");
Serial.print(oldPicState);
Serial.print(" to ");
Serial.println(picState);
if((oldPicState == 'R') && (picState == 'O')) {
eepromFlag = true;
}
}
}
while (Serial3.available()) {
Serial3.read();
}
}
if (ts.touched()) {
uint8_t buttVal;
int deltaVal = 4;
uint8_t editVal;
uint8_t editIndex;
for (int buttID = 0; buttID < 5; buttID++) {
buttVal = Pages[sysMode].buttInx[buttID]; //Can be a (binary) number or a letter
if (is_pressed(buttID)) {
tic = true;
if (buttVal < 30) { //For navigation
sysMode = buttVal;
if (buttVal == 16) {
eepromFlag = true;
}
}
else { //A letter for an action
switch (buttVal) {
case 'A':
editTt = untTt; //For adjusting clock
breakTime(editTt, &editTm);
editList[0] = editTm.Second;
editList[1] = editTm.Minute; // 0 - 59
editList[2] = editTm.Hour; // 0 - 23
editList[5] = editTm.Year; // - 2000
editList[3] = editTm.Day;
editList[4] = editTm.Month;
sysMode = 10;
break;
case 'B':
readDateVal = clockList[4]; //Convenient preset for file operations
readMonthVal = clockList[3];
readYearVal = clockList[5];
sysMode = 9;
break;
case 'C':
tzHours = 8;
break;
case 'D':
tzHours = 7;
break;
case 'F':
deltaVal -= 2;
case 'E':
deltaVal -= 2;
switch (sysMode) {
case 10:
editIndex = 5;
break;
case 11:
editIndex = 4;
break;
case 12:
editIndex = 3;
break;
case 13:
editIndex = 2;
break;
case 14:
editIndex = 1;
break;
}
editVal = editList[editIndex];
editVal += deltaVal - 1;
editList[editIndex] = editVal;
dispHourMin(editIndex);
break;
case 'G':
editList[0] = editTm.Second;
editTm.Minute = editList[1]; // 0 - 59
editTm.Hour = editList[2]; // 0 - 23
editTm.Year = editList[5]; // - 2000
editTm.Day = editList[3];
editTm.Month = editList[4];
setRTCtm(&editTm);
sysMode = 16;
break;
case 'H':
if (msgs[11].msgData[7] != 'O') {
displaySdFile();
sysMode = 16;
}
break;
case 'I':
if (readDateVal < 31) {
++readDateVal;
}
break;
case 'J':
if (readDateVal > 1) {
--readDateVal;
}
break;
case 'K':
if (readMonthVal < 12) {
++readMonthVal;
}
else {
++readYearVal;
readMonthVal = 1;
}
break;
case 'L':
if (readMonthVal > 1) {
--readMonthVal;
}
else {
--readYearVal;
readMonthVal = 12;
}
break;
case 'M':
eepromFlag = true;
sysMode = 16;
break;
case 'N':
deltaVal -= 2;
case 'O':
deltaVal -= 2;
ticInterval += deltaVal - 1;
break;
case 'P':
deltaVal -= 2;
case 'Q':
deltaVal -= 2;
blTurnoffCountMax += deltaVal - 1;
break;
}
}
}
delay(300);
}
}
untTt = readRTC();
timeDateGet();
count = clockList[0];
if (count != oldSec) {
oldSec = count;
if (secCount < maxSecCount) {
++secCount;
}
else {
secCount = 0;
}
if ((sysMode == 6) && (chargeFlag < '3')) {
if (blTurnoffCount > 0) {
--blTurnoffCount;
}
else {
digitalWrite(blPort, LOW);
}
}
switch (Pages[sysMode].tdDisp) {
case 0: //Initial big time
displayBigTime(15, 80);
break;
case 1: //Adjust clock
displayEditDate();
break;
case 2: // Date & Month set
displayReadDate(22);
break;
case 3:
displayTimeDate(); //Most
break;
case 4:
displayPeriod(10 * ticInterval);
break;
case 5:
displayPeriod(blTurnoffCountMax);
break;
}
envCount = secCount % (10 * ticInterval);
if ((envCount == 11) || (envCount == 12)) {
// if ((envCount == 8) || (envCount == 11) || (envCount == 12)) {
getEnvironmental();
msgs[envCount].hours = clockList[2]; //To time-tag BME680 file entries
msgs[envCount].mins = clockList[1];
recordMsg(envCount);
if (sysMode != 9) { //Initial is already updated every second
tic = true;
}
}
}
if (newMsg) {
gotIndex = verifyRecMsg();
//Serial.print("Got message = ");
// Serial.println(gotIndex);
if ((gotIndex < 7)) {
recordMsg(gotIndex);
digitalWrite(blPort, HIGH);
blTurnoffCount = blTurnoffCountMax;
tic = true;
if (sysMode == 6) {
displayMsgNames(gotIndex, activePos);
}
}
if (sysMode == 6) {
const uint8_t rowPos[4] = {activePos + 25, activePos + 50 , activePos + 75 , activePos + 100};
switch (gotIndex) {
case 1:
displayField(0, 1, rowPos[0]); //Outside temperature
displayField(1, 1, rowPos[1]); //Outside humidity
displayField(1, 2, rowPos[2]); //Solar Current
displayField(2, 3, rowPos[3]); //Solar battery voltage
break;
case 2:
displayField(0, 4, rowPos[0]); //Barometer
displayField(1, 3, rowPos[1]); //Today Charge
displayField(1, 4, rowPos[2]); //Yesterday MAH
displayField(2, 1, rowPos[3]); //Solar Charging voltage
break;
case 3:
displayField(3, 1, rowPos[0]); //Den Gas Quality Hot
displayField(3, 2, rowPos[1]); //Den Gas Quality Cold
displayField(3, 3, rowPos[2]); //Gas Alarm
break;
case 4:
displayField(0, 2, rowPos[0]); //Den temperature
displayField(2, 4, rowPos[1]); //Den Light
break;
case 5:
displayField(4, 0, rowPos[0]); //Garage door
displayField(4, 1, rowPos[1]); //Garage Fan
displayField(4, 2, rowPos[2]); //Garage temperature
break;
}
}
}
newMsg = false;
if (sysMode != prevMode) {
prevMode = sysMode;
TFTscreen.fillRect(0, 0, 310, 205, TFT_BLACK);
prevMode = sysMode;
tic = true;
digitalWrite(blPort, HIGH);
blTurnoffCount = blTurnoffCountMax;
}
if (tic ) {
displayButtons();
dispHeader();
}
if (tic && (sysMode <= 6)) {
switch (sysMode) {
case 0:
TFTscreen.setTextColor(TFT_WHITE);
for (int j = 0; j < 7; j++) {
if ((msgs[j].len > 0)) {
row = 15 + (25 * j);
TFTscreen.setCursor(0, row);
TFTscreen.fillRect(0, row, 319, 20, TFT_BLACK); // Erase previous display
TFTscreen.setCursor(0, row);
TFTscreen.print(msgs[j].code);
TFTscreen.print(',');
TFTscreen.print(msgs[j].hours);
TFTscreen.print(':');
TFTscreen.print(msgs[j].mins);
for (int i = 0; i <= msgs[j].len; i++) {
TFTscreen.print(msgs[j].msgData[i]);
}
}
}
break;
case 1:
displayField(0, 0, 65); //Local temperature
displayField(0, 1, 90); //Outside temperature
displayField(0, 2, 115); //Den temperature
displayField(0, 3, 140); //Garage Temperature
displayField(0, 4, 165); //Barometer
break;
case 2:
displayField(1, 0, 65); //Local humidity
displayField(1, 1, 90); //Outside humidity
displayField(1, 2, 115); //Solar Current
displayField(1, 3, 140); //Today Charge
displayField(1, 4, 165); //Yesterday MAH
break;
case 3:
displayField(2, 0, 65); //Local Charging voltage
displayField(2, 1, 90); //Solar Charging voltage
displayField(2, 2, 115); //Local battery voltage
displayField(2, 3, 140); //Solar battery voltage
displayField(2, 4, 165); //Den Light
break;
case 4:
displayField(3, 0, 65); //Local Gas Quality
displayField(3, 1, 90); //Den Gas Quality Hot
displayField(3, 2, 115); //Den Gas Quality Cold
displayField(3, 3, 140); //Gas Alarm
break;
case 5:
displayField(4, 0, 65); //Garage door
displayField(4, 1, 90); //Garage Fan
displayField(4, 2, 115); //Garage temperature
break;
}
}
tic = false;
if (eepromFlag) {
EEPROM.write(0, tzHours);
EEPROM.write(1, blTurnoffCountMax);
EEPROM.write(2, ticInterval);
for (int i = 1; i < 7; i++) {
EEPROMaddr = 40 * i;
EEPROM.write(EEPROMaddr, msgs[i].len);
EEPROM.write((EEPROMaddr + 1), msgs[i].code);
EEPROM.write((EEPROMaddr + 2), msgs[i].mins);
EEPROM.write((EEPROMaddr + 3), msgs[i].hours);
for (int j = 0; j < msgSize; j++) {
EEPROM.write((EEPROMaddr + 4 + j), msgs[i].msgData[j]);
}
}
}
eepromFlag = false;
oldPicState = picState;
delay(10);
}