first commit

This commit is contained in:
jaksatomovic 2024-03-06 12:40:28 +01:00
commit 868b14f8c8
286 changed files with 59925 additions and 0 deletions

View file

@ -0,0 +1,107 @@
/***************************************************************************************
** Code for the GFX button UI element
** Grabbed from Adafruit_GFX library and enhanced to handle any label font
***************************************************************************************/
TFT_eSPI_Button::TFT_eSPI_Button(void) {
_gfx = nullptr;
_xd = 0;
_yd = 0;
_textdatum = MC_DATUM;
_label[9] = '\0';
currstate = false;
laststate = false;
}
// Classic initButton() function: pass center & size
void TFT_eSPI_Button::initButton(
TFT_eSPI *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
uint16_t outline, uint16_t fill, uint16_t textcolor,
char *label, uint8_t textsize)
{
// Tweak arguments and pass to the newer initButtonUL() function...
initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
textcolor, label, textsize);
}
// Newer function instead accepts upper-left corner & size
void TFT_eSPI_Button::initButtonUL(
TFT_eSPI *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
uint16_t outline, uint16_t fill, uint16_t textcolor,
char *label, uint8_t textsize)
{
_x1 = x1;
_y1 = y1;
_w = w;
_h = h;
_outlinecolor = outline;
_fillcolor = fill;
_textcolor = textcolor;
_textsize = textsize;
_gfx = gfx;
strncpy(_label, label, 9);
}
// Adjust text datum and x, y deltas
void TFT_eSPI_Button::setLabelDatum(int16_t x_delta, int16_t y_delta, uint8_t datum)
{
_xd = x_delta;
_yd = y_delta;
_textdatum = datum;
}
void TFT_eSPI_Button::drawButton(bool inverted, String long_name) {
uint16_t fill, outline, text;
if(!inverted) {
fill = _fillcolor;
outline = _outlinecolor;
text = _textcolor;
} else {
fill = _textcolor;
outline = _outlinecolor;
text = _fillcolor;
}
uint8_t r = min(_w, _h) / 4; // Corner radius
_gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
_gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
if (_gfx->textfont == 255) {
_gfx->setCursor(_x1 + (_w / 8),
_y1 + (_h / 4));
_gfx->setTextColor(text);
_gfx->setTextSize(_textsize);
_gfx->print(_label);
}
else {
_gfx->setTextColor(text, fill);
_gfx->setTextSize(_textsize);
uint8_t tempdatum = _gfx->getTextDatum();
_gfx->setTextDatum(_textdatum);
uint16_t tempPadding = _gfx->getTextPadding();
_gfx->setTextPadding(0);
if (long_name == "")
_gfx->drawString(_label, _x1 + (_w/2) + _xd, _y1 + (_h/2) - 4 + _yd);
else
_gfx->drawString(long_name, _x1 + (_w/2) + _xd, _y1 + (_h/2) - 4 + _yd);
_gfx->setTextDatum(tempdatum);
_gfx->setTextPadding(tempPadding);
}
}
bool TFT_eSPI_Button::contains(int16_t x, int16_t y) {
return ((x >= _x1) && (x < (_x1 + _w)) &&
(y >= _y1) && (y < (_y1 + _h)));
}
void TFT_eSPI_Button::press(bool p) {
laststate = currstate;
currstate = p;
}
bool TFT_eSPI_Button::isPressed() { return currstate; }
bool TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
bool TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }

View file

@ -0,0 +1,44 @@
/***************************************************************************************
// The following button class has been ported over from the Adafruit_GFX library so
// should be compatible.
// A slightly different implementation in this TFT_eSPI library allows the button
// legends to be in any font, allow longer labels and to adjust text positioning
// within button
***************************************************************************************/
class TFT_eSPI_Button : public TFT_eSPI {
public:
TFT_eSPI_Button(void);
// "Classic" initButton() uses centre & size
void initButton(TFT_eSPI *gfx, int16_t x, int16_t y,
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize);
// New/alt initButton() uses upper-left corner & size
void initButtonUL(TFT_eSPI *gfx, int16_t x1, int16_t y1,
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize);
// Adjust text datum and x, y deltas
void setLabelDatum(int16_t x_delta, int16_t y_delta, uint8_t datum = MC_DATUM);
void drawButton(bool inverted = false, String long_name = "");
bool contains(int16_t x, int16_t y);
void press(bool p);
bool isPressed();
bool justPressed();
bool justReleased();
private:
TFT_eSPI *_gfx;
int16_t _x1, _y1; // Coordinates of top-left corner of button
int16_t _xd, _yd; // Button text datum offsets (wrt centre of button)
uint16_t _w, _h; // Width and height of button
uint8_t _textsize, _textdatum; // Text size multiplier and text datum for button
uint16_t _outlinecolor, _fillcolor, _textcolor;
char _label[10]; // Button text is 9 chars maximum unless long_name used
bool currstate, laststate; // Button states
};

View file

