RadioSonde/libraries/SondeLib/TFT22_ILI9225.cpp
2022-08-24 08:35:44 +02:00

1413 lines
42 KiB
C++
Executable File

// SPDX-License-Identifier: GPL-3.0
// original source: https://github.com/Nkawu/TFT22_ILI9225
#include "TFT22_ILI9225.h"
//#define DEBUG
#ifdef DEBUG
//#define DB_PRINT( x, ... ) { char dbgbuf[60]; sprintf_P( dbgbuf, (const char*) F( x ), __VA_ARGS__ ) ; Serial.print( dbgbuf ); }
#define DB_PRINT( ... ) { char dbgbuf[60]; sprintf( dbgbuf, __VA_ARGS__ ) ; Serial.println( dbgbuf ); }
#else
#define DB_PRINT( ... ) ;
#endif
#ifndef ARDUINO_STM32_FEATHER
#include "pins_arduino.h"
#ifndef RASPI
#include "wiring_private.h"
#endif
#endif
#include <limits.h>
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#endif
// Many (but maybe not all) non-AVR board installs define macros
// for compatibility with existing PROGMEM-reading AVR code.
// Do our own checks and defines here for good measure...
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif
// Pointers are a peculiar case...typically 16-bit on AVR boards,
// 32 bits elsewhere. Try to accommodate both...
#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
#else
#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif
// Control pins
#ifdef USE_FAST_PINIO
#define SPI_DC_HIGH() *dcport |= dcpinmask
#define SPI_DC_LOW() *dcport &= ~dcpinmask
#define SPI_CS_HIGH() *csport |= cspinmask
#define SPI_CS_LOW() *csport &= ~cspinmask
#else
#define SPI_DC_HIGH() digitalWrite(_rs, HIGH)
#define SPI_DC_LOW() digitalWrite(_rs, LOW)
#define SPI_CS_HIGH() digitalWrite(_cs, HIGH)
#define SPI_CS_LOW() digitalWrite(_cs, LOW)
#endif
// Software SPI Macros
#ifdef USE_FAST_PINIO
#define SSPI_MOSI_HIGH() *mosiport |= mosipinmask
#define SSPI_MOSI_LOW() *mosiport &= ~mosipinmask
#define SSPI_SCK_HIGH() *clkport |= clkpinmask
#define SSPI_SCK_LOW() *clkport &= ~clkpinmask
#else
#define SSPI_MOSI_HIGH() digitalWrite(_sdi, HIGH)
#define SSPI_MOSI_LOW() digitalWrite(_sdi, LOW)
#define SSPI_SCK_HIGH() digitalWrite(_clk, HIGH)
#define SSPI_SCK_LOW() digitalWrite(_clk, LOW)
#endif
#define SSPI_BEGIN_TRANSACTION()
#define SSPI_END_TRANSACTION()
#define SSPI_WRITE(v) _spiWrite(v)
#define SSPI_WRITE16(s) SSPI_WRITE((s) >> 8); SSPI_WRITE(s)
#define SSPI_WRITE32(l) SSPI_WRITE((l) >> 24); SSPI_WRITE((l) >> 16); SSPI_WRITE((l) >> 8); SSPI_WRITE(l)
#define SSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ SSPI_WRITE(((uint8_t*)(c))[i+1]); SSPI_WRITE(((uint8_t*)(c))[i]); }
// Hardware SPI Macros
#ifndef ESP32
#ifdef SPI_CHANNEL
extern SPIClass SPI_CHANNEL;
#define SPI_OBJECT SPI_CHANNEL
#else
#define SPI_OBJECT SPI
#endif
#else
#define SPI_OBJECT _spi
#endif
#if defined (__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(SPI_CLOCK_DIV2);
#elif defined (__arm__)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(11);
#elif defined(ESP8266) || defined(ESP32)
#define HSPI_SET_CLOCK() SPI_OBJECT.setFrequency(SPI_DEFAULT_FREQ);
#elif defined(RASPI)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClock(SPI_DEFAULT_FREQ);
#elif defined(ARDUINO_ARCH_STM32F1)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClock(SPI_DEFAULT_FREQ);
#else
#define HSPI_SET_CLOCK()
#endif
#ifdef SPI_HAS_TRANSACTION
#define HSPI_BEGIN_TRANSACTION() SPI_OBJECT.beginTransaction(SPISettings(SPI_DEFAULT_FREQ, MSBFIRST, SPI_MODE0))
#define HSPI_END_TRANSACTION() SPI_OBJECT.endTransaction()
#else
#define HSPI_BEGIN_TRANSACTION() HSPI_SET_CLOCK(); SPI_OBJECT.setBitOrder(MSBFIRST); SPI_OBJECT.setDataMode(SPI_MODE0)
#define HSPI_END_TRANSACTION()
#endif
#ifdef ESP32
#define SPI_HAS_WRITE_PIXELS
#endif
#if defined(ESP8266) || defined(ESP32)
// Optimized SPI (ESP8266 and ESP32)
#define HSPI_READ() SPI_OBJECT.transfer(0)
#define HSPI_WRITE(b) SPI_OBJECT.write(b)
#define HSPI_WRITE16(s) SPI_OBJECT.write16(s)
#define HSPI_WRITE32(l) SPI_OBJECT.write32(l)
#ifdef SPI_HAS_WRITE_PIXELS
#define SPI_MAX_PIXELS_AT_ONCE 32
#define HSPI_WRITE_PIXELS(c,l) SPI_OBJECT.writePixels(c,l)
#else
#define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<((l)/2); i++){ SPI_WRITE16(((uint16_t*)(c))[i]); }
#endif
#elif defined ( __STM32F1__ )
#define HSPI_WRITE(b) SPI_OBJECT.write(b)
#define HSPI_WRITE16(s) SPI_OBJECT.write16(s)
#else
// Standard Byte-by-Byte SPI
#if defined (__AVR__) || defined(TEENSYDUINO)
static inline uint8_t _avr_spi_read(void) __attribute__((always_inline));
static inline uint8_t _avr_spi_read(void) {
uint8_t r = 0;
SPDR = r;
while(!(SPSR & _BV(SPIF)));
r = SPDR;
return r;
}
#define HSPI_WRITE(b) {SPDR = (b); while(!(SPSR & _BV(SPIF)));}
// #define HSPI_READ() _avr_spi_read()
#else
#define HSPI_WRITE(b) SPI_OBJECT.transfer((uint8_t)(b))
// #define HSPI_READ() HSPI_WRITE(0)
#endif
// #define HSPI_WRITE16(s) HSPI_WRITE((s) >> 8); HSPI_WRITE(s)
// #define HSPI_WRITE32(l) HSPI_WRITE((l) >> 24); HSPI_WRITE((l) >> 16); HSPI_WRITE((l) >> 8); HSPI_WRITE(l)
// #define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ HSPI_WRITE(((uint8_t*)(c))[i+1]); HSPI_WRITE(((uint8_t*)(c))[i]); }
#endif
// Final SPI Macros
#if defined (ARDUINO_ARCH_ARC32)
#define SPI_DEFAULT_FREQ 16000000
#elif defined (__AVR__) || defined(TEENSYDUINO)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ESP8266) || defined(ESP32)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(RASPI)
#define SPI_DEFAULT_FREQ 80000000
#elif defined(ARDUINO_ARCH_STM32F1)
#define SPI_DEFAULT_FREQ 18000000
//#define SPI_DEFAULT_FREQ 36000000
#else
#define SPI_DEFAULT_FREQ 24000000
#endif
#define SPI_BEGIN() if(_clk < 0){SPI_OBJECT.begin();}
#define SPI_BEGIN_TRANSACTION() if(_clk < 0){HSPI_BEGIN_TRANSACTION();}
#define SPI_END_TRANSACTION() if(_clk < 0){HSPI_END_TRANSACTION();}
// #define SPI_WRITE16(s) if(_clk < 0){HSPI_WRITE16(s);}else{SSPI_WRITE16(s);}
// #define SPI_WRITE32(l) if(_clk < 0){HSPI_WRITE32(l);}else{SSPI_WRITE32(l);}
// #define SPI_WRITE_PIXELS(c,l) if(_clk < 0){HSPI_WRITE_PIXELS(c,l);}else{SSPI_WRITE_PIXELS(c,l);}
// Constructor when using software SPI. All output pins are configurable.
TFT22_ILI9225::TFT22_ILI9225(int8_t rst, int8_t rs, int8_t cs, int8_t sdi, int8_t clk, int8_t led) {
_rst = rst;
_rs = rs;
_cs = cs;
_sdi = sdi;
_clk = clk;
_led = led;
_brightness = 255; // Set to maximum brightness
hwSPI = false;
writeFunctionLevel = 0;
gfxFont = NULL;
}
// Constructor when using software SPI. All output pins are configurable. Adds backlight brightness 0-255
TFT22_ILI9225::TFT22_ILI9225(int8_t rst, int8_t rs, int8_t cs, int8_t sdi, int8_t clk, int8_t led, uint8_t brightness) {
_rst = rst;
_rs = rs;
_cs = cs;
_sdi = sdi;
_clk = clk;
_led = led;
_brightness = brightness;
hwSPI = false;
writeFunctionLevel = 0;
gfxFont = NULL;
}
// Constructor when using hardware SPI. Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
TFT22_ILI9225::TFT22_ILI9225(int8_t rst, int8_t rs, int8_t cs, int8_t led) {
_rst = rst;
_rs = rs;
_cs = cs;
_sdi = _clk = -1;
_led = led;
_brightness = 255; // Set to maximum brightness
hwSPI = true;
writeFunctionLevel = 0;
gfxFont = NULL;
}
// Constructor when using hardware SPI. Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
// Adds backlight brightness 0-255
TFT22_ILI9225::TFT22_ILI9225(int8_t rst, int8_t rs, int8_t cs, int8_t led, uint8_t brightness) {
_rst = rst;
_rs = rs;
_cs = cs;
_sdi = _clk = -1;
_led = led;
_brightness = brightness;
hwSPI = true;
writeFunctionLevel = 0;
gfxFont = NULL;
}
#ifdef ESP32
void TFT22_ILI9225::begin(SPIClass &spi)
#else
void TFT22_ILI9225::begin()
#endif
{
#ifdef ESP32
_spi = spi;
#endif
// Set up reset pin
if (_rst > 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, LOW);
}
// Set up backlight pin, turn off initially
if (_led > 0) {
pinMode(_led, OUTPUT);
setBacklight(false);
}
// Control pins
pinMode(_rs, OUTPUT);
digitalWrite(_rs, LOW);
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
#ifdef USE_FAST_PINIO
csport = portOutputRegister(digitalPinToPort(_cs));
cspinmask = digitalPinToBitMask(_cs);
dcport = portOutputRegister(digitalPinToPort(_rs));
dcpinmask = digitalPinToBitMask(_rs);
#endif
// Software SPI
if(_clk >= 0){
pinMode(_sdi, OUTPUT);
digitalWrite(_sdi, LOW);
pinMode(_clk, OUTPUT);
digitalWrite(_clk, HIGH);
#ifdef USE_FAST_PINIO
clkport = portOutputRegister(digitalPinToPort(_clk));
clkpinmask = digitalPinToBitMask(_clk);
mosiport = portOutputRegister(digitalPinToPort(_sdi));
mosipinmask = digitalPinToBitMask(_sdi);
SSPI_SCK_LOW();
SSPI_MOSI_LOW();
} else {
clkport = 0;
clkpinmask = 0;
mosiport = 0;
mosipinmask = 0;
#endif
}
// Hardware SPI
if(_clk < 0){
SPI_BEGIN();
} else {
SPI_OBJECT.begin(_clk, -1, _sdi, _cs);
_clk = -1; // force use of hardware SPI
}
// Initialization Code
if (_rst > 0) {
digitalWrite(_rst, HIGH); // Pull the reset pin high to release the ILI9225C from the reset status
delay(1);
digitalWrite(_rst, LOW); // Pull the reset pin low to reset ILI9225
delay(10);
digitalWrite(_rst, HIGH); // Pull the reset pin high to release the ILI9225C from the reset status
delay(50);
}
/* Start Initial Sequence */
/* Set SS bit and direction output from S528 to S1 */
startWrite();
_writeRegister(ILI9225_POWER_CTRL1, 0x0000); // Set SAP,DSTB,STB
_writeRegister(ILI9225_POWER_CTRL2, 0x0000); // Set APON,PON,AON,VCI1EN,VC
_writeRegister(ILI9225_POWER_CTRL3, 0x0000); // Set BT,DC1,DC2,DC3
_writeRegister(ILI9225_POWER_CTRL4, 0x0000); // Set GVDD
_writeRegister(ILI9225_POWER_CTRL5, 0x0000); // Set VCOMH/VCOML voltage
endWrite();
delay(40);
// Power-on sequence
startWrite();
_writeRegister(ILI9225_POWER_CTRL2, 0x0018); // Set APON,PON,AON,VCI1EN,VC
_writeRegister(ILI9225_POWER_CTRL3, 0x6121); // Set BT,DC1,DC2,DC3
_writeRegister(ILI9225_POWER_CTRL4, 0x006F); // Set GVDD /*007F 0088 */
_writeRegister(ILI9225_POWER_CTRL5, 0x495F); // Set VCOMH/VCOML voltage
_writeRegister(ILI9225_POWER_CTRL1, 0x0800); // Set SAP,DSTB,STB
endWrite();
delay(10);
startWrite();
_writeRegister(ILI9225_POWER_CTRL2, 0x103B); // Set APON,PON,AON,VCI1EN,VC
endWrite();
delay(50);
startWrite();
_writeRegister(ILI9225_DRIVER_OUTPUT_CTRL, 0x011C); // set the display line number and display direction
_writeRegister(ILI9225_LCD_AC_DRIVING_CTRL, 0x0100); // set 1 line inversion
_writeRegister(ILI9225_ENTRY_MODE, 0x1038); // set GRAM write direction and BGR=1.
_writeRegister(ILI9225_DISP_CTRL1, 0x0000); // Display off
_writeRegister(ILI9225_BLANK_PERIOD_CTRL1, 0x0808); // set the back porch and front porch
_writeRegister(ILI9225_FRAME_CYCLE_CTRL, 0x1100); // set the clocks number per line
_writeRegister(ILI9225_INTERFACE_CTRL, 0x0000); // CPU interface
_writeRegister(ILI9225_OSC_CTRL, 0x0D01); // Set Osc /*0e01*/
_writeRegister(ILI9225_VCI_RECYCLING, 0x0020); // Set VCI recycling
_writeRegister(ILI9225_RAM_ADDR_SET1, 0x0000); // RAM Address
_writeRegister(ILI9225_RAM_ADDR_SET2, 0x0000); // RAM Address
/* Set GRAM area */
_writeRegister(ILI9225_GATE_SCAN_CTRL, 0x0000);
_writeRegister(ILI9225_VERTICAL_SCROLL_CTRL1, 0x00DB);
_writeRegister(ILI9225_VERTICAL_SCROLL_CTRL2, 0x0000);
_writeRegister(ILI9225_VERTICAL_SCROLL_CTRL3, 0x0000);
_writeRegister(ILI9225_PARTIAL_DRIVING_POS1, 0x00DB);
_writeRegister(ILI9225_PARTIAL_DRIVING_POS2, 0x0000);
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, 0x00AF);
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, 0x0000);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, 0x00DB);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, 0x0000);
/* Set GAMMA curve */
_writeRegister(ILI9225_GAMMA_CTRL1, 0x0000);
_writeRegister(ILI9225_GAMMA_CTRL2, 0x0808);
_writeRegister(ILI9225_GAMMA_CTRL3, 0x080A);
_writeRegister(ILI9225_GAMMA_CTRL4, 0x000A);
_writeRegister(ILI9225_GAMMA_CTRL5, 0x0A08);
_writeRegister(ILI9225_GAMMA_CTRL6, 0x0808);
_writeRegister(ILI9225_GAMMA_CTRL7, 0x0000);
_writeRegister(ILI9225_GAMMA_CTRL8, 0x0A00);
_writeRegister(ILI9225_GAMMA_CTRL9, 0x0710);
_writeRegister(ILI9225_GAMMA_CTRL10, 0x0710);
_writeRegister(ILI9225_DISP_CTRL1, 0x0012);
endWrite();
delay(50);
startWrite();
_writeRegister(ILI9225_DISP_CTRL1, 0x1017);
endWrite();
// Turn on backlight
setBacklight(true);
setOrientation(0);
// Initialize variables
setBackgroundColor( COLOR_BLACK );
clear();
}
void TFT22_ILI9225::_spiWrite(uint8_t b) {
if(_clk < 0){
HSPI_WRITE(b);
return;
}
// Fast SPI bitbang swiped from LPD8806 library
for(uint8_t bit = 0x80; bit; bit >>= 1){
if((b) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_HIGH();
SSPI_SCK_LOW();
}
}
void TFT22_ILI9225::_spiWrite16(uint16_t s)
{
// Attempt to use HSPI_WRITE16 if available
#ifdef HSPI_WRITE16
if(_clk < 0){
HSPI_WRITE16(s);
return;
}
#endif
// Fallback to SSPI_WRITE16 if HSPI_WRITE16 not available
SSPI_WRITE16(s);
}
void TFT22_ILI9225::_spiWriteCommand(uint8_t c) {
SPI_DC_LOW();
SPI_CS_LOW();
_spiWrite(c);
SPI_CS_HIGH();
}
void TFT22_ILI9225::_spiWriteData(uint8_t c) {
SPI_DC_HIGH();
SPI_CS_LOW();
_spiWrite(c);
SPI_CS_HIGH();
}
void TFT22_ILI9225::_orientCoordinates(uint16_t &x1, uint16_t &y1) {
switch (_orientation) {
case 0: // ok
break;
case 1: // ok
y1 = _maxY - y1 - 1;
_swap(x1, y1);
break;
case 2: // ok
x1 = _maxX - x1 - 1;
y1 = _maxY - y1 - 1;
break;
case 3: // ok
x1 = _maxX - x1 - 1;
_swap(x1, y1);
break;
}
}
void TFT22_ILI9225::_setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
_setWindow( x0, y0, x1, y1, TopDown_L2R ); // default for drawing characters
}
void TFT22_ILI9225::_setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, autoIncMode_t mode) {
DB_PRINT( "setWindows( x0=%d, y0=%d, x1=%d, y1=%d, mode=%d", x0,y0,x1,y1,mode );
// clip to TFT-Dimensions
x0 = min( x0, (uint16_t) (_maxX-1) );
x1 = min( x1, (uint16_t) (_maxX-1) );
y0 = min( y0, (uint16_t) (_maxY-1) );
y1 = min( y1, (uint16_t) (_maxY-1) );
_orientCoordinates(x0, y0);
_orientCoordinates(x1, y1);
if (x1<x0) _swap(x0, x1);
if (y1<y0) _swap(y0, y1);
startWrite();
// autoincrement mode
if ( _orientation > 0 ) mode = modeTab[_orientation-1][mode];
_writeRegister(ILI9225_ENTRY_MODE, 0x1000 | ( mode<<3) );
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1,x1);
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2,x0);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1,y1);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2,y0);
DB_PRINT( "gedreht: x0=%d, y0=%d, x1=%d, y1=%d, mode=%d", x0,y0,x1,y1,mode );
// starting position within window and increment/decrement direction
switch ( mode>>1 ) {
case 0:
_writeRegister(ILI9225_RAM_ADDR_SET1,x1);
_writeRegister(ILI9225_RAM_ADDR_SET2,y1);
break;
case 1:
_writeRegister(ILI9225_RAM_ADDR_SET1,x0);
_writeRegister(ILI9225_RAM_ADDR_SET2,y1);
break;
case 2:
_writeRegister(ILI9225_RAM_ADDR_SET1,x1);
_writeRegister(ILI9225_RAM_ADDR_SET2,y0);
break;
case 3:
_writeRegister(ILI9225_RAM_ADDR_SET1,x0);
_writeRegister(ILI9225_RAM_ADDR_SET2,y0);
break;
}
_writeCommand16( ILI9225_GRAM_DATA_REG );
//_writeRegister(ILI9225_RAM_ADDR_SET1,x0);
//_writeRegister(ILI9225_RAM_ADDR_SET2,y0);
//_writeCommand(0x00, 0x22);
endWrite();
}
void TFT22_ILI9225::_resetWindow() {
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, 0x00AF);
_writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, 0x0000);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, 0x00DB);
_writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, 0x0000);
}
void TFT22_ILI9225::clear() {
uint8_t old = _orientation;
setOrientation(0);
fillRectangle(0, 0, _maxX - 1, _maxY - 1, COLOR_BLACK);
setOrientation(old);
delay(10);
}
void TFT22_ILI9225::invert(boolean flag) {
startWrite();
_writeCommand16(flag ? ILI9225C_INVON : ILI9225C_INVOFF);
//_writeCommand(0x00, flag ? ILI9225C_INVON : ILI9225C_INVOFF);
endWrite();
}
void TFT22_ILI9225::setBacklight(boolean flag) {
blState = flag;
#ifndef ESP32
if (_led) analogWrite(_led, blState ? _brightness : 0);
#endif
}
void TFT22_ILI9225::setBacklightBrightness(uint8_t brightness) {
_brightness = brightness;
setBacklight(blState);
}
void TFT22_ILI9225::setDisplay(boolean flag) {
if (flag) {
startWrite();
_writeRegister(0x00ff, 0x0000);
_writeRegister(ILI9225_POWER_CTRL1, 0x0000);
endWrite();
delay(50);
startWrite();
_writeRegister(ILI9225_DISP_CTRL1, 0x1017);
endWrite();
delay(200);
} else {
startWrite();
_writeRegister(0x00ff, 0x0000);
_writeRegister(ILI9225_DISP_CTRL1, 0x0000);
endWrite();
delay(50);
startWrite();
_writeRegister(ILI9225_POWER_CTRL1, 0x0003);
endWrite();
delay(200);
}
}
void TFT22_ILI9225::setOrientation(uint8_t orientation) {
_orientation = orientation % 4;
switch (_orientation) {
case 0:
_maxX = ILI9225_LCD_WIDTH;
_maxY = ILI9225_LCD_HEIGHT;
break;
case 1:
_maxX = ILI9225_LCD_HEIGHT;
_maxY = ILI9225_LCD_WIDTH;
break;
case 2:
_maxX = ILI9225_LCD_WIDTH;
_maxY = ILI9225_LCD_HEIGHT;
break;
case 3:
_maxX = ILI9225_LCD_HEIGHT;
_maxY = ILI9225_LCD_WIDTH;
break;
}
}
uint8_t TFT22_ILI9225::getOrientation() {
return _orientation;
}
void TFT22_ILI9225::drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
startWrite();
drawLine(x1, y1, x1, y2, color);
drawLine(x1, y1, x2, y1, color);
drawLine(x1, y2, x2, y2, color);
drawLine(x2, y1, x2, y2, color);
endWrite();
}
void TFT22_ILI9225::fillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
_setWindow(x1, y1, x2, y2);
startWrite();
for(uint16_t t=(y2 - y1 + 1) * (x2 - x1 + 1); t > 0; t--)
_writeData16(color);
endWrite();
_resetWindow();
}
void TFT22_ILI9225::drawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
startWrite();
drawPixel(x0, y0 + r, color);
drawPixel(x0, y0- r, color);
drawPixel(x0 + r, y0, color);
drawPixel(x0 - r, y0, color);
while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
drawPixel(x0 + x, y0 + y, color);
drawPixel(x0 - x, y0 + y, color);
drawPixel(x0 + x, y0 - y, color);
drawPixel(x0 - x, y0 - y, color);
drawPixel(x0 + y, y0 + x, color);
drawPixel(x0 - y, y0 + x, color);
drawPixel(x0 + y, y0 - x, color);
drawPixel(x0 - y, y0 - x, color);
}
endWrite();
}
void TFT22_ILI9225::fillCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color) {
int16_t f = 1 - radius;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * radius;
int16_t x = 0;
int16_t y = radius;
startWrite();
while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
drawLine(x0 + x, y0 + y, x0 - x, y0 + y, color); // bottom
drawLine(x0 + x, y0 - y, x0 - x, y0 - y, color); // top
drawLine(x0 + y, y0 - x, x0 + y, y0 + x, color); // right
drawLine(x0 - y, y0 - x, x0 - y, y0 + x, color); // left
}
endWrite();
fillRectangle(x0-x, y0-y, x0+x, y0+y, color);
}
void TFT22_ILI9225::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
// Classic Bresenham algorithm
int16_t steep = abs((int16_t)(y2 - y1)) > abs((int16_t)(x2 - x1));
int16_t dx, dy;
if (steep) {
_swap(x1, y1);
_swap(x2, y2);
}
if (x1 > x2) {
_swap(x1, x2);
_swap(y1, y2);
}
dx = x2 - x1;
dy = abs((int16_t)(y2 - y1));
int16_t err = dx / 2;
int16_t ystep;
if (y1 < y2) ystep = 1;
else ystep = -1;
startWrite();
for (; x1<=x2; x1++) {
if (steep) drawPixel(y1, x1, color);
else drawPixel(x1, y1, color);
err -= dy;
if (err < 0) {
y1 += ystep;
err += dx;
}
}
endWrite();
}
void TFT22_ILI9225::drawPixel(uint16_t x1, uint16_t y1, uint16_t color) {
if((x1 >= _maxX) || (y1 >= _maxY)) return;
/*
_setWindow(x1, y1, x1+1, y1+1);
_orientCoordinates(x1, y1);
startWrite();
//_writeData(color >> 8, color);
_writeData16(color);
endWrite();
*/
_orientCoordinates(x1, y1);
startWrite();
_writeRegister(ILI9225_RAM_ADDR_SET1,x1);
_writeRegister(ILI9225_RAM_ADDR_SET2,y1);
_writeRegister(ILI9225_GRAM_DATA_REG,color);
endWrite();
}
uint16_t TFT22_ILI9225::maxX() {
return _maxX;
}
uint16_t TFT22_ILI9225::maxY() {
return _maxY;
}
uint16_t TFT22_ILI9225::setColor(uint8_t red8, uint8_t green8, uint8_t blue8) {
// rgb16 = red5 green6 blue5
return (red8 >> 3) << 11 | (green8 >> 2) << 5 | (blue8 >> 3);
}
void TFT22_ILI9225::splitColor(uint16_t rgb, uint8_t &red, uint8_t &green, uint8_t &blue) {
// rgb16 = red5 green6 blue5
red = (rgb & 0b1111100000000000) >> 11 << 3;
green = (rgb & 0b0000011111100000) >> 5 << 2;
blue = (rgb & 0b0000000000011111) << 3;
}
void TFT22_ILI9225::_swap(uint16_t &a, uint16_t &b) {
uint16_t w = a;
a = b;
b = w;
}
// Utilities
/*void TFT22_ILI9225::_writeCommand16(uint16_t command) {
# ifdef HSPI_WRITE16
SPI_DC_LOW();
SPI_CS_LOW();
HSPI_WRITE16(command);
SPI_CS_HIGH();
#else
_spiWriteCommand(command >> 8);
_spiWriteCommand(0x00ff & command);
#endif
}
void TFT22_ILI9225::_writeData16(uint16_t data) {
# ifdef HSPI_WRITE16
SPI_DC_HIGH();
SPI_CS_LOW();
HSPI_WRITE16(data);
SPI_CS_HIGH();
#else
_spiWriteData(data >> 8);
_spiWriteData(0x00ff & data);
#endif
}
*/
void TFT22_ILI9225::_writeCommand16(uint16_t command) {
SPI_DC_LOW();
SPI_CS_LOW();
if ( _clk < 0 ) {
# ifdef HSPI_WRITE16
HSPI_WRITE16(command);
#else
HSPI_WRITE(command >> 8);
HSPI_WRITE(0x00ff & command);
#endif
} else {
// Fast SPI bitbang swiped from LPD8806 library
for(uint16_t bit = 0x8000; bit; bit >>= 1){
if((command) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_HIGH();
SSPI_SCK_LOW();
}
}
SPI_CS_HIGH();
}
void TFT22_ILI9225::_writeData16(uint16_t data) {
SPI_DC_HIGH();
SPI_CS_LOW();
if ( _clk < 0 ) {
# ifdef HSPI_WRITE16
HSPI_WRITE16(data);
#else
HSPI_WRITE(data >> 8);
HSPI_WRITE(0x00ff & data);
#endif
} else {
// Fast SPI bitbang swiped from LPD8806 library
for(uint16_t bit = 0x8000; bit; bit >>= 1){
if((data) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_HIGH();
SSPI_SCK_LOW();
}
}
SPI_CS_HIGH();
}
/*void TFT22_ILI9225::_writeData(uint8_t HI, uint8_t LO) {
_spiWriteData(HI);
_spiWriteData(LO);
}
void TFT22_ILI9225::_writeCommand(uint8_t HI, uint8_t LO) {
_spiWriteCommand(HI);
_spiWriteCommand(LO);
}*/
void TFT22_ILI9225::_writeRegister(uint16_t reg, uint16_t data) {
_writeCommand16(reg);
_writeData16(data);
}
void TFT22_ILI9225::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {
startWrite();
drawLine(x1, y1, x2, y2, color);
drawLine(x2, y2, x3, y3, color);
drawLine(x3, y3, x1, y1, color);
endWrite();
}
void TFT22_ILI9225::fillTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {
uint16_t a, b, y, last;
// Sort coordinates by Y order (y3 >= y2 >= y1)
if (y1 > y2) {
_swap(y1, y2); _swap(x1, x2);
}
if (y2 > y3) {
_swap(y3, y2); _swap(x3, x2);
}
if (y1 > y2) {
_swap(y1, y2); _swap(x1, x2);
}
startWrite();
if (y1 == y3) { // Handle awkward all-on-same-line case as its own thing
a = b = x1;
if (x2 < a) a = x2;
else if (x2 > b) b = x2;
if (x3 < a) a = x3;
else if (x3 > b) b = x3;
drawLine(a, y1, b, y1, color);
return;
}
int16_t dx11 = x2 - x1,
dy11 = y2 - y1,
dx12 = x3 - x1,
dy12 = y3 - y1,
dx22 = x3 - x2,
dy22 = y3 - y2;
int32_t sa = 0,
sb = 0;
// For upper part of triangle, find scanline crossings for segments
// 0-1 and 0-2. If y2=y3 (flat-bottomed triangle), the scanline y2
// is included here (and second loop will be skipped, avoiding a /0
// error there), otherwise scanline y2 is skipped here and handled
// in the second loop...which also avoids a /0 error here if y1=y2
// (flat-topped triangle).
if (y2 == y3) last = y2; // Include y2 scanline
else last = y2 - 1; // Skip it
for (y = y1; y <= last; y++) {
a = x1 + sa / dy11;
b = x1 + sb / dy12;
sa += dx11;
sb += dx12;
/* longhand:
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
*/
if (a > b) _swap(a,b);
drawLine(a, y, b, y, color);
}
// For lower part of triangle, find scanline crossings for segments
// 0-2 and 1-2. This loop is skipped if y2=y3.
sa = dx22 * (y - y2);
sb = dx12 * (y - y1);
for (; y<=y3; y++) {
a = x2 + sa / dy22;
b = x1 + sb / dy12;
sa += dx22;
sb += dx12;
/* longhand:
a = x2 + (x3 - x2) * (y - y2) / (y3 - y2);
b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
*/
if (a > b) _swap(a,b);
drawLine(a, y, b, y, color);
}
endWrite();
}
void TFT22_ILI9225::setBackgroundColor(uint16_t color) {
_bgColor = color;
}
void TFT22_ILI9225::setFont(uint8_t* font, bool monoSp) {
cfont.font = font;
cfont.width = readFontByte(0);
cfont.height = readFontByte(1);
cfont.offset = readFontByte(2);
cfont.numchars = readFontByte(3);
cfont.nbrows = cfont.height / 8;
cfont.monoSp = monoSp;
if (cfont.height % 8) cfont.nbrows++; // Set number of bytes used by height of font in multiples of 8
}
_currentFont TFT22_ILI9225::getFont() {
return cfont;
}
uint16_t TFT22_ILI9225::drawText(uint16_t x, uint16_t y, STRING s, uint16_t color) {
uint16_t currx = x;
// Print every character in string
#ifdef USE_STRING_CLASS
for (uint8_t k = 0; k < s.length(); k++) {
currx += drawChar(currx, y, s.charAt(k), color) + 1;
}
#else
for (uint8_t k = 0; k < strlen(s); k++) {
currx += drawChar(currx, y, s[k], color) + 1;
}
#endif
return currx;
}
uint16_t TFT22_ILI9225::getTextWidth( STRING s ) {
uint16_t width = 0;
// Count every character in string ( +1 for spacing )
#ifdef USE_STRING_CLASS
for (uint8_t k = 0; k < s.length(); k++) {
width += getCharWidth(s.charAt(k) ) + 1;
}
#else
for (uint8_t k = 0; k < strlen(s); k++) {
width += getCharWidth(s[k]) + 1;
}
#endif
return width;
}
uint16_t TFT22_ILI9225::drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color) {
uint8_t charData, charWidth;
uint8_t h, i, j;
uint16_t charOffset;
bool fastMode;
charOffset = (cfont.width * cfont.nbrows) + 1; // bytes used by each character
charOffset = (charOffset * (ch - cfont.offset)) + FONT_HEADER_SIZE; // char offset (add 4 for font header)
if ( cfont.monoSp ) charWidth = cfont.width; // monospaced: get char width from font
else charWidth = readFontByte(charOffset); // get chracter width from 1st byte
charOffset++; // increment pointer to first character data byte
startWrite();
// use autoincrement/decrement feature, if character fits completely on screen
fastMode = ( (x+charWidth+1) < _maxX && (y+cfont.height-1) < _maxY ) ;
if ( fastMode )_setWindow( x,y,x+charWidth+1, y+cfont.height-1 ); // set character Window
for (i = 0; i <= charWidth; i++) { // each font "column" (+1 blank column for spacing)
h = 0; // keep track of char height
for (j = 0; j < cfont.nbrows; j++) { // each column byte
if (i == charWidth) charData = (uint8_t)0x0; // Insert blank column
else charData = readFontByte(charOffset);
charOffset++;
// Process every row in font character
for (uint8_t k = 0; k < 8; k++) {
if (h >= cfont.height ) break; // No need to process excess bits
if (fastMode ) _writeData16( bitRead(charData, k)?color:_bgColor );
else drawPixel( x + i, y + (j * 8) + k, bitRead(charData, k)?color:_bgColor );
h++;
}
}
}
endWrite();
_resetWindow();
return charWidth;
}
uint16_t TFT22_ILI9225::getCharWidth(uint16_t ch) {
uint16_t charOffset;
charOffset = (cfont.width * cfont.nbrows) + 1; // bytes used by each character
charOffset = (charOffset * (ch - cfont.offset)) + FONT_HEADER_SIZE; // char offset (add 4 for font header)
return readFontByte(charOffset); // get font width from 1st byte
}
// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
// provided bitmap buffer (must be PROGMEM memory) using the specified
// foreground color (unset bits are transparent).
void TFT22_ILI9225::drawBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
_drawBitmap( x, y, bitmap, w, h, color, 0, true, true, false );
}
// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
// provided bitmap buffer (must be PROGMEM memory) using the specified
// foreground (for set bits) and background (for clear bits) colors.
void TFT22_ILI9225::drawBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
_drawBitmap( x, y, bitmap, w, h, color, bg, false, true, false );
}
// drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps.
void TFT22_ILI9225::drawBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
_drawBitmap( x, y, bitmap, w, h, color, 0, true, false, false );
}
// drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps.
void TFT22_ILI9225::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
_drawBitmap( x, y, bitmap, w, h, color, bg, false, false, false );
}
//Draw XBitMap Files (*.xbm), exported from GIMP,
//Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
//C Array can be directly used with this function
void TFT22_ILI9225::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
_drawBitmap( x, y, bitmap, w, h, color, 0, true, true, true );
}
void TFT22_ILI9225::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
_drawBitmap( x, y, bitmap, w, h, color, bg, false, true, true );
}
// internal function for drawing bitmaps with/without transparent bg, or from ram or progmem
void TFT22_ILI9225::_drawBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg, bool transparent, bool progmem,bool Xbit) {
bool noAutoInc = false; // Flag set when transparent pixel was 'written'
int16_t i, j, byteWidth = (w + 7) / 8;
int16_t wx0,wy0,wx1,wy1,wh;//,ww; // Window-position and size
uint8_t byte=0, maskBit;
maskBit = Xbit? 0x01:0x80;
// adjust window hight/width to displaydimensions
DB_PRINT( "DrawBitmap.. maxX=%d, maxY=%d", _maxX,_maxY );
wx0 = x<0?0:x;
wy0 = y<0?0:y;
wx1 = (x+w>_maxX?_maxX:x+w)-1;
wy1 = (y+h>_maxY?_maxY:y+h)-1;
wh = wy1-wy0 +1;
//ww = wx1-wx0 +1;
_setWindow( wx0,wy0,wx1,wy1,L2R_TopDown);
startWrite();
for (j = y>=0?0:-y; j < (y>=0?0:-y)+wh; j++) {
for (i = 0; i < w; i++ ) {
if (i & 7) { if ( Xbit ) byte >>=1; else byte <<= 1; }
else { if ( progmem ) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
else byte = bitmap[j * byteWidth + i / 8];
}
if ( x+i >= wx0 && x+i <= wx1 ) {
// write only if pixel is within window
if (byte & maskBit) {
if (noAutoInc) {
//there was a transparent area, set pixelkoordinates again
drawPixel(x + i, y + j, color);
noAutoInc = false;
}
else {
_writeData16(color);
}
}
else {
if (transparent) noAutoInc = true; // no autoincrement in transparent area!
else _writeData16( bg);
}
}
}
}
endWrite();
}
//Draw XBitMap Files (*.xbm), exported from GIMP,
//Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
//C Array can be directly used with this function
/*void TFT22_ILI9225::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
startWrite();
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++ ) {
if (i & 7) byte >>= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if (byte & 0x01) drawPixel(x + i, y + j, color);
}
}
endWrite();
}
*/
//High speed color bitmap
void TFT22_ILI9225::drawBitmap(uint16_t x1, uint16_t y1,
const uint16_t** bitmap, int16_t w, int16_t h) {
_setWindow(x1, y1, x1+w-1, y1+h-1,L2R_TopDown);
startWrite();
SPI_DC_HIGH();
SPI_CS_LOW();
for (uint16_t y = 0; y < h; y++) {
#ifdef HSPI_WRITE_PIXELS
if (_clk < 0) {
HSPI_WRITE_PIXELS(bitmap[y], w * sizeof(uint16_t));
continue;
}
#endif
for (uint16_t x = 0; x < w; x++) {
_spiWrite16(bitmap[y][x]);
}
}
SPI_CS_HIGH();
endWrite();
}
//High speed color bitmap
void TFT22_ILI9225::drawBitmap(uint16_t x1, uint16_t y1,
uint16_t** bitmap, int16_t w, int16_t h) {
_setWindow(x1, y1, x1+w-1, y1+h-1,L2R_TopDown);
startWrite();
SPI_DC_HIGH();
SPI_CS_LOW();
for (uint16_t y = 0; y < h; y++) {
#ifdef HSPI_WRITE_PIXELS
if (_clk < 0) {
HSPI_WRITE_PIXELS(bitmap[y], w * sizeof(uint16_t));
continue;
}
#endif
for (uint16_t x = 0; x < w; x++) {
_spiWrite16(bitmap[y][x]);
}
}
SPI_CS_HIGH();
endWrite();
}
//1-D array High speed color bitmap
void TFT22_ILI9225::drawBitmap(uint16_t x1, uint16_t y1,
const uint16_t* bitmap, int16_t w, int16_t h) {
_setWindow(x1, y1, x1+w-1, y1+h-1,L2R_TopDown);
startWrite();
SPI_DC_HIGH();
SPI_CS_LOW();
#ifdef HSPI_WRITE_PIXELS
if (_clk < 0) {
HSPI_WRITE_PIXELS(bitmap, w * h * sizeof(uint16_t));
} else
#endif
for (uint16_t i = 0; i < h * w; ++i) {
_spiWrite16(bitmap[i]);
}
SPI_CS_HIGH();
endWrite();
}
//1-D array High speed color bitmap
void TFT22_ILI9225::drawBitmap(uint16_t x1, uint16_t y1,
uint16_t* bitmap, int16_t w, int16_t h) {
_setWindow(x1, y1, x1+w-1, y1+h-1,L2R_TopDown);
startWrite();
SPI_DC_HIGH();
SPI_CS_LOW();
#ifdef HSPI_WRITE_PIXELS
if (_clk < 0) {
HSPI_WRITE_PIXELS(bitmap, w * h * sizeof(uint16_t));
} else
#endif
for (uint16_t i = 0; i < h * w; ++i) {
_spiWrite16(bitmap[i]);
}
SPI_CS_HIGH();
endWrite();
}
void TFT22_ILI9225::startWrite(void){
if (writeFunctionLevel++ == 0) {
SPI_BEGIN_TRANSACTION();
SPI_CS_LOW();
}
}
void TFT22_ILI9225::endWrite(void){
if (--writeFunctionLevel == 0) {
SPI_CS_HIGH();
SPI_END_TRANSACTION();
}
}
// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
void TFT22_ILI9225::setGFXFont(const GFXfont *f) {
gfxFont = (GFXfont *)f;
}
// Draw a string
void TFT22_ILI9225::drawGFXText(int16_t x, int16_t y, STRING s, uint16_t color) {
int16_t currx = x;
if(gfxFont) {
// Print every character in string
#ifdef USE_STRING_CLASS
for (uint8_t k = 0; k < s.length(); k++) {
currx += drawGFXChar(currx, y, s.charAt(k), color) + 1;
}
#else
for (uint8_t k = 0; k < strlen(s); k++) {
currx += drawGFXChar(currx, y, s[k], color) + 1;
}
#endif
}
}
// Draw a character
uint16_t TFT22_ILI9225::drawGFXChar(int16_t x, int16_t y, unsigned char c, uint16_t color) {
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
uint16_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;
// Add character clipping here one day
startWrite();
for(yy=0; yy<h; yy++) {
for(xx=0; xx<w; xx++) {
if(!(bit++ & 7)) {
bits = pgm_read_byte(&bitmap[bo++]);
}
if(bits & 0x80) {
drawPixel(x+xo+xx, y+yo+yy, color);
}
bits <<= 1;
}
}
endWrite();
return (uint16_t)xa;
}
// Write a character to a bitmap
uint16_t TFT22_ILI9225::drawGFXcharBM(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t *bm, int bmwd) {
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
uint16_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;
for(yy=0; yy<h; yy++) {
if(y+yo+yy>=bmwd) continue;
if(y+yo+yy<0) continue; // yo can be negative
for(xx=0; xx<w; xx++) {
if(x+xo+xx>=bmwd) continue;
if(!(bit++ & 7)) {
bits = pgm_read_byte(&bitmap[bo++]);
}
if(bits & 0x80) {
bm[x+xo+xx + bmwd*(y+yo+yy)] = color;
}
bits <<= 1;
}
}
return (uint16_t)xa;
}
void TFT22_ILI9225::getGFXCharExtent(uint8_t c, int16_t *gw, int16_t *gh, int16_t *xa) {
uint8_t first = pgm_read_byte(&gfxFont->first),
last = pgm_read_byte(&gfxFont->last);
// Char present in this font?
if((c >= first) && (c <= last)) {
GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c - first]);
*gw = pgm_read_byte(&glyph->width);
*gh = 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);
}
}
void TFT22_ILI9225::getGFXTextExtent(STRING str, int16_t x, int16_t y, int16_t *w, int16_t *h) {
*w = *h = 0;
#ifdef USE_STRING_CLASS
for (uint8_t k = 0; k < str.length(); k++) {
uint8_t c = str.charAt(k);
#else
for (uint8_t k = 0; k < strlen(str); k++) {
uint8_t c = str[k];
#endif
int16_t gw, gh, xa;
getGFXCharExtent(c, &gw, &gh, &xa);
if(gh > *h) {
*h = gh;
}
*w += xa + 1;
}
if(*w>0) (*w)--;
}