#include "UTFT.h"
#include <util/delay.h>
#include <stdlib.h>
static void myseek(FILE*f,int dist) {
if (f->flags&__SSTR) { // mine! Do fast access
f->len+=(int)dist;
}//else fseek(f,dist,SEEK_CUR);
}
static word mygetw(FILE*f) {
word w;
if (f->flags&__SSTR) { // mine! Do fast access
word*p=(word*)f->len;
if (f->flags&__SPGM) w=pgm_read_word(p);
else w=*p;
++p;
f->len=(int)p;
}else{ // not mine! Use function pointer
w=fgetc(f)&0xFF;
w|=fgetc(f)<<8;
}
return w;
}
/********************
* Basic LCD access *
********************/
void UTFT::writeB(byte b) {
#if DISP_TRANSFER==16
writeW(b); // always 16-bit
#elif DISP_TRANSFER==1
for (byte m=0x80; m; m>>=1) {
if (VL & 0x80) DISP_SDA(1); else DISP_SDA(0);
DISP_SCL(0);
DISP_SCL(1);
}
#else
DISP_OUT(b);
DISP_WR(0);
DISP_WR(1);
#endif
}
void UTFT::writeW(word w) {
#if DISP_TRANSFER<16
writeB(w>>8);
writeB(w);
#elif defined(DISP_ALE)
DISP_OUT(w>>8);
DISP_ALE(1);
DISP_ALE(0);
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
#else
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
#endif
}
void UTFT::fillW(word w, int r1, int r2) {
#ifdef __MPS430__ // 16-bit optimized loops
if (r1<r2) SWAP(r1,r2); // ensure more inner loop executions
if (!r2) return;
#define DO do {int r=r1; do // two nested loops
#define WHILE while (--r);} while(--r2)
#else // 8-bit optimized loops
unsigned long rep=(unsigned long)(word)r1*(word)r2;
if (!rep) return;
byte rep0=byte(rep);
byte rep1=byte(rep>>8);
byte rep2=byte(rep>>16); // 24 bits are sufficient here
if (rep0) rep1++;
if (rep1) rep2++;
#define DO do do do // three nested loops
#define WHILE while (--rep0); while(--rep1); while(--rep2)
#endif
#if DISP_TRANSFER==16
DISP_OUT(w);
DO{
DISP_WR(0);
DISP_WR(1);
}WHILE;
#elif DISP_TRANSFER==8
if (w>>8==(w&0xFF)) {
DISP_OUT(w);
DO{
DISP_WR(0);
DISP_WR(1);
DISP_WR(0);
DISP_WR(1);
}WHILE;
}else{
DO{
DISP_OUT(w>>8);
DISP_WR(0);
DISP_WR(1);
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
}WHILE;
}
#else
DO setPixel(w); WHILE;
#endif
#undef DO
#undef WHILE
}
void UTFT::writeCW(byte b,word w) {
writeC(b);
#ifdef DISP_CMD16
writeW(w);
#else
writeB(w>>8);
writeB(w);
#endif
}
void UTFT::writeCWW(byte b,word x,word y) {
writeC(b);
#ifdef DISP_CMD16
writeW(x);
writeW(y);
#else
writeB(x>>8);
writeB(x);
writeB(y>>8);
writeB(y);
#endif
}
void UTFT::writeCBList(const byte*z) {
for(byte len;len=pgm_read_byte(z++);) {
UTFT::writeC(pgm_read_byte(z++));
while (--len) UTFT::writeB(pgm_read_byte(z++));
};
}
/*************************************
* Hardware-dependent initialization *
*************************************/
void UTFT::InitLCD(byte orientation) {
orient=orientation;
flags=0;
align=0;
clrClip();
clrOrg();
//clrScale();
DISP_INIT();
#ifdef DISP_DDR
DISP_DDR(1); // data port is output port
#endif
#ifdef DISP_RST
DISP_RST(1);
_delay_ms(5);
DISP_RST(0);
_delay_ms(15);
DISP_RST(1);
_delay_ms(15);
#endif
DISP_CS(0);
#ifdef DISP_ILI9325D
static const struct {byte a;word b;} pairs[] PROGMEM={
{0xE5,0x78F0}, // set SRAM internal timing
{0x01,0}, // set Driver Output Control, bit 8 reflects X counting
{0x02,0x0200}, // set 1 line inversion
{0x03,0x1030},
{0x04,0}, // Resize register
// {0x08,0x0207}, // set the back porch and front porch
// {0x09,0}, // set non-display area refresh cycle ISC[3:0]
// {0x0A,0}, // FMARK function
// {0x0C,0}, // RGB interface setting
// {0x0D,0}, // Frame marker Position
// {0x0F,0}, // RGB interface polarity
//*************Power On sequence ****************//
{0x10,0}, // SAP, BT[3:0], AP, DSTB, SLP, STB
{0x11,0x0007}, // DC1[2:0], DC0[2:0], VC[2:0]
{0x12,0}, // VREG1OUT voltage
{0x13,0}, // VDV[4:0] for VCOM amplitude
{0x07,0x0001},
{0xFF,200}, // Dis-charge capacitor power voltage
{0x10,0x1690}, // SAP, BT[3:0], AP, DSTB, SLP, STB
{0x11,0x0227}, // Set DC1[2:0], DC0[2:0], VC[2:0]
{0xFF,50},
{0x12,0x000D},
{0xFF,50},
{0x13,0x1200}, // VDV[4:0] for VCOM amplitude
{0x29,0x000A}, // 04 VCM[5:0] for VCOMH
// {0x2B,0x000D}, // Set Frame Rate
{0xFF,50},
// ----------- Adjust the Gamma Curve ----------//
{0x30,0},
{0x31,0x0700},
{0x32,0x0707},
{0x35,0},
{0x36,0x000F},
{0x37,0x0707},
{0x38,0x0007},
{0x39,0},
{0x3C,0},
{0x3D,0x0F00},
//------------------ Set GRAM area ---------------//
{0xFE,0},
{0x60,0x2700}, // Gate Scan Line, bit 15 reflects Y counting
{0x61,0x0003}, // NDL,VLE, REV
// {0x6A,0}, // set scrolling line
//-------------- Partial Display Control ---------//
// {0x80,0},
// {0x81,0},
// {0x82,0},
// {0x83,0},
// {0x84,0},
// {0x85,0},
//-------------- Panel Control -------------------//
{0x90,0x0010},
{0x92,0},
{0x07,0x0133}}; // 262K color and display ON
for (char*z=(char*)pairs; z<(char*)pairs+sizeof pairs;) {
byte a=pgm_read_byte(z++);
word b=pgm_read_word(z); z+=2;
switch (a) {
case 1: b|=orient<<7&0x0100; break; //bit 8 reflects X counting
case 0xFF: _delay_ms(200); continue;
case 0xFE: unsetWindow(); continue;
case 0x60: b|=orient<<13&0x8000; break; // bit 15 reflects Y counting
}
writeCW(a,b);
}
#elif defined(DISP_ILI9341)
PROGMEM static const byte data_init[]={ // Kette von Pascal-Strings
6,0xCB,0x39,0x2C,0x00,0x34,0x02,
4,0xCF,0x00,0XC1,0X30,
4,0xE8,0x85,0x00,0x78,
3,0xEA,0x00,0x00,
5,0xED,0x64,0x03,0X12,0X81,
2,0xF7,0x20,
2,0xC0,0x23, //VRH[5:0] //Power control
2,0xC1,0x10, //SAP[2:0];BT[3:0]
3,0xC5,0x3e,0x28, //Contrast //VCM control
2,0xC7,0x86, //--
2,0x3A,0x55, // RGB16
3,0xB1,0x00,0x18, // DIVA[1:0]=0 // RTNA[4:0]=24 = 79 Hz // Frame Control
5,0xB6,0x0A,0x82,0x27,0x00, // PTG = Interval Scan, PT = Source Output: GND // Display Function Control
2,0xF2,0x00, // 3Gamma Function Disable
2,0x26,0x01, //Gamma curve selected
16,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,
0x0E,0x09,0x00, //Set Gamma
16,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,
0x31,0x36,0x0F,
1,0x11, //Exit Sleep
0};
writeCBList(data_init);
_delay_ms(120);
PROGMEM static const byte data_dispon[]={
1,0x29, //Display on
2,0x36,0x48, // Memory Access Control // MY=0, MX=0, MV=0, ML=0, BGR=1, MH=0, -=0, -=0
0};
writeCBList(data_dispon);
// writeC(0x2c);
#elif defined(DISP_SPFD5408) // September 2016
#define ILI9341_SOFTRESET 0x01
#define ILI9341_SLEEPIN 0x10
#define ILI9341_SLEEPOUT 0x11
#define ILI9341_NORMALDISP 0x13
#define ILI9341_INVERTOFF 0x20
#define ILI9341_INVERTON 0x21
#define ILI9341_GAMMASET 0x26
#define ILI9341_DISPLAYOFF 0x28
#define ILI9341_DISPLAYON 0x29
#define ILI9341_COLADDRSET 0x2A
#define ILI9341_PAGEADDRSET 0x2B
#define ILI9341_MEMORYWRITE 0x2C
#define ILI9341_PIXELFORMAT 0x3A
#define ILI9341_FRAMECONTROL 0xB1
#define ILI9341_DISPLAYFUNC 0xB6
#define ILI9341_ENTRYMODE 0xB7
#define ILI9341_POWERCONTROL1 0xC0
#define ILI9341_POWERCONTROL2 0xC1
#define ILI9341_VCOMCONTROL1 0xC5
#define ILI9341_VCOMCONTROL2 0xC7
#define ILI9341_MEMCONTROL 0x36
#define ILI9341_MADCTL 0x36
#define ILI9341_MADCTL_MY 0x80
#define ILI9341_MADCTL_MX 0x40
#define ILI9341_MADCTL_MV 0x20
#define ILI9341_MADCTL_ML 0x10
#define ILI9341_MADCTL_RGB 0x00
#define ILI9341_MADCTL_BGR 0x08
#define ILI9341_MADCTL_MH 0x04
#define writeRegister8(a,b) writeC(a);writeB(b)
#define writeRegister16(a,b) writeC(a);writeB((b)>>8);writeB((b)&0xFF)
writeRegister8(0x01, 0);
_delay_ms(50);
writeRegister8(0x28, 0);
writeRegister8(0xC0, 0x23);
writeRegister8(0xC1, 0x10);
writeRegister16(0xC5, 0x2B2B);
writeRegister8(0xC7, 0xC0);
writeRegister8(0x36, 0x88);
writeRegister8(0x3A, 0x55);
writeRegister16(0xB1, 0x001B);
writeRegister8(0xB7, 0x07);
/* writeRegister32(0xB6, 0x0A822700);*/
writeRegister8(0x11, 0);
_delay_ms(150);
writeRegister8(0x29, 0);
_delay_ms(500);
// *** SPFD5408 change -- Begin
// Not tested yet
//writeRegister8(0x20, 0);
//delay(500);
// *** SPFD5408 change -- End
// setAddrWindow(0, 0, 240-1, 320-1);
#elif defined(DISP_S6D04H0)
// PowerOn
_delay_ms(50);
// Init
PROGMEM static const byte data_init[]={ // Kette von Pascal-Strings
3,0xF0,0x5A,0x5A,
3,0xFC,0x5A,0x5A,
12,0xFD,0x00,0x00,0x10,0x14,0x12,0x00,0x04,0x48,0x40,0x16,0x16,
1,0x35,
2,0x36,0x48,
2,0x3A,0x55,
18,0xF2,0x28,0x5B,0x7F,0x08,0x08,0x00,0x00,0x15,0x48,0x04,0x07,0x01,
0x00,0x00,0x63,0x08,0x08,
5,0xF7,0x01,0x00,0x10,0x00,
4,0xF8,0x33,0x00,0x00,
0};
writeCBList(data_init);
PROGMEM static const byte data_power[]={
10,0xF6,0x01,0x01,0x07,0x00,0x01,0x0C,0x03,0x0C,0x03,
13,0xF5,0x00,0x2E,0x40,0x00,0x00,0x01,0x00,0x00,0x0D,0x0D,0x00,0x00,
21,0xF4,0x07,0x00,0x00,0x00,0x22,0x64,0x01,0x02,0x2A,0x4D,0x06,0x2A,
0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
2,0xF3,0x01,
0};
writeCBList(data_power);
PROGMEM static const byte data_gamma[]={
13,0xFA,0x0A,0x04,0x0C,0x19,0x25,0x33,0x2D,0x27,0x22,0x1E,0x1A,0x00,
13,0xFB,0x0C,0x04,0x19,0x1E,0x20,0x23,0x18,0x3D,0x25,0x19,0x0B,0x00,
0};
for (byte i=4; i; i>>=1) {
writeC(0xF9); writeB(i); // Gamma Red-green-blue
writeCBList(data_gamma);
}
writeC(0x11);
_delay_ms(120);
PROGMEM static const byte data_dispon[]={
3,0xF0,0xA5,0xA5,
3,0xFC,0xA5,0xA5,
1,0x29,
0};
writeCBList(data_dispon);
#elif defined(DISP_ILI9481)
writeC(0x11);
_delay_ms(20);
PROGMEM static const byte data_init[]={
4,0xD0,0x07,0x42,0x18,
4,0xD1,0x00,0x07,0x10,
3,0xD2,0x01,0x02,
6,0xC0,0x10,0x3B,0x00,0x02,0x11,
2,0xC5,0x03,
13,0xC8,0x00,0x32,0x36,0x45,0x06,0x16,0x37,0x75,0x77,0x54,0x0C,0x00,
2,0x36,0x0A,
2,0x3A,0x55,
5,0x2A,0x00,0x00,0x01,0x3F,
5,0x2B,0x00,0x00,0x01,0xE0,
0};
writeCBList(data_init);
_delay_ms(120);
writeC(0x29);
#else
# error Add code here!
#endif
DISP_CS(1);
setColor(COLOR_BLACK);
setBackColor(COLOR_WHITE);
}
void UTFT::lcdOff() {
#ifdef DISP_PCF8833
DISP_CS(0);
writeC(0x28);
DISP_CS(1);
#elif defined(DISP_CPLD)
DISP_CS(0);
writeCW(0x01,0x0000);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::lcdOn() {
#ifdef DISP_PCF8833
DISP_CS(0);
writeC(0x29);
DISP_CS(1);
#elif defined(DISP_CPLD)
DISP_CS(0);
writeCW(0x01,0x0010);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setContrast(char c) {
#ifdef DISP_PCF8833
DISP_CS(0);
if (c>64) c=64;
writeC(0x25);
writeB(c);
DISP_CS(1);
#endif
}
void UTFT::setBrightness(byte br) {
#ifdef DISP_CPLD
DISP_CS(0);
if (br>16) br=16;
writeCW(0x01,br);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setDisplayPage(byte page) {
#ifdef DISP_CPLD
DISP_CS(0);
if (page>7) page=7;
writeCW(0x04,page);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setWritePage(byte page) {
#ifdef DISP_CPLD
DISP_CS(0);
if (page>7) page=7;
writeCW(0x05,page);
writeC(0x0F);
DISP_CS(1);
#endif
}
// UTF-8 string processing helpers
// No error checking!
// 2-byte UTF-8 (110x xxxx 10xx xxxx)
// 3-byte UTF-8 (1110 xxxx 10xx xxxx 10xx xxxx)
wchar_t UTFT::take_wchar(const char*&s) {
wchar_t ret=*s++;
if (ret&0x80) {
if (ret&0x20) {
ret=ret<<12|(*s++&0x3F)<<6;
}else ret=ret<<6&0x07C0;
ret|=*s++&0x3F;
}
return ret;
}
wchar_t UTFT::take_wchar(const __FlashString*&h) {
const char*&s=reinterpret_cast<const char*&>(h);
wchar_t ret=pgm_read_byte(s++);
if (ret&0x80) {
if (ret&0x20) {
ret=ret<<12|(pgm_read_byte(s++)&0x3F)<<6;
}else ret=ret<<6&0x07C0;
ret|=pgm_read_byte(s++)&0x3F;
}
return ret;
}
/**********************************************
* Speed-optimized setpixel + bitblt routines *
**********************************************/
void UTFT::setXY(int X, int Y, bool swap) {
#if defined(DISP_ILI9325D)
writeCW(0x20^swap,X);
writeCW(0x21^swap,Y);
writeC(0x22); // prepare pixel value output
#elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
writeCWW(0x2A,X,X); // Column Address Set
writeCWW(0x2B,Y,Y); // Page Address Set
writeC(0x2C); // Memory write
#else
# error Add code here!
#endif
}
void UTFT::setWindow(byte o) {
byte ori=orient&1;
#if defined(DISP_ILI9325D)
if (o&0x80) {
if (ori) o=o&0xF9 | o<<1&4 | o>>1&2; // irgendwie müssen die Bits getauscht werden, hm...
writeCW(0x03,0x1030^(o&7^ori)<<3);
}
if (o&0x40) {
ori<<=1;
writeCW(0x50^ori,L);
writeCW(0x52^ori,T);
writeCW(0x51^ori,R);
writeCW(0x53^ori,B);
ori>>=1;
}
if (o&0x10) setXY(X,Y,ori); // set pixel address
#elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
if (o&0x80) {
writeC(0x36); // Memory Access Control
writeB((o^ori)<<5|0x08|orient&0x04|orient<<3&0x10|1
# ifndef DISP_ILI9481
^0x40
# endif
);
}
if (o&0x40) {
writeCWW(0x2A,L,R); // Column Address Set
writeCWW(0x2B,T,B); // Page Address Set
writeC(0x2C); // Memory write
}else if (o&0x10) setXY(X,Y,ori); // set pixel address
#else
# error Add code here!
#endif
}
void UTFT::scroll(int v) {
DISP_CS(0);
#if defined(DISP_ILI9325D)
writeCW(0x6A,v);
#elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
writeCW(0x37,v); // Vertical Scrolling Start Address
#else
# error Add code here!
#endif
DISP_CS(1);
}
void UTFT::setPixel() {
if (clipOk()) {setWindow(0x30); writeW(fc);}
}
// Skips unset pixels for transparent bitblt:
// Calculates the new horizontal and vertical GRAM address
// x and y are _reversed_ _source_ coordinates
void UTFT::advance(int x,int y) {
byte o=orient>>3;
if (o&1) {
x-=H;
y-=W;
if (o&2) x+=B; else x=T-x;
if (o&4) y+=R; else y=L-y;
}else{
x-=W; // W-x = current positive x, therefore, x is now 0 or negative
y-=H;
if (o&2) x+=R; else x=L-x;
if (o&4) y+=B; else y=T-y;
}
#ifdef DISP_SETXY
setXY(x,y,(o^orient)&1); // don't touch current position here!!
#else
#endif
}
void UTFT::advance() {
byte o=orient;
if (o&0x40) Y=o&0x80?(Y<<1)-YE:YE; // escapement: advance current position
else X=o&0x80?(X<<1)-XE:XE;
}
// Schwarzweiß-Version, vom Flash-Speicher, MSBfirst
// startbit = 0..7 (0 = MSB, 7 = LSB)
// Can work with very dense bitmaps (for bitmap fonts!)
// startbit is not limited to 0..7, can be any bit number
void UTFT::bitblt(const byte*data, int bitsperline, int startbit) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (orient&8) SWAP(x,y);
startbit+=y*bitsperline+x;
data+=startbit>>3; // correct source address
startbit&=7;
x=W;
y=H;
if (orient&8) SWAP(x,y);
bitsperline-=x; // now: bits at end of line to skip
bool skip=false;
DISP_CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{
byte b=pgm_read_byte(data); // load first byte (possible multiple times!)
byte m=1<<(~startbit&7); // make first bit mask
for (int xx=x;;) {
if (flags&TRANS) {
if (b&m) {
if (skip) advance(xx,y); // set new address only at non-contiguous pixels (for more speed)
skip=false;
writeW(fc); // set pixel to foreground color at X/Y
}else skip=true;
}else writeW(b&m?fc:bc); // set pixel (always)
startbit++; // track bit where we are
if (!--xx) break; // end of line
m>>=1; // next bit in mask
if (!m) { // if emptied...
b=pgm_read_byte(++data); // load next byte
m=0x80; // set next mask bit (MSB)
startbit-=8; // should be 0
}
}
startbit+=bitsperline; // startbit can be 0..8 inclusive(!) at loop exit
data+=startbit>>3; // prepate for next line
startbit&=7;
#ifndef DISP_SETXY
skip=true;
#endif
}while(--y);
unsetWindow();
DISP_CS(1);
}//else drawCircle(100,100,80);
advance();
}
// HiColor-Version, vom Massenspeicher (Live-JPG-Dekompressor?)
void UTFT::bitblt(FILE*f, int wordsperline) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (x||y) {
if (orient&8) SWAP(x,y);
myseek(f,y*wordsperline+x<<1); // correct source pointer
}
x=W;
y=H;
if (orient&8) SWAP(x,y);
wordsperline-=x; // now: skip words at end (should be >=0!)
wordsperline<<=1; // now: skip bytes at end
bool skip=false;
DISP_CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{ // iterate over source's y (lines)
int xx=x;
do{ // iterate over source's x (pixels)
word w=mygetw(f); // cannot handle EOF here
if (flags&TRANS) {
if (w==bc) skip=true;
else{
if (skip) advance(xx,y); // set new address _only_ at non-contiguous pixels (for more speed)
skip=false;
goto w;
}
}else w: writeW(w); // set pixel (always)
}while(--xx);
if (wordsperline) myseek(f,wordsperline); // next line
}while(--y);
unsetWindow();
DISP_CS(1);
}//else drawCircle(120,120,80);
advance();
}
void UTFT::bitblt(const word*w, int wordsperline) {
FILE f;
fdev_setup_stream(&f,0,0,_FDEV_SETUP_READ|__SSTR|__SPGM);
f.len=(int)w;
bitblt(&f,wordsperline);
}
/*********************************
* Hardware-independent graphics *
*********************************/
/*==== clipping ====*/
void UTFT::setClip(int l, int t, int r, int b) {
if (flags&MOVE) {
l+=XO; t+=YO; r+=XO; b+=YO;
flags&=~MOVE;
}
if (l<0) l=0;
if (t<0) t=0;
int e=getDisplayXSize()-1;
if (r>e) r=e;
e=getDisplayYSize()-1;
if (b>e) b=e;
clip.L=l; clip.T=t; clip.R=r; clip.B=b;
}
bool UTFT::clipX() {
int o=clip.L-L;
XC=0;
if (o>0) {L=clip.L; XC=o;}
if (R>clip.R) R=clip.R;
return (W=R-L+1)>0; // new width, return true when not empty
}
bool UTFT::clipOk() const{ // checks point inside clipping area
return clip.L<=X && X<=clip.R && clip.T<=Y && Y<=clip.B;
}
/*==== position calculation ====*/
void UTFT::setOrg(int x, int y) {
if (flags&MOVE) {
XO+=x; YO+=y;
flags&=~MOVE; // one-time flag!
}else XO=x, YO=y;
}
void UTFT::gotoXY(int x,int y) {
if (flags&MOVE) {
X+=x;
Y+=y;
flags&=~MOVE; // one-time flag!
}else X=x+XO, Y=y+YO;
}
void UTFT::targetXY(int x,int y) {
if (flags&MOVE) {
XE=X+x;
YE=Y+y;
flags&=~MOVE; // one-time flag!
}else XE=x+XO, YE=y+YO;
}
void UTFT::calcRectX() {
int w=XE-X;
R=(w<0?(L=XE)+(W=-w):(L=X)+(W=w))-1; // W never negative
}
// remove a limiting bitblt window; CS must be 0
void UTFT::unsetWindow() {
L=clip.L; T=clip.T; R=clip.R; B=clip.B;
#ifdef DISP_SETXY
setWindow(0xC0);
#endif
}
/*==== points and lines ====*/
void UTFT::drawPixel() {
DISP_CS(0);
setPixel();
DISP_CS(1);
}
void UTFT::lineTo(int x, int y) {
targetXY(x,y);
calcRect(); // calculate W and H
if (!W) {
R=L; B+=flags&ENDPIX; goto fr;
}else if (!H) {
B=T; R+=flags&ENDPIX; fr:
fillRect(); // clip and draw
X=XE;
Y=YE;
}else{
int xs=XE<X?-1:1;
int ys=YE<Y?-1:1;
int err=W-H;
DISP_CS(0);
for(;X!=XE || Y!=YE;) {
setPixel(); // clip and draw using DISPLAY X/Y coordinate
int e2=err<<1;
if (e2+H>0) err-=H, X+=xs;
if (e2<W) err+=W, Y+=ys;
}
if (flags&ENDPIX) setPixel();
DISP_CS(1);
}
}
/*==== outline figures ====*/
void UTFT::drawRect(int x1, int y1, int x2, int y2, int w) {
if (x1>x2) SWAP(x1,x2);
if (y1>y2) SWAP(y1,y2);
flags&=~MOVE;
if (x1+w+w>=x2 || y1+w+w>=y2) {
fillRect(x1,y1,x2,y2); // nicht offen
}else{
fillRect(x1,y1,x1+w,y2-w); // links
fillRect(x1+w,y1,x2,y1+w); // oben
fillRect(x2-w,y1+w,x2,y2); // rechts
fillRect(x1,y2-w,x2-w,y2); // unten
}
}
void UTFT::drawRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) SWAP(x1,x2);
if (y1>y2) SWAP(y1,y2);
int w=x2-x1; // stets >=0
int h=y2-y1;
if ((unsigned)w>=4 && (unsigned)h>=4) {
drawPixel(x1+1,y1+1);
drawPixel(x2-2,y1+1);
drawPixel(x1+1,y2-2);
drawPixel(x2-2,y2-2);
drawHLine(x1+2,y1,w-4);
drawHLine(x1+2,y2-1,w-4);
drawVLine(x1,y1+2,h-4);
drawVLine(x2-1,y1+2,h-4);
}
}
void UTFT::drawCircle(int x, int y, int radius) {
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
DISP_CS(0);
flags&=~MOVE;
setPixel(x,y+radius);
setPixel(x,y-radius);
setPixel(x+radius,y);
setPixel(x-radius,y);
while(x1 < y1) {
if (f>=0) {
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
setPixel(x+x1,y+y1);
setPixel(x-x1,y+y1);
setPixel(x+x1,y-y1);
setPixel(x-x1,y-y1);
setPixel(x+y1,y+x1);
setPixel(x-y1,y+x1);
setPixel(x+y1,y-x1);
setPixel(x-y1,y-x1);
}
DISP_CS(1);
}
void UTFT::drawPoly(const POINT*p,int n) {
gotoXY(p[n-1].x,p[n-1].y);
for (int i=0; i<n; i++) lineTo(p[i].x,p[i].y);
}
/*==== filled figures ====*/
void UTFT::fillRect() {
if (clipX() && clipY()) {
DISP_CS(0);
setWindow(0xF0); // no specific fill direction
fillW(fc,W,H);
unsetWindow();
DISP_CS(1);
}
}
void UTFT::fillRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) SWAP(x1,x2);
if (y1>y2) SWAP(y1,y2);
int w=x2-x1; // stets >=0
int h=y2-y1;
if ((unsigned)w>=4 && (unsigned)h>=4) {
drawHLine(x1+2,y1,w-4);
drawHLine(x1+1,y1+1,w-2);
fillRectW(x1,y1+2,w,h-4);
drawHLine(x1+1,y2-2,w-2);
drawHLine(x1+2,y2-1,w-4);
}
}
void UTFT::fillCircle(int x, int y, int radius) {
flags&=~MOVE;
for (int y1=-radius; y1<=0; y1++)
for (int x1=-radius; x1<=0; x1++)
if (x1*x1+y1*y1 <= radius*radius) {
drawHLine(x+x1, y+y1, 2*(-x1));
drawHLine(x+x1, y-y1, 2*(-x1));
break;
}
}
void UTFT::fillScr(word color) {
DISP_CS(0);
unsetWindow();
setWindow(0xF0);
// setXY(L,T,orient);
fillW(color,DISP_X_SIZE,DISP_Y_SIZE);
DISP_CS(1);
}
/*==== character output ====*/
const wchar_t*wcschr_P(const wchar_t*p,wchar_t c) {
for(;;p++) {
wchar_t v=pgm_read_word(p);
if (v==c) return p;
if (!v) return 0;
}
}
static wchar_t uni2cp1252(wchar_t c) {
// Generiert die Kodepositionen 0x80..0x9F
static const PROGMEM wchar_t codes[]=
L"€ ‚ƒ„…†‡ˆ‰Š‹Œ Ž "
L" ‘’“”•–—˜™š›œ žŸ";
if (c>128) {
const wchar_t*p=wcschr_P(codes,c);
if (p) c=0x80+p-codes;
}
return c;
}
void UTFT::print(wchar_t c) {
if (flags&COOKED) {
if (c=='\n') {
byte o=orient;
o^=o>>3; // include font rotation and character direction
o^=o>>5&6; // include string escapement
if (o&1) { // rotated screen ^ rotated font
Y=YO;
if (o&2) X-=cfont.cy; else X+=cfont.cy;
}else{
X=XO;
if (o&4) Y-=cfont.cy; else Y+=cfont.cy;
}
return;
}
}
c=uni2cp1252(c);
if (c<cfont.first || c>=cfont.first+cfont.count) c='?';
c-=cfont.first;
int bitsperline=0;
int startbit=0;
char cx=cfont.cx;
char cy=cfont.cy;
const byte*addr=cfont.bits;
if (cx<=0) { // propotional font
char w=0;
if (cx==-16) {
for (wchar_t i=0;i<cfont.count;i++) {
byte n=pgm_read_byte(addr++); // width of this character
if (i==c) {
startbit=bitsperline; // take that snapshot
w=n;
}
bitsperline+=n; // sum all widths
}
}else{
for (wchar_t i=0;;) {
byte b=pgm_read_byte(addr++);
for (byte m=0; m<2; m++) {
byte n=(b&15)-cx; // width of this character
if (i==c) {
startbit=bitsperline; // take that snapshot
w=n;
}
bitsperline+=n; // sum the widths
b>>=4;
if (++i==cfont.count) goto exi;
}
}
}
exi: cx=w;
#ifdef DEBUG
deb1=w;
deb2=bitsperline;
#endif
}else{
bitsperline=cfont.cx+7&~7;
addr+=(byte)c*((byte)bitsperline>>3)*cy;
}
if (orient&8) SWAP(cx,cy); // rotate target character cell (more precisely, flip on main diagonal)
if (orient&16) cx=-cx; // reflect character cell towards left
if (orient&32) cy=-cy; // reflect character cell towards top
targetWH(cx,cy);
calcRect(); // generate character cell
bitblt(addr,bitsperline,startbit);
}
void UTFT::realign(int textlen) {
if (align&0x0F) { // horizontal
if (align&2) textlen>>=1; // zentrieren
if (orient&8) { // TODO: Operationen prüfen/korrigieren
if (orient&0x20) Y+=textlen; else Y-=textlen;
}else{
if (orient&0x10) X+=textlen; else X-=textlen;
}
}
}
void UTFT::print(const char *s) {
realign(align&0x0F?getTextExtent(s):0);
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
print(c);
}
}
void UTFT::print(const __FlashString*s) {
realign(align&0x0F?getTextExtent(s):0);
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
print(c);
}
}
int UTFT::getTextExtent(wchar_t c) {
int ext=cfont.cx;
if (ext>0) return ext; // return constant for monospaced font
if (c<cfont.first || c+cfont.first>=cfont.count) c='?';
c-=cfont.first;
if (ext==-16) { // Byte-Angaben
return pgm_read_byte(cfont.bits+c);
}else{ // Nibble-Angaben
byte b=pgm_read_byte(cfont.bits+(c>>1));
if (c&1) b>>=4; // use high nibble
return (b&15)-ext; // "add" the minimum character width
}
}
int UTFT::getTextExtent(const char *s) {
int ext=0;
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
int UTFT::getTextExtent(const __FlashString*s) {
int ext=0;
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
#ifdef DISP_PRINTF
int UTFT::sendByte(char b, FILE*f) {
return reinterpret_cast<UTFT*>(f->get)->print(b),0;
}
void UTFT::vprintf(const char*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf(&f,fmt,args);
}
void UTFT::printf(const char*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
void UTFT::vprintf(const __FlashString*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf_P(&f,reinterpret_cast<const char*>(fmt),args);
}
void UTFT::printf(const __FlashString*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
#endif
void UTFT::setFont(const byte*font) {
cfont.cx=pgm_read_byte(font++);
cfont.cy=pgm_read_byte(font++);
cfont.first=pgm_read_byte(font++);
cfont.count=pgm_read_byte(font++);
cfont.bits=font;
}
Vorgefundene Kodierung: UTF-8 | 0
|