@ -0,0 +1,582 @@
// Coded by Bodmer 10/2/18, see license in root directory.
// This is part of the TFT_eSPI class and is associated with anti-aliased font functions
////////////////////////////////////////////////////////////////////////////////////////
// New anti-aliased (smoothed) font functions added below
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: loadFont
** Description: loads parameters from a font vlw array in memory
*************************************************************************************x*/
void TFT_eSPI::loadFont(const uint8_t array[])
{
if (array == nullptr) return;
fontPtr = (uint8_t*) array;
loadFont("", false);
}
#ifdef FONT_FS_AVAILABLE
/***************************************************************************************
** Function name: loadFont
** Description: loads parameters from a font vlw file
*************************************************************************************x*/
void TFT_eSPI::loadFont(String fontName, fs::FS &ffs)
{
fontFS = ffs;
loadFont(fontName, false);
}
#endif
/***************************************************************************************
** Function name: loadFont
** Description: loads parameters from a font vlw file
*************************************************************************************x*/
void TFT_eSPI::loadFont(String fontName, bool flash)
{
/*
The vlw font format does not appear to be documented anywhere, so some reverse
engineering has been applied!
Header of vlw file comprises 6 uint32_t parameters (24 bytes total):
1. The gCount (number of character glyphs)
2. A version number (0xB = 11 for the one I am using)
3. The font size (in points, not pixels)
4. Deprecated mboxY parameter (typically set to 0)
5. Ascent in pixels from baseline to top of "d"
6. Descent in pixels from baseline to bottom of "p"
Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes):
1. Glyph Unicode stored as a 32 bit value
2. Height of bitmap bounding box
3. Width of bitmap bounding box
4. gxAdvance for cursor (setWidth in Processing)
5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up)
6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left)
7. padding value, typically 0
The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file.
Each pixel is 1 byte, an 8 bit Alpha value which represents the transparency from
0xFF foreground colour, 0x00 background. The library uses a linear interpolation
between the foreground and background RGB component colours. e.g.
pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255
To gain a performance advantage fixed point arithmetic is used with rounding and
division by 256 (shift right 8 bits is faster).
After the bitmaps is:
1 byte for font name string length (excludes null)
a zero terminated character string giving the font name
1 byte for Postscript name string length
a zero/one terminated character string giving the font name
last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed)
Glyph bitmap example is:
// Cursor coordinate positions for this and next character are marked by 'C'
// C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position
// | |
// | | ascent is top of "d", descent is bottom of "p"
// +-- gdX --+ ascent
// | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap
// | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of
// | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX)
// | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions
// | | .@@@.....@@@@ | |
// | gHeight ....@@@@@..@@ + + <-- baseline
// | | ...........@@ |
// | | ...........@@ | gdY is the offset to the top edge of the bitmap
// | | .@@.......@@. descent plot top edge of bitmap at (cursorY + ascent - gdY)
// | + x..@@@@@@@..x | x marks the corner pixels of the bitmap
// | |
// +---------------------------+ yAdvance is y delta for the next line, font size or (ascent + descent)
// some fonts can overlay in y direction so may need a user adjust value
*/
if (fontLoaded) unloadFont();
#ifdef FONT_FS_AVAILABLE
if (fontName == "") fs_font = false;
else { fontPtr = nullptr; fs_font = true; }
if (fs_font) {
spiffs = flash; // true if font is in SPIFFS
if(spiffs) fontFS = SPIFFS;
// Avoid a crash on the ESP32 if the file does not exist
if (fontFS.exists("/" + fontName + ".vlw") == false) {
Serial.println("Font file " + fontName + " not found!");
return;
}
fontFile = fontFS.open( "/" + fontName + ".vlw", "r");
if(!fontFile) return;
fontFile.seek(0, fs::SeekSet);
}
#else
// Avoid unused varaible warning
fontName = fontName;
flash = flash;
#endif
gFont.gArray = (const uint8_t*)fontPtr;
gFont.gCount = (uint16_t)readInt32(); // glyph count in file
readInt32(); // vlw encoder version - discard
gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels
readInt32(); // discard
gFont.ascent = (uint16_t)readInt32(); // top of "d"
gFont.descent = (uint16_t)readInt32(); // bottom of "p"
// These next gFont values might be updated when the Metrics are fetched
gFont.maxAscent = gFont.ascent; // Determined from metrics
gFont.maxDescent = gFont.descent; // Determined from metrics
gFont.yAdvance = gFont.ascent + gFont.descent;
gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width
fontLoaded = true;
// Fetch the metrics for each glyph
loadMetrics();
}
/***************************************************************************************
** Function name: loadMetrics
** Description: Get the metrics for each glyph and store in RAM
*************************************************************************************x*/
//#define SHOW_ASCENT_DESCENT
void TFT_eSPI::loadMetrics(void)
{
uint32_t headerPtr = 24;
uint32_t bitmapPtr = headerPtr + gFont.gCount * 28;
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if ( psramFound() )
{
gUnicode = (uint16_t*)ps_malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF)
gHeight = (uint8_t*)ps_malloc( gFont.gCount ); // Height of glyph
gWidth = (uint8_t*)ps_malloc( gFont.gCount ); // Width of glyph
gxAdvance = (uint8_t*)ps_malloc( gFont.gCount ); // xAdvance - to move x cursor
gdY = (int16_t*)ps_malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character
gdX = (int8_t*)ps_malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X
gBitmap = (uint32_t*)ps_malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file
}
else
#endif
{
gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF)
gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph
gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph
gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor
gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character
gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X
gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file
}
#ifdef SHOW_ASCENT_DESCENT
Serial.print("ascent = "); Serial.println(gFont.ascent);
Serial.print("descent = "); Serial.println(gFont.descent);
#endif
#ifdef FONT_FS_AVAILABLE
if (fs_font) fontFile.seek(headerPtr, fs::SeekSet);
#endif
uint16_t gNum = 0;
while (gNum < gFont.gCount)
{
gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value
gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph
gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph
gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor
gdY[gNum] = (int16_t)readInt32(); // y delta from baseline
gdX[gNum] = (int8_t)readInt32(); // x delta from cursor
readInt32(); // ignored
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]);
// Different glyph sets have different ascent values not always based on "d", so we could get
// the maximum glyph ascent by checking all characters. BUT this method can generate bad values
// for non-existent glyphs, so we will reply on processing for the value and disable this code for now...
/*
if (gdY[gNum] > gFont.maxAscent)
{
// Try to avoid UTF coding values and characters that tend to give duff values
if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0))
{
gFont.maxAscent = gdY[gNum];
#ifdef SHOW_ASCENT_DESCENT
Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent);
#endif
}
}
*/
// Different glyph sets have different descent values not always based on "p", so get maximum glyph descent
if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent)
{
// Avoid UTF coding values and characters that tend to give duff values
if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF))
{
gFont.maxDescent = gHeight[gNum] - gdY[gNum];
#ifdef SHOW_ASCENT_DESCENT
Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxDescent = "); Serial.println(gHeight[gNum] - gdY[gNum]);
#endif
}
}
gBitmap[gNum] = bitmapPtr;
bitmapPtr += gWidth[gNum] * gHeight[gNum];
gNum++;
yield();
}
gFont.yAdvance = gFont.maxAscent + gFont.maxDescent;
gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width
}
/***************************************************************************************
** Function name: deleteMetrics
** Description: Delete the old glyph metrics and free up the memory
*************************************************************************************x*/
void TFT_eSPI::unloadFont( void )
{
if (gUnicode)
{
free(gUnicode);
gUnicode = NULL;
}
if (gHeight)
{
free(gHeight);
gHeight = NULL;
}
if (gWidth)
{
free(gWidth);
gWidth = NULL;
}
if (gxAdvance)
{
free(gxAdvance);
gxAdvance = NULL;
}
if (gdY)
{
free(gdY);
gdY = NULL;
}
if (gdX)
{
free(gdX);
gdX = NULL;
}
if (gBitmap)
{
free(gBitmap);
gBitmap = NULL;
}
gFont.gArray = nullptr;
#ifdef FONT_FS_AVAILABLE
if (fs_font && fontFile) fontFile.close();
#endif
fontLoaded = false;
}
/***************************************************************************************
** Function name: readInt32
** Description: Get a 32 bit integer from the font file
*************************************************************************************x*/
uint32_t TFT_eSPI::readInt32(void)
{
uint32_t val = 0;
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
val = fontFile.read() << 24;
val |= fontFile.read() << 16;
val |= fontFile.read() << 8;
val |= fontFile.read();
}
else
#endif
{
val = pgm_read_byte(fontPtr++) << 24;
val |= pgm_read_byte(fontPtr++) << 16;
val |= pgm_read_byte(fontPtr++) << 8;
val |= pgm_read_byte(fontPtr++);
}
return val;
}
/***************************************************************************************
** Function name: getUnicodeIndex
** Description: Get the font file index of a Unicode character
*************************************************************************************x*/
bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index)
{
for (uint16_t i = 0; i < gFont.gCount; i++)
{
if (gUnicode[i] == unicode)
{
*index = i;
return true;
}
}
return false;
}
/***************************************************************************************
** Function name: drawGlyph
** Description: Write a character to the TFT cursor position
*************************************************************************************x*/
// Expects file to be open
void TFT_eSPI::drawGlyph(uint16_t code)
{
uint16_t fg = textcolor;
uint16_t bg = textbgcolor;
// Check if cursor has moved
if (last_cursor_x != cursor_x)
{
bg_cursor_x = cursor_x;
last_cursor_x = cursor_x;
}
if (code < 0x21)
{
if (code == 0x20) {
if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg);
cursor_x += gFont.spaceWidth;
bg_cursor_x = cursor_x;
last_cursor_x = cursor_x;
return;
}
if (code == '\n') {
cursor_x = 0;
bg_cursor_x = 0;
last_cursor_x = 0;
cursor_y += gFont.yAdvance;
if (textwrapY && (cursor_y >= height())) cursor_y = 0;
return;
}
}
uint16_t gNum = 0;
bool found = getUnicodeIndex(code, &gNum);
if (found)
{
if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width()))
{
cursor_y += gFont.yAdvance;
cursor_x = 0;
bg_cursor_x = 0;
}
if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0;
if (cursor_x == 0) cursor_x -= gdX[gNum];
uint8_t* pbuffer = nullptr;
const uint8_t* gPtr = (const uint8_t*) gFont.gArray;
#ifdef FONT_FS_AVAILABLE
if (fs_font)
{
fontFile.seek(gBitmap[gNum], fs::SeekSet);
pbuffer = (uint8_t*)malloc(gWidth[gNum]);
}
#endif
int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum];
int16_t cx = cursor_x + gdX[gNum];
// if (cx > width() && bg_cursor_x > width()) return;
// if (cursor_y > height()) return;
int16_t fxs = cx;
uint32_t fl = 0;
int16_t bxs = cx;
uint32_t bl = 0;
int16_t bx = 0;
uint8_t pixel;
startWrite(); // Avoid slow ESP32 transaction overhead for every pixel
int16_t fillwidth = 0;
int16_t fillheight = 0;
// Fill area above glyph
if (_fillbg) {
fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x;
if (fillwidth > 0) {
fillheight = gFont.maxAscent - gdY[gNum];
// Could be negative
if (fillheight > 0) {
fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor);
}
}
else {
// Could be negative
fillwidth = 0;
}
// Fill any area to left of glyph
if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor);
// Set x position in glyph area where background starts
if (bg_cursor_x > cx) bx = bg_cursor_x - cx;
// Fill any area to right of glyph
if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) {
fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor);
}
}
for (int32_t y = 0; y < gHeight[gNum]; y++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
if (spiffs)
{
fontFile.read(pbuffer, gWidth[gNum]);
//Serial.println("SPIFFS");
}
else
{
endWrite(); // Release SPI for SD card transaction
fontFile.read(pbuffer, gWidth[gNum]);
startWrite(); // Re-start SPI for TFT transaction
//Serial.println("Not SPIFFS");
}
}
#endif
for (int32_t x = 0; x < gWidth[gNum]; x++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) pixel = pbuffer[x];
else
#endif
pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y);
if (pixel)
{
if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; }
if (pixel != 0xFF)
{
if (fl) {
if (fl==1) drawPixel(fxs, y + cy, fg);
else drawFastHLine( fxs, y + cy, fl, fg);
fl = 0;
}
if (getColor) bg = getColor(x + cx, y + cy);
drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg));
}
else
{
if (fl==0) fxs = x + cx;
fl++;
}
}
else
{
if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; }
if (_fillbg) {
if (x >= bx) {
if (bl==0) bxs = x + cx;
bl++;
}
}
}
}
if (fl) { drawFastHLine( fxs, y + cy, fl, fg); fl = 0; }
if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; }
}
// Fill area below glyph
if (fillwidth > 0) {
fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]);
if (fillheight > 0) {
fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor);
}
}
if (pbuffer) free(pbuffer);
cursor_x += gxAdvance[gNum];
endWrite();
}
else
{
// Point code not in font so draw a rectangle and move on cursor
drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg);
cursor_x += gFont.spaceWidth + 1;
}
bg_cursor_x = cursor_x;
last_cursor_x = cursor_x;
}
/***************************************************************************************
** Function name: showFont
** Description: Page through all characters in font, td ms between screens
*************************************************************************************x*/
void TFT_eSPI::showFont(uint32_t td)
{
if(!fontLoaded) return;
int16_t cursorX = width(); // Force start of new page to initialise cursor
int16_t cursorY = height();// for the first character
uint32_t timeDelay = 0; // No delay before first page
fillScreen(textbgcolor);
for (uint16_t i = 0; i < gFont.gCount; i++)
{
// Check if this will need a new screen
if (cursorX + gdX[i] + gWidth[i] >= width()) {
cursorX = -gdX[i];
cursorY += gFont.yAdvance;
if (cursorY + gFont.maxAscent + gFont.descent >= height()) {
cursorX = -gdX[i];
cursorY = 0;
delay(timeDelay);
timeDelay = td;
fillScreen(textbgcolor);
}
}
setCursor(cursorX, cursorY);
drawGlyph(gUnicode[i]);
cursorX += gxAdvance[i];
yield();
}
delay(timeDelay);
fillScreen(textbgcolor);
}

