/*
Dialog only TEST derived from defragster button abstraction code..
https://github.com/Defragster/XPT2046_Touch_Examples
Specifically, this is an adapted version of ColorButtonsMark2.ino
(Thanks, Defragster!)
Attempt number one - can I just implement an easy menu system
based on this abstraction code..
Interweaving my own data collection from the encoder is easy-pie if
I can get a handle on button management..
Eric Timberlake, March 25th, 2019..
*/
float VERSION = 2.3;
/*
Version 2.0 -
- Just get basic abstraction code setup, create buttons for all the screens
trigger actions on touch.. Still some work to debounce and de-double hit
(button on screen 1 overlays button on screen 2) is a problem...
Eric Timberlake, 3.25.2019
- Next: wrap head around screen rotation and preserving rotation state..
an "info" or "about" screen, perhaps an easter egg in the config
screen?
Version 2.1 -
- something..... Got Rotation and basic menu working, got rotation to
store persistently, but THEN....
- Dog gone it - SOMETHING effed up - this will not compile any more - I think
I was tired and touched/altered something, but for the life of me, can't
find out why!! Claims "ButtonInit" is previously delcared variable or field.
I sure can't see how or why.. Very frustrating to have a working outline just
stop working..
Version 2.2 -
- *(^) if I know - copy entire file - fails. Cut and paste in pieces back into
original code example and it works fine, just like it was.. WTF? What follows
is that reconstruction with NOT A CLUE IN THE WORLD what went wrong.. Obviously
I created an unclosed brace or something of the sort somewhere..
- So, we have basic rotation, but not all the required portrait screens and
button deffinitions.. We need to set a decision tree on when to be using
landscape vs. poitrait versions.
- I need to figure a way to stop button re-trigger?
DONE! Well, done-ish for now.. I'll investigate superior button re-trigger
detection later. For now, time to start designing data output screens!
Version 2.3 -
- start working on calibration routine and various displays? Try actually attaching
the encoder? ;-)
*/
#include <SPI.h>
#include <Wire.h>
//#define LC 1
#if LC
#include "Adafruit_ILI9341.h"
#else
#include <ILI9341_t3.h>
#endif
#include <XPT2046_Touchscreen.h>
#define CS_PIN 8
//XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts and TeensyDuino version 1.26 libs
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
#define TIRQ_PIN 2
//XPT2046_Touchscreen ts(CS_PIN, 255); // Param 2 - 255 - No interrupts
XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
#define TFT_CS 10
#define TFT_DC 9
// MOSI=11, MISO=12, SCK=13
#ifdef LC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// ADAFRUIT MISSING COLORS
#define ILI9341_NAVY 0x000F /* 0, 0, 128 */
#define ILI9341_DARKCYAN 0x03EF /* 0, 128, 128 */
#define ILI9341_ORANGE 0xFD20 /* 255, 165, 0 */
#define ILI9341_PINK 0xF81F
#else
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
#endif
#include <font_Arial.h> // from ILI9341_t3, font
#include <font_CourierNew.h> // from ILI9341_t3, font
#include <font_CourierNewBold.h> // from ILI9341_t3, font
#include <font_AwesomeF100.h> // from ILI9341_t3 library - symbols font..
#include <Encoder.h> // optimized encoder library to track motion easily!!
#include <Adafruit_FRAM_SPI.h> // access tools for FRAM storage where we store "stuff"..
uint8_t FRAM_CS = 22; // use CS pin 22 for chip select / SS
Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(); // use hardware SPI
// a little FRAM address tracking...
uint16_t SAVEDODO = 0x00; //FRAM address for long odometer 0x00, 01 02 and 03
uint16_t SAVEDUNITS = 0x04; //FRAM addres for byte units 0x04
uint16_t SAVEDTRIP = 0x05; //FRAM address for long trip 0x05. 06 07 and 08
uint16_t SAVEDSCALE = 0x10; //FRAM address for long scale 0x10, 11 12 and 13
uint16_t ALTSCALE = 0x20; //FRAM address for byte scale array pointer 0x20
uint16_t TSROTATE = 0x30; //FRAM address for integer screen orientation, 0-3
uint16_t SERIALNM = 0x40; //FRAM address for a permanent serial number - we only
// ever READ THIS a separate program sets it at prod time..
// -----------------------------------------
// --- Button Data Starts here
// -----------------------------------------
int16_t TS_Rotate = 1; // INVALID until set on startup
static int16_t TS_iiSlide = -1;
#define TS_SLIDET 40 // Reject SLIDE buttons farther apart than this
struct TS_MAP {
int16_t xt;
int16_t xb;
int16_t yl;
int16_t yr;
};
// Zero is calibration for mapping to pixel, 1-4 follow screen rotation for mapping math
//TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
// restore original TS_MAP and use "ts.ButtonRotate( 3 );" in void setup()
// re-restore - ts.ButtonRotate( 3 ); isn't working...
TS_MAP tsMap[5] = { {3700, 200, 3670, 325 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
int16_t TS_xMax = 0; // Current Screen orientation x,y Max values
int16_t TS_yMax = 0;
struct TS_BUTTON {
char *text; // Literal string put into FLASH on compile leaving a pointer that is user changeable
int16_t tx, ty; // Top Left X,Y
int16_t ww, hh; // Width, Height
uint16_t fgc; // forground text/frame color
uint16_t bgc; // background color button or empty frame
uint8_t btype; // for toggle/slider two bytes TYPE & info PAIRING number
uint8_t info; // for toggle/slider two bytes TYPE & info PAIRING number
byte bState; // button state
byte fontsz; // font size
byte bId; // Button ID
uint8_t TS_data; // Toggle FRAME stores state value here
};
#define TS_JITTER 250 // ms Threshold for Toggle/Slider re-activate
#define TS_FBUTN 0x01 // Frame Button
#define TS_RBUTN 0x03 // Rounded Button
#define TS_FRAME 0x10 // FRAME for two TOGGLE button areas
#define TS_TOGOFF 0x20 // Off Toggle
#define TS_TOGON 0x30
#define TS_ASLIDE 0x40 // Slide Button : A position
#define TS_BSLIDE 0x50 // Slide Button : B position
int TS_bCount = 0; // Set at run time from sizeof()
// -----------------------------------------
// --- Button Data Ends here
// -----------------------------------------
// -----------------------------------------
// --- USER Button Data Starts here
// { text *, tx, ty, ww, hh, fgc, bgc, btype, info, bState, fontsz, bId, TS_data } << Struct looks like this
// REQUIRED LAST ITEM :: {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
// -----------------------------------------
uint16_t gobuttonclr=0x34C4;
uint16_t cancelclr=0xD165;
//unsigned long menuclr=0x5E23;
uint16_t menuclr=0xEFE0;
int16_t stdbuttonwidth=147;
int16_t stdLborder=7;
// main screen buttons...
TS_BUTTON mainscreen_l[] = {
{(char *)"Reset", 10, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 1, 0} ,
{(char *)" BIG", 105, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 2, 0} ,
{(char *)"Config", 200, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 3, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON mainscreen_p[] = {
{(char *)"Reset", 10, 225, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 1, 0} ,
{(char *)" BIG", 104, 225, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 2, 0} ,
{(char *)"Config", 10, 273, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 3, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// configuration choices selection dialog buttons - just rough form for now
TS_BUTTON configscreen_l[] = {
{(char *)"Rotation", stdLborder, 15, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 4, 0} ,
{(char *)"Calibration", stdLborder, 60, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 5, 0} ,
{(char *)"Scale", stdLborder, 105, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 6, 0} ,
{(char *)"Units", stdLborder, 150, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 7, 0} ,
{(char *)"CANCEL", stdLborder, 195, stdbuttonwidth, 35, cancelclr, 325, TS_FBUTN, 0, 0, 2, 8, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON configscreen_p[] = {
{(char *)"Rotation", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 4, 0} ,
{(char *)"Calibration", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 5, 0} ,
{(char *)"Scale", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 6, 0} ,
{(char *)"Units", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 7, 0} ,
{(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 3, 8, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// scale selection dialog buttons - just rough form for now
TS_BUTTON scalescreen_l[] = {
{(char *)"1:32 Scale", stdLborder, 5, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 9, 0} ,
{(char *)"1:29 Scale", stdLborder, 44, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 10, 0} ,
{(char *)"1:24 Scale", stdLborder, 83, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 11, 0} ,
{(char *)"1:22.5 Scale", stdLborder, 122, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 12, 0} ,
{(char *)"1:20.5 Scale", stdLborder, 161, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 13, 0} ,
{(char *)"CANCEL", stdLborder, 198, stdbuttonwidth, 32, cancelclr, 325, TS_FBUTN, 0, 0, 2, 14, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON scalescreen_p[] = {
{(char *)"1:32 Scale", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 9, 0} ,
{(char *)"1:29 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 10, 0} ,
{(char *)"1:24 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 11, 0} ,
{(char *)"1:22.5 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 12, 0} ,
{(char *)"1:20.5", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 13, 0} ,
{(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 14, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// Units selection dialog buttons - just rough form for now
TS_BUTTON unitsscreen_l[] = {
{(char *)"Imperial", stdLborder, 5, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 15, 0} ,
{(char *)"Metric", stdLborder, 55, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 16, 0} ,
{(char *)"CANCEL", stdLborder, 105, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 17, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON unitsscreen_p[] = {
{(char *)"Ipmerial", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 15, 0} ,
{(char *)"Metric", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 16, 0} ,
{(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 17, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// Calibration start/help screen dialog
TS_BUTTON calibrationstartscreen_l[] = {
{(char *)"Start, 1 Meter", stdLborder, 5, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 18, 0} ,
{(char *)"Start, 2 Meter", stdLborder, 55, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 19, 0} ,
{(char *)"CANCEL", stdLborder, 105, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 20, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON calibrationstartscreen_p[] = {
{(char *)"Start 1M", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 18, 0} ,
{(char *)"Start 2M", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 19, 0} ,
{(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 20, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// Calibration stop/set dialog
TS_BUTTON calibrationstopscreen_l[] = {
{(char *)"Set", stdLborder, 140, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 21, 0} ,
{(char *)"CANCEL", stdLborder, 190, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 22, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON calibrationstopscreen_p[] = {
{(char *)"Set", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 21, 0} ,
{(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 22, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// Set rotation dialog!
TS_BUTTON rotationscreen_l[] = {
{(char *)"Rotate", stdLborder, 10, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 23, 0} ,
{(char *)"Set", stdLborder, 60, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 24, 0} ,
{(char *)"CANCEL", stdLborder, 110, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 25, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
TS_BUTTON rotationscreen_p[] = {
{(char *)"Rotate", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 23, 0} ,
{(char *)"Set", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 24, 0} ,
{(char *)"CANCEL", stdLborder , stdbuttonwidth, 220, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 25, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
// -----------------------------------------
// --- USER Button Data Ends here
// -----------------------------------------
uint16_t bg1 = ILI9341_BLUE; // define a background color in one place..
int16_t beepPin = 23; // we have a 4KHz buzzer attached here - drive low for tone!
int16_t beepTime = 50; // beep duration, longer is louder and more irritating..
uint8_t prevTS_Rotate = 0; // when we cancel, what rotation do we cancel back to?
void setup(void)
{
fram.begin(FRAM_CS, 2); // intialize fram instance to save various data to.. Testing reveils 2 byte addressing..
fram.setAddressSize(2); // ... so we set that here.
Serial.begin(9600);
while ( !Serial && (millis() < 2000)) ;
tft.begin();
if (!ts.begin()) Serial.println("Unable to start touchscreen.");
else Serial.println("Touchscreen started.");
// doesnt' work - mark2 versus mark3?
//ts.ButtonRotate( 3 ); // set button to line up with DISPLAY - for some reason we're mirrored with my hardware?
tft.setFont(Arial_16); // sort of globally affect the button fonts.. What happens after displaying data??
TS_Rotate = framReadByte(TSROTATE); // recall last set rotation from FRAM
ButtonInit( 0 );
tft.fillScreen(bg1);
if ((TS_Rotate % 2)) {
ButtonInit( &mainscreen_l[0] );
}
else {
ButtonInit( &mainscreen_p[0] );
}
ButtonDraw( 0 );
pinMode(beepPin, OUTPUT); // setup beeper driving pin
digitalWrite(beepPin, HIGH); // make sure we're not beeping! ;-)
beep(50);
}
void loop()
{
/*
We do stuff here - check encoder for changes, if so, update data, then appropriate
display updates.. THEN, look to see if someone is pressing a button and act on it.
*/
// See if there's any touch data for us
static elapsedMillis userTime;
uint16_t userDebounce = 1555;
static int16_t lastbValue;
boolean istouched = false;
int16_t bValue;
int16_t x, y;
istouched = TS_GetMap( x, y, true );
if (istouched && ButtonHit(x , y, bValue))
{
if ( lastbValue == bValue ) userDebounce = userTime;
// Main Screen...
// buttons 1 2 3 are on main screen
if ( 1 == bValue ) { // reset trip meter data
// do something that actually resets the trip meter here!
beep(beepTime);
Serial.println("Reset the trip meter data!!");
delay(1000); //stop button rehits crudely?
}
if ( 2 == bValue ) { // full screen display
// some sort of data only, press and hold for 3 seconds to return?
beep(beepTime);
Serial.println("Enter Full Screen Mode!!");
delay(1000); //stop button rehits crudely?
}
if ( 3 == bValue ) { // goto the sconfig screen..
prevTS_Rotate = TS_Rotate;
Serial.println("Go to the Configuration selection screen...");
configscreen(); // redraw the config screen
}
// Config Screen actions...
// buttons 4, 5, 6, 7 and 8 are located on the config screen.. 8 is cancel.
if ( 4 == bValue ) { // goto rotation screen
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &rotationscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Goto rotation screen...");
}
if ( 5 == bValue ) { // goto calibration screen
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &calibrationstartscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Goto calibration screen...");
}
if ( 6 == bValue ) { // goto scale selection screen
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &scalescreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Goto scale selection...");
delay(1500);
}
if ( 7 == bValue ) { // go to units
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &unitsscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Go to units selection...");
}
if ( 8 == bValue ) { // cancel
tft.fillScreen(bg1);
ButtonInit( 0 );
if ((TS_Rotate % 2)) {
ButtonInit( &mainscreen_l[0] );
}
else {
ButtonInit( &mainscreen_p[0] );
}
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Return from config screen unchanged...");
}
// Scale Select Screen actions...
// buttons 9 - 14 are to scelect scale
if ( 9 == bValue ) { // 1:32
// do something to set scale to 1:32nd here
configscreen(); // redraw the config screen
Serial.println("Select 1:32nd scale and return to main screen...");
}
if ( 10 == bValue ) { // 1:29
// do something to set scale to 1:29th here
configscreen(); // redraw the config screen
Serial.println("Select 1:29th scale and return to main screen...");
}
if ( 11 == bValue ) { // 1:24
// do something to set scale to 1:24th here
configscreen(); // redraw the config screen
Serial.println("Select 1:24th scale and return to main screen...");
}
if ( 12 == bValue ) { // 1:22.5
// do something to set scale to 1:22.5 here
configscreen(); // redraw the config screen
Serial.println("Select 1:22.5 scale and return to main screen...");
}
if ( 13 == bValue ) { // 1:20.5
// do something to set scale to 1:20.5 here
tft.fillScreen(bg1);
configscreen(); // redraw the config screen
Serial.println("Select 1:20.5th scale and return to main screen...");
}
if ( 14 == bValue ) { // cancel
// Don't do anything and return to the main screen...
configscreen(); // redraw the config screen
Serial.println("cancel from select scale screen...");
}
// Units Select Screen actions...
// units select are buttons 15, 16 and 17..
if ( 15 == bValue ) { // imperial units select
// do something to set units to Imperial here
configscreen(); // redraw the config screen
Serial.println("Set units to Imperial measure...");
}
if ( 16 == bValue ) { // metric
// do something to set units to Metric here
configscreen(); // redraw the config screen
Serial.println("Set units to Metric measure...");
}
if ( 17 == bValue ) { // cancel
// return to main screen without doing anything
configscreen(); // redraw the config screen
Serial.println("Return to main screen from units select...");
}
// Calibration start screen...
// Calibration start is button 18, cancel is 19..
if ( 18 == bValue ) { // calibration start using 1M reference
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &calibrationstopscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Start calibration count using 1 meter reference...");
}
if ( 19 == bValue ) { // calibration start using 2m reference
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &calibrationstopscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Start calibration count using 2 meter reference...");
}
if ( 20 == bValue ) { // cancel
// return to main screen without doing anything
configscreen(); // redraw the config screen
Serial.println("Cancel from set units screen without saving changes...");
}
// Calibration stop screen...
// Calibration stop is button 18, cancel is 19..
if ( 21 == bValue ) { // calibration stop at reference distance..
// do seomthing here to save encoder data!!
configscreen(); // redraw the config screen
Serial.println("Stop calibration count using selected reference...");
}
if ( 22 == bValue ) { // cancel
// return to main screen without doing anything
configscreen(); // redraw the config screen
Serial.println("Cancel from set units setup without saving changes...");
}
// Rotation start screen...
// Rotation is button 18, cancel is 19..
if ( 23 == bValue ) { // Rotate the screen
tft.fillScreen(bg1);
ButtonRotate( 1 + TS_Rotate );
ButtonInit( 0 );
ButtonInit( &rotationscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Rotate the screen here...");
}
if ( 24 == bValue ) { // save the current rotation!
// save rotation settings in some persistent fashion here.
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &configscreen_l[0] );
prevTS_Rotate = TS_Rotate;
framWriteByte(TSROTATE, TS_Rotate);
ButtonDraw( 0 );
beep(beepTime);
Serial.println("Save rotation settings...");
}
if ( 25 == bValue ) { // cancel
// return to main screen without doing anything
tft.fillScreen(bg1);
TS_Rotate = prevTS_Rotate; // set back to original rotation
configscreen(); // redraw the config screen
Serial.println("Cancel from set rotation screen without saving changes...");
}
lastbValue = bValue;
userTime = 0;
}
} // end void loop
// -----------------------------------------
// --- Button Code Starts here
// -----------------------------------------
TS_BUTTON TS_NoButton[] = { {(char *)"X", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0} };
TS_BUTTON *TS_pbtn = TS_NoButton;
#define TS_LIMIT 10 // millisecond limit to check touch value
#define TS_MINPRESS 800 // Z Pressure return minimum to use point
#define TS_DEBOUNCE 3 // TX_Map() debounce factor
boolean TS_GetMap( int16_t &xx, int16_t &yy, boolean twoHits )
{
static int16_t lastxx = 500, lastyy = 500; // if twoHits: require two hits same point
static TS_Point pp;
static elapsedMillis tsLimit;
static int16_t xxo = 500, yyo = 500; // Store old/last returned x,y point
if ( tsLimit < TS_LIMIT ) return false;
if (!ts.touched()) return false;
if ( tsLimit >= TS_SLIDET ) TS_iiSlide = -1;
tsLimit = 0;
pp = ts.getPoint();
if ( pp.z < TS_MINPRESS ) return false;
xx = map(pp.x, tsMap[0].xt, tsMap[0].xb, tsMap[TS_Rotate].xt, tsMap[TS_Rotate].xb);
yy = map(pp.y, tsMap[0].yl, tsMap[0].yr, tsMap[TS_Rotate].yl, tsMap[TS_Rotate].yr);
if (!(TS_Rotate % 2)) {
int16_t swap = xx;
xx = yy;
yy = swap;
}
// Debounce by +/-# pixel to minimize point jitter
if ( ((xxo - TS_DEBOUNCE) <= xx) && ((xxo + TS_DEBOUNCE) >= xx) ) xx = xxo; else xxo = xx;
if ( ((yyo - TS_DEBOUNCE) <= yy) && ((yyo + TS_DEBOUNCE) >= yy) ) yy = yyo; else yyo = yy;
if ( twoHits && (xx != lastxx || yy != lastyy) ) {
lastxx = xx; lastyy = yy;
}
if ( 500 == lastyy) TS_iiSlide = -1;
lastxx = 500; lastyy = 500;
return true;
}
// int8_t ButtonType( int16_t idBut ) { return buttons[idBut].btype; }
void ButtonDraw( int16_t idBut ) {
int ii = 0;
while ( ii < TS_bCount ) {
if ((( TS_pbtn[ii].tx + TS_pbtn[ii].ww ) <= TS_xMax ) && (( TS_pbtn[ii].ty + TS_pbtn[ii].hh ) <= TS_yMax)) {
if ( !idBut || idBut == TS_pbtn[ii].bId ) {
if ( TS_TOGOFF == TS_pbtn[ii].btype || TS_FBUTN == TS_pbtn[ii].btype || TS_RBUTN == TS_pbtn[ii].btype || TS_BSLIDE == TS_pbtn[ii].btype ) {
if (TS_RBUTN == TS_pbtn[ii].btype) {
tft.fillRoundRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].hh / 2, TS_pbtn[ii].bgc);
}
else
tft.fillRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].bgc);
tft.setCursor(TS_pbtn[ii].tx + 6, TS_pbtn[ii].ty + (TS_pbtn[ii].hh / 3));
tft.setTextColor(TS_pbtn[ii].fgc); // ForeGround Text color same as Frame
tft.setTextSize(TS_pbtn[ii].fontsz);
tft.println(TS_pbtn[ii].text);
}
else if ( TS_TOGON == TS_pbtn[ii].btype || TS_ASLIDE == TS_pbtn[ii].btype )
tft.fillRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].fgc);
}
}
ii++;
}
ii = 0;
while ( ii < TS_bCount ) {
if ((( TS_pbtn[ii].tx + TS_pbtn[ii].ww ) <= TS_xMax ) && (( TS_pbtn[ii].ty + TS_pbtn[ii].hh ) <= TS_yMax)) {
if ( !idBut || idBut == TS_pbtn[ii].bId ) {
if ( TS_FRAME == TS_pbtn[ii].btype || TS_FBUTN == TS_pbtn[ii].btype )
tft.drawRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].fgc);
}
}
ii++;
}
}
boolean ButtonHit( int16_t xx, uint16_t yy, int16_t &bHit ) {
static elapsedMillis toggleTime; // Debounce/Jitter Toggle and Slider
int16_t ii = 0, iiOn = -1, iiHit = -1, idTog = 0, iiFrame = -1;
if ( toggleTime > 10000 ) toggleTime = 1000;
while ( ii < TS_bCount ) {
if ( (xx >= TS_pbtn[ii].tx && xx <= TS_pbtn[ii].tx + TS_pbtn[ii].ww) && (yy >= TS_pbtn[ii].ty && yy <= TS_pbtn[ii].ty + TS_pbtn[ii].hh)) {
if ( TS_ASLIDE == TS_pbtn[ii].btype ) {
TS_iiSlide = TS_pbtn[ii].info; // track slide start - do nothing now
return false;
}
else if ( (TS_FBUTN == TS_pbtn[ii].btype) || TS_RBUTN == TS_pbtn[ii].btype ) {
bHit = TS_pbtn[ii].bId;
TS_iiSlide = -1;
return true;
}
else if (TS_TOGOFF == TS_pbtn[ii].btype) {
iiHit = ii;
idTog = (TS_pbtn[ii].info);
TS_iiSlide = -1;
}
else if ( (TS_iiSlide == TS_pbtn[ii].info) && (TS_BSLIDE == TS_pbtn[ii].btype)) {
iiHit = ii;
idTog = (TS_pbtn[ii].info);
}
}
ii++;
}
ii = 0;
while ( ii < TS_bCount ) {
if ( ((TS_TOGON == TS_pbtn[ii].btype) || (TS_ASLIDE == TS_pbtn[ii].btype)) && (idTog == TS_pbtn[ii].info) )
iiOn = ii;
if ( (TS_FRAME == TS_pbtn[ii].btype) && (idTog == TS_pbtn[ii].info) )
iiFrame = ii;
ii++;
}
if ( -1 != iiOn && -1 != iiFrame ) {
if ( toggleTime < TS_JITTER ) {
TS_iiSlide = -1;
return false;
}
TS_pbtn[iiFrame].TS_data = !TS_pbtn[iiFrame].TS_data;
bHit = TS_pbtn[iiHit].bId;
if ( TS_iiSlide == TS_pbtn[iiOn].info ) {
TS_pbtn[iiOn].btype = TS_BSLIDE;
TS_pbtn[iiHit].btype = TS_ASLIDE;
}
else {
TS_pbtn[iiOn].btype = TS_TOGOFF;
TS_pbtn[iiHit].btype = TS_TOGON;
}
ButtonDraw( TS_pbtn[iiOn].bId ); // Limit Redraw to Framed TS_pbtn - not all buttons
ButtonDraw( TS_pbtn[iiHit].bId );
ButtonDraw( TS_pbtn[iiFrame].bId );
TS_iiSlide = -1;
toggleTime = 0;
return true;
}
return false;
}
void ButtonRotate( int setrotate )
{
TS_Rotate = setrotate;
if ( TS_Rotate > 4 ) TS_Rotate = 1;
if ( TS_Rotate < 1 ) TS_Rotate = 4;
tft.setRotation(TS_Rotate);
if ((TS_Rotate % 2)) {
TS_xMax = tsMap[1].xb;
TS_yMax = tsMap[1].yr;
}
else {
TS_xMax = tsMap[1].yr;
TS_yMax = tsMap[1].xb;
}
/*Serial.print( "\nTS_xMax =" );
Serial.println( TS_xMax );
Serial.print( "TS_yMax =" );
Serial.println( TS_yMax );*/
}
void ButtonInit( TS_BUTTON *userbuttons )
{
if ( 0 == userbuttons ) {
TS_pbtn = TS_NoButton;
tft.fillScreen(ILI9341_BLUE);
ButtonRotate( TS_Rotate );
}
else TS_pbtn = userbuttons;
TS_bCount = 0;
while ( -1 != TS_pbtn[TS_bCount].tx ) {
TS_bCount++;
}
/*Serial.print( "Buttons count =" );
Serial.println( TS_bCount );
Serial.println( sizeof( TS_BUTTON) );*/
ButtonDraw( 0 );
}
// -----------------------------------------
// --- Button Code Ends here
// -----------------------------------------
// Eric's datacar support routines start here...
void configscreen(void) { // a lot of routines return to config screen..
tft.fillScreen(bg1);
ButtonInit( 0 );
ButtonInit( &configscreen_l[0] );
ButtonDraw( 0 );
beep(beepTime);
delay(1000); //stop button rehits crudely?
}
void beep(int beeptime) { // Elemental Beep function - not much going on here anyway...
digitalWrite(beepPin, LOW);
delay(beeptime); // ..cause we just don't care, just make it beep the old fashioned way...
digitalWrite(beepPin, HIGH);
}
void framWritelong(uint16_t address, unsigned long value) { // write a long to four consecutive bytes.
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
fram.writeEnable(true); //Write the 4 bytes into the eeprom memory.
fram.write8(address, four);
fram.writeEnable(false);
fram.writeEnable(true);
fram.write8(address + 1, three);
fram.writeEnable(false);
fram.writeEnable(true);
fram.write8(address + 2, two);
fram.writeEnable(false);
fram.writeEnable(true);
fram.write8(address + 3, one);
fram.writeEnable(false);
}
void framWriteByte(uint16_t address, uint8_t value) { // write a single byte..
fram.writeEnable(true);
fram.write8(address, value);
fram.writeEnable(false);
}
unsigned long framReadlong(uint16_t address) { //Read the 4 bytes from the eeprom memory.
long four = fram.read8(address);
long three = fram.read8(address + 1);
long two = fram.read8(address + 2);
long one = fram.read8(address + 3);
//Return the recomposed long by using bitshift.
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}
uint8_t framReadByte(uint16_t address) { // read single byte
return fram.read8(address);
}