5372 lines
		
	
	
		
			145 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			5372 lines
		
	
	
		
			145 KiB
		
	
	
	
		
			C++
		
	
	
	
/***************************************************
 | 
						|
  Arduino TFT graphics library targeted at ESP8266
 | 
						|
  and ESP32 based boards.
 | 
						|
 | 
						|
  This is a standalone library that contains the
 | 
						|
  hardware driver, the graphics functions and the
 | 
						|
  proportional fonts.
 | 
						|
 | 
						|
  The larger fonts are Run Length Encoded to reduce their
 | 
						|
  size.
 | 
						|
 | 
						|
  Created by Bodmer 2/12/16
 | 
						|
  Bodmer: Added RPi 16 bit display support
 | 
						|
 ****************************************************/
 | 
						|
 | 
						|
 | 
						|
#include "TFT_eSPI.h"
 | 
						|
 | 
						|
#if defined (ESP32)
 | 
						|
  #if !defined (ESP32_PARALLEL)
 | 
						|
    #ifdef USE_HSPI_PORT
 | 
						|
      SPIClass spi = SPIClass(HSPI);
 | 
						|
    #else // use default VSPI port
 | 
						|
      SPIClass& spi = SPI;
 | 
						|
    #endif
 | 
						|
  #endif
 | 
						|
#else // ESP8266
 | 
						|
  SPIClass& spi = SPI;
 | 
						|
#endif
 | 
						|
 | 
						|
  // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
 | 
						|
#if defined (ESP32) && !defined (SUPPORT_TRANSACTIONS)
 | 
						|
  #define SUPPORT_TRANSACTIONS
 | 
						|
#endif
 | 
						|
 | 
						|
// If it is a 16bit serial display we must transfer 16 bits every time
 | 
						|
#ifdef RPI_ILI9486_DRIVER
 | 
						|
  #define CMD_BITS 16-1
 | 
						|
#else
 | 
						|
  #define CMD_BITS 8-1
 | 
						|
#endif
 | 
						|
 | 
						|
// Fast block write prototype
 | 
						|
void writeBlock(uint16_t color, uint32_t repeat);
 | 
						|
 | 
						|
// Byte read prototype
 | 
						|
uint8_t readByte(void);
 | 
						|
 | 
						|
// GPIO parallel input/output control
 | 
						|
void busDir(uint32_t mask, uint8_t mode);
 | 
						|
 | 
						|
inline void TFT_eSPI::spi_begin(void){
 | 
						|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
 | 
						|
  if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L;}
 | 
						|
#else
 | 
						|
  CS_L;
 | 
						|
#endif
 | 
						|