View file

@ -0,0 +1,61 @@
// Coded by Bodmer 10/2/18, see license in root directory.
// This is part of the TFT_eSPI class and is associated with anti-aliased font functions
public:
// These are for the new anti-aliased fonts
void loadFont(const uint8_t array[]);
#ifdef FONT_FS_AVAILABLE
void loadFont(String fontName, fs::FS &ffs);
#endif
void loadFont(String fontName, bool flash = true);
void unloadFont( void );
bool getUnicodeIndex(uint16_t unicode, uint16_t *index);
virtual void drawGlyph(uint16_t code);
void showFont(uint32_t td);
// This is for the whole font
typedef struct
{
const uint8_t* gArray; //array start pointer
uint16_t gCount; // Total number of characters
uint16_t yAdvance; // Line advance
uint16_t spaceWidth; // Width of a space character
int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller
int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent
uint16_t maxAscent; // Maximum ascent found in font
uint16_t maxDescent; // Maximum descent found in font
} fontMetrics;
fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 };
// These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time)
uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential
uint8_t* gHeight = NULL; //cheight
uint8_t* gWidth = NULL; //cwidth
uint8_t* gxAdvance = NULL; //setWidth
int16_t* gdY = NULL; //topExtent
int8_t* gdX = NULL; //leftExtent
uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap
bool fontLoaded = false; // Flags when a anti-aliased font is loaded
#ifdef FONT_FS_AVAILABLE
fs::File fontFile;
fs::FS &fontFS = SPIFFS;
bool spiffs = true;
bool fs_font = false; // For ESP32/8266 use smooth font file or FLASH (PROGMEM) array
#else
bool fontFile = true;
#endif
private:
void loadMetrics(void);
uint32_t readInt32(void);
uint8_t* fontPtr = nullptr;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
/***************************************************************************************
// The following class creates Sprites in RAM, graphics can then be drawn in the Sprite
// and rendered quickly onto the TFT screen. The class inherits the graphics functions
// from the TFT_eSPI class. Some functions are overridden by this class so that the
// graphics are written to the Sprite rather than the TFT.
***************************************************************************************/
class TFT_eSprite : public TFT_eSPI {
public:
explicit TFT_eSprite(TFT_eSPI *tft);
~TFT_eSprite(void);
// Create a sprite of width x height pixels, return a pointer to the RAM area
// Sketch can cast returned value to (uint16_t*) for 16 bit depth if needed
// RAM required is:
// - 1 bit per pixel for 1 bit colour depth
// - 1 nibble per pixel for 4 bit colour (with palette table)
// - 1 byte per pixel for 8 bit colour (332 RGB format)
// - 2 bytes per pixel for 16 bit color depth (565 RGB format)
void* createSprite(int16_t width, int16_t height, uint8_t frames = 1);
// Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type
void* getPointer(void);
// Returns true if sprite has been created
bool created(void);
// Delete the sprite to free up the RAM
void deleteSprite(void);
// Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer)
// Returns a pointer to the Sprite frame buffer
void* frameBuffer(int8_t f);
// Set or get the colour depth to 1, 4, 8 or 16 bits. Can be used to change depth an existing
// sprite, but clears it to black, returns a new pointer if sprite is re-created.
void* setColorDepth(int8_t b);
int8_t getColorDepth(void);
// Set the palette for a 4 bit depth sprite. Only the first 16 colours in the map are used.
void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in RAM
void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in FLASH
// Set a single palette index to the given color
void setPaletteColor(uint8_t index, uint16_t color);
// Get the color at the given palette index
uint16_t getPaletteColor(uint8_t index);
// Set foreground and background colours for 1 bit per pixel Sprite
void setBitmapColor(uint16_t fg, uint16_t bg);
// Draw a single pixel at x,y
void drawPixel(int32_t x, int32_t y, uint32_t color);
// Draw a single character in the GLCD or GFXFF font
void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size),
// Fill Sprite with a colour
fillSprite(uint32_t color),
// Define a window to push 16 bit colour pixels into in a raster order
// Colours are converted to the set Sprite colour bit depth
setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1),
// Push a color (aka singe pixel) to the sprite's set window area
pushColor(uint16_t color),
// Push len colors (pixels) to the sprite's set window area
pushColor(uint16_t color, uint32_t len),
// Push a pixel pre-formatted as a 1, 4, 8 or 16 bit colour (avoids conversion overhead)
writeColor(uint16_t color),
// Set the scroll zone, top left corner at x,y with defined width and height
// The colour (optional, black is default) is used to fill the gap after the scroll
setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color = TFT_BLACK),
// Scroll the defined zone dx,dy pixels. Negative values left,up, positive right,down
// dy is optional (default is 0, so no up/down scroll).
// The sprite coordinate frame does not move because pixels are moved
scroll(int16_t dx, int16_t dy = 0),
// Draw lines
drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color),
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color),
// Fill a rectangular area with a color (aka draw a filled rectangle)
fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
// Set the coordinate rotation of the Sprite (for 1bpp Sprites only)
// Note: this uses coordinate rotation and is primarily for ePaper which does not support
// CGRAM rotation (like TFT drivers do) within the displays internal hardware
void setRotation(uint8_t rotation);
uint8_t getRotation(void);
// Push a rotated copy of Sprite to TFT with optional transparent colour
bool pushRotated(int16_t angle, uint32_t transp = 0x00FFFFFF);
// Push a rotated copy of Sprite to another different Sprite with optional transparent colour
bool pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp = 0x00FFFFFF);
// Get the TFT bounding box for a rotated copy of this Sprite
bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
// Get the destination Sprite bounding box for a rotated copy of this Sprite
bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y,
int16_t *max_x, int16_t *max_y);
// Bounding box support function
void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp,
int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x0, int32_t y0);
// return the numerical value of the pixel at x,y (used when scrolling)
// 16bpp = colour, 8bpp = byte, 4bpp = colour index, 1bpp = 1 or 0
uint16_t readPixelValue(int32_t x, int32_t y);
// Write an image (colour bitmap) to the sprite.
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0);
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
// Push the sprite to the TFT screen, this fn calls pushImage() in the TFT class.
// Optionally a "transparent" colour can be defined, pixels of that colour will not be rendered
void pushSprite(int32_t x, int32_t y);
void pushSprite(int32_t x, int32_t y, uint16_t transparent);
// Push a windowed area of the sprite to the TFT at tx, ty
bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh);
// Push the sprite to another sprite at x,y. This fn calls pushImage() in the destination sprite (dspr) class.
bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y);
bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent);
// Draw a single character in the selected font
int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font),
drawChar(uint16_t uniCode, int32_t x, int32_t y);
// Return the width and height of the sprite
int16_t width(void),
height(void);
// Functions associated with anti-aliased fonts
// Draw a single unicode character using the loaded font
void drawGlyph(uint16_t code);
// Print string to sprite using loaded font at cursor position
void printToSprite(String string);
// Print char array to sprite using loaded font at cursor position
void printToSprite(char *cbuffer, uint16_t len);
// Print indexed glyph to sprite using loaded font at x,y
int16_t printToSprite(int16_t x, int16_t y, uint16_t index);
private:
TFT_eSPI *_tft;
// Reserve memory for the Sprite and return a pointer
void* callocSprite(int16_t width, int16_t height, uint8_t frames = 1);
// Override the non-inlined TFT_eSPI functions
void begin_nin_write(void) { ; }
void end_nin_write(void) { ; }
protected:
uint8_t _bpp; // bits per pixel (1, 4, 8 or 16)
uint16_t *_img; // pointer to 16 bit sprite
uint8_t *_img8; // pointer to 1 and 8 bit sprite frame 1 or frame 2
uint8_t *_img4; // pointer to 4 bit sprite (uses color map)
uint8_t *_img8_1; // pointer to frame 1
uint8_t *_img8_2; // pointer to frame 2
uint16_t *_colorMap; // color map pointer: 16 entries, used with 4 bit color map.
int32_t _sinra; // Sine of rotation angle in fixed point
int32_t _cosra; // Cosine of rotation angle in fixed point
bool _created; // A Sprite has been created and memory reserved
bool _gFont = false;
int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; // for setWindow
int32_t _sx, _sy; // x,y for scroll zone
uint32_t _sw, _sh; // w,h for scroll zone
uint32_t _scolor; // gap fill colour for scroll zone
int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations)
int32_t _dwidth, _dheight; // Real sprite width and height (for <8bpp Sprites)
int32_t _bitwidth; // Sprite image bit width for drawPixel (for <8bpp Sprites, not swapped)
};

View file

@ -0,0 +1,345 @@
// The following touch screen support code by maxpautsch was merged 1/10/17
// https://github.com/maxpautsch
// Define TOUCH_CS is the user setup file to enable this code
// A demo is provided in examples Generic folder
// Additions by Bodmer to double sample, use Z value to improve detection reliability
// and to correct rotation handling
// See license in root directory.
/***************************************************************************************
** Function name: begin_touch_read_write - was spi_begin_touch
** Description: Start transaction and select touch controller
***************************************************************************************/
// The touch controller has a low SPI clock rate
inline void TFT_eSPI::begin_touch_read_write(void){
DMA_BUSY_CHECK;
CS_H; // Just in case it has been left low
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
#else
spi.setFrequency(SPI_TOUCH_FREQUENCY);
#endif
SET_BUS_READ_MODE;
T_CS_L;
}
/***************************************************************************************
** Function name: end_touch_read_write - was spi_end_touch
** Description: End transaction and deselect touch controller
***************************************************************************************/
inline void TFT_eSPI::end_touch_read_write(void){
T_CS_H;
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}}
#else
spi.setFrequency(SPI_FREQUENCY);
#endif
//SET_BUS_WRITE_MODE;
}
/***************************************************************************************
** Function name: Legacy - deprecated
** Description: Start/end transaction
***************************************************************************************/
void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();}
void TFT_eSPI::spi_end_touch() { end_touch_read_write();}
/***************************************************************************************
** Function name: getTouchRaw
** Description: read raw touch position. Always returns true.
***************************************************************************************/
uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
uint16_t tmp;
begin_touch_read_write();
// Start YP sample request for x position, read 4 times and keep last sample
spi.transfer(0xd0); // Start new YP conversion
spi.transfer(0); // Read first 8 bits
spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
spi.transfer(0); // Read first 8 bits
spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
spi.transfer(0); // Read first 8 bits
spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
tmp = spi.transfer(0); // Read first 8 bits
tmp = tmp <<5;
tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion
*x = tmp;
// Start XP sample request for y position, read 4 times and keep last sample
spi.transfer(0); // Read first 8 bits
spi.transfer(0x90); // Read last 8 bits and start new XP conversion
spi.transfer(0); // Read first 8 bits
spi.transfer(0x90); // Read last 8 bits and start new XP conversion
spi.transfer(0); // Read first 8 bits
spi.transfer(0x90); // Read last 8 bits and start new XP conversion
tmp = spi.transfer(0); // Read first 8 bits
tmp = tmp <<5;
tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits
*y = tmp;
end_touch_read_write();
return true;
}
/***************************************************************************************
** Function name: getTouchRawZ
** Description: read raw pressure on touchpad and return Z value.
***************************************************************************************/
uint16_t TFT_eSPI::getTouchRawZ(void){
begin_touch_read_write();
// Z sample request
int16_t tz = 0xFFF;
spi.transfer(0xb0); // Start new Z1 conversion
tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion
tz -= spi.transfer16(0x00) >> 3; // Read Z2
end_touch_read_write();
if (tz == 4095) tz = 0;
return (uint16_t)tz;
}
/***************************************************************************************
** Function name: validTouch
** Description: read validated position. Return false if not pressed.
***************************************************************************************/
#define _RAWERR 20 // Deadband error allowed in successive position samples
uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2;
// Wait until pressure stops increasing to debounce pressure
uint16_t z1 = 1;
uint16_t z2 = 0;
while (z1 > z2)
{
z2 = z1;
z1 = getTouchRawZ();
delay(1);
}
// Serial.print("Z = ");Serial.println(z1);
if (z1 <= threshold) return false;
getTouchRaw(&x_tmp,&y_tmp);
// Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp);
// Serial.print(", Z = ");Serial.println(z1);
delay(1); // Small delay to the next sample
if (getTouchRawZ() <= threshold) return false;
delay(2); // Small delay to the next sample
getTouchRaw(&x_tmp2,&y_tmp2);
// Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2);
// Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2));
if (abs(x_tmp - x_tmp2) > _RAWERR) return false;
if (abs(y_tmp - y_tmp2) > _RAWERR) return false;
*x = x_tmp;
*y = y_tmp;
return true;
}
/***************************************************************************************
** Function name: getTouch
** Description: read callibrated position. Return false if not pressed.
***************************************************************************************/
#define Z_THRESHOLD 350 // Touch pressure threshold for validating touches
uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
uint16_t x_tmp, y_tmp;
if (threshold<20) threshold = 20;
if (_pressTime > millis()) threshold=20;
uint8_t n = 5;
uint8_t valid = 0;
while (n--)
{
if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;;
}
if (valid<1) { _pressTime = 0; return false; }
_pressTime = millis() + 50;
convertRawXY(&x_tmp, &y_tmp);
if (x_tmp >= _width || y_tmp >= _height) return false;
_pressX = x_tmp;
_pressY = y_tmp;
*x = _pressX;
*y = _pressY;
return valid;
}
/***************************************************************************************
** Function name: convertRawXY
** Description: convert raw touch x,y values to screen coordinates
***************************************************************************************/
void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y)
{
uint16_t x_tmp = *x, y_tmp = *y, xx, yy;
if(!touchCalibration_rotate){
xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
if(touchCalibration_invert_x)
xx = _width - xx;
if(touchCalibration_invert_y)
yy = _height - yy;
} else {
xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
if(touchCalibration_invert_x)
xx = _width - xx;
if(touchCalibration_invert_y)
yy = _height - yy;
}
*x = xx;
*y = yy;
}
/***************************************************************************************
** Function name: calibrateTouch
** Description: generates calibration parameters for touchscreen.
***************************************************************************************/
void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){
int16_t values[] = {0,0,0,0,0,0,0,0};
uint16_t x_tmp, y_tmp;
for(uint8_t i = 0; i<4; i++){
fillRect(0, 0, size+1, size+1, color_bg);
fillRect(0, _height-size-1, size+1, size+1, color_bg);
fillRect(_width-size-1, 0, size+1, size+1, color_bg);
fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg);
if (i == 5) break; // used to clear the arrows
switch (i) {
case 0: // up left
drawLine(0, 0, 0, size, color_fg);
drawLine(0, 0, size, 0, color_fg);
drawLine(0, 0, size , size, color_fg);
break;
case 1: // bot left
drawLine(0, _height-size-1, 0, _height-1, color_fg);
drawLine(0, _height-1, size, _height-1, color_fg);
drawLine(size, _height-size-1, 0, _height-1 , color_fg);
break;
case 2: // up right
drawLine(_width-size-1, 0, _width-1, 0, color_fg);
drawLine(_width-size-1, size, _width-1, 0, color_fg);
drawLine(_width-1, size, _width-1, 0, color_fg);
break;
case 3: // bot right
drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg);
drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg);
drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg);
break;
}
// user has to get the chance to release
if(i>0) delay(1000);
for(uint8_t j= 0; j<8; j++){
// Use a lower detect threshold as corners tend to be less sensitive
while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2));
values[i*2 ] += x_tmp;
values[i*2+1] += y_tmp;
}
values[i*2 ] /= 8;
values[i*2+1] /= 8;
}
// from case 0 to case 1, the y value changed.
// If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched.
touchCalibration_rotate = false;
if(abs(values[0]-values[2]) > abs(values[1]-values[3])){
touchCalibration_rotate = true;
touchCalibration_x0 = (values[1] + values[3])/2; // calc min x
touchCalibration_x1 = (values[5] + values[7])/2; // calc max x
touchCalibration_y0 = (values[0] + values[4])/2; // calc min y
touchCalibration_y1 = (values[2] + values[6])/2; // calc max y
} else {
touchCalibration_x0 = (values[0] + values[2])/2; // calc min x
touchCalibration_x1 = (values[4] + values[6])/2; // calc max x
touchCalibration_y0 = (values[1] + values[5])/2; // calc min y
touchCalibration_y1 = (values[3] + values[7])/2; // calc max y
}
// in addition, the touch screen axis could be in the opposite direction of the TFT axis
touchCalibration_invert_x = false;
if(touchCalibration_x0 > touchCalibration_x1){
values[0]=touchCalibration_x0;
touchCalibration_x0 = touchCalibration_x1;
touchCalibration_x1 = values[0];
touchCalibration_invert_x = true;
}
touchCalibration_invert_y = false;
if(touchCalibration_y0 > touchCalibration_y1){
values[0]=touchCalibration_y0;
touchCalibration_y0 = touchCalibration_y1;
touchCalibration_y1 = values[0];
touchCalibration_invert_y = true;
}
// pre calculate
touchCalibration_x1 -= touchCalibration_x0;
touchCalibration_y1 -= touchCalibration_y0;
if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
// export parameters, if pointer valid
if(parameters != NULL){
parameters[0] = touchCalibration_x0;
parameters[1] = touchCalibration_x1;
parameters[2] = touchCalibration_y0;
parameters[3] = touchCalibration_y1;
parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2);
}
}
/***************************************************************************************
** Function name: setTouch
** Description: imports calibration parameters for touchscreen.
***************************************************************************************/
void TFT_eSPI::setTouch(uint16_t *parameters){
touchCalibration_x0 = parameters[0];
touchCalibration_x1 = parameters[1];
touchCalibration_y0 = parameters[2];
touchCalibration_y1 = parameters[3];
if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
touchCalibration_rotate = parameters[4] & 0x01;
touchCalibration_invert_x = parameters[4] & 0x02;
touchCalibration_invert_y = parameters[4] & 0x04;
}