#ifdef ESP8266
 | 
						|
  SPI1U = SPI1U_WRITE;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void TFT_eSPI::spi_end(void){
 | 
						|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
 | 
						|
  if(!inTransaction) {if (!locked) {locked = true; CS_H; spi.endTransaction();}}
 | 
						|
  #ifdef ESP8266
 | 
						|
    SPI1U = SPI1U_READ;
 | 
						|
  #endif
 | 
						|
#else
 | 
						|
  if(!inTransaction) CS_H;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void TFT_eSPI::spi_begin_read(void){
 | 
						|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
 | 
						|
  if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L;}
 | 
						|
#else
 | 
						|
  #if !defined(ESP32_PARALLEL)
 | 
						|
    spi.setFrequency(SPI_READ_FREQUENCY);
 | 
						|
  #endif
 | 
						|
   CS_L;
 | 
						|
#endif
 | 
						|
#ifdef ESP8266
 | 
						|
  SPI1U = SPI1U_READ;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
inline void TFT_eSPI::spi_end_read(void){
 | 
						|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
 | 
						|
  if(!inTransaction) {if (!locked) {locked = true; CS_H; spi.endTransaction();}}
 | 
						|
#else
 | 
						|
  #if !defined(ESP32_PARALLEL)
 | 
						|
    spi.setFrequency(SPI_FREQUENCY);
 | 
						|
  #endif
 | 
						|
   if(!inTransaction) CS_H;
 | 
						|
#endif
 | 
						|
#ifdef ESP8266
 | 
						|
  SPI1U = SPI1U_WRITE;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#if defined (TOUCH_CS) && defined (SPI_TOUCH_FREQUENCY) // && !defined(ESP32_PARALLEL)
 | 
						|
 | 
						|
  inline void TFT_eSPI::spi_begin_touch(void){
 | 
						|
   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
 | 
						|
 | 
						|
  #ifdef ESP8266
 | 
						|
    SPI1U = SPI1U_READ;
 | 
						|
  #endif
 | 
						|
 | 
						|
  T_CS_L;
 | 
						|
  }
 | 
						|
 | 
						|
  inline void TFT_eSPI::spi_end_touch(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
 | 
						|
 | 
						|
  #ifdef ESP8266
 | 
						|
    SPI1U = SPI1U_WRITE;
 | 
						|
  #endif
 | 
						|
  }
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           TFT_eSPI
 | 
						|
** Description:             Constructor , we must use hardware SPI pins
 | 
						|
***************************************************************************************/
 | 
						|
TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
 | 
						|
{
 | 
						|
 | 
						|
// The control pins are deliberately set to the inactive state (CS high) as setup()
 | 
						|
// might call and initialise other SPI peripherals which would could cause conflicts
 | 
						|
// if CS is floating or undefined.
 | 
						|
#ifdef TFT_CS
 | 
						|
  digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
 | 
						|
  pinMode(TFT_CS, OUTPUT);
 | 
						|
#endif
 | 
						|
 | 
						|
// Configure chip select for touchscreen controller if present
 | 
						|
#ifdef TOUCH_CS
 | 
						|
  digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive)
 | 
						|
  pinMode(TOUCH_CS, OUTPUT);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef TFT_WR
 | 
						|
  digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive)
 | 
						|
  pinMode(TFT_WR, OUTPUT);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef TFT_DC
 | 
						|
  digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
 | 
						|
  pinMode(TFT_DC, OUTPUT);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef TFT_RST
 | 
						|
  if (TFT_RST >= 0) {
 | 
						|
    digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device
 | 
						|
    pinMode(TFT_RST, OUTPUT);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef ESP32_PARALLEL
 | 
						|
 | 
						|
  // Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically
 | 
						|
  for (int32_t c = 0; c<256; c++)
 | 
						|
  {
 | 
						|
    xset_mask[c] = 0;
 | 
						|
    if ( c & 0x01 ) xset_mask[c] |= (1 << TFT_D0);
 | 
						|
    if ( c & 0x02 ) xset_mask[c] |= (1 << TFT_D1);
 | 
						|
    if ( c & 0x04 ) xset_mask[c] |= (1 << TFT_D2);
 | 
						|
    if ( c & 0x08 ) xset_mask[c] |= (1 << TFT_D3);
 | 
						|
    if ( c & 0x10 ) xset_mask[c] |= (1 << TFT_D4);
 | 
						|
    if ( c & 0x20 ) xset_mask[c] |= (1 << TFT_D5);
 | 
						|
    if ( c & 0x40 ) xset_mask[c] |= (1 << TFT_D6);
 | 
						|
    if ( c & 0x80 ) xset_mask[c] |= (1 << TFT_D7);
 | 
						|
  }
 | 
						|
 | 
						|
  // Make sure read is high before we set the bus to output
 | 
						|
  digitalWrite(TFT_RD, HIGH);
 | 
						|
  pinMode(TFT_RD, OUTPUT);
 | 
						|
  
 | 
						|
  GPIO.out_w1ts = set_mask(255); // Set data bus to 0xFF
 | 
						|
 | 
						|
  // Set TFT data bus lines to output
 | 
						|
  busDir(dir_mask, OUTPUT);
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
  _init_width  = _width  = w; // Set by specific xxxxx_Defines.h file or by users sketch
 | 
						|
  _init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch
 | 
						|
  rotation  = 0;
 | 
						|
  cursor_y  = cursor_x  = 0;
 | 
						|
  textfont  = 1;
 | 
						|
  textsize  = 1;
 | 
						|
  textcolor   = bitmap_fg = 0xFFFF; // White
 | 
						|
  textbgcolor = bitmap_bg = 0x0000; // Black
 | 
						|
  padX = 0;             // No padding
 | 
						|
  isDigits   = false;   // No bounding box adjustment
 | 
						|
  textwrapX  = true;    // Wrap text at end of line when using print stream
 | 
						|
  textwrapY  = false;   // Wrap text at bottom of screen when using print stream
 | 
						|
  textdatum = TL_DATUM; // Top Left text alignment is default
 | 
						|
  fontsloaded = 0;
 | 
						|
 | 
						|
  _swapBytes = false;   // Do not swap colour bytes by default
 | 
						|
 | 
						|
  locked = true;        // ESP32 transaction mutex lock flags
 | 
						|
  inTransaction = false;
 | 
						|
 | 
						|
  _booted   = true;
 | 
						|
  _cp437    = true;
 | 
						|
  _utf8     = true;
 | 
						|
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
 | 
						|
  _xpivot = 0;
 | 
						|
  _ypivot = 0;
 | 
						|
 | 
						|
  cspinmask = 0;
 | 
						|
  dcpinmask = 0;
 | 
						|
  wrpinmask = 0;
 | 
						|
  sclkpinmask = 0;
 | 
						|
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
  fontsloaded  = 0x0002; // Bit 1 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT2
 | 
						|
  fontsloaded |= 0x0004; // Bit 2 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT4
 | 
						|
  fontsloaded |= 0x0010; // Bit 4 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT6
 | 
						|
  fontsloaded |= 0x0040; // Bit 6 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT7
 | 
						|
  fontsloaded |= 0x0080; // Bit 7 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT8
 | 
						|
  fontsloaded |= 0x0100; // Bit 8 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_FONT8N
 | 
						|
  fontsloaded |= 0x0200; // Bit 9 set
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  fontsloaded |= 0x8000; // Bit 15 set
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           begin
 | 
						|
** Description:             Included for backwards compatibility
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::begin(uint8_t tc)
 | 
						|
{
 | 
						|
 init(tc);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           init (tc is tab colour for ST7735 displays only)
 | 
						|
** Description:             Reset, then initialise the TFT display registers
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::init(uint8_t tc)
 | 
						|
{
 | 
						|
  if (_booted)
 | 
						|
  {
 | 
						|
#if !defined (ESP32)
 | 
						|
  #if defined (TFT_CS) && (TFT_CS >= 0)
 | 
						|
    cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS);
 | 
						|
  #endif
 | 
						|
 | 
						|
  #if defined (TFT_DC) && (TFT_DC >= 0)
 | 
						|
    dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
 | 
						|
  #endif
 | 
						|
  
 | 
						|
  #if defined (TFT_WR) && (TFT_WR >= 0)
 | 
						|
    wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
 | 
						|
  #endif
 | 
						|
  
 | 
						|
  #if defined (TFT_SCLK) && (TFT_SCLK >= 0)
 | 
						|
    sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK);
 | 
						|
  #endif
 | 
						|
  
 | 
						|
  #ifdef TFT_SPI_OVERLAP
 | 
						|
    // Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS
 | 
						|
    //    pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
 | 
						|
    //spi.pins(        6,          7,           8,          0);
 | 
						|
    spi.pins(6, 7, 8, 0);
 | 
						|
  #endif
 | 
						|
 | 
						|
  spi.begin(); // This will set HMISO to input
 | 
						|
 | 
						|
#else
 | 
						|
  #if !defined(ESP32_PARALLEL)
 | 
						|
    #if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP)
 | 
						|
      spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
 | 
						|
    #else
 | 
						|
      spi.begin();
 | 
						|
    #endif
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
    inTransaction = false;
 | 
						|
    locked = true;
 | 
						|
 | 
						|
  // SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
 | 
						|
  // so the code here is for ESP8266 only
 | 
						|
#if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266)
 | 
						|
    spi.setBitOrder(MSBFIRST);
 | 
						|
    spi.setDataMode(TFT_SPI_MODE);
 | 
						|
    spi.setFrequency(SPI_FREQUENCY);
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(ESP32_PARALLEL)
 | 
						|
    digitalWrite(TFT_CS, LOW); // Chip select low permanently
 | 
						|
    pinMode(TFT_CS, OUTPUT);
 | 
						|
#else
 | 
						|
  #ifdef TFT_CS
 | 
						|
    // Set to output once again in case D6 (MISO) is used for CS
 | 
						|
    digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
 | 
						|
    pinMode(TFT_CS, OUTPUT);
 | 
						|
  #else
 | 
						|
    spi.setHwCs(1); // Use hardware SS toggling
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  // Set to output once again in case D6 (MISO) is used for DC
 | 
						|
#ifdef TFT_DC
 | 
						|
    digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
 | 
						|
    pinMode(TFT_DC, OUTPUT);
 | 
						|
#endif
 | 
						|
 | 
						|
    _booted = false;
 | 
						|
    spi_end();
 | 
						|
  } // end of: if just _booted
 | 
						|
 | 
						|
  // Toggle RST low to reset
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
#ifdef TFT_RST
 | 
						|
  if (TFT_RST >= 0) {
 | 
						|
    digitalWrite(TFT_RST, HIGH);
 | 
						|
    delay(5);
 | 
						|
    digitalWrite(TFT_RST, LOW);
 | 
						|
    delay(20);
 | 
						|
    digitalWrite(TFT_RST, HIGH);
 | 
						|
  }
 | 
						|
  else writecommand(TFT_SWRST); // Software reset
 | 
						|
#else
 | 
						|
  writecommand(TFT_SWRST); // Software reset
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
 | 
						|
  delay(150); // Wait for reset to complete
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  
 | 
						|
  // This loads the driver specific initialisation code  <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
#if   defined (ILI9341_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9341_Init.h"
 | 
						|
 | 
						|
#elif defined (ST7735_DRIVER)
 | 
						|
    tabcolor = tc;
 | 
						|
    #include "TFT_Drivers/ST7735_Init.h"
 | 
						|
 | 
						|
#elif defined (ILI9163_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9163_Init.h"
 | 
						|
 | 
						|
#elif defined (S6D02A1_DRIVER)
 | 
						|
    #include "TFT_Drivers/S6D02A1_Init.h"
 | 
						|
     
 | 
						|
#elif defined (RPI_ILI9486_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9486_Init.h"
 | 
						|
 | 
						|
#elif defined (ILI9486_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9486_Init.h"
 | 
						|
 | 
						|
#elif defined (ILI9481_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9481_Init.h"
 | 
						|
 | 
						|
#elif defined (ILI9488_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9488_Init.h"
 | 
						|
 | 
						|
#elif defined (HX8357D_DRIVER)
 | 
						|
    #include "TFT_Drivers/HX8357D_Init.h"
 | 
						|
 | 
						|
#elif defined (ST7789_DRIVER)
 | 
						|
    #include "TFT_Drivers/ST7789_Init.h"
 | 
						|
 | 
						|
#elif defined (R61581_DRIVER)
 | 
						|
    #include "TFT_Drivers/R61581_Init.h"
 | 
						|
 | 
						|
#elif defined (RM68140_DRIVER)
 | 
						|
	#include "TFT_Drivers/RM68140_Init.h"
 | 
						|
 | 
						|
#elif defined (ST7789_2_DRIVER)
 | 
						|
    #include "TFT_Drivers/ST7789_2_Init.h"
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef TFT_INVERSION_ON
 | 
						|
  writecommand(TFT_INVON);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef TFT_INVERSION_OFF
 | 
						|
  writecommand(TFT_INVOFF);
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
 | 
						|
  setRotation(rotation);
 | 
						|
 | 
						|
#if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON)
 | 
						|
  digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
 | 
						|
  pinMode(TFT_BL, OUTPUT);
 | 
						|
#else
 | 
						|
  #if defined (TFT_BL) && defined (M5STACK)
 | 
						|
    // Turn on the back-light LED
 | 
						|
    digitalWrite(TFT_BL, HIGH);
 | 
						|
    pinMode(TFT_BL, OUTPUT);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setRotation
 | 
						|
** Description:             rotate the screen orientation m = 0-3 or 4-7 for BMP drawing
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setRotation(uint8_t m)
 | 
						|
{
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
    // This loads the driver specific rotation code  <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
#if   defined (ILI9341_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9341_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ST7735_DRIVER)
 | 
						|
    #include "TFT_Drivers/ST7735_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ILI9163_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9163_Rotation.h"
 | 
						|
 | 
						|
#elif defined (S6D02A1_DRIVER)
 | 
						|
    #include "TFT_Drivers/S6D02A1_Rotation.h"
 | 
						|
 | 
						|
#elif defined (RPI_ILI9486_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9486_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ILI9486_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9486_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ILI9481_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9481_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ILI9488_DRIVER)
 | 
						|
    #include "TFT_Drivers/ILI9488_Rotation.h"
 | 
						|
 | 
						|
#elif defined (HX8357D_DRIVER)
 | 
						|
    #include "TFT_Drivers/HX8357D_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ST7789_DRIVER)
 | 
						|
    #include "TFT_Drivers/ST7789_Rotation.h"
 | 
						|
 | 
						|
#elif defined (R61581_DRIVER)
 | 
						|
    #include "TFT_Drivers/R61581_Rotation.h"
 | 
						|
 | 
						|
#elif defined (RM68140_DRIVER)
 | 
						|
	#include "TFT_Drivers/RM68140_Rotation.h"
 | 
						|
 | 
						|
#elif defined (ST7789_2_DRIVER)
 | 
						|
    #include "TFT_Drivers/ST7789_2_Rotation.h"
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
  delayMicroseconds(10);
 | 
						|
 | 
						|
  spi_end();
 | 
						|
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           commandList, used for FLASH based lists only (e.g. ST7735)
 | 
						|
** Description:             Get initialisation commands from FLASH and send to TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::commandList (const uint8_t *addr)
 | 
						|
{
 | 
						|
  uint8_t  numCommands;
 | 
						|
  uint8_t  numArgs;
 | 
						|
  uint8_t  ms;
 | 
						|
 | 
						|
  numCommands = pgm_read_byte(addr++);   // Number of commands to follow
 | 
						|
 | 
						|
  while (numCommands--)                  // For each command...
 | 
						|
  {
 | 
						|
    writecommand(pgm_read_byte(addr++)); // Read, issue command
 | 
						|
    numArgs = pgm_read_byte(addr++);     // Number of args to follow
 | 
						|
    ms = numArgs & TFT_INIT_DELAY;       // If hibit set, delay follows args
 | 
						|
    numArgs &= ~TFT_INIT_DELAY;          // Mask out delay bit
 | 
						|
 | 
						|
    while (numArgs--)                    // For each argument...
 | 
						|
    {
 | 
						|
      writedata(pgm_read_byte(addr++));  // Read, issue argument
 | 
						|
    }
 | 
						|
 | 
						|
    if (ms)
 | 
						|
    {
 | 
						|
      ms = pgm_read_byte(addr++);        // Read post-command delay time (ms)
 | 
						|
      delay( (ms==255 ? 500 : ms) );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           spiwrite
 | 
						|
** Description:             Write 8 bits to SPI port (legacy support only)
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::spiwrite(uint8_t c)
 | 
						|
{
 | 
						|
  tft_Write_8(c);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           writecommand
 | 
						|
** Description:             Send an 8 bit command to the TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::writecommand(uint8_t c)
 | 
						|
{
 | 
						|
  spi_begin(); // CS_L;
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  tft_Write_8(c);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  spi_end();  // CS_H;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           writedata
 | 
						|
** Description:             Send a 8 bit data value to the TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::writedata(uint8_t d)
 | 
						|
{
 | 
						|
  spi_begin(); // CS_L;
 | 
						|
 | 
						|
  DC_D;        // Play safe, but should already be in data mode
 | 
						|
 | 
						|
  tft_Write_8(d);
 | 
						|
 | 
						|
  CS_L;        // Allow more hold time for low VDI rail
 | 
						|
 | 
						|
  spi_end();   // CS_H;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           readcommand8
 | 
						|
** Description:             Read a 8 bit data value from an indexed command register
 | 
						|
***************************************************************************************/
 | 
						|
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
 | 
						|
{
 | 
						|
  uint8_t reg = 0;
 | 
						|
#ifdef ESP32_PARALLEL
 | 
						|
 | 
						|
  writecommand(cmd_function); // Sets DC and CS high 
 | 
						|
 | 
						|
  busDir(dir_mask, INPUT);
 | 
						|
 | 
						|
  CS_L;
 | 
						|
 | 
						|
  // Read nth parameter (assumes caller discards 1st parameter or points index to 2nd)
 | 
						|
  while(index--) reg = readByte();
 | 
						|
 | 
						|
  busDir(dir_mask, OUTPUT);
 | 
						|
 | 
						|
  CS_H;
 | 
						|
 | 
						|
#else
 | 
						|
  // for ILI9341 Interface II i.e. IM [3:0] = "1101"
 | 
						|
  spi_begin_read();
 | 
						|
  index = 0x10 + (index & 0x0F);
 | 
						|
 | 
						|
  DC_C;
 | 
						|
  tft_Write_8(0xD9);
 | 
						|
  DC_D;
 | 
						|
  tft_Write_8(index);
 | 
						|
 | 
						|
  CS_H; // Some displays seem to need CS to be pulsed here, or is just a delay needed?
 | 
						|
  CS_L;
 | 
						|
 | 
						|
  DC_C;
 | 
						|
  tft_Write_8(cmd_function);
 | 
						|
  DC_D;
 | 
						|
  reg = tft_Read_8();
 | 
						|
 | 
						|
  spi_end_read();
 | 
						|
#endif
 | 
						|
  return reg;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           readcommand16
 | 
						|
** Description:             Read a 16 bit data value from an indexed command register
 | 
						|
***************************************************************************************/
 | 
						|
uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index)
 | 
						|
{
 | 
						|
  uint32_t reg;
 | 
						|
 | 
						|
  reg  = (readcommand8(cmd_function, index + 0) <<  8);
 | 
						|
  reg |= (readcommand8(cmd_function, index + 1) <<  0);
 | 
						|
 | 
						|
  return reg;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           readcommand32
 | 
						|
** Description:             Read a 32 bit data value from an indexed command register
 | 
						|
***************************************************************************************/
 | 
						|
uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index)
 | 
						|
{
 | 
						|
  uint32_t reg;
 | 
						|
 | 
						|
  reg  = (readcommand8(cmd_function, index + 0) << 24);
 | 
						|
  reg |= (readcommand8(cmd_function, index + 1) << 16);
 | 
						|
  reg |= (readcommand8(cmd_function, index + 2) <<  8);
 | 
						|
  reg |= (readcommand8(cmd_function, index + 3) <<  0);
 | 
						|
 | 
						|
  return reg;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           read pixel (for SPI Interface II i.e. IM [3:0] = "1101")
 | 
						|
** Description:             Read 565 pixel colours from a pixel
 | 
						|
***************************************************************************************/
 | 
						|
uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
 | 
						|
{
 | 
						|
#if defined(ESP32_PARALLEL)
 | 
						|
 | 
						|
  readAddrWindow(x0, y0, 1, 1); // Sets CS low
 | 
						|
 | 
						|
  // Set masked pins D0- D7 to input
 | 
						|
  busDir(dir_mask, INPUT); 
 | 
						|
 | 
						|
  // Dummy read to throw away don't care value
 | 
						|
  readByte();
 | 
						|
 | 
						|
  // Fetch the 16 bit BRG pixel
 | 
						|
  //uint16_t rgb = (readByte() << 8) | readByte();
 | 
						|
 | 
						|
  #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes
 | 
						|
 | 
						|
  // Read window pixel 24 bit RGB values and fill in LS bits
 | 
						|
  uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
 | 
						|
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  // Set masked pins D0- D7 to output
 | 
						|
  busDir(dir_mask, OUTPUT);
 | 
						|
 | 
						|
  return rgb;
 | 
						|
 | 
						|
  #else // ILI9481 16 bit read
 | 
						|
 | 
						|
  // Fetch the 16 bit BRG pixel
 | 
						|
  uint16_t bgr = (readByte() << 8) | readByte();
 | 
						|
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  // Set masked pins D0- D7 to output
 | 
						|
  busDir(dir_mask, OUTPUT);
 | 
						|
 | 
						|
  // Swap Red and Blue (could check MADCTL setting to see if this is needed)
 | 
						|
  return  (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
 | 
						|
  #endif
 | 
						|
 | 
						|
#else // Not ESP32_PARALLEL
 | 
						|
 | 
						|
  spi_begin_read();
 | 
						|
 | 
						|
  readAddrWindow(x0, y0, 1, 1); // Sets CS low
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    begin_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  // Dummy read to throw away don't care value
 | 
						|
  tft_Read_8();
 | 
						|
  
 | 
						|
  //#if !defined (ILI9488_DRIVER)
 | 
						|
 | 
						|
    // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
 | 
						|
    // as the TFT stores colours as 18 bits
 | 
						|
    uint8_t r = tft_Read_8();
 | 
						|
    uint8_t g = tft_Read_8();
 | 
						|
    uint8_t b = tft_Read_8();
 | 
						|
/*
 | 
						|
  #else
 | 
						|
 | 
						|
    // The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
 | 
						|
    // so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
 | 
						|
    uint8_t r = (tft_Read_8()&0x7E)<<1;
 | 
						|
    uint8_t g = (tft_Read_8()&0x7E)<<1;
 | 
						|
    uint8_t b = (tft_Read_8()&0x7E)<<1;
 | 
						|
 | 
						|
  #endif
 | 
						|
*/
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    end_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  spi_end_read();
 | 
						|
 | 
						|
  return color565(r, g, b);
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           read byte  - supports class functions
 | 
						|
** Description:             Read a byte from ESP32 8 bit data port
 | 
						|
***************************************************************************************/
 | 
						|
// Bus MUST be set to input before calling this function!
 | 
						|
uint8_t readByte(void)
 | 
						|
{
 | 
						|
  uint8_t b = 0;
 | 
						|
 | 
						|
#ifdef ESP32_PARALLEL
 | 
						|
  RD_L;
 | 
						|
  uint32_t reg;           // Read all GPIO pins 0-31
 | 
						|
  reg = gpio_input_get(); // Read three times to allow for bus access time
 | 
						|
  reg = gpio_input_get();
 | 
						|
  reg = gpio_input_get(); // Data should be stable now
 | 
						|
  RD_H;
 | 
						|
 | 
						|
  // Check GPIO bits used and build value
 | 
						|
  b  = (((reg>>TFT_D0)&1) << 0);
 | 
						|
  b |= (((reg>>TFT_D1)&1) << 1);
 | 
						|
  b |= (((reg>>TFT_D2)&1) << 2);
 | 
						|
  b |= (((reg>>TFT_D3)&1) << 3);
 | 
						|
  b |= (((reg>>TFT_D4)&1) << 4);
 | 
						|
  b |= (((reg>>TFT_D5)&1) << 5);
 | 
						|
  b |= (((reg>>TFT_D6)&1) << 6);
 | 
						|
  b |= (((reg>>TFT_D7)&1) << 7);
 | 
						|
#endif
 | 
						|
 | 
						|
  return b;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           masked GPIO direction control  - supports class functions
 | 
						|
** Description:             Set masked ESP32 GPIO pins to input or output
 | 
						|
***************************************************************************************/
 | 
						|
void busDir(uint32_t mask, uint8_t mode)
 | 
						|
{
 | 
						|
#ifdef ESP32_PARALLEL
 | 
						|
 | 
						|
  // Supports GPIO 0 - 31 on ESP32 only
 | 
						|
  gpio_config_t gpio;
 | 
						|
 | 
						|
  gpio.pin_bit_mask = mask;
 | 
						|
  gpio.mode         = GPIO_MODE_INPUT;
 | 
						|
  gpio.pull_up_en   = GPIO_PULLUP_ENABLE;
 | 
						|
  gpio.pull_down_en = GPIO_PULLDOWN_DISABLE;
 | 
						|
  gpio.intr_type    = GPIO_INTR_DISABLE;
 | 
						|
 | 
						|
  if (mode == OUTPUT) gpio.mode = GPIO_MODE_OUTPUT;
 | 
						|
 | 
						|
  gpio_config(&gpio);
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
 | 
						|
** Description:             Read 565 pixel colours from a defined area
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
 | 
						|
{
 | 
						|
  if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
 | 
						|
 | 
						|
#if defined(ESP32_PARALLEL)
 | 
						|
 | 
						|
  readAddrWindow(x, y, w, h); // Sets CS low
 | 
						|
 | 
						|
  // Set masked pins D0- D7 to input
 | 
						|
  busDir(dir_mask, INPUT);
 | 
						|
 | 
						|
  // Dummy read to throw away don't care value
 | 
						|
  readByte();
 | 
						|
 | 
						|
  // Total pixel count
 | 
						|
  uint32_t len = w * h;
 | 
						|
 | 
						|
#if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes
 | 
						|
  // Fetch the 24 bit RGB value
 | 
						|
  while (len--) {
 | 
						|
    // Assemble the RGB 16 bit colour
 | 
						|
    uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
 | 
						|
 | 
						|
    // Swapped byte order for compatibility with pushRect()
 | 
						|
    *data++ = (rgb<<8) | (rgb>>8);
 | 
						|
  }
 | 
						|
#else // ILI9481 reads as 16 bits
 | 
						|
  // Fetch the 16 bit BRG pixels
 | 
						|
  while (len--) {
 | 
						|
    // Read the BRG 16 bit colour
 | 
						|
    uint16_t bgr = (readByte() << 8) | readByte();
 | 
						|
 | 
						|
    // Swap Red and Blue (could check MADCTL setting to see if this is needed)
 | 
						|
    uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
 | 
						|
 | 
						|
    // Swapped byte order for compatibility with pushRect()
 | 
						|
    *data++ = (rgb<<8) | (rgb>>8);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  // Set masked pins D0- D7 to output
 | 
						|
  busDir(dir_mask, OUTPUT);
 | 
						|
 | 
						|
#else // Not ESP32_PARALLEL
 | 
						|
 | 
						|
  spi_begin_read();
 | 
						|
 | 
						|
  readAddrWindow(x, y, w, h); // Sets CS low
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    begin_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  // Dummy read to throw away don't care value
 | 
						|
  tft_Read_8();
 | 
						|
 | 
						|
  // Read window pixel 24 bit RGB values
 | 
						|
  uint32_t len = w * h;
 | 
						|
  while (len--) {
 | 
						|
 | 
						|
  #if !defined (ILI9488_DRIVER)
 | 
						|
 | 
						|
    // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
 | 
						|
    // as the TFT stores colours as 18 bits
 | 
						|
    uint8_t r = tft_Read_8();
 | 
						|
    uint8_t g = tft_Read_8();
 | 
						|
    uint8_t b = tft_Read_8();
 | 
						|
 | 
						|
  #else
 | 
						|
 | 
						|
    // The 6 colour bits are in LS 6 bits of each byte but we do not include the extra clock pulse
 | 
						|
    // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left
 | 
						|
    uint8_t r = (tft_Read_8()&0x7E)<<1;
 | 
						|
    uint8_t g = (tft_Read_8()&0x7E)<<1;
 | 
						|
    uint8_t b = (tft_Read_8()&0x7E)<<1;
 | 
						|
 | 
						|
  #endif
 | 
						|
 | 
						|
    // Swapped colour byte order for compatibility with pushRect()
 | 
						|
    *data++ = (r & 0xF8) | (g & 0xE0) >> 5 | (b & 0xF8) << 5 | (g & 0x1C) << 11;
 | 
						|
  }
 | 
						|
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    end_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  spi_end_read();
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           tft_Read_8
 | 
						|
** Description:             Software SPI to read bidirectional SDA line
 | 
						|
***************************************************************************************/
 | 
						|
#if defined (ESP8266) && defined (TFT_SDA_READ)
 | 
						|
uint8_t TFT_eSPI::tft_Read_8(void)
 | 
						|
{
 | 
						|
  uint8_t  ret = 0;
 | 
						|
  uint32_t reg = 0;
 | 
						|
 | 
						|
  for (uint8_t i = 0; i < 8; i++) {  // read results
 | 
						|
    ret <<= 1;
 | 
						|
    SCLK_L;
 | 
						|
    if (digitalRead(TFT_MOSI)) ret |= 1;
 | 
						|
    SCLK_H;
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           beginSDA
 | 
						|
** Description:             Detach SPI from pin to permit software SPI
 | 
						|
***************************************************************************************/
 | 
						|
#ifdef TFT_SDA_READ
 | 
						|
void TFT_eSPI::begin_SDA_Read(void)
 | 
						|
{
 | 
						|
  #ifdef ESP32
 | 
						|
    pinMatrixOutDetach(TFT_MOSI, false, false);
 | 
						|
    pinMode(TFT_MOSI, INPUT);
 | 
						|
    pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false);
 | 
						|
  #else // ESP8266
 | 
						|
    #ifdef TFT_SPI_OVERLAP
 | 
						|
      // Reads in overlap mode not supported
 | 
						|
    #else
 | 
						|
      spi.end();
 | 
						|
    #endif
 | 
						|
  #endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           endSDA
 | 
						|
** Description:             Attach SPI pins after software SPI
 | 
						|
***************************************************************************************/
 | 
						|
#ifdef TFT_SDA_READ
 | 
						|
void TFT_eSPI::end_SDA_Read(void)
 | 
						|
{
 | 
						|
  #ifdef ESP32
 | 
						|
    pinMode(TFT_MOSI, OUTPUT);
 | 
						|
    pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false);
 | 
						|
    pinMode(TFT_MISO, INPUT);
 | 
						|
    pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false);
 | 
						|
  #else
 | 
						|
    #ifdef TFT_SPI_OVERLAP
 | 
						|
      spi.pins(6, 7, 8, 0);
 | 
						|
    #else
 | 
						|
      spi.begin();
 | 
						|
    #endif
 | 
						|
  #endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           push rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
 | 
						|
** Description:             push 565 pixel colours into a defined area
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
 | 
						|
{
 | 
						|
  // Function deprecated, remains for backwards compatibility
 | 
						|
  // pushImage() is better as it will crop partly off-screen image blocks
 | 
						|
  pushImage(x, y, w, h, data);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage
 | 
						|
** Description:             plot 16 bit colour sprite or image onto TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
 | 
						|
{
 | 
						|
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  setWindow(x, y, x + dw - 1, y + dh - 1);
 | 
						|
 | 
						|
  data += dx + dy * w;
 | 
						|
 | 
						|
  while (dh--)
 | 
						|
  {
 | 
						|
    pushColors(data, dw, _swapBytes);
 | 
						|
    data += w;
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage
 | 
						|
** Description:             plot 16 bit sprite or image with 1 colour being transparent
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transp)
 | 
						|
{
 | 
						|
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
  
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  data += dx + dy * w;
 | 
						|
 | 
						|
  int32_t xe = x + dw - 1, ye = y + dh - 1;
 | 
						|
 | 
						|
  uint16_t  lineBuf[dw];
 | 
						|
 | 
						|
  if (!_swapBytes) transp = transp >> 8 | transp << 8;
 | 
						|
 | 
						|
  while (dh--)
 | 
						|
  {
 | 
						|
    int32_t len = dw;
 | 
						|
    uint16_t* ptr = data;
 | 
						|
    int32_t px = x;
 | 
						|
    boolean move = true;
 | 
						|
    uint16_t np = 0;
 | 
						|
 | 
						|
    while (len--)
 | 
						|
    {
 | 
						|
      if (transp != *ptr)
 | 
						|
      {
 | 
						|
        if (move) { move = false; setWindow(px, y, xe, ye); }
 | 
						|
        lineBuf[np] = *ptr;
 | 
						|
        np++;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        move = true;
 | 
						|
        if (np)
 | 
						|
        {
 | 
						|
           pushColors((uint16_t*)lineBuf, np, _swapBytes);
 | 
						|
           np = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      px++;
 | 
						|
      ptr++;
 | 
						|
    }
 | 
						|
    if (np) pushColors((uint16_t*)lineBuf, np, _swapBytes);
 | 
						|
 | 
						|
    y++;
 | 
						|
    data += w;
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage - for FLASH (PROGMEM) stored images
 | 
						|
** Description:             plot 16 bit image
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data)
 | 
						|
{
 | 
						|
#ifdef ESP32
 | 
						|
  pushImage(x, y, w, h, (uint16_t*)data);
 | 
						|
#else
 | 
						|
  // Partitioned memory FLASH processor
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
  
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  data += dx + dy * w;
 | 
						|
 | 
						|
  uint16_t  buffer[64];
 | 
						|
  uint16_t* pix_buffer = buffer;
 | 
						|
 | 
						|
  setWindow(x, y, x + dw - 1, y + dh - 1);
 | 
						|
 | 
						|
  // Work out the number whole buffers to send
 | 
						|
  uint16_t nb = (dw * dh) / 64;
 | 
						|
 | 
						|
  // Fill and send "nb" buffers to TFT
 | 
						|
  for (int32_t i = 0; i < nb; i++) {
 | 
						|
    for (int32_t j = 0; j < 64; j++) {
 | 
						|
      pix_buffer[j] = pgm_read_word(&data[i * 64 + j]);
 | 
						|
    }
 | 
						|
    pushColors(pix_buffer, 64, _swapBytes);
 | 
						|
  }
 | 
						|
 | 
						|
  // Work out number of pixels not yet sent
 | 
						|
  uint16_t np = (dw * dh) % 64;
 | 
						|
 | 
						|
  // Send any partial buffer left over
 | 
						|
  if (np) {
 | 
						|
    for (int32_t i = 0; i < np; i++)
 | 
						|
    {
 | 
						|
      pix_buffer[i] = pgm_read_word(&data[nb * 64 + i]);
 | 
						|
    }
 | 
						|
    pushColors(pix_buffer, np, _swapBytes);
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
#endif // if ESP32 else ESP8266 check
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage - for FLASH (PROGMEM) stored images
 | 
						|
** Description:             plot 16 bit image with 1 colour being transparent
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transp)
 | 
						|
{
 | 
						|
#ifdef ESP32
 | 
						|
  pushImage(x, y, w, h, (uint16_t*) data, transp);
 | 
						|
#else
 | 
						|
  // Partitioned memory FLASH processor
 | 
						|
  if ((x >= _width) || (y >= (int32_t)_height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
  
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  data += dx + dy * w;
 | 
						|
 | 
						|
  int32_t xe = x + dw - 1, ye = y + dh - 1;
 | 
						|
 | 
						|
  uint16_t  lineBuf[dw];
 | 
						|
 | 
						|
  if (!_swapBytes) transp = transp >> 8 | transp << 8;
 | 
						|
 | 
						|
  while (dh--)
 | 
						|
  {
 | 
						|
    int32_t len = dw;
 | 
						|
    uint16_t* ptr = (uint16_t*)data;
 | 
						|
    int32_t px = x;
 | 
						|
    boolean move = true;
 | 
						|
 | 
						|
    uint16_t np = 0;
 | 
						|
 | 
						|
    while (len--)
 | 
						|
    {
 | 
						|
      uint16_t color = pgm_read_word(ptr);
 | 
						|
      if (transp != color)
 | 
						|
      {
 | 
						|
        if (move) { move = false; setWindow(px, y, xe, ye); }
 | 
						|
        lineBuf[np] = color;
 | 
						|
        np++;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        move = true;
 | 
						|
        if (np)
 | 
						|
        {
 | 
						|
           pushColors(lineBuf, np, _swapBytes);
 | 
						|
           np = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      px++;
 | 
						|
      ptr++;
 | 
						|
    }
 | 
						|
    if (np) pushColors(lineBuf, np, _swapBytes);
 | 
						|
 | 
						|
    y++;
 | 
						|
    data += w;
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
#endif // if ESP32 else ESP8266 check
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage
 | 
						|
** Description:             plot 8 bit image or sprite using a line buffer
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8)
 | 
						|
{
 | 
						|
  if ((x >= _width) || (y >= (int32_t)_height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
  
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  setWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
 | 
						|
 | 
						|
  // Line buffer makes plotting faster
 | 
						|
  uint16_t  lineBuf[dw];
 | 
						|
 | 
						|
  if (bpp8)
 | 
						|
  {
 | 
						|
    uint8_t  blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
 | 
						|
 | 
						|
    _lastColor = -1; // Set to illegal value
 | 
						|
 | 
						|
    // Used to store last shifted colour
 | 
						|
    uint8_t msbColor = 0;
 | 
						|
    uint8_t lsbColor = 0;
 | 
						|
 | 
						|
    data += dx + dy * w;
 | 
						|
    while (dh--)
 | 
						|
    {
 | 
						|
      uint32_t len = dw;
 | 
						|
      uint8_t* ptr = data;
 | 
						|
      uint8_t* linePtr = (uint8_t*)lineBuf;
 | 
						|
 | 
						|
      while(len--)
 | 
						|
      {
 | 
						|
        uint32_t color = *ptr++;
 | 
						|
 | 
						|
        // Shifts are slow so check if colour has changed first
 | 
						|
        if (color != _lastColor) {
 | 
						|
          //          =====Green=====     ===============Red==============
 | 
						|
          msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
 | 
						|
          //          =====Green=====    =======Blue======
 | 
						|
          lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
 | 
						|
          _lastColor = color;
 | 
						|
        }
 | 
						|
 | 
						|
       *linePtr++ = msbColor;
 | 
						|
       *linePtr++ = lsbColor;
 | 
						|
      }
 | 
						|
 | 
						|
      pushColors(lineBuf, dw, false);
 | 
						|
 | 
						|
      data += w;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    while (dh--)
 | 
						|
    {
 | 
						|
      w =  (w+7) & 0xFFF8;
 | 
						|
 | 
						|
      int32_t len = dw;
 | 
						|
      uint8_t* ptr = data;
 | 
						|
      uint8_t* linePtr = (uint8_t*)lineBuf;
 | 
						|
      uint8_t  bits = 8;
 | 
						|
      while(len>0)
 | 
						|
      {
 | 
						|
        if (len < 8) bits = len;
 | 
						|
        uint32_t xp = dx;
 | 
						|
        for (uint16_t i = 0; i < bits; i++)
 | 
						|
        {
 | 
						|
          uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
 | 
						|
          if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;}
 | 
						|
          else     {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;}
 | 
						|
          //if (col) drawPixel((dw-len)+xp,h-dh,bitmap_fg);
 | 
						|
          //else     drawPixel((dw-len)+xp,h-dh,bitmap_bg);
 | 
						|
          xp++;
 | 
						|
        }
 | 
						|
        ptr++;
 | 
						|
        len -= 8;
 | 
						|
      }
 | 
						|
 | 
						|
      pushColors(lineBuf, dw, false);
 | 
						|
 | 
						|
      dy++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushImage
 | 
						|
** Description:             plot 8 or 1 bit image or sprite with a transparent colour
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transp, bool bpp8)
 | 
						|
{
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  int32_t dx = 0;
 | 
						|
  int32_t dy = 0;
 | 
						|
  int32_t dw = w;
 | 
						|
  int32_t dh = h;
 | 
						|
 | 
						|
  if (x < 0) { dw += x; dx = -x; x = 0; }
 | 
						|
  if (y < 0) { dh += y; dy = -y; y = 0; }
 | 
						|
  
 | 
						|
  if ((x + w) > _width ) dw = _width  - x;
 | 
						|
  if ((y + h) > _height) dh = _height - y;
 | 
						|
 | 
						|
  if (dw < 1 || dh < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  int32_t xe = x + dw - 1, ye = y + dh - 1;
 | 
						|
 | 
						|
  // Line buffer makes plotting faster
 | 
						|
  uint16_t  lineBuf[dw];
 | 
						|
 | 
						|
  if (bpp8)
 | 
						|
  {
 | 
						|
    data += dx + dy * w;
 | 
						|
 | 
						|
    uint8_t  blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
 | 
						|
 | 
						|
    _lastColor = -1; // Set to illegal value
 | 
						|
 | 
						|
    // Used to store last shifted colour
 | 
						|
    uint8_t msbColor = 0;
 | 
						|
    uint8_t lsbColor = 0;
 | 
						|
 | 
						|
    //int32_t spx = x, spy = y;
 | 
						|
 | 
						|
    while (dh--)
 | 
						|
    {
 | 
						|
      int32_t len = dw;
 | 
						|
      uint8_t* ptr = data;
 | 
						|
      uint8_t* linePtr = (uint8_t*)lineBuf;
 | 
						|
 | 
						|
      int32_t px = x;
 | 
						|
      boolean move = true;
 | 
						|
      uint16_t np = 0;
 | 
						|
 | 
						|
      while (len--)
 | 
						|
      {
 | 
						|
        if (transp != *ptr)
 | 
						|
        {
 | 
						|
          if (move) { move = false; setWindow(px, y, xe, ye);}
 | 
						|
          uint8_t color = *ptr;
 | 
						|
 | 
						|
          // Shifts are slow so check if colour has changed first
 | 
						|
          if (color != _lastColor) {
 | 
						|
            //          =====Green=====     ===============Red==============
 | 
						|
            msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
 | 
						|
            //          =====Green=====    =======Blue======
 | 
						|
            lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
 | 
						|
            _lastColor = color;
 | 
						|
          }
 | 
						|
          *linePtr++ = msbColor;
 | 
						|
          *linePtr++ = lsbColor;
 | 
						|
          np++;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          move = true;
 | 
						|
          if (np)
 | 
						|
          {
 | 
						|
            pushColors(lineBuf, np, false);
 | 
						|
            linePtr = (uint8_t*)lineBuf;
 | 
						|
            np = 0;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        px++;
 | 
						|
        ptr++;
 | 
						|
      }
 | 
						|
 | 
						|
      if (np) pushColors(lineBuf, np, false);
 | 
						|
 | 
						|
      y++;
 | 
						|
      data += w;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    w =  (w+7) & 0xFFF8;
 | 
						|
    while (dh--)
 | 
						|
    {
 | 
						|
      int32_t px = x;
 | 
						|
      boolean move = true;
 | 
						|
      uint16_t np = 0;
 | 
						|
      int32_t len = dw;
 | 
						|
      uint8_t* ptr = data;
 | 
						|
      uint8_t  bits = 8;
 | 
						|
      while(len>0)
 | 
						|
      {
 | 
						|
        if (len < 8) bits = len;
 | 
						|
        uint32_t xp = dx;
 | 
						|
        uint32_t yp = (dy * w)>>3;
 | 
						|
        for (uint16_t i = 0; i < bits; i++)
 | 
						|
        {
 | 
						|
          //uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
 | 
						|
          if ((ptr[(xp>>3) + yp] << (xp & 0x7)) & 0x80)
 | 
						|
          {
 | 
						|
            if (move)
 | 
						|
            {
 | 
						|
              move = false;
 | 
						|
              setWindow(px, y, xe, ye);
 | 
						|
            }
 | 
						|
            np++;
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            if (np)
 | 
						|
            {
 | 
						|
              pushColor(bitmap_fg, np);
 | 
						|
              np = 0;
 | 
						|
              move = true;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          px++;
 | 
						|
          xp++;
 | 
						|
        }
 | 
						|
        ptr++;
 | 
						|
        len -= 8;
 | 
						|
      }
 | 
						|
      if (np) pushColor(bitmap_fg, np);
 | 
						|
      y++;
 | 
						|
      dy++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setSwapBytes
 | 
						|
** Description:             Used by 16 bit pushImage() to swap byte order in colours
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setSwapBytes(bool swap)
 | 
						|
{
 | 
						|
  _swapBytes = swap;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getSwapBytes
 | 
						|
** Description:             Return the swap byte order for colours
 | 
						|
***************************************************************************************/
 | 
						|
bool TFT_eSPI::getSwapBytes(void)
 | 
						|
{
 | 
						|
  return _swapBytes;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
 | 
						|
** Description:             Read RGB pixel colours from a defined area
 | 
						|
***************************************************************************************/
 | 
						|
// If w and h are 1, then 1 pixel is read, *data array size must be 3 bytes per pixel
 | 
						|
void  TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data)
 | 
						|
{
 | 
						|
#if defined(ESP32_PARALLEL)
 | 
						|
 | 
						|
  // ESP32 parallel bus supported yet
 | 
						|
 | 
						|
#else  // Not ESP32_PARALLEL
 | 
						|
 | 
						|
  spi_begin_read();
 | 
						|
 | 
						|
  readAddrWindow(x0, y0, w, h); // Sets CS low
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    begin_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  // Dummy read to throw away don't care value
 | 
						|
  tft_Read_8();
 | 
						|
 | 
						|
  // Read window pixel 24 bit RGB values, buffer must be set in sketch to 3 * w * h
 | 
						|
  uint32_t len = w * h;
 | 
						|
  while (len--) {
 | 
						|
 | 
						|
  #if !defined (ILI9488_DRIVER)
 | 
						|
 | 
						|
    // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
 | 
						|
    // as the TFT stores colours as 18 bits
 | 
						|
    *data++ = tft_Read_8();
 | 
						|
    *data++ = tft_Read_8();
 | 
						|
    *data++ = tft_Read_8();
 | 
						|
 | 
						|
  #else
 | 
						|
 | 
						|
    // The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
 | 
						|
    // so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
 | 
						|
    *data++ = (tft_Read_8()&0x7E)<<1;
 | 
						|
    *data++ = (tft_Read_8()&0x7E)<<1;
 | 
						|
    *data++ = (tft_Read_8()&0x7E)<<1;
 | 
						|
 | 
						|
  #endif
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  CS_H;
 | 
						|
 | 
						|
  #ifdef TFT_SDA_READ
 | 
						|
    end_SDA_Read();
 | 
						|
  #endif
 | 
						|
 | 
						|
  spi_end_read();
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawCircle
 | 
						|
** Description:             Draw a circle outline
 | 
						|
***************************************************************************************/
 | 
						|
// Optimised midpoint circle algorithm
 | 
						|
void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
 | 
						|
{
 | 
						|
  int32_t  x  = 0;
 | 
						|
  int32_t  dx = 1;
 | 
						|
  int32_t  dy = r+r;
 | 
						|
  int32_t  p  = -(r>>1);
 | 
						|
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  // These are ordered to minimise coordinate changes in x or y
 | 
						|
  // drawPixel can then send fewer bounding box commands
 | 
						|
  drawPixel(x0 + r, y0, color);
 | 
						|
  drawPixel(x0 - r, y0, color);
 | 
						|
  drawPixel(x0, y0 - r, color);
 | 
						|
  drawPixel(x0, y0 + r, color);
 | 
						|
 | 
						|
  while(x<r){
 | 
						|
 | 
						|
    if(p>=0) {
 | 
						|
      dy-=2;
 | 
						|
      p-=dy;
 | 
						|
      r--;
 | 
						|
    }
 | 
						|
 | 
						|
    dx+=2;
 | 
						|
    p+=dx;
 | 
						|
 | 
						|
    x++;
 | 
						|
 | 
						|
    // These are ordered to minimise coordinate changes in x or y
 | 
						|
    // drawPixel can then send fewer bounding box commands
 | 
						|
    drawPixel(x0 + x, y0 + r, color);
 | 
						|
    drawPixel(x0 - x, y0 + r, color);
 | 
						|
    drawPixel(x0 - x, y0 - r, color);
 | 
						|
    drawPixel(x0 + x, y0 - r, color);
 | 
						|
 | 
						|
    drawPixel(x0 + r, y0 + x, color);
 | 
						|
    drawPixel(x0 - r, y0 + x, color);
 | 
						|
    drawPixel(x0 - r, y0 - x, color);
 | 
						|
    drawPixel(x0 + r, y0 - x, color);
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawCircleHelper
 | 
						|
** Description:             Support function for circle drawing
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t r, uint8_t cornername, uint32_t color)
 | 
						|
{
 | 
						|
  int32_t f     = 1 - r;
 | 
						|
  int32_t ddF_x = 1;
 | 
						|
  int32_t ddF_y = -2 * r;
 | 
						|
  int32_t x     = 0;
 | 
						|
 | 
						|
  while (x < r) {
 | 
						|
    if (f >= 0) {
 | 
						|
      r--;
 | 
						|
      ddF_y += 2;
 | 
						|
      f     += ddF_y;
 | 
						|
    }
 | 
						|
    x++;
 | 
						|
    ddF_x += 2;
 | 
						|
    f     += ddF_x;
 | 
						|
    if (cornername & 0x4) {
 | 
						|
      drawPixel(x0 + x, y0 + r, color);
 | 
						|
      drawPixel(x0 + r, y0 + x, color);
 | 
						|
    }
 | 
						|
    if (cornername & 0x2) {
 | 
						|
      drawPixel(x0 + x, y0 - r, color);
 | 
						|
      drawPixel(x0 + r, y0 - x, color);
 | 
						|
    }
 | 
						|
    if (cornername & 0x8) {
 | 
						|
      drawPixel(x0 - r, y0 + x, color);
 | 
						|
      drawPixel(x0 - x, y0 + r, color);
 | 
						|
    }
 | 
						|
    if (cornername & 0x1) {
 | 
						|
      drawPixel(x0 - r, y0 - x, color);
 | 
						|
      drawPixel(x0 - x, y0 - r, color);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillCircle
 | 
						|
** Description:             draw a filled circle
 | 
						|
***************************************************************************************/
 | 
						|
// Optimised midpoint circle algorithm, changed to horizontal lines (faster in sprites)
 | 
						|
void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
 | 
						|
{
 | 
						|
  int32_t  x  = 0;
 | 
						|
  int32_t  dx = 1;
 | 
						|
  int32_t  dy = r+r;
 | 
						|
  int32_t  p  = -(r>>1);
 | 
						|
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  drawFastHLine(x0 - r, y0, dy+1, color);
 | 
						|
 | 
						|
  while(x<r){
 | 
						|
 | 
						|
    if(p>=0) {
 | 
						|
      dy-=2;
 | 
						|
      p-=dy;
 | 
						|
      r--;
 | 
						|
    }
 | 
						|
 | 
						|
    dx+=2;
 | 
						|
    p+=dx;
 | 
						|
 | 
						|
    x++;
 | 
						|
 | 
						|
    drawFastHLine(x0 - r, y0 + x, 2 * r+1, color);
 | 
						|
    drawFastHLine(x0 - r, y0 - x, 2 * r+1, color);
 | 
						|
    drawFastHLine(x0 - x, y0 + r, 2 * x+1, color);
 | 
						|
    drawFastHLine(x0 - x, y0 - r, 2 * x+1, color);
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;  
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillCircleHelper
 | 
						|
** Description:             Support function for filled circle drawing
 | 
						|
***************************************************************************************/
 | 
						|
// Used to support drawing roundrects, changed to horizontal lines (faster in sprites)
 | 
						|
void TFT_eSPI::fillCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t cornername, int32_t delta, uint32_t color)
 | 
						|
{
 | 
						|
  int32_t f     = 1 - r;
 | 
						|
  int32_t ddF_x = 1;
 | 
						|
  int32_t ddF_y = -r - r;
 | 
						|
  int32_t y     = 0;
 | 
						|
 | 
						|
  delta++;
 | 
						|
  while (y < r) {
 | 
						|
    if (f >= 0) {
 | 
						|
      r--;
 | 
						|
      ddF_y += 2;
 | 
						|
      f     += ddF_y;
 | 
						|
    }
 | 
						|
    y++;
 | 
						|
    //x++;
 | 
						|
    ddF_x += 2;
 | 
						|
    f     += ddF_x;
 | 
						|
 | 
						|
    if (cornername & 0x1)
 | 
						|
    {
 | 
						|
      drawFastHLine(x0 - r, y0 + y, r + r + delta, color);
 | 
						|
      drawFastHLine(x0 - y, y0 + r, y + y + delta, color);
 | 
						|
    }
 | 
						|
    if (cornername & 0x2) {
 | 
						|
      drawFastHLine(x0 - r, y0 - y, r + r + delta, color); // 11995, 1090
 | 
						|
      drawFastHLine(x0 - y, y0 - r, y + y + delta, color);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawEllipse
 | 
						|
** Description:             Draw a ellipse outline
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint16_t color)
 | 
						|
{
 | 
						|
  if (rx<2) return;
 | 
						|
  if (ry<2) return;
 | 
						|
  int32_t x, y;
 | 
						|
  int32_t rx2 = rx * rx;
 | 
						|
  int32_t ry2 = ry * ry;
 | 
						|
  int32_t fx2 = 4 * rx2;
 | 
						|
  int32_t fy2 = 4 * ry2;
 | 
						|
  int32_t s;
 | 
						|
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
 | 
						|
  {
 | 
						|
    // These are ordered to minimise coordinate changes in x or y
 | 
						|
    // drawPixel can then send fewer bounding box commands
 | 
						|
    drawPixel(x0 + x, y0 + y, color);
 | 
						|
    drawPixel(x0 - x, y0 + y, color);
 | 
						|
    drawPixel(x0 - x, y0 - y, color);
 | 
						|
    drawPixel(x0 + x, y0 - y, color);
 | 
						|
    if (s >= 0)
 | 
						|
    {
 | 
						|
      s += fx2 * (1 - y);
 | 
						|
      y--;
 | 
						|
    }
 | 
						|
    s += ry2 * ((4 * x) + 6);
 | 
						|
  }
 | 
						|
 | 
						|
  for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
 | 
						|
  {
 | 
						|
    // These are ordered to minimise coordinate changes in x or y
 | 
						|
    // drawPixel can then send fewer bounding box commands
 | 
						|
    drawPixel(x0 + x, y0 + y, color);
 | 
						|
    drawPixel(x0 - x, y0 + y, color);
 | 
						|
    drawPixel(x0 - x, y0 - y, color);
 | 
						|
    drawPixel(x0 + x, y0 - y, color);
 | 
						|
    if (s >= 0)
 | 
						|
    {
 | 
						|
      s += fy2 * (1 - x);
 | 
						|
      x--;
 | 
						|
    }
 | 
						|
    s += rx2 * ((4 * y) + 6);
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillEllipse
 | 
						|
** Description:             draw a filled ellipse
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::fillEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint16_t color)
 | 
						|
{
 | 
						|
  if (rx<2) return;
 | 
						|
  if (ry<2) return;
 | 
						|
  int32_t x, y;
 | 
						|
  int32_t rx2 = rx * rx;
 | 
						|
  int32_t ry2 = ry * ry;
 | 
						|
  int32_t fx2 = 4 * rx2;
 | 
						|
  int32_t fy2 = 4 * ry2;
 | 
						|
  int32_t s;
 | 
						|
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
 | 
						|
  {
 | 
						|
    drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
 | 
						|
    drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
 | 
						|
 | 
						|
    if (s >= 0)
 | 
						|
    {
 | 
						|
      s += fx2 * (1 - y);
 | 
						|
      y--;
 | 
						|
    }
 | 
						|
    s += ry2 * ((4 * x) + 6);
 | 
						|
  }
 | 
						|
 | 
						|
  for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
 | 
						|
  {
 | 
						|
    drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
 | 
						|
    drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
 | 
						|
 | 
						|
    if (s >= 0)
 | 
						|
    {
 | 
						|
      s += fy2 * (1 - x);
 | 
						|
      x--;
 | 
						|
    }
 | 
						|
    s += rx2 * ((4 * y) + 6);
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillScreen
 | 
						|
** Description:             Clear the screen to defined colour
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::fillScreen(uint32_t color)
 | 
						|
{
 | 
						|
  fillRect(0, 0, _width, _height, color);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawRect
 | 
						|
** Description:             Draw a rectangle outline
 | 
						|
***************************************************************************************/
 | 
						|
// Draw a rectangle
 | 
						|
void TFT_eSPI::drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  drawFastHLine(x, y, w, color);
 | 
						|
  drawFastHLine(x, y + h - 1, w, color);
 | 
						|
  // Avoid drawing corner pixels twice
 | 
						|
  drawFastVLine(x, y+1, h-2, color);
 | 
						|
  drawFastVLine(x + w - 1, y+1, h-2, color);
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawRoundRect
 | 
						|
** Description:             Draw a rounded corner rectangle outline
 | 
						|
***************************************************************************************/
 | 
						|
// Draw a rounded rectangle
 | 
						|
void TFT_eSPI::drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  // smarter version
 | 
						|
  drawFastHLine(x + r  , y    , w - r - r, color); // Top
 | 
						|
  drawFastHLine(x + r  , y + h - 1, w - r - r, color); // Bottom
 | 
						|
  drawFastVLine(x    , y + r  , h - r - r, color); // Left
 | 
						|
  drawFastVLine(x + w - 1, y + r  , h - r - r, color); // Right
 | 
						|
  // draw four corners
 | 
						|
  drawCircleHelper(x + r    , y + r    , r, 1, color);
 | 
						|
  drawCircleHelper(x + w - r - 1, y + r    , r, 2, color);
 | 
						|
  drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
 | 
						|
  drawCircleHelper(x + r    , y + h - r - 1, r, 8, color);
 | 
						|
  
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillRoundRect
 | 
						|
** Description:             Draw a rounded corner filled rectangle
 | 
						|
***************************************************************************************/
 | 
						|
// Fill a rounded rectangle, changed to horizontal lines (faster in sprites)
 | 
						|
void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  // smarter version
 | 
						|
  fillRect(x, y + r, w, h - r - r, color);
 | 
						|
 | 
						|
  // draw four corners
 | 
						|
  fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color);
 | 
						|
  fillCircleHelper(x + r    , y + r, r, 2, w - r - r - 1, color);
 | 
						|
  
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawTriangle
 | 
						|
** Description:             Draw a triangle outline using 3 arbitrary points
 | 
						|
***************************************************************************************/
 | 
						|
// Draw a triangle
 | 
						|
void TFT_eSPI::drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  drawLine(x0, y0, x1, y1, color);
 | 
						|
  drawLine(x1, y1, x2, y2, color);
 | 
						|
  drawLine(x2, y2, x0, y0, color);
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillTriangle
 | 
						|
** Description:             Draw a filled triangle using 3 arbitrary points
 | 
						|
***************************************************************************************/
 | 
						|
// Fill a triangle - original Adafruit function works well and code footprint is small
 | 
						|
void TFT_eSPI::fillTriangle ( int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
 | 
						|
{
 | 
						|
  int32_t a, b, y, last;
 | 
						|
 | 
						|
  // Sort coordinates by Y order (y2 >= y1 >= y0)
 | 
						|
  if (y0 > y1) {
 | 
						|
    swap_coord(y0, y1); swap_coord(x0, x1);
 | 
						|
  }
 | 
						|
  if (y1 > y2) {
 | 
						|
    swap_coord(y2, y1); swap_coord(x2, x1);
 | 
						|
  }
 | 
						|
  if (y0 > y1) {
 | 
						|
    swap_coord(y0, y1); swap_coord(x0, x1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
 | 
						|
    a = b = x0;
 | 
						|
    if (x1 < a)      a = x1;
 | 
						|
    else if (x1 > b) b = x1;
 | 
						|
    if (x2 < a)      a = x2;
 | 
						|
    else if (x2 > b) b = x2;
 | 
						|
    drawFastHLine(a, y0, b - a + 1, color);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  int32_t
 | 
						|
  dx01 = x1 - x0,
 | 
						|
  dy01 = y1 - y0,
 | 
						|
  dx02 = x2 - x0,
 | 
						|
  dy02 = y2 - y0,
 | 
						|
  dx12 = x2 - x1,
 | 
						|
  dy12 = y2 - y1,
 | 
						|
  sa   = 0,
 | 
						|
  sb   = 0;
 | 
						|
 | 
						|
  // For upper part of triangle, find scanline crossings for segments
 | 
						|
  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
 | 
						|
  // is included here (and second loop will be skipped, avoiding a /0
 | 
						|
  // error there), otherwise scanline y1 is skipped here and handled
 | 
						|
  // in the second loop...which also avoids a /0 error here if y0=y1
 | 
						|
  // (flat-topped triangle).
 | 
						|
  if (y1 == y2) last = y1;  // Include y1 scanline
 | 
						|
  else         last = y1 - 1; // Skip it
 | 
						|
 | 
						|
  for (y = y0; y <= last; y++) {
 | 
						|
    a   = x0 + sa / dy01;
 | 
						|
    b   = x0 + sb / dy02;
 | 
						|
    sa += dx01;
 | 
						|
    sb += dx02;
 | 
						|
 | 
						|
    if (a > b) swap_coord(a, b);
 | 
						|
    drawFastHLine(a, y, b - a + 1, color);
 | 
						|
  }
 | 
						|
 | 
						|
  // For lower part of triangle, find scanline crossings for segments
 | 
						|
  // 0-2 and 1-2.  This loop is skipped if y1=y2.
 | 
						|
  sa = dx12 * (y - y1);
 | 
						|
  sb = dx02 * (y - y0);
 | 
						|
  for (; y <= y2; y++) {
 | 
						|
    a   = x1 + sa / dy12;
 | 
						|
    b   = x0 + sb / dy02;
 | 
						|
    sa += dx12;
 | 
						|
    sb += dx02;
 | 
						|
 | 
						|
    if (a > b) swap_coord(a, b);
 | 
						|
    drawFastHLine(a, y, b - a + 1, color);
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawBitmap
 | 
						|
** Description:             Draw an image stored in an array on the TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  int32_t i, j, byteWidth = (w + 7) / 8;
 | 
						|
 | 
						|
  for (j = 0; j < h; j++) {
 | 
						|
    for (i = 0; i < w; i++ ) {
 | 
						|
      if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
 | 
						|
        drawPixel(x + i, y + j, color);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawXBitmap
 | 
						|
** Description:             Draw an image stored in an XBM array onto the TFT
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  int32_t i, j, byteWidth = (w + 7) / 8;
 | 
						|
 | 
						|
  for (j = 0; j < h; j++) {
 | 
						|
    for (i = 0; i < w; i++ ) {
 | 
						|
      if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7))) {
 | 
						|
        drawPixel(x + i, y + j, color);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawXBitmap
 | 
						|
** Description:             Draw an XBM image with foreground and background colors
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bgcolor)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
 | 
						|
  int32_t i, j, byteWidth = (w + 7) / 8;
 | 
						|
 | 
						|
  for (j = 0; j < h; j++) {
 | 
						|
    for (i = 0; i < w; i++ ) {
 | 
						|
      if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7)))
 | 
						|
           drawPixel(x + i, y + j,   color);
 | 
						|
      else drawPixel(x + i, y + j, bgcolor);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setCursor
 | 
						|
** Description:             Set the text cursor x,y position
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setCursor(int16_t x, int16_t y)
 | 
						|
{
 | 
						|
  cursor_x = x;
 | 
						|
  cursor_y = y;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setCursor
 | 
						|
** Description:             Set the text cursor x,y position and font
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setCursor(int16_t x, int16_t y, uint8_t font)
 | 
						|
{
 | 
						|
  textfont = font;
 | 
						|
  cursor_x = x;
 | 
						|
  cursor_y = y;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getCursorX
 | 
						|
** Description:             Get the text cursor x position
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::getCursorX(void)
 | 
						|
{
 | 
						|
  return cursor_x;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getCursorY
 | 
						|
** Description:             Get the text cursor y position
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::getCursorY(void)
 | 
						|
{
 | 
						|
  return cursor_y;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextSize
 | 
						|
** Description:             Set the text size multiplier
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextSize(uint8_t s)
 | 
						|
{
 | 
						|
  if (s>7) s = 7; // Limit the maximum size multiplier so byte variables can be used for rendering
 | 
						|
  textsize = (s > 0) ? s : 1; // Don't allow font size 0
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextColor
 | 
						|
** Description:             Set the font foreground colour (background is transparent)
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextColor(uint16_t c)
 | 
						|
{
 | 
						|
  // For 'transparent' background, we'll set the bg
 | 
						|
  // to the same as fg instead of using a flag
 | 
						|
  textcolor = textbgcolor = c;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextColor
 | 
						|
** Description:             Set the font foreground and background colour
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextColor(uint16_t c, uint16_t b)
 | 
						|
{
 | 
						|
  textcolor   = c;
 | 
						|
  textbgcolor = b;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setPivot
 | 
						|
** Description:             Set the pivot point on the TFT
 | 
						|
*************************************************************************************x*/
 | 
						|
void TFT_eSPI::setPivot(int16_t x, int16_t y)
 | 
						|
{
 | 
						|
  _xpivot = x;
 | 
						|
  _ypivot = y;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getPivotX
 | 
						|
** Description:             Get the x pivot position
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::getPivotX(void)
 | 
						|
{
 | 
						|
  return _xpivot;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getPivotY
 | 
						|
** Description:             Get the y pivot position
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::getPivotY(void)
 | 
						|
{
 | 
						|
  return _ypivot;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setBitmapColor
 | 
						|
** Description:             Set the foreground foreground and background colour
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setBitmapColor(uint16_t c, uint16_t b)
 | 
						|
{
 | 
						|
  if (c == b) b = ~c;
 | 
						|
  bitmap_fg = c;
 | 
						|
  bitmap_bg = b;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextWrap
 | 
						|
** Description:             Define if text should wrap at end of line
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextWrap(boolean wrapX, boolean wrapY)
 | 
						|
{
 | 
						|
  textwrapX = wrapX;
 | 
						|
  textwrapY = wrapY;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextDatum
 | 
						|
** Description:             Set the text position reference datum
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextDatum(uint8_t d)
 | 
						|
{
 | 
						|
  textdatum = d;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextPadding
 | 
						|
** Description:             Define padding width (aids erasing old text and numbers)
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextPadding(uint16_t x_width)
 | 
						|
{
 | 
						|
  padX = x_width;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getRotation
 | 
						|
** Description:             Return the rotation value (as used by setRotation())
 | 
						|
***************************************************************************************/
 | 
						|
uint8_t TFT_eSPI::getRotation(void)
 | 
						|
{
 | 
						|
  return rotation;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getTextDatum
 | 
						|
** Description:             Return the text datum value (as used by setTextDatum())
 | 
						|
***************************************************************************************/
 | 
						|
uint8_t TFT_eSPI::getTextDatum(void)
 | 
						|
{
 | 
						|
  return textdatum;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           width
 | 
						|
** Description:             Return the pixel width of display (per current rotation)
 | 
						|
***************************************************************************************/
 | 
						|
// Return the size of the display (per current rotation)
 | 
						|
int16_t TFT_eSPI::width(void)
 | 
						|
{
 | 
						|
  return _width;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           height
 | 
						|
** Description:             Return the pixel height of display (per current rotation)
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::height(void)
 | 
						|
{
 | 
						|
  return _height;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           textWidth
 | 
						|
** Description:             Return the width in pixels of a string in a given font
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::textWidth(const String& string)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return textWidth(buffer, textfont);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::textWidth(const String& string, uint8_t font)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return textWidth(buffer, font);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::textWidth(const char *string)
 | 
						|
{
 | 
						|
  return textWidth(string, textfont);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
 | 
						|
{
 | 
						|
  int32_t str_width = 0;
 | 
						|
  uint16_t uniCode  = 0;
 | 
						|
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  if(fontLoaded)
 | 
						|
  {
 | 
						|
    while (*string)
 | 
						|
    {
 | 
						|
      uniCode = decodeUTF8(*string++);
 | 
						|
      if (uniCode)
 | 
						|
      {
 | 
						|
        if (uniCode == 0x20) str_width += gFont.spaceWidth;
 | 
						|
        else
 | 
						|
        {
 | 
						|
          uint16_t gNum = 0;
 | 
						|
          bool found = getUnicodeIndex(uniCode, &gNum);
 | 
						|
          if (found)
 | 
						|
          {
 | 
						|
            if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
 | 
						|
            if (*string || isDigits) str_width += gxAdvance[gNum];
 | 
						|
            else str_width += (gdX[gNum] + gWidth[gNum]);
 | 
						|
          }
 | 
						|
          else str_width += gFont.spaceWidth + 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    isDigits = false;
 | 
						|
    return str_width;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (font>1 && font<9)
 | 
						|
  {
 | 
						|
    char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
 | 
						|
 | 
						|
    while (*string)
 | 
						|
    {
 | 
						|
      uniCode = *(string++);
 | 
						|
      if (uniCode > 31 && uniCode < 128)
 | 
						|
      str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subtract 32 from uniCode
 | 
						|
      else str_width += pgm_read_byte( widthtable + 32); // Set illegal character = space width
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
    if(gfxFont) // New font
 | 
						|
    {
 | 
						|
      while (*string)
 | 
						|
      {
 | 
						|
        uniCode = decodeUTF8(*string++);
 | 
						|
        if ((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last )))
 | 
						|
        {
 | 
						|
          uniCode -= pgm_read_word(&gfxFont->first);
 | 
						|
          GFXglyph *glyph  = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[uniCode]);
 | 
						|
          // If this is not the  last character or is a digit then use xAdvance
 | 
						|
          if (*string  || isDigits) str_width += pgm_read_byte(&glyph->xAdvance);
 | 
						|
          // Else use the offset plus width since this can be bigger than xAdvance
 | 
						|
          else str_width += ((int8_t)pgm_read_byte(&glyph->xOffset) + pgm_read_byte(&glyph->width));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
#endif
 | 
						|
    {
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
      while (*string++) str_width += 6;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
  }
 | 
						|
  isDigits = false;
 | 
						|
  return str_width * textsize;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fontsLoaded
 | 
						|
** Description:             return an encoded 16 bit value showing the fonts loaded
 | 
						|
***************************************************************************************/
 | 
						|
// Returns a value showing which fonts are loaded (bit N set =  Font N loaded)
 | 
						|
 | 
						|
uint16_t TFT_eSPI::fontsLoaded(void)
 | 
						|
{
 | 
						|
  return fontsloaded;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fontHeight
 | 
						|
** Description:             return the height of a font (yAdvance for free fonts)
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::fontHeight(int16_t font)
 | 
						|
{
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  if(fontLoaded) return gFont.yAdvance;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  if (font==1)
 | 
						|
  {
 | 
						|
    if(gfxFont) // New font
 | 
						|
    {
 | 
						|
      return pgm_read_byte(&gfxFont->yAdvance) * textsize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  return pgm_read_byte( &fontdata[font].height ) * textsize;
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::fontHeight(void)
 | 
						|
{
 | 
						|
  return fontHeight(textfont);
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawChar
 | 
						|
** Description:             draw a single character in the Adafruit GLCD font
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size)
 | 
						|
{
 | 
						|
  if ((x >= _width)            || // Clip right
 | 
						|
      (y >= _height)           || // Clip bottom
 | 
						|
      ((x + 6 * size - 1) < 0) || // Clip left
 | 
						|
      ((y + 8 * size - 1) < 0))   // Clip top
 | 
						|
    return;
 | 
						|
 | 
						|
  if (c < 32) return;
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
//>>>>>>>>>>>>>>>>>>
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  if(!gfxFont) { // 'Classic' built-in font
 | 
						|
#endif
 | 
						|
//>>>>>>>>>>>>>>>>>>
 | 
						|
 | 
						|
  boolean fillbg = (bg != color);
 | 
						|
 | 
						|
  if ((size==1) && fillbg)
 | 
						|
  {
 | 
						|
    uint8_t column[6];
 | 
						|
    uint8_t mask = 0x1;
 | 
						|
    spi_begin();
 | 
						|
 | 
						|
    setWindow(x, y, x+5, y+8);
 | 
						|
 | 
						|
    for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i);
 | 
						|
    column[5] = 0;
 | 
						|
 | 
						|
#if defined (ESP8266) && !defined (ILI9488_DRIVER)
 | 
						|
    color = (color >> 8) | (color << 8);
 | 
						|
    bg = (bg >> 8) | (bg << 8);
 | 
						|
 | 
						|
    for (int8_t j = 0; j < 8; j++) {
 | 
						|
      for (int8_t k = 0; k < 5; k++ ) {
 | 
						|
        if (column[k] & mask) {
 | 
						|
          SPI1W0 = color;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          SPI1W0 = bg;
 | 
						|
        }
 | 
						|
        SPI1CMD |= SPIBUSY;
 | 
						|
        while(SPI1CMD & SPIBUSY) {}
 | 
						|
      }
 | 
						|
 | 
						|
      mask <<= 1;
 | 
						|
 | 
						|
      SPI1W0 = bg;
 | 
						|
      SPI1CMD |= SPIBUSY;
 | 
						|
      while(SPI1CMD & SPIBUSY) {}
 | 
						|
    }
 | 
						|
#else // for ESP32 or ILI9488
 | 
						|
 | 
						|
    for (int8_t j = 0; j < 8; j++) {
 | 
						|
      for (int8_t k = 0; k < 5; k++ ) {
 | 
						|
        if (column[k] & mask) {tft_Write_16(color);}
 | 
						|
        else {tft_Write_16(bg);}
 | 
						|
      }
 | 
						|
      mask <<= 1;
 | 
						|
      tft_Write_16(bg);
 | 
						|
    }
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
    spi_end();
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
    inTransaction = true;
 | 
						|
    for (int8_t i = 0; i < 6; i++ ) {
 | 
						|
      uint8_t line;
 | 
						|
      if (i == 5)
 | 
						|
        line = 0x0;
 | 
						|
      else
 | 
						|
        line = pgm_read_byte(font + (c * 5) + i);
 | 
						|
 | 
						|
      if (size == 1) // default size
 | 
						|
      {
 | 
						|
        for (int8_t j = 0; j < 8; j++) {
 | 
						|
          if (line & 0x1) drawPixel(x + i, y + j, color);
 | 
						|
          line >>= 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {  // big size
 | 
						|
        for (int8_t j = 0; j < 8; j++) {
 | 
						|
          if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color);
 | 
						|
          else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg);
 | 
						|
          line >>= 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    inTransaction = false;
 | 
						|
    spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
  }
 | 
						|
 | 
						|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  } else { // Custom font
 | 
						|
#endif
 | 
						|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
						|
#endif // LOAD_GLCD
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
    // Filter out bad characters not present in font
 | 
						|
    if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last )))
 | 
						|
    {
 | 
						|
      //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
      inTransaction = true;
 | 
						|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
						|
 | 
						|
      c -= pgm_read_word(&gfxFont->first);
 | 
						|
      GFXglyph *glyph  = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
 | 
						|
      uint8_t  *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
 | 
						|
 | 
						|
      uint32_t bo = pgm_read_word(&glyph->bitmapOffset);
 | 
						|
      uint8_t  w  = pgm_read_byte(&glyph->width),
 | 
						|
               h  = pgm_read_byte(&glyph->height);
 | 
						|
               //xa = pgm_read_byte(&glyph->xAdvance);
 | 
						|
      int8_t   xo = pgm_read_byte(&glyph->xOffset),
 | 
						|
               yo = pgm_read_byte(&glyph->yOffset);
 | 
						|
      uint8_t  xx, yy, bits=0, bit=0;
 | 
						|
      int16_t  xo16 = 0, yo16 = 0;
 | 
						|
  
 | 
						|
      if(size > 1) {
 | 
						|
        xo16 = xo;
 | 
						|
        yo16 = yo;
 | 
						|
      }
 | 
						|
 | 
						|
// Here we have 3 versions of the same function just for evaluation purposes
 | 
						|
// Comment out the next two #defines to revert to the slower Adafruit implementation
 | 
						|
 | 
						|
// If FAST_LINE is defined then the free fonts are rendered using horizontal lines
 | 
						|
// this makes rendering fonts 2-5 times faster. Particularly good for large fonts.
 | 
						|
// This is an elegant solution since it still uses generic functions present in the
 | 
						|
// stock library.
 | 
						|
 | 
						|
// If FAST_SHIFT is defined then a slightly faster (at least for AVR processors)
 | 
						|
// shifting bit mask is used
 | 
						|
 | 
						|
// Free fonts don't look good when the size multiplier is >1 so we could remove
 | 
						|
// code if this is not wanted and speed things up
 | 
						|
 | 
						|
#define FAST_HLINE
 | 
						|
#define FAST_SHIFT
 | 
						|
//FIXED_SIZE is an option in User_Setup.h that only works with FAST_LINE enabled
 | 
						|
 | 
						|
#ifdef FIXED_SIZE
 | 
						|
      x+=xo; // Save 88 bytes of FLASH
 | 
						|
      y+=yo;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef FAST_HLINE
 | 
						|
 | 
						|
  #ifdef FAST_SHIFT
 | 
						|
      uint16_t hpc = 0; // Horizontal foreground pixel count
 | 
						|
      for(yy=0; yy<h; yy++) {
 | 
						|
        for(xx=0; xx<w; xx++) {
 | 
						|
          if(bit == 0) {
 | 
						|
            bits = pgm_read_byte(&bitmap[bo++]);
 | 
						|
            bit  = 0x80;
 | 
						|
          }
 | 
						|
          if(bits & bit) hpc++;
 | 
						|
          else {
 | 
						|
           if (hpc) {
 | 
						|
#ifndef FIXED_SIZE
 | 
						|
              if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
 | 
						|
              else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
 | 
						|
#else
 | 
						|
              drawFastHLine(x+xx-hpc, y+yy, hpc, color);
 | 
						|
#endif
 | 
						|
              hpc=0;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          bit >>= 1;
 | 
						|
        }
 | 
						|
      // Draw pixels for this line as we are about to increment yy
 | 
						|
        if (hpc) {
 | 
						|
#ifndef FIXED_SIZE
 | 
						|
          if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
 | 
						|
          else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
 | 
						|
#else
 | 
						|
          drawFastHLine(x+xx-hpc, y+yy, hpc, color);
 | 
						|
#endif
 | 
						|
          hpc=0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
  #else
 | 
						|
      uint16_t hpc = 0; // Horizontal foreground pixel count
 | 
						|
      for(yy=0; yy<h; yy++) {
 | 
						|
        for(xx=0; xx<w; xx++) {
 | 
						|
          if(!(bit++ & 7)) {
 | 
						|
            bits = pgm_read_byte(&bitmap[bo++]);
 | 
						|
          }
 | 
						|
          if(bits & 0x80) hpc++;
 | 
						|
          else {
 | 
						|
            if (hpc) {
 | 
						|
              if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
 | 
						|
              else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
 | 
						|
              hpc=0;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          bits <<= 1;
 | 
						|
        }
 | 
						|
        // Draw pixels for this line as we are about to increment yy
 | 
						|
        if (hpc) {
 | 
						|
          if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
 | 
						|
          else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
 | 
						|
          hpc=0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
  #endif
 | 
						|
 | 
						|
#else
 | 
						|
      for(yy=0; yy<h; yy++) {
 | 
						|
        for(xx=0; xx<w; xx++) {
 | 
						|
          if(!(bit++ & 7)) {
 | 
						|
            bits = pgm_read_byte(&bitmap[bo++]);
 | 
						|
          }
 | 
						|
          if(bits & 0x80) {
 | 
						|
            if(size == 1) {
 | 
						|
              drawPixel(x+xo+xx, y+yo+yy, color);
 | 
						|
            } else {
 | 
						|
              fillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
 | 
						|
            }
 | 
						|
          }
 | 
						|
          bits <<= 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
#endif
 | 
						|
      inTransaction = false;
 | 
						|
      spi_end();              // Does nothing if Sprite class uses this function
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
  #ifdef LOAD_GFXFF
 | 
						|
  } // End classic vs custom font
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setAddrWindow
 | 
						|
** Description:             define an area to receive a stream of pixels
 | 
						|
***************************************************************************************/
 | 
						|
// Chip select is high at the end of this function
 | 
						|
void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t w, int32_t h)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x0, y0, x0 + w - 1, y0 + h - 1);
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setWindow
 | 
						|
** Description:             define an area to receive a stream of pixels
 | 
						|
***************************************************************************************/
 | 
						|
// Chip select stays low, call spi_begin first. Use setAddrWindow() from sketches
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) && !defined (RPI_ILI9486_DRIVER)
 | 
						|
void TFT_eSPI::setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
 | 
						|
{
 | 
						|
  //spi_begin(); // Must be called before setWimdow
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  xs+=colstart;
 | 
						|
  xe+=colstart;
 | 
						|
  ys+=rowstart;
 | 
						|
  ye+=rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  // Column addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_CASET;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
  // Load the two coords as a 32 bit value and shift in one go
 | 
						|
  SPI1W0 = (xs >> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24));
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  // Row addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_PASET;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
  // Load the two coords as a 32 bit value and shift in one go
 | 
						|
  SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24));
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  // write to RAM
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
  SPI1W0 = TFT_RAMWR;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO);
 | 
						|
  //spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
 | 
						|
 | 
						|
void TFT_eSPI::setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
 | 
						|
{
 | 
						|
  //spi_begin(); // Must be called before setWimdow
 | 
						|
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  
 | 
						|
  // Column addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_CASET<<8;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  uint8_t xb[] = { 0, (uint8_t) (xs>>8), 0, (uint8_t) (xs>>0), 0, (uint8_t) (xe>>8), 0, (uint8_t) (xe>>0), };
 | 
						|
  spi.writePattern(&xb[0], 8, 1);
 | 
						|
 | 
						|
  // Row addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_PASET<<8;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  uint8_t yb[] = { 0, (uint8_t) (ys>>8), 0, (uint8_t) (ys>>0), 0, (uint8_t) (ye>>8), 0, (uint8_t) (ye>>0), };
 | 
						|
  spi.writePattern(&yb[0], 8, 1);
 | 
						|
 | 
						|
  // write to RAM
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
  SPI1W0 = TFT_RAMWR<<8;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  // Re-instate SPI flags settings corrupted by SPI library writePattern() call
 | 
						|
  SPI1U = SPI1U_WRITE;
 | 
						|
 | 
						|
  //spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
 | 
						|
void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
 | 
						|
{
 | 
						|
  //spi_begin(); // Must be called before setWimdow
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  // Column addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  addr_col = 0xFFFF; // Use the waiting time to do something useful
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1W0 = x0 >> 0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  x0 = x0 << 8; // Use the waiting time to do something useful
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = x0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = x1 >> 0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  x1 = x1 << 8; // Use the waiting time to do something useful
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = x1;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
  
 | 
						|
  // Row addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1W0 = y0 >> 0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  y0 = y0 << 8; // Use the waiting time to do something useful
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = y0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = y1 >> 0;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  y1 = y1 << 8; // Use the waiting time to do something useful
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  SPI1W0 = y1;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
  
 | 
						|
  // write to RAM
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  //spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else // This is for the ESP32
 | 
						|
 | 
						|
void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
 | 
						|
{
 | 
						|
  //spi_begin(); // Must be called before setWimdow
 | 
						|
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  x0+=colstart;
 | 
						|
  x1+=colstart;
 | 
						|
  y0+=rowstart;
 | 
						|
  y1+=rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  tft_Write_8(TFT_CASET);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER)
 | 
						|
  uint8_t xb[] = { 0, (uint8_t) (x0>>8), 0, (uint8_t) (x0>>0), 0, (uint8_t) (x1>>8), 0, (uint8_t) (x1>>0), };
 | 
						|
  spi.writePattern(&xb[0], 8, 1);
 | 
						|
#else
 | 
						|
  tft_Write_32(SPI_32(x0, x1));
 | 
						|
#endif
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  // Row addr set
 | 
						|
  tft_Write_8(TFT_PASET);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER)
 | 
						|
  uint8_t yb[] = { 0, (uint8_t) (y0>>8), 0, (uint8_t) (y0>>0), 0, (uint8_t) (y1>>8), 0, (uint8_t) (y1>>0), };
 | 
						|
  spi.writePattern(&yb[0], 8, 1);
 | 
						|
#else
 | 
						|
  tft_Write_32(SPI_32(y0, y1));
 | 
						|
#endif
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  // write to RAM
 | 
						|
  tft_Write_8(TFT_RAMWR);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  //spi_end();
 | 
						|
}
 | 
						|
#endif // end RPI_ILI9486_DRIVER check
 | 
						|
#endif // end ESP32 check
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           readAddrWindow
 | 
						|
** Description:             define an area to read a stream of pixels
 | 
						|
***************************************************************************************/
 | 
						|
// Chip select stays low
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
 | 
						|
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h)
 | 
						|
{
 | 
						|
 | 
						|
  int32_t xe = xs + w - 1;
 | 
						|
  int32_t ye = ys + h - 1;
 | 
						|
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
  
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  xs += colstart;
 | 
						|
  xe += colstart;
 | 
						|
  ys += rowstart;
 | 
						|
  ye += rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  // Column addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_CASET;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
  // Load the two coords as a 32 bit value and shift in one go
 | 
						|
  SPI1W0 = (xs >> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24));
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  // Row addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_PASET;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
  // Load the two coords as a 32 bit value and shift in one go
 | 
						|
  SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24));
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  // read from RAM
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
  SPI1W0 = TFT_RAMRD;
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#else //ESP32
 | 
						|
 | 
						|
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h)
 | 
						|
{
 | 
						|
 | 
						|
  int32_t xe = xs + w - 1;
 | 
						|
  int32_t ye = ys + h - 1;
 | 
						|
 | 
						|
  addr_col = 0xFFFF;
 | 
						|
  addr_row = 0xFFFF;
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
xs += colstart;
 | 
						|
xe += colstart;
 | 
						|
ys += rowstart;
 | 
						|
ye += rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  // Column addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  tft_Write_8(TFT_CASET);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  tft_Write_32(SPI_32(xs, xe));
 | 
						|
 | 
						|
  // Row addr set
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  tft_Write_8(TFT_PASET);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  tft_Write_32(SPI_32(ys, ye));
 | 
						|
  
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  tft_Write_8(TFT_RAMRD); // Read CGRAM command
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawPixel
 | 
						|
** Description:             push a single pixel at an arbitrary position
 | 
						|
***************************************************************************************/
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
 | 
						|
void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
 | 
						|
{
 | 
						|
  // Range checking
 | 
						|
  if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  x+=colstart;
 | 
						|
  y+=rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  // No need to send x if it has not changed (speeds things up)
 | 
						|
  if (addr_col != x) {
 | 
						|
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
    SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte
 | 
						|
    uint8_t cBin[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0)};
 | 
						|
    spi.writePattern(&cBin[0], 4, 2);
 | 
						|
#else
 | 
						|
    SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
    // Load the two coords as a 32 bit value and shift in one go
 | 
						|
    uint32_t xswap = (x >> 8) | (uint16_t)(x << 8);
 | 
						|
    SPI1W0 = xswap | (xswap << 16);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
#endif
 | 
						|
 | 
						|
    addr_col = x;
 | 
						|
  }
 | 
						|
 | 
						|
  // No need to send y if it has not changed (speeds things up)
 | 
						|
  if (addr_row != y) {
 | 
						|
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
    SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte
 | 
						|
    uint8_t cBin[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0)};
 | 
						|
    spi.writePattern(&cBin[0], 4, 2);
 | 
						|
#else
 | 
						|
    SPI1U1 = (31 << SPILMOSI) | (31 << SPILMISO);
 | 
						|
    // Load the two coords as a 32 bit value and shift in one go
 | 
						|
    uint32_t yswap = (y >> 8) | (uint16_t)(y << 8);
 | 
						|
    SPI1W0 = yswap | (yswap << 16);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
#endif
 | 
						|
 | 
						|
    addr_row = y;
 | 
						|
  }
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
#if  defined (ILI9488_DRIVER)
 | 
						|
  tft_Write_16(color);
 | 
						|
#else
 | 
						|
  SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO);
 | 
						|
 | 
						|
  SPI1W0 = (color >> 8) | (color << 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
 | 
						|
 | 
						|
void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
 | 
						|
{
 | 
						|
  // Range checking
 | 
						|
  if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
 | 
						|
  // No need to send x if it has not changed (speeds things up)
 | 
						|
  if (addr_col != x) {
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    DC_D;
 | 
						|
 | 
						|
    SPI1W0 = x >> 0;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = x << 8;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = x >> 0;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = x << 8;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    
 | 
						|
    addr_col = x;
 | 
						|
  }
 | 
						|
 | 
						|
  // No need to send y if it has not changed (speeds things up)
 | 
						|
  if (addr_row != y) {
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    DC_D;
 | 
						|
 | 
						|
    SPI1W0 = y >> 0;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = y << 8;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = y >> 0;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
    SPI1W0 = y << 8;
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    
 | 
						|
    addr_row = y;
 | 
						|
  }
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  SPI1W0 = (color >> 8) | (color << 8);
 | 
						|
  SPI1CMD |= SPIBUSY;
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else // ESP32
 | 
						|
 | 
						|
void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
 | 
						|
{
 | 
						|
  // Range checking
 | 
						|
  if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  x+=colstart;
 | 
						|
  y+=rowstart;
 | 
						|
#endif
 | 
						|
 | 
						|
  DC_C;
 | 
						|
 | 
						|
  // No need to send x if it has not changed (speeds things up)
 | 
						|
  if (addr_col != x) {
 | 
						|
 | 
						|
    tft_Write_8(TFT_CASET);
 | 
						|
 | 
						|
    DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER)
 | 
						|
    uint8_t xb[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), };
 | 
						|
    spi.writePattern(&xb[0], 8, 1);
 | 
						|
#else
 | 
						|
    tft_Write_32(SPI_32(x, x));
 | 
						|
#endif
 | 
						|
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    addr_col = x;
 | 
						|
  }
 | 
						|
 | 
						|
  // No need to send y if it has not changed (speeds things up)
 | 
						|
  if (addr_row != y) {
 | 
						|
 | 
						|
    tft_Write_8(TFT_PASET);
 | 
						|
 | 
						|
    DC_D;
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER)
 | 
						|
    uint8_t yb[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), };
 | 
						|
    spi.writePattern(&yb[0], 8, 1);
 | 
						|
#else
 | 
						|
    tft_Write_32(SPI_32(y, y));
 | 
						|
#endif
 | 
						|
 | 
						|
    DC_C;
 | 
						|
 | 
						|
    addr_row = y;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  tft_Write_8(TFT_RAMWR);
 | 
						|
 | 
						|
  DC_D;
 | 
						|
 | 
						|
  tft_Write_16(color);
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushColor
 | 
						|
** Description:             push a single pixel
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushColor(uint16_t color)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  tft_Write_16(color);
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushColor
 | 
						|
** Description:             push a single colour to "len" pixels
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushColor(uint16_t color, uint32_t len)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
  uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color };
 | 
						|
  if(len) spi.writePattern(&colorBin[0], 2, 1); len--;
 | 
						|
  while(len--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
  #if defined (ESP32_PARALLEL)
 | 
						|
    while (len--) {tft_Write_16(color);}
 | 
						|
  #else
 | 
						|
    writeBlock(color, len);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           startWrite
 | 
						|
** Description:             begin transaction with CS low, MUST later call endWrite
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::startWrite(void)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
  inTransaction = true;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           endWrite
 | 
						|
** Description:             end transaction with CS high
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::endWrite(void)
 | 
						|
{
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           writeColor (use startWrite() and endWrite() before & after)
 | 
						|
** Description:             raw write of "len" pixels avoiding transaction check
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::writeColor(uint16_t color, uint32_t len)
 | 
						|
{
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
  uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color };
 | 
						|
  if(len) spi.writePattern(&colorBin[0], 2, 1); len--;
 | 
						|
  while(len--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
  #if defined (ESP32_PARALLEL)
 | 
						|
    while (len--) {tft_Write_16(color);}
 | 
						|
  #else
 | 
						|
    writeBlock(color, len);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushColors
 | 
						|
** Description:             push an array of pixels for 16 bit raw image drawing
 | 
						|
***************************************************************************************/
 | 
						|
// Assumed that setAddrWindow() has previously been called
 | 
						|
 | 
						|
void TFT_eSPI::pushColors(uint8_t *data, uint32_t len)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
#if defined (RPI_WRITE_STROBE)
 | 
						|
  while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; }
 | 
						|
  if (len) spi.writePattern(data, len, 1);
 | 
						|
#else
 | 
						|
  #ifdef ESP32_PARALLEL
 | 
						|
    while (len--) {tft_Write_8(*data); data++;}
 | 
						|
  #elif  defined (ILI9488_DRIVER)
 | 
						|
    uint16_t color;
 | 
						|
    while (len>1) {color = (*data++); color |= ((*data++)<<8); tft_Write_16(color); len-=2;}
 | 
						|
  #else
 | 
						|
    #if (SPI_FREQUENCY == 80000000)
 | 
						|
      while ( len >=64 ) {spi.writePattern(data, 64, 1); data += 64; len -= 64; }
 | 
						|
      if (len) spi.writePattern(data, len, 1);
 | 
						|
    #else
 | 
						|
      spi.writeBytes(data, len);
 | 
						|
    #endif
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           pushColors
 | 
						|
** Description:             push an array of pixels, for image drawing
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
#if defined (ESP32) || defined (ILI9488_DRIVER)
 | 
						|
  #if defined (ESP32_PARALLEL) || defined (ILI9488_DRIVER)
 | 
						|
    if (swap) while ( len-- ) {tft_Write_16(*data); data++;}
 | 
						|
    else while ( len-- ) {tft_Write_16S(*data); data++;}
 | 
						|
  #else
 | 
						|
    if (swap) spi.writePixels(data,len<<1);
 | 
						|
    else spi.writeBytes((uint8_t*)data,len<<1);
 | 
						|
  #endif
 | 
						|
#else
 | 
						|
 | 
						|
  uint32_t color[8];
 | 
						|
 | 
						|
  SPI1U1 = (255 << SPILMOSI) | (255 << SPILMISO);
 | 
						|
 | 
						|
 | 
						|
  while(len>15)
 | 
						|
  {
 | 
						|
 | 
						|
    if (swap)
 | 
						|
    {
 | 
						|
      uint32_t i = 0;
 | 
						|
      while(i<8)
 | 
						|
      {
 | 
						|
        color[i]  = (*data >> 8) | (uint16_t)(*data << 8);
 | 
						|
        data++;
 | 
						|
        color[i] |= ((*data >> 8) | (*data << 8)) << 16;
 | 
						|
        data++;
 | 
						|
        i++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      memcpy(color,data,32);
 | 
						|
      data+=16;
 | 
						|
    }
 | 
						|
 | 
						|
    len -= 16;
 | 
						|
 | 
						|
    // ESP8266 wait time here at 40MHz SPI is ~5.45us
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    SPI1W0 = color[0];
 | 
						|
    SPI1W1 = color[1];
 | 
						|
    SPI1W2 = color[2];
 | 
						|
    SPI1W3 = color[3];
 | 
						|
    SPI1W4 = color[4];
 | 
						|
    SPI1W5 = color[5];
 | 
						|
    SPI1W6 = color[6];
 | 
						|
    SPI1W7 = color[7];
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  if(len)
 | 
						|
  {
 | 
						|
    uint32_t bits = (len*16-1); // bits left to shift - 1
 | 
						|
    if (swap)
 | 
						|
    {
 | 
						|
      uint16_t* ptr = (uint16_t*)color;
 | 
						|
      while(len--)
 | 
						|
      {
 | 
						|
        *ptr++ = (*(data) >> 8) | (uint16_t)(*(data) << 8);
 | 
						|
        data++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      memcpy(color,data,len<<1);
 | 
						|
    }
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
    SPI1U1 = (bits << SPILMOSI) | (bits << SPILMISO);
 | 
						|
    SPI1W0 = color[0];
 | 
						|
    SPI1W1 = color[1];
 | 
						|
    SPI1W2 = color[2];
 | 
						|
    SPI1W3 = color[3];
 | 
						|
    SPI1W4 = color[4];
 | 
						|
    SPI1W5 = color[5];
 | 
						|
    SPI1W6 = color[6];
 | 
						|
    SPI1W7 = color[7];
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawLine
 | 
						|
** Description:             draw a line between 2 arbitrary points
 | 
						|
***************************************************************************************/
 | 
						|
// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use
 | 
						|
// an efficient FastH/V Line draw routine for line segments of 2 pixels or more
 | 
						|
 | 
						|
#if defined (RPI_ILI9486_DRIVER) || defined (ESP32) || defined (RPI_WRITE_STROBE) || defined (HX8357D_DRIVER) || defined (ILI9488_DRIVER)
 | 
						|
 | 
						|
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
 | 
						|
{
 | 
						|
  //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
  inTransaction = true;
 | 
						|
  boolean steep = abs(y1 - y0) > abs(x1 - x0);
 | 
						|
  if (steep) {
 | 
						|
    swap_coord(x0, y0);
 | 
						|
    swap_coord(x1, y1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (x0 > x1) {
 | 
						|
    swap_coord(x0, x1);
 | 
						|
    swap_coord(y0, y1);
 | 
						|
  }
 | 
						|
 | 
						|
  int32_t dx = x1 - x0, dy = abs(y1 - y0);;
 | 
						|
 | 
						|
  int32_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
 | 
						|
 | 
						|
  if (y0 < y1) ystep = 1;
 | 
						|
 | 
						|
  // Split into steep and not steep for FastH/V separation
 | 
						|
  if (steep) {
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      dlen++;
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
        err += dx;
 | 
						|
        if (dlen == 1) drawPixel(y0, xs, color);
 | 
						|
        else drawFastVLine(y0, xs, dlen, color);
 | 
						|
        dlen = 0; y0 += ystep; xs = x0 + 1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (dlen) drawFastVLine(y0, xs, dlen, color);
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      dlen++;
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
        err += dx;
 | 
						|
        if (dlen == 1) drawPixel(xs, y0, color);
 | 
						|
        else drawFastHLine(xs, y0, dlen, color);
 | 
						|
        dlen = 0; y0 += ystep; xs = x0 + 1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (dlen) drawFastHLine(xs, y0, dlen, color);
 | 
						|
  }
 | 
						|
  inTransaction = false;
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
// This is a weeny bit faster
 | 
						|
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
 | 
						|
{
 | 
						|
 | 
						|
  boolean steep = abs(y1 - y0) > abs(x1 - x0);
 | 
						|
 | 
						|
  if (steep) {
 | 
						|
    swap_coord(x0, y0);
 | 
						|
    swap_coord(x1, y1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (x0 > x1) {
 | 
						|
    swap_coord(x0, x1);
 | 
						|
    swap_coord(y0, y1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (x1 < 0) return;
 | 
						|
 | 
						|
  int16_t dx, dy;
 | 
						|
  dx = x1 - x0;
 | 
						|
  dy = abs(y1 - y0);
 | 
						|
 | 
						|
  int16_t err = dx / 2;
 | 
						|
  int8_t ystep = (y0 < y1) ? 1 : (-1);
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  int16_t swapped_color = (color >> 8) | (color << 8);
 | 
						|
 | 
						|
  if (steep)  // y increments every iteration (y0 is x-axis, and x0 is y-axis)
 | 
						|
  {
 | 
						|
    if (x1 >= (int32_t)_height) x1 = _height - 1;
 | 
						|
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) break;
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
        err += dx;
 | 
						|
        y0 += ystep;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (x0 > x1) {spi_end(); return;}
 | 
						|
 | 
						|
    setWindow(y0, x0, y0, _height);
 | 
						|
    SPI1W0 = swapped_color;
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      while(SPI1CMD & SPIBUSY) {}
 | 
						|
      SPI1CMD |= SPIBUSY;
 | 
						|
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
        y0 += ystep;
 | 
						|
        if ((y0 < 0) || (y0 >= _width)) break;
 | 
						|
        err += dx;
 | 
						|
        while(SPI1CMD & SPIBUSY) {}
 | 
						|
        setWindow(y0, x0+1, y0, _height);
 | 
						|
        SPI1W0 = swapped_color;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else    // x increments every iteration (x0 is x-axis, and y0 is y-axis)
 | 
						|
  {
 | 
						|
    if (x1 >= _width) x1 = _width - 1;
 | 
						|
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      if ((x0 >= 0) && (y0 >= 0) && (y0 < (int32_t)_height)) break;
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
          err += dx;
 | 
						|
          y0 += ystep;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (x0 > x1) {spi_end(); return;}
 | 
						|
 | 
						|
    setWindow(x0, y0, _width, y0);
 | 
						|
    SPI1W0 = swapped_color;
 | 
						|
    for (; x0 <= x1; x0++) {
 | 
						|
      while(SPI1CMD & SPIBUSY) {}
 | 
						|
      SPI1CMD |= SPIBUSY;
 | 
						|
 | 
						|
      err -= dy;
 | 
						|
      if (err < 0) {
 | 
						|
        y0 += ystep;
 | 
						|
        if ((y0 < 0) || (y0 >= (int32_t)_height)) break;
 | 
						|
        err += dx;
 | 
						|
        while(SPI1CMD & SPIBUSY) {}
 | 
						|
        setWindow(x0+1, y0, _width, y0);
 | 
						|
        SPI1W0 = swapped_color;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  while(SPI1CMD & SPIBUSY) {}
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawFastVLine
 | 
						|
** Description:             draw a vertical line
 | 
						|
***************************************************************************************/
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
 | 
						|
void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
 | 
						|
{
 | 
						|
  // Clipping
 | 
						|
  if ((x < 0) || (x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  if (y < 0) { h += y; y = 0; }
 | 
						|
 | 
						|
  if ((y + h) > _height) h = _height - y;
 | 
						|
 | 
						|
  if (h < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x, y + h - 1);
 | 
						|
 | 
						|
  writeBlock(color, h);
 | 
						|
  
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
 | 
						|
{
 | 
						|
  // Clipping
 | 
						|
  if ((x < 0) || (x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  if (y < 0) { h += y; y = 0; }
 | 
						|
 | 
						|
  if ((y + h) > _height) h = _height - y;
 | 
						|
 | 
						|
  if (h < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x, y + h - 1);
 | 
						|
    
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
  #if defined (ESP8266)
 | 
						|
    SPI1W0 = (color >> 8) | (color << 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  #else
 | 
						|
    tft_Write_16(color);
 | 
						|
  #endif
 | 
						|
    h--;
 | 
						|
    while(h--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
  #ifdef ESP32_PARALLEL
 | 
						|
    while (h--) {tft_Write_16(color);}
 | 
						|
  #else
 | 
						|
    writeBlock(color, h);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawFastHLine
 | 
						|
** Description:             draw a horizontal line
 | 
						|
***************************************************************************************/
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
 | 
						|
void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
 | 
						|
{
 | 
						|
  // Clipping
 | 
						|
  if ((y < 0) || (x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  if (x < 0) { w += x; x = 0; }
 | 
						|
 | 
						|
  if ((x + w) > _width)  w = _width  - x;
 | 
						|
 | 
						|
  if (w < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x + w - 1, y);
 | 
						|
 | 
						|
  writeBlock(color, w);
 | 
						|
  
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
 | 
						|
{
 | 
						|
  // Clipping
 | 
						|
  if ((y < 0) || (x >= _width) || (y >= _height)) return;
 | 
						|
 | 
						|
  if (x < 0) { w += x; x = 0; }
 | 
						|
 | 
						|
  if ((x + w) > _width)  w = _width  - x;
 | 
						|
 | 
						|
  if (w < 1) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x + w - 1, y);
 | 
						|
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
  #if defined (ESP8266)
 | 
						|
    SPI1W0 = (color >> 8) | (color << 8);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  #else
 | 
						|
    tft_Write_16(color);
 | 
						|
  #endif
 | 
						|
    w--;
 | 
						|
    while(w--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
  #ifdef ESP32_PARALLEL
 | 
						|
    while (w--) {tft_Write_16(color);}
 | 
						|
  #else
 | 
						|
    writeBlock(color, w);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           fillRect
 | 
						|
** Description:             draw a filled rectangle
 | 
						|
***************************************************************************************/
 | 
						|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
 | 
						|
void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
 | 
						|
{
 | 
						|
  // Clipping
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
  
 | 
						|
  if (x < 0) { w += x; x = 0; }
 | 
						|
  if (y < 0) { h += y; y = 0; }
 | 
						|
 | 
						|
  if ((x + w) > _width)  w = _width  - x;
 | 
						|
  if ((y + h) > _height) h = _height - y;
 | 
						|
 | 
						|
  if ((w < 1) || (h < 1)) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x + w - 1, y + h - 1);
 | 
						|
 | 
						|
  writeBlock(color, w * h);
 | 
						|
  
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
 | 
						|
{
 | 
						|
 | 
						|
  // Clipping
 | 
						|
  if ((x >= _width) || (y >= _height)) return;
 | 
						|
  
 | 
						|
  if (x < 0) { w += x; x = 0; }
 | 
						|
  if (y < 0) { h += y; y = 0; }
 | 
						|
 | 
						|
  if ((x + w) > _width)  w = _width  - x;
 | 
						|
  if ((y + h) > _height) h = _height - y;
 | 
						|
 | 
						|
  if ((w < 1) || (h < 1)) return;
 | 
						|
 | 
						|
  spi_begin();
 | 
						|
 | 
						|
  setWindow(x, y, x + w - 1, y + h - 1);
 | 
						|
 | 
						|
  uint32_t n = (uint32_t)w * (uint32_t)h;
 | 
						|
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
  tft_Write_16(color);
 | 
						|
  while(n--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
  #ifdef ESP32_PARALLEL
 | 
						|
    if (color>>8 == (uint8_t)color)
 | 
						|
    {
 | 
						|
      tft_Write_8(color);
 | 
						|
      n--; WR_L; WR_H;
 | 
						|
      while (n) {WR_L; WR_H; n--; WR_L; WR_H;}
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      while (n--) {tft_Write_16(color);}
 | 
						|
    }
 | 
						|
  #else
 | 
						|
    writeBlock(color, n);
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           color565
 | 
						|
** Description:             convert three 8 bit RGB levels to a 16 bit colour value
 | 
						|
***************************************************************************************/
 | 
						|
uint16_t TFT_eSPI::color565(uint8_t r, uint8_t g, uint8_t b)
 | 
						|
{
 | 
						|
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           color16to8
 | 
						|
** Description:             convert 16 bit colour to an 8 bit 332 RGB colour value
 | 
						|
***************************************************************************************/
 | 
						|
uint8_t TFT_eSPI::color16to8(uint16_t c)
 | 
						|
{
 | 
						|
  return ((c & 0xE000)>>8) | ((c & 0x0700)>>6) | ((c & 0x0018)>>3);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           color8to16
 | 
						|
** Description:             convert 8 bit colour to a 16 bit 565 colour value
 | 
						|
***************************************************************************************/
 | 
						|
uint16_t TFT_eSPI::color8to16(uint8_t color)
 | 
						|
{
 | 
						|
  uint8_t  blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
 | 
						|
  uint16_t color16 = 0;
 | 
						|
 | 
						|
  //        =====Green=====     ===============Red==============
 | 
						|
  color16  = (color & 0x1C)<<6 | (color & 0xC0)<<5 | (color & 0xE0)<<8;
 | 
						|
  //        =====Green=====    =======Blue======
 | 
						|
  color16 |= (color & 0x1C)<<3 | blue[color & 0x03];
 | 
						|
 | 
						|
  return color16;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           invertDisplay
 | 
						|
** Description:             invert the display colours i = 1 invert, i = 0 normal
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::invertDisplay(boolean i)
 | 
						|
{
 | 
						|
  spi_begin();
 | 
						|
  // Send the command twice as otherwise it does not always work!
 | 
						|
  writecommand(i ? TFT_INVON : TFT_INVOFF);
 | 
						|
  writecommand(i ? TFT_INVON : TFT_INVOFF);
 | 
						|
  spi_end();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**************************************************************************
 | 
						|
** Function name:           setAttribute
 | 
						|
** Description:             Sets a control parameter of an attribute
 | 
						|
**************************************************************************/
 | 
						|
void TFT_eSPI::setAttribute(uint8_t attr_id, uint8_t param) {
 | 
						|
    switch (attr_id) {
 | 
						|
            break;
 | 
						|
        case 1:
 | 
						|
            _cp437 = param;
 | 
						|
            break;
 | 
						|
        case 2:
 | 
						|
            _utf8  = param;
 | 
						|
            break;
 | 
						|
        //case 3: // TBD future feature control
 | 
						|
        //    _tbd = param;
 | 
						|
        //    break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**************************************************************************
 | 
						|
** Function name:           getAttribute
 | 
						|
** Description:             Get value of an attribute (control parameter)
 | 
						|
**************************************************************************/
 | 
						|
uint8_t TFT_eSPI::getAttribute(uint8_t attr_id) {
 | 
						|
    switch (attr_id) {
 | 
						|
        case 1: // ON/OFF control of full CP437 character set
 | 
						|
            return _cp437;
 | 
						|
            break;
 | 
						|
        case 2: // ON/OFF control of UTF-8 decoding
 | 
						|
            return _utf8;
 | 
						|
            break;
 | 
						|
        //case 3: // TBD future feature control
 | 
						|
        //    return _tbd;
 | 
						|
        //    break;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           decodeUTF8
 | 
						|
** Description:             Serial UTF-8 decoder with fall-back to extended ASCII
 | 
						|
*************************************************************************************x*/
 | 
						|
#define DECODE_UTF8 // Test only, comment out to stop decoding
 | 
						|
uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
 | 
						|
{
 | 
						|
#ifdef DECODE_UTF8
 | 
						|
  // 7 bit Unicode Code Point
 | 
						|
  if ((c & 0x80) == 0x00) {
 | 
						|
    decoderState = 0;
 | 
						|
    return (uint16_t)c;
 | 
						|
  }
 | 
						|
 | 
						|
  if (decoderState == 0)
 | 
						|
  {
 | 
						|
    // 11 bit Unicode Code Point
 | 
						|
    if ((c & 0xE0) == 0xC0)
 | 
						|
    {
 | 
						|
      decoderBuffer = ((c & 0x1F)<<6);
 | 
						|
      decoderState = 1;
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // 16 bit Unicode Code Point
 | 
						|
    if ((c & 0xF0) == 0xE0)
 | 
						|
    {
 | 
						|
      decoderBuffer = ((c & 0x0F)<<12);
 | 
						|
      decoderState = 2;
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    // 21 bit Unicode  Code Point not supported so fall-back to extended ASCII
 | 
						|
    if ((c & 0xF8) == 0xF0) return (uint16_t)c;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if (decoderState == 2)
 | 
						|
    {
 | 
						|
      decoderBuffer |= ((c & 0x3F)<<6);
 | 
						|
      decoderState--;
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      decoderBuffer |= (c & 0x3F);
 | 
						|
      decoderState = 0;
 | 
						|
      return decoderBuffer;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  decoderState = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
  return (uint16_t)c; // fall-back to extended ASCII
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           decodeUTF8
 | 
						|
** Description:             Line buffer UTF-8 decoder with fall-back to extended ASCII
 | 
						|
*************************************************************************************x*/
 | 
						|
uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
 | 
						|
{
 | 
						|
  uint16_t c = buf[(*index)++];
 | 
						|
  //Serial.print("Byte from string = 0x"); Serial.println(c, HEX);
 | 
						|
 | 
						|
#ifdef DECODE_UTF8
 | 
						|
  // 7 bit Unicode
 | 
						|
  if ((c & 0x80) == 0x00) return c;
 | 
						|
 | 
						|
  // 11 bit Unicode
 | 
						|
  if (((c & 0xE0) == 0xC0) && (remaining > 1))
 | 
						|
    return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F);
 | 
						|
 | 
						|
  // 16 bit Unicode
 | 
						|
  if (((c & 0xF0) == 0xE0) && (remaining > 2))
 | 
						|
  {
 | 
						|
    c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6);
 | 
						|
    return  c | ((buf[(*index)++]&0x3F));
 | 
						|
  }
 | 
						|
 | 
						|
  // 21 bit Unicode not supported so fall-back to extended ASCII
 | 
						|
  // if ((c & 0xF8) == 0xF0) return c;
 | 
						|
#endif
 | 
						|
 | 
						|
  return c; // fall-back to extended ASCII
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           write
 | 
						|
** Description:             draw characters piped through serial stream
 | 
						|
***************************************************************************************/
 | 
						|
size_t TFT_eSPI::write(uint8_t utf8)
 | 
						|
{
 | 
						|
  if (utf8 == '\r') return 1;
 | 
						|
 | 
						|
  uint16_t uniCode = utf8;
 | 
						|
 | 
						|
  if (_utf8) uniCode = decodeUTF8(utf8);
 | 
						|
 | 
						|
  if (uniCode == 0) return 1;
 | 
						|
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  if(fontLoaded)
 | 
						|
  {
 | 
						|
    //Serial.print("UniCode="); Serial.println(uniCode);
 | 
						|
    //Serial.print("UTF8   ="); Serial.println(utf8);
 | 
						|
 | 
						|
    //fontFile = SPIFFS.open( _gFontFilename, "r" );
 | 
						|
 | 
						|
    //if(!fontFile)
 | 
						|
    //{
 | 
						|
    //  fontLoaded = false;
 | 
						|
    //  return 1;
 | 
						|
    //}
 | 
						|
 | 
						|
    drawGlyph(uniCode);
 | 
						|
 | 
						|
    //fontFile.close();
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors
 | 
						|
  else if (uniCode < 32) return 1;
 | 
						|
 | 
						|
  uint16_t width = 0;
 | 
						|
  uint16_t height = 0;
 | 
						|
 | 
						|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 | 
						|
  //Serial.print((uint8_t) uniCode); // Debug line sends all printed TFT text to serial port
 | 
						|
  //Serial.println(uniCode, HEX); // Debug line sends all printed TFT text to serial port
 | 
						|
  //delay(5);                     // Debug optional wait for serial port to flush through
 | 
						|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  if(!gfxFont) {
 | 
						|
#endif
 | 
						|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
 | 
						|
#ifdef LOAD_FONT2
 | 
						|
  if (textfont == 2)
 | 
						|
  {
 | 
						|
    if (uniCode > 127) return 1;
 | 
						|
 | 
						|
    width = pgm_read_byte(widtbl_f16 + uniCode-32);
 | 
						|
    height = chr_hgt_f16;
 | 
						|
    // Font 2 is rendered in whole byte widths so we must allow for this
 | 
						|
    width = (width + 6) / 8;  // Width in whole bytes for font 2, should be + 7 but must allow for font width change
 | 
						|
    width = width * 8;        // Width converted back to pixels
 | 
						|
  }
 | 
						|
  #ifdef LOAD_RLE
 | 
						|
  else
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_RLE
 | 
						|
  {
 | 
						|
    if ((textfont>2) && (textfont<9))
 | 
						|
    {
 | 
						|
      if (uniCode > 127) return 1;
 | 
						|
      // Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
 | 
						|
      width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
 | 
						|
      height= pgm_read_byte( &fontdata[textfont].height );
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
  if (textfont==1)
 | 
						|
  {
 | 
						|
      width =  6;
 | 
						|
      height = 8;
 | 
						|
  }
 | 
						|
#else
 | 
						|
  if (textfont==1) return 1;
 | 
						|
#endif
 | 
						|
 | 
						|
  height = height * textsize;
 | 
						|
 | 
						|
  if (utf8 == '\n') {
 | 
						|
    cursor_y += height;
 | 
						|
    cursor_x  = 0;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if (textwrapX && (cursor_x + width * textsize > _width))
 | 
						|
    {
 | 
						|
      cursor_y += height;
 | 
						|
      cursor_x = 0;
 | 
						|
    }
 | 
						|
    if (textwrapY && (cursor_y >= (int32_t)_height)) cursor_y = 0;
 | 
						|
    cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont);
 | 
						|
  }
 | 
						|
 | 
						|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  } // Custom GFX font
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if(utf8 == '\n') {
 | 
						|
      cursor_x  = 0;
 | 
						|
      cursor_y += (int16_t)textsize *
 | 
						|
                  (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
 | 
						|
    } else {
 | 
						|
      if (uniCode > pgm_read_word(&gfxFont->last )) return 1;
 | 
						|
      if (uniCode < pgm_read_word(&gfxFont->first)) return 1;
 | 
						|
 | 
						|
      uint16_t   c2    = uniCode - pgm_read_word(&gfxFont->first);
 | 
						|
      GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
 | 
						|
      uint8_t   w     = pgm_read_byte(&glyph->width),
 | 
						|
                h     = pgm_read_byte(&glyph->height);
 | 
						|
      if((w > 0) && (h > 0)) { // Is there an associated bitmap?
 | 
						|
        int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset);
 | 
						|
        if(textwrapX && ((cursor_x + textsize * (xo + w)) > _width)) {
 | 
						|
          // Drawing character would go off right edge; wrap to new line
 | 
						|
          cursor_x  = 0;
 | 
						|
          cursor_y += (int16_t)textsize *
 | 
						|
                      (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
 | 
						|
        }
 | 
						|
        if (textwrapY && (cursor_y >= (int32_t)_height)) cursor_y = 0;
 | 
						|
        drawChar(cursor_x, cursor_y, uniCode, textcolor, textbgcolor, textsize);
 | 
						|
      }
 | 
						|
      cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif // LOAD_GFXFF
 | 
						|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawChar
 | 
						|
** Description:             draw a Unicode glyph onto the screen
 | 
						|
***************************************************************************************/
 | 
						|
  // Any UTF-8 decoding must be done before calling drawChar()
 | 
						|
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y)
 | 
						|
{
 | 
						|
  return drawChar(uniCode, x, y, textfont);
 | 
						|
}
 | 
						|
 | 
						|
  // Any UTF-8 decoding must be done before calling drawChar()
 | 
						|
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
 | 
						|
{
 | 
						|
  if (!uniCode) return 0;
 | 
						|
 | 
						|
  if (font==1)
 | 
						|
  {
 | 
						|
#ifdef LOAD_GLCD
 | 
						|
  #ifndef LOAD_GFXFF
 | 
						|
    drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
 | 
						|
    return 6 * textsize;
 | 
						|
  #endif
 | 
						|
#else
 | 
						|
  #ifndef LOAD_GFXFF
 | 
						|
    return 0;
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
    drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
 | 
						|
    if(!gfxFont) { // 'Classic' built-in font
 | 
						|
    #ifdef LOAD_GLCD
 | 
						|
      return 6 * textsize;
 | 
						|
    #else
 | 
						|
      return 0;
 | 
						|
    #endif
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) ))
 | 
						|
      {
 | 
						|
        uint16_t   c2    = uniCode - pgm_read_word(&gfxFont->first);
 | 
						|
        GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
 | 
						|
        return pgm_read_byte(&glyph->xAdvance) * textsize;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0;
 | 
						|
 | 
						|
  int32_t width  = 0;
 | 
						|
  int32_t height = 0;
 | 
						|
  uint32_t flash_address = 0;
 | 
						|
  uniCode -= 32;
 | 
						|
 | 
						|
#ifdef LOAD_FONT2
 | 
						|
  if (font == 2)
 | 
						|
  {
 | 
						|
    flash_address = pgm_read_dword(&chrtbl_f16[uniCode]);
 | 
						|
    width = pgm_read_byte(widtbl_f16 + uniCode);
 | 
						|
    height = chr_hgt_f16;
 | 
						|
  }
 | 
						|
  #ifdef LOAD_RLE
 | 
						|
  else
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef LOAD_RLE
 | 
						|
  {
 | 
						|
    if ((font>2) && (font<9))
 | 
						|
    {
 | 
						|
      flash_address = pgm_read_dword( (const void*)(pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *)) );
 | 
						|
      width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode );
 | 
						|
      height= pgm_read_byte( &fontdata[font].height );
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  int32_t w = width;
 | 
						|
  int32_t pX      = 0;
 | 
						|
  int32_t pY      = y;
 | 
						|
  uint8_t line = 0;
 | 
						|
 | 
						|
#ifdef LOAD_FONT2 // chop out code if we do not need it
 | 
						|
  if (font == 2) {
 | 
						|
    w = w + 6; // Should be + 7 but we need to compensate for width increment
 | 
						|
    w = w / 8;
 | 
						|
    if (x + width * textsize >= (int16_t)_width) return width * textsize ;
 | 
						|
 | 
						|
    if (textcolor == textbgcolor || textsize != 1) {
 | 
						|
      //spi_begin();          // Sprite class can use this function, avoiding spi_begin()
 | 
						|
      inTransaction = true;
 | 
						|
 | 
						|
      for (int32_t i = 0; i < height; i++)
 | 
						|
      {
 | 
						|
        if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor);
 | 
						|
 | 
						|
        for (int32_t k = 0; k < w; k++)
 | 
						|
        {
 | 
						|
          line = pgm_read_byte((uint8_t *)flash_address + w * i + k);
 | 
						|
          if (line) {
 | 
						|
            if (textsize == 1) {
 | 
						|
              pX = x + k * 8;
 | 
						|
              if (line & 0x80) drawPixel(pX, pY, textcolor);
 | 
						|
              if (line & 0x40) drawPixel(pX + 1, pY, textcolor);
 | 
						|
              if (line & 0x20) drawPixel(pX + 2, pY, textcolor);
 | 
						|
              if (line & 0x10) drawPixel(pX + 3, pY, textcolor);
 | 
						|
              if (line & 0x08) drawPixel(pX + 4, pY, textcolor);
 | 
						|
              if (line & 0x04) drawPixel(pX + 5, pY, textcolor);
 | 
						|
              if (line & 0x02) drawPixel(pX + 6, pY, textcolor);
 | 
						|
              if (line & 0x01) drawPixel(pX + 7, pY, textcolor);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              pX = x + k * 8 * textsize;
 | 
						|
              if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
              if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor);
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        pY += textsize;
 | 
						|
      }
 | 
						|
 | 
						|
      inTransaction = false;
 | 
						|
      spi_end();
 | 
						|
    }
 | 
						|
    else
 | 
						|
      // Faster drawing of characters and background using block write
 | 
						|
    {
 | 
						|
      spi_begin();
 | 
						|
 | 
						|
      setWindow(x, y, x + width - 1, y + height - 1);
 | 
						|
 | 
						|
      uint8_t mask;
 | 
						|
      for (int32_t i = 0; i < height; i++)
 | 
						|
      {
 | 
						|
        pX = width;
 | 
						|
        for (int32_t k = 0; k < w; k++)
 | 
						|
        {
 | 
						|
          line = pgm_read_byte((uint8_t *) (flash_address + w * i + k) );
 | 
						|
          mask = 0x80;
 | 
						|
          while (mask && pX) {
 | 
						|
            if (line & mask) {tft_Write_16(textcolor);}
 | 
						|
            else {tft_Write_16(textbgcolor);}
 | 
						|
            pX--;
 | 
						|
            mask = mask >> 1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (pX) {tft_Write_16(textbgcolor);}
 | 
						|
      }
 | 
						|
 | 
						|
      spi_end();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  #ifdef LOAD_RLE
 | 
						|
  else
 | 
						|
  #endif
 | 
						|
#endif  //FONT2
 | 
						|
 | 
						|
#ifdef LOAD_RLE  //674 bytes of code
 | 
						|
  // Font is not 2 and hence is RLE encoded
 | 
						|
  {
 | 
						|
    spi_begin();
 | 
						|
    inTransaction = true;
 | 
						|
 | 
						|
    w *= height; // Now w is total number of pixels in the character
 | 
						|
    if ((textsize != 1) || (textcolor == textbgcolor)) {
 | 
						|
      if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
 | 
						|
      int32_t px = 0, py = pY; // To hold character block start and end column and row values
 | 
						|
      int32_t pc = 0; // Pixel count
 | 
						|
      uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel
 | 
						|
 | 
						|
      uint8_t tnp = 0; // Temporary copy of np for while loop
 | 
						|
      uint8_t ts = textsize - 1; // Temporary copy of textsize
 | 
						|
      // 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
 | 
						|
      // w is total number of pixels to plot to fill character block
 | 
						|
      while (pc < w)
 | 
						|
      {
 | 
						|
        line = pgm_read_byte((uint8_t *)flash_address);
 | 
						|
        flash_address++;
 | 
						|
        if (line & 0x80) {
 | 
						|
          line &= 0x7F;
 | 
						|
          line++;
 | 
						|
          if (ts) {
 | 
						|
            px = x + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow
 | 
						|
            py = y + textsize * (pc / width);
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            px = x + pc % width; // Keep these px and py calculations outside the loop as they are slow
 | 
						|
            py = y + pc / width;
 | 
						|
          }
 | 
						|
          while (line--) { // In this case the while(line--) is faster
 | 
						|
            pc++; // This is faster than putting pc+=line before while()?
 | 
						|
            setWindow(px, py, px + ts, py + ts);
 | 
						|
 | 
						|
            if (ts) {
 | 
						|
              tnp = np;
 | 
						|
              while (tnp--) {tft_Write_16(textcolor);}
 | 
						|
            }
 | 
						|
            else {tft_Write_16(textcolor);}
 | 
						|
            px += textsize;
 | 
						|
 | 
						|
            if (px >= (x + width * textsize))
 | 
						|
            {
 | 
						|
              px = x;
 | 
						|
              py += textsize;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          line++;
 | 
						|
          pc += line;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else // Text colour != background && textsize = 1
 | 
						|
         // so use faster drawing of characters and background using block write
 | 
						|
    {
 | 
						|
      setWindow(x, y, x + width - 1, y + height - 1);
 | 
						|
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
      uint8_t textcolorBin[] = { (uint8_t) (textcolor >> 8), (uint8_t) textcolor };
 | 
						|
      uint8_t textbgcolorBin[] = { (uint8_t) (textbgcolor >> 8), (uint8_t) textbgcolor };
 | 
						|
#endif
 | 
						|
 | 
						|
      // Maximum font size is equivalent to 180x180 pixels in area
 | 
						|
      while (w > 0)
 | 
						|
      {
 | 
						|
        line = pgm_read_byte((uint8_t *)flash_address++); // 8 bytes smaller when incrementing here
 | 
						|
        if (line & 0x80) {
 | 
						|
          line &= 0x7F;
 | 
						|
          line++; w -= line;
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
          spi.writePattern(&textcolorBin[0], 2, 1); line--;
 | 
						|
          while(line--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
          #ifdef ESP32_PARALLEL
 | 
						|
            while (line--) {tft_Write_16(textcolor);}
 | 
						|
          #else
 | 
						|
            writeBlock(textcolor,line);
 | 
						|
          #endif
 | 
						|
#endif
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          line++; w -= line;
 | 
						|
#ifdef RPI_WRITE_STROBE
 | 
						|
          spi.writePattern(&textbgcolorBin[0], 2, 1); line--;
 | 
						|
          while(line--) {WR_L; WR_H;}
 | 
						|
#else
 | 
						|
          #ifdef ESP32_PARALLEL
 | 
						|
            while (line--) {tft_Write_16(textbgcolor);}
 | 
						|
          #else
 | 
						|
            writeBlock(textbgcolor,line);
 | 
						|
          #endif
 | 
						|
#endif
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    inTransaction = false;
 | 
						|
    spi_end();
 | 
						|
  }
 | 
						|
  // End of RLE font rendering
 | 
						|
#endif
 | 
						|
  return width * textsize;    // x +
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawString (with or without user defined font)
 | 
						|
** Description :            draw string with padding if it is defined
 | 
						|
***************************************************************************************/
 | 
						|
// Without font number, uses font set by setTextFont()
 | 
						|
int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return drawString(buffer, poX, poY, textfont);
 | 
						|
}
 | 
						|
// With font number
 | 
						|
int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return drawString(buffer, poX, poY, font);
 | 
						|
}
 | 
						|
 | 
						|
// Without font number, uses font set by setTextFont()
 | 
						|
int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY)
 | 
						|
{
 | 
						|
  return drawString(string, poX, poY, textfont);
 | 
						|
}
 | 
						|
 | 
						|
// With font number. Note: font number is over-ridden if a smooth font is loaded
 | 
						|
int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  int16_t sumX = 0;
 | 
						|
  uint8_t padding = 1, baseline = 0;
 | 
						|
  uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font
 | 
						|
  uint16_t cheight = 8 * textsize;
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  #ifdef SMOOTH_FONT
 | 
						|
    bool freeFont = (font == 1 && gfxFont && !fontLoaded);
 | 
						|
  #else
 | 
						|
    bool freeFont = (font == 1 && gfxFont);
 | 
						|
  #endif
 | 
						|
 | 
						|
  if (freeFont) {
 | 
						|
    cheight = glyph_ab * textsize;
 | 
						|
    poY += cheight; // Adjust for baseline datum of free fonts
 | 
						|
    baseline = cheight;
 | 
						|
    padding =101; // Different padding method used for Free Fonts
 | 
						|
 | 
						|
    // We need to make an adjustment for the bottom of the string (eg 'y' character)
 | 
						|
    if ((textdatum == BL_DATUM) || (textdatum == BC_DATUM) || (textdatum == BR_DATUM)) {
 | 
						|
      cheight += glyph_bb * textsize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
  // If it is not font 1 (GLCD or free font) get the baseline and pixel height of the font
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  if(fontLoaded) {
 | 
						|
    baseline = gFont.maxAscent;
 | 
						|
    cheight  = fontHeight();
 | 
						|
  }
 | 
						|
  else
 | 
						|
#endif
 | 
						|
  if (font!=1) {
 | 
						|
    baseline = pgm_read_byte( &fontdata[font].baseline ) * textsize;
 | 
						|
    cheight = fontHeight(font);
 | 
						|
  }
 | 
						|
 | 
						|
  if (textdatum || padX)
 | 
						|
  {
 | 
						|
 | 
						|
    switch(textdatum) {
 | 
						|
      case TC_DATUM:
 | 
						|
        poX -= cwidth/2;
 | 
						|
        padding += 1;
 | 
						|
        break;
 | 
						|
      case TR_DATUM:
 | 
						|
        poX -= cwidth;
 | 
						|
        padding += 2;
 | 
						|
        break;
 | 
						|
      case ML_DATUM:
 | 
						|
        poY -= cheight/2;
 | 
						|
        //padding += 0;
 | 
						|
        break;
 | 
						|
      case MC_DATUM:
 | 
						|
        poX -= cwidth/2;
 | 
						|
        poY -= cheight/2;
 | 
						|
        padding += 1;
 | 
						|
        break;
 | 
						|
      case MR_DATUM:
 | 
						|
        poX -= cwidth;
 | 
						|
        poY -= cheight/2;
 | 
						|
        padding += 2;
 | 
						|
        break;
 | 
						|
      case BL_DATUM:
 | 
						|
        poY -= cheight;
 | 
						|
        //padding += 0;
 | 
						|
        break;
 | 
						|
      case BC_DATUM:
 | 
						|
        poX -= cwidth/2;
 | 
						|
        poY -= cheight;
 | 
						|
        padding += 1;
 | 
						|
        break;
 | 
						|
      case BR_DATUM:
 | 
						|
        poX -= cwidth;
 | 
						|
        poY -= cheight;
 | 
						|
        padding += 2;
 | 
						|
        break;
 | 
						|
      case L_BASELINE:
 | 
						|
        poY -= baseline;
 | 
						|
        //padding += 0;
 | 
						|
        break;
 | 
						|
      case C_BASELINE:
 | 
						|
        poX -= cwidth/2;
 | 
						|
        poY -= baseline;
 | 
						|
        padding += 1;
 | 
						|
        break;
 | 
						|
      case R_BASELINE:
 | 
						|
        poX -= cwidth;
 | 
						|
        poY -= baseline;
 | 
						|
        padding += 2;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    // Check coordinates are OK, adjust if not
 | 
						|
    if (poX < 0) poX = 0;
 | 
						|
    if (poX+cwidth > width())   poX = width() - cwidth;
 | 
						|
    if (poY < 0) poY = 0;
 | 
						|
    if (poY+cheight-baseline> height()) poY = height() - cheight;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  int8_t xo = 0;
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
  if (freeFont && (textcolor!=textbgcolor))
 | 
						|
    {
 | 
						|
      cheight = (glyph_ab + glyph_bb) * textsize;
 | 
						|
      // Get the offset for the first character only to allow for negative offsets
 | 
						|
      uint16_t c2 = 0;
 | 
						|
      uint16_t len = strlen(string);
 | 
						|
      uint16_t n = 0;
 | 
						|
 | 
						|
      while (n < len && c2 == 0) c2 = decodeUTF8((uint8_t*)string, &n, len - n);
 | 
						|
 | 
						|
      if((c2 >= pgm_read_word(&gfxFont->first)) && (c2 <= pgm_read_word(&gfxFont->last) ))
 | 
						|
      {
 | 
						|
        c2 -= pgm_read_word(&gfxFont->first);
 | 
						|
        GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
 | 
						|
        xo = pgm_read_byte(&glyph->xOffset) * textsize;
 | 
						|
        // Adjust for negative xOffset
 | 
						|
        if (xo > 0) xo = 0;
 | 
						|
        else cwidth -= xo;
 | 
						|
        // Add 1 pixel of padding all round
 | 
						|
        //cheight +=2;
 | 
						|
        //fillRect(poX+xo-1, poY - 1 - glyph_ab * textsize, cwidth+2, cheight, textbgcolor);
 | 
						|
        fillRect(poX+xo, poY - glyph_ab * textsize, cwidth, cheight, textbgcolor);
 | 
						|
      }
 | 
						|
      padding -=100;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
  uint16_t len = strlen(string);
 | 
						|
  uint16_t n = 0;
 | 
						|
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  if(fontLoaded)
 | 
						|
  {
 | 
						|
    if (textcolor!=textbgcolor) fillRect(poX, poY, cwidth, cheight, textbgcolor);
 | 
						|
    //drawLine(poX - 5, poY, poX + 5, poY, TFT_GREEN);
 | 
						|
    //drawLine(poX, poY - 5, poX, poY + 5, TFT_GREEN);
 | 
						|
    //fontFile = SPIFFS.open( _gFontFilename, "r");
 | 
						|
    if(!fontFile) return 0;
 | 
						|
 | 
						|
    setCursor(poX, poY);
 | 
						|
 | 
						|
    while (n < len)
 | 
						|
    {
 | 
						|
      uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
 | 
						|
      drawGlyph(uniCode);
 | 
						|
    }
 | 
						|
    sumX += cwidth;
 | 
						|
    //fontFile.close();
 | 
						|
  }
 | 
						|
  else
 | 
						|
#endif
 | 
						|
  {
 | 
						|
    while (n < len)
 | 
						|
    {
 | 
						|
      uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
 | 
						|
      sumX += drawChar(uniCode, poX+sumX, poY, font);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 | 
						|
// Switch on debugging for the padding areas
 | 
						|
//#define PADDING_DEBUG
 | 
						|
 | 
						|
#ifndef PADDING_DEBUG
 | 
						|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
  if((padX>cwidth) && (textcolor!=textbgcolor))
 | 
						|
  {
 | 
						|
    int16_t padXc = poX+cwidth+xo;
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
    if (freeFont)
 | 
						|
    {
 | 
						|
      poX +=xo; // Adjust for negative offset start character
 | 
						|
      poY -= glyph_ab * textsize;
 | 
						|
      sumX += poX;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    switch(padding) {
 | 
						|
      case 1:
 | 
						|
        fillRect(padXc,poY,padX-cwidth,cheight, textbgcolor);
 | 
						|
        break;
 | 
						|
      case 2:
 | 
						|
        fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
 | 
						|
        padXc = (padX-cwidth)>>1;
 | 
						|
        if (padXc>poX) padXc = poX;
 | 
						|
        fillRect(poX - padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
 | 
						|
        break;
 | 
						|
      case 3:
 | 
						|
        if (padXc>padX) padXc = padX;
 | 
						|
        fillRect(poX + cwidth - padXc,poY,padXc-cwidth,cheight, textbgcolor);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 | 
						|
// This is debug code to show text (green box) and blanked (white box) areas
 | 
						|
// It shows that the padding areas are being correctly sized and positioned
 | 
						|
 | 
						|
  if((padX>sumX) && (textcolor!=textbgcolor))
 | 
						|
  {
 | 
						|
    int16_t padXc = poX+sumX; // Maximum left side padding
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
    if ((font == 1) && (gfxFont)) poY -= glyph_ab;
 | 
						|
#endif
 | 
						|
    drawRect(poX,poY,sumX,cheight, TFT_GREEN);
 | 
						|
    switch(padding) {
 | 
						|
      case 1:
 | 
						|
        drawRect(padXc,poY,padX-sumX,cheight, TFT_WHITE);
 | 
						|
        break;
 | 
						|
      case 2:
 | 
						|
        drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE);
 | 
						|
        padXc = (padX-sumX)>>1;
 | 
						|
        if (padXc>poX) padXc = poX;
 | 
						|
        drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE);
 | 
						|
        break;
 | 
						|
      case 3:
 | 
						|
        if (padXc>padX) padXc = padX;
 | 
						|
        drawRect(poX + sumX - padXc,poY,padXc-sumX,cheight, TFT_WHITE);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
return sumX;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawCentreString (deprecated, use setTextDatum())
 | 
						|
** Descriptions:            draw string centred on dX
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::drawCentreString(const String& string, int32_t dX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return drawCentreString(buffer, dX, poY, font);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::drawCentreString(const char *string, int32_t dX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  uint8_t tempdatum = textdatum;
 | 
						|
  int32_t sumX = 0;
 | 
						|
  textdatum = TC_DATUM;
 | 
						|
  sumX = drawString(string, dX, poY, font);
 | 
						|
  textdatum = tempdatum;
 | 
						|
  return sumX;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawRightString (deprecated, use setTextDatum())
 | 
						|
** Descriptions:            draw string right justified to dX
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::drawRightString(const String& string, int32_t dX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  int16_t len = string.length() + 2;
 | 
						|
  char buffer[len];
 | 
						|
  string.toCharArray(buffer, len);
 | 
						|
  return drawRightString(buffer, dX, poY, font);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::drawRightString(const char *string, int32_t dX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  uint8_t tempdatum = textdatum;
 | 
						|
  int16_t sumX = 0;
 | 
						|
  textdatum = TR_DATUM;
 | 
						|
  sumX = drawString(string, dX, poY, font);
 | 
						|
  textdatum = tempdatum;
 | 
						|
  return sumX;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawNumber
 | 
						|
** Description:             draw a long integer
 | 
						|
***************************************************************************************/
 | 
						|
int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY)
 | 
						|
{
 | 
						|
  isDigits = true; // Eliminate jiggle in monospaced fonts
 | 
						|
  char str[12];
 | 
						|
  ltoa(long_num, str, 10);
 | 
						|
  return drawString(str, poX, poY, textfont);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  isDigits = true; // Eliminate jiggle in monospaced fonts
 | 
						|
  char str[12];
 | 
						|
  ltoa(long_num, str, 10);
 | 
						|
  return drawString(str, poX, poY, font);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           drawFloat
 | 
						|
** Descriptions:            drawFloat, prints 7 non zero digits maximum
 | 
						|
***************************************************************************************/
 | 
						|
// Assemble and print a string, this permits alignment relative to a datum
 | 
						|
// looks complicated but much more compact and actually faster than using print class
 | 
						|
int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY)
 | 
						|
{
 | 
						|
  return drawFloat(floatNumber, dp, poX, poY, textfont);
 | 
						|
}
 | 
						|
 | 
						|
int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY, uint8_t font)
 | 
						|
{
 | 
						|
  isDigits = true;
 | 
						|
  char str[14];               // Array to contain decimal string
 | 
						|
  uint8_t ptr = 0;            // Initialise pointer for array
 | 
						|
  int8_t  digits = 1;         // Count the digits to avoid array overflow
 | 
						|
  float rounding = 0.5;       // Round up down delta
 | 
						|
 | 
						|
  if (dp > 7) dp = 7; // Limit the size of decimal portion
 | 
						|
 | 
						|
  // Adjust the rounding value
 | 
						|
  for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0;
 | 
						|
 | 
						|
  if (floatNumber < -rounding)    // add sign, avoid adding - sign to 0.0!
 | 
						|
  {
 | 
						|
    str[ptr++] = '-'; // Negative number
 | 
						|
    str[ptr] = 0; // Put a null in the array as a precaution
 | 
						|
    digits = 0;   // Set digits to 0 to compensate so pointer value can be used later
 | 
						|
    floatNumber = -floatNumber; // Make positive
 | 
						|
  }
 | 
						|
 | 
						|
  floatNumber += rounding; // Round up or down
 | 
						|
 | 
						|
  // For error put ... in string and return (all TFT_eSPI library fonts contain . character)
 | 
						|
  if (floatNumber >= 2147483647) {
 | 
						|
    strcpy(str, "...");
 | 
						|
    return drawString(str, poX, poY, font);
 | 
						|
  }
 | 
						|
  // No chance of overflow from here on
 | 
						|
 | 
						|
  // Get integer part
 | 
						|
  uint32_t temp = (uint32_t)floatNumber;
 | 
						|
 | 
						|
  // Put integer part into array
 | 
						|
  ltoa(temp, str + ptr, 10);
 | 
						|
 | 
						|
  // Find out where the null is to get the digit count loaded
 | 
						|
  while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along
 | 
						|
  digits += ptr;                  // Count the digits
 | 
						|
 | 
						|
  str[ptr++] = '.'; // Add decimal point
 | 
						|
  str[ptr] = '0';   // Add a dummy zero
 | 
						|
  str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten
 | 
						|
 | 
						|
  // Get the decimal portion
 | 
						|
  floatNumber = floatNumber - temp;
 | 
						|
 | 
						|
  // Get decimal digits one by one and put in array
 | 
						|
  // Limit digit count so we don't get a false sense of resolution
 | 
						|
  uint8_t i = 0;
 | 
						|
  while ((i < dp) && (digits < 9)) // while (i < dp) for no limit but array size must be increased
 | 
						|
  {
 | 
						|
    i++;
 | 
						|
    floatNumber *= 10;       // for the next decimal
 | 
						|
    temp = floatNumber;      // get the decimal
 | 
						|
    ltoa(temp, str + ptr, 10);
 | 
						|
    ptr++; digits++;         // Increment pointer and digits count
 | 
						|
    floatNumber -= temp;     // Remove that digit
 | 
						|
  }
 | 
						|
 | 
						|
  // Finally we can plot the string and return pixel length
 | 
						|
  return drawString(str, poX, poY, font);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setFreeFont
 | 
						|
** Descriptions:            Sets the GFX free font to use
 | 
						|
***************************************************************************************/
 | 
						|
 | 
						|
#ifdef LOAD_GFXFF
 | 
						|
 | 
						|
void TFT_eSPI::setFreeFont(const GFXfont *f)
 | 
						|
{
 | 
						|
  if (f == nullptr) // Fix issue #400 (ESP32 crash)
 | 
						|
  {
 | 
						|
    setTextFont(1); // Use GLCD font
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  textfont = 1;
 | 
						|
  gfxFont = (GFXfont *)f;
 | 
						|
 | 
						|
  glyph_ab = 0;
 | 
						|
  glyph_bb = 0;
 | 
						|
  uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
 | 
						|
  
 | 
						|
  // Find the biggest above and below baseline offsets
 | 
						|
  for (uint8_t c = 0; c < numChars; c++)
 | 
						|
  {
 | 
						|
    GFXglyph *glyph1  = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
 | 
						|
    int8_t ab = -pgm_read_byte(&glyph1->yOffset);
 | 
						|
    if (ab > glyph_ab) glyph_ab = ab;
 | 
						|
    int8_t bb = pgm_read_byte(&glyph1->height) - ab;
 | 
						|
    if (bb > glyph_bb) glyph_bb = bb;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextFont
 | 
						|
** Description:             Set the font for the print stream
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextFont(uint8_t f)
 | 
						|
{
 | 
						|
  textfont = (f > 0) ? f : 1; // Don't allow font 0
 | 
						|
  gfxFont = NULL;
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
    
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setFreeFont
 | 
						|
** Descriptions:            Sets the GFX free font to use
 | 
						|
***************************************************************************************/
 | 
						|
 | 
						|
// Alternative to setTextFont() so we don't need two different named functions
 | 
						|
void TFT_eSPI::setFreeFont(uint8_t font)
 | 
						|
{
 | 
						|
  setTextFont(font);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           setTextFont
 | 
						|
** Description:             Set the font for the print stream
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::setTextFont(uint8_t f)
 | 
						|
{
 | 
						|
  textfont = (f > 0) ? f : 1; // Don't allow font 0
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           writeBlock
 | 
						|
** Description:             Write a block of pixels of the same colour
 | 
						|
***************************************************************************************/
 | 
						|
//Clear screen test 76.8ms theoretical. 81.5ms TFT_eSPI, 967ms Adafruit_ILI9341
 | 
						|
//Performance 26.15Mbps@26.66MHz, 39.04Mbps@40MHz, 75.4Mbps@80MHz SPI clock
 | 
						|
//Efficiency:
 | 
						|
//       TFT_eSPI       98.06%              97.59%          94.24%
 | 
						|
//       Adafruit_GFX   19.62%              14.31%           7.94%
 | 
						|
//
 | 
						|
#if defined (ESP8266) && !defined (ILI9488_DRIVER)
 | 
						|
void writeBlock(uint16_t color, uint32_t repeat)
 | 
						|
{
 | 
						|
  uint16_t color16 = (color >> 8) | (color << 8);
 | 
						|
  uint32_t color32 = color16 | color16 << 16;
 | 
						|
 | 
						|
  SPI1W0 = color32;
 | 
						|
  SPI1W1 = color32;
 | 
						|
  SPI1W2 = color32;
 | 
						|
  SPI1W3 = color32;
 | 
						|
  if (repeat > 8)
 | 
						|
  {
 | 
						|
    SPI1W4 = color32;
 | 
						|
    SPI1W5 = color32;
 | 
						|
    SPI1W6 = color32;
 | 
						|
    SPI1W7 = color32;
 | 
						|
  }
 | 
						|
  if (repeat > 16)
 | 
						|
  {
 | 
						|
    SPI1W8 = color32;
 | 
						|
    SPI1W9 = color32;
 | 
						|
    SPI1W10 = color32;
 | 
						|
    SPI1W11 = color32;
 | 
						|
  }
 | 
						|
  if (repeat > 24)
 | 
						|
  {
 | 
						|
    SPI1W12 = color32;
 | 
						|
    SPI1W13 = color32;
 | 
						|
    SPI1W14 = color32;
 | 
						|
    SPI1W15 = color32;
 | 
						|
  }
 | 
						|
  if (repeat > 31)
 | 
						|
  {
 | 
						|
    SPI1U1 = (511 << SPILMOSI);
 | 
						|
    while(repeat>31)
 | 
						|
    {
 | 
						|
#if defined SPI_FREQUENCY && (SPI_FREQUENCY == 80000000)
 | 
						|
      if(SPI1CMD & SPIBUSY) // added to sync with flag change
 | 
						|
#endif
 | 
						|
      while(SPI1CMD & SPIBUSY) {}
 | 
						|
      SPI1CMD |= SPIBUSY;
 | 
						|
      repeat -= 32;
 | 
						|
    }
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  }
 | 
						|
 | 
						|
  if (repeat)
 | 
						|
  {
 | 
						|
    repeat = (repeat << 4) - 1;
 | 
						|
    SPI1U1 = (repeat << SPILMOSI);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#elif defined (ILI9488_DRIVER)
 | 
						|
 | 
						|
#ifdef ESP8266
 | 
						|
void writeBlock(uint16_t color, uint32_t repeat)
 | 
						|
{
 | 
						|
 | 
						|
  // Split out the colours
 | 
						|
  uint8_t r = (color & 0xF800)>>8;
 | 
						|
  uint8_t g = (color & 0x07E0)>>3;
 | 
						|
  uint8_t b = (color & 0x001F)<<3;
 | 
						|
  // Concatenate 4 pixels into three 32 bit blocks
 | 
						|
  uint32_t r0 = r<<24 | b<<16 | g<<8 | r;
 | 
						|
  uint32_t r1 = g<<24 | r<<16 | b<<8 | g;
 | 
						|
  uint32_t r2 = b<<24 | g<<16 | r<<8 | b;
 | 
						|
 | 
						|
  SPI1W0 = r0;
 | 
						|
  SPI1W1 = r1;
 | 
						|
  SPI1W2 = r2;
 | 
						|
 | 
						|
  if (repeat > 4)
 | 
						|
  {
 | 
						|
    SPI1W3 = r0;
 | 
						|
    SPI1W4 = r1;
 | 
						|
    SPI1W5 = r2;
 | 
						|
  }
 | 
						|
  if (repeat > 8)
 | 
						|
  {
 | 
						|
    SPI1W6 = r0;
 | 
						|
    SPI1W7 = r1;
 | 
						|
    SPI1W8 = r2;
 | 
						|
  }
 | 
						|
  if (repeat > 12)
 | 
						|
  {
 | 
						|
    SPI1W9  = r0;
 | 
						|
    SPI1W10 = r1;
 | 
						|
    SPI1W11 = r2;
 | 
						|
    SPI1W12 = r0;
 | 
						|
    SPI1W13 = r1;
 | 
						|
    SPI1W14 = r2;
 | 
						|
    SPI1W15 = r0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (repeat > 20)
 | 
						|
  {
 | 
						|
    SPI1U1 = (503 << SPILMOSI);
 | 
						|
    while(repeat>20)
 | 
						|
    {
 | 
						|
      while(SPI1CMD & SPIBUSY) {}
 | 
						|
      SPI1CMD |= SPIBUSY;
 | 
						|
      repeat -= 21;
 | 
						|
    }
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  }
 | 
						|
 | 
						|
  if (repeat)
 | 
						|
  {
 | 
						|
    repeat = (repeat * 24) - 1;
 | 
						|
    SPI1U1 = (repeat << SPILMOSI);
 | 
						|
    SPI1CMD |= SPIBUSY;
 | 
						|
    while(SPI1CMD & SPIBUSY) {}
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
#else // Now the code for ESP32 and ILI9488
 | 
						|
 | 
						|
void writeBlock(uint16_t color, uint32_t repeat)
 | 
						|
{
 | 
						|
  // Split out the colours
 | 
						|
  uint32_t r = (color & 0xF800)>>8;
 | 
						|
  uint32_t g = (color & 0x07E0)<<5;
 | 
						|
  uint32_t b = (color & 0x001F)<<19;
 | 
						|
  // Concatenate 4 pixels into three 32 bit blocks
 | 
						|
  uint32_t r0 = r<<24 | b | g | r;
 | 
						|
  uint32_t r1 = r0>>8 | g<<16;
 | 
						|
  uint32_t r2 = r1>>8 | b<<8;
 | 
						|
 | 
						|
  if (repeat > 19)
 | 
						|
  {
 | 
						|
    SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, 479, SPI_USR_MOSI_DBITLEN_S);
 | 
						|
 | 
						|
    while(repeat>19)
 | 
						|
    {
 | 
						|
      while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
      WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2);
 | 
						|
      SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
 | 
						|
      repeat -= 20;
 | 
						|
    }
 | 
						|
    while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
  }
 | 
						|
 | 
						|
  if (repeat)
 | 
						|
  {
 | 
						|
    SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_PORT), SPI_USR_MOSI_DBITLEN, (repeat * 24) - 1, SPI_USR_MOSI_DBITLEN_S);
 | 
						|
    WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), r0);
 | 
						|
    WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), r1);
 | 
						|
    WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), r2);
 | 
						|
    WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), r0);
 | 
						|
    WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), r1);
 | 
						|
    WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), r2);
 | 
						|
    if (repeat > 8 )
 | 
						|
    {
 | 
						|
      WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), r2);
 | 
						|
      WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), r0);
 | 
						|
      WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), r1);
 | 
						|
      WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), r2);
 | 
						|
    }
 | 
						|
 | 
						|
    SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
 | 
						|
    while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#else // Low level register based ESP32 code for 16 bit colour SPI TFTs
 | 
						|
 | 
						|
void writeBlock(uint16_t color, uint32_t repeat)
 | 
						|
{
 | 
						|
  uint32_t color32 = COL_32(color, color);
 | 
						|
 | 
						|
  if (repeat > 31) // Revert legacy toggle buffer change
 | 
						|
  {
 | 
						|
    WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511);
 | 
						|
    while(repeat>31)
 | 
						|
    {
 | 
						|
      while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
      WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W2_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W3_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W4_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W5_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W6_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W7_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W8_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W9_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W10_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W11_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W12_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W13_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W14_REG(SPI_PORT), color32);
 | 
						|
      WRITE_PERI_REG(SPI_W15_REG(SPI_PORT), color32);
 | 
						|
      SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
 | 
						|
      repeat -= 32;
 | 
						|
    }
 | 
						|
    while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
  }
 | 
						|
 | 
						|
  if (repeat)
 | 
						|
  {
 | 
						|
    // Revert toggle buffer change
 | 
						|
    WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (repeat << 4) - 1);
 | 
						|
    for (uint32_t i=0; i <= (repeat>>1); i++) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + (i << 2)), color32);
 | 
						|
    SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR);
 | 
						|
    while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
 | 
						|
  }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getSPIinstance
 | 
						|
** Description:             Get the instance of the SPI class (for ESP32 only)
 | 
						|
***************************************************************************************/
 | 
						|
#ifndef ESP32_PARALLEL
 | 
						|
SPIClass& TFT_eSPI::getSPIinstance(void)
 | 
						|
{
 | 
						|
  return spi;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************************
 | 
						|
** Function name:           getSetup
 | 
						|
** Description:             Get the setup details for diagnostic and sketch access
 | 
						|
***************************************************************************************/
 | 
						|
void TFT_eSPI::getSetup(setup_t &tft_settings)
 | 
						|
{
 | 
						|
// tft_settings.version is set in header file
 | 
						|
 | 
						|
#if defined (ESP8266)
 | 
						|
  tft_settings.esp = 8266;
 | 
						|
#elif defined (ESP32)
 | 
						|
  tft_settings.esp = 32;
 | 
						|
#else
 | 
						|
  tft_settings.esp = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (SUPPORT_TRANSACTIONS)
 | 
						|
  tft_settings.trans = true;
 | 
						|
#else
 | 
						|
  tft_settings.trans = false;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (ESP32_PARALLEL)
 | 
						|
  tft_settings.serial = false;
 | 
						|
  tft_settings.tft_spi_freq = 0;
 | 
						|
#else
 | 
						|
  tft_settings.serial = true;
 | 
						|
  tft_settings.tft_spi_freq = SPI_FREQUENCY/100000;
 | 
						|
  #ifdef SPI_READ_FREQUENCY
 | 
						|
    tft_settings.tft_rd_freq = SPI_READ_FREQUENCY/100000;
 | 
						|
  #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(TFT_SPI_OVERLAP)
 | 
						|
  tft_settings.overlap = true;
 | 
						|
#else
 | 
						|
  tft_settings.overlap = false;
 | 
						|
#endif
 | 
						|
 | 
						|
  tft_settings.tft_driver = TFT_DRIVER;
 | 
						|
  tft_settings.tft_width  = _init_width;
 | 
						|
  tft_settings.tft_height = _init_height;
 | 
						|
 | 
						|
#ifdef CGRAM_OFFSET
 | 
						|
  tft_settings.r0_x_offset = colstart;
 | 
						|
  tft_settings.r0_y_offset = rowstart;
 | 
						|
  tft_settings.r1_x_offset = 0;
 | 
						|
  tft_settings.r1_y_offset = 0;
 | 
						|
  tft_settings.r2_x_offset = 0;
 | 
						|
  tft_settings.r2_y_offset = 0;
 | 
						|
  tft_settings.r3_x_offset = 0;
 | 
						|
  tft_settings.r3_y_offset = 0;
 | 
						|
#else
 | 
						|
  tft_settings.r0_x_offset = 0;
 | 
						|
  tft_settings.r0_y_offset = 0;
 | 
						|
  tft_settings.r1_x_offset = 0;
 | 
						|
  tft_settings.r1_y_offset = 0;
 | 
						|
  tft_settings.r2_x_offset = 0;
 | 
						|
  tft_settings.r2_y_offset = 0;
 | 
						|
  tft_settings.r3_x_offset = 0;
 | 
						|
  tft_settings.r3_y_offset = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_MOSI)
 | 
						|
  tft_settings.pin_tft_mosi = TFT_MOSI;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_mosi = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_MISO)
 | 
						|
  tft_settings.pin_tft_miso = TFT_MISO;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_miso = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_SCLK)
 | 
						|
  tft_settings.pin_tft_clk  = TFT_SCLK;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_clk  = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_CS)
 | 
						|
  tft_settings.pin_tft_cs   = TFT_CS;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_cs   = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_DC)
 | 
						|
  tft_settings.pin_tft_dc  = TFT_DC;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_dc  = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_RD)
 | 
						|
  tft_settings.pin_tft_rd  = TFT_RD;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_rd  = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_WR)
 | 
						|
  tft_settings.pin_tft_wr  = TFT_WR;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_wr  = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TFT_RST)
 | 
						|
  tft_settings.pin_tft_rst = TFT_RST;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_rst = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (ESP32_PARALLEL)
 | 
						|
  tft_settings.pin_tft_d0 = TFT_D0;
 | 
						|
  tft_settings.pin_tft_d1 = TFT_D1;
 | 
						|
  tft_settings.pin_tft_d2 = TFT_D2;
 | 
						|
  tft_settings.pin_tft_d3 = TFT_D3;
 | 
						|
  tft_settings.pin_tft_d4 = TFT_D4;
 | 
						|
  tft_settings.pin_tft_d5 = TFT_D5;
 | 
						|
  tft_settings.pin_tft_d6 = TFT_D6;
 | 
						|
  tft_settings.pin_tft_d7 = TFT_D7;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tft_d0 = -1;
 | 
						|
  tft_settings.pin_tft_d1 = -1;
 | 
						|
  tft_settings.pin_tft_d2 = -1;
 | 
						|
  tft_settings.pin_tft_d3 = -1;
 | 
						|
  tft_settings.pin_tft_d4 = -1;
 | 
						|
  tft_settings.pin_tft_d5 = -1;
 | 
						|
  tft_settings.pin_tft_d6 = -1;
 | 
						|
  tft_settings.pin_tft_d7 = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (TOUCH_CS)
 | 
						|
  tft_settings.pin_tch_cs   = TOUCH_CS;
 | 
						|
  tft_settings.tch_spi_freq = SPI_TOUCH_FREQUENCY/100000;
 | 
						|
#else
 | 
						|
  tft_settings.pin_tch_cs   = -1;
 | 
						|
  tft_settings.tch_spi_freq = 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
#ifdef TOUCH_CS
 | 
						|
  #include "Extensions/Touch.cpp"
 | 
						|
  #include "Extensions/Button.cpp"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "Extensions/Sprite.cpp"
 | 
						|
 | 
						|
#ifdef SMOOTH_FONT
 | 
						|
  #include "Extensions/Smooth_font.cpp"
 | 
						|
#endif
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
 |