View file

@ -0,0 +1,39 @@
// Coded by Bodmer 10/2/18, see license in root directory.
// This is part of the TFT_eSPI class and is associated with the Touch Screen handlers
public:
// Get raw x,y ADC values from touch controller
uint8_t getTouchRaw(uint16_t *x, uint16_t *y);
// Get raw z (i.e. pressure) ADC value from touch controller
uint16_t getTouchRawZ(void);
// Convert raw x,y values to calibrated and correctly rotated screen coordinates
void convertRawXY(uint16_t *x, uint16_t *y);
// Get the screen touch coordinates, returns true if screen has been touched
// if the touch coordinates are off screen then x and y are not updated
// The returned value can be treated as a bool type, false or 0 means touch not detected
// In future the function may return an 8 "quality" (jitter) value.
uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600);
// Run screen calibration and test, report calibration values to the serial port
void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size);
// Set the screen calibration values
void setTouch(uint16_t *data);
private:
// Legacy support only - deprecated TODO: delete
void spi_begin_touch();
void spi_end_touch();
// Handlers for the touch controller bus settings
inline void begin_touch_read_write() __attribute__((always_inline));
inline void end_touch_read_write() __attribute__((always_inline));
// Private function to validate a touch, allow settle time and reduce spurious coordinates
uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600);
// Initialise with example calibration values so processor does not crash if setTouch() not called in setup()
uint16_t touchCalibration_x0 = 300, touchCalibration_x1 = 3600, touchCalibration_y0 = 300, touchCalibration_y1 = 3600;
uint8_t touchCalibration_rotate = 1, touchCalibration_invert_x = 2, touchCalibration_invert_y = 0;
uint32_t _pressTime; // Press and hold time-out
uint16_t _pressX, _pressY; // For future use (last sampled calibrated coordinates)