Source file: /~heha/Mikrocontroller/Displays/utft/Kalender.zip/ILI9341/UTFT.cpp

     1  #include "UTFT.h"
     2  
     3  #include <util/delay.h>
     4  #include <stdlib.h>
     5  
     6  static void myseek(FILE*f,int dist) {
     7   if (f->flags&__SSTR) {	// mine! Do fast access
     8    f->len+=(int)dist;
     9   }//else fseek(f,dist,SEEK_CUR);
    10  }
    11  static word mygetw(FILE*f) {
    12   word w;
    13   if (f->flags&__SSTR) {	// mine! Do fast access
    14    word*p=(word*)f->len;
    15    if (f->flags&__SPGM) w=pgm_read_word(p);
    16    else w=*p;
    17    ++p;
    18    f->len=(int)p;
    19   }else{			// not mine! Use function pointer
    20    w=fgetc(f)&0xFF;
    21    w|=fgetc(f)<<8;
    22   }
    23   return w;
    24  }
    25  
    26  /********************
    27   * Basic LCD access *
    28   ********************/
    29  
    30  void UTFT::writeB(byte b) {
    31  #if DISP_TRANSFER==16
    32   writeW(b);		// always 16-bit
    33  #elif DISP_TRANSFER==1
    34   for (byte m=0x80; m; m>>=1) {
    35    if (VL & 0x80) DISP_SDA(1); else DISP_SDA(0);
    36    DISP_SCL(0);
    37    DISP_SCL(1);
    38   }
    39  #else
    40   DISP_OUT(b);
    41   DISP_WR(0);
    42   DISP_WR(1);
    43  #endif
    44  }
    45  
    46  void UTFT::writeW(word w) {
    47  #if DISP_TRANSFER<16
    48   writeB(w>>8);
    49   writeB(w);
    50  #elif defined(DISP_ALE)
    51   DISP_OUT(w>>8);
    52   DISP_ALE(1);
    53   DISP_ALE(0);
    54   DISP_OUT(w);
    55   DISP_WR(0);
    56   DISP_WR(1);
    57  #else
    58   DISP_OUT(w);
    59   DISP_WR(0);
    60   DISP_WR(1);
    61  #endif
    62  }
    63  
    64  void UTFT::fillW(word w, int r1, int r2) {
    65  #ifdef __MPS430__	// 16-bit optimized loops
    66   if (r1<r2) SWAP(r1,r2);	// ensure more inner loop executions
    67   if (!r2) return;
    68  #define DO do {int r=r1; do	// two nested loops
    69  #define WHILE while (--r);} while(--r2)
    70  #else			// 8-bit optimized loops
    71   unsigned long rep=(unsigned long)(word)r1*(word)r2;
    72   if (!rep) return;
    73   byte rep0=byte(rep);
    74   byte rep1=byte(rep>>8);
    75   byte rep2=byte(rep>>16);	// 24 bits are sufficient here
    76   if (rep0) rep1++;
    77   if (rep1) rep2++;
    78  #define DO do do do	// three nested loops
    79  #define WHILE while (--rep0); while(--rep1); while(--rep2)
    80  #endif
    81  #if DISP_TRANSFER==16
    82   DISP_OUT(w);
    83   DO{
    84    DISP_WR(0);
    85    DISP_WR(1);
    86   }WHILE;
    87  #elif DISP_TRANSFER==8
    88   if (w>>8==(w&0xFF)) {
    89    DISP_OUT(w);
    90    DO{
    91     DISP_WR(0);
    92     DISP_WR(1);
    93     DISP_WR(0);
    94     DISP_WR(1);
    95    }WHILE;
    96   }else{
    97    DO{
    98     DISP_OUT(w>>8);
    99     DISP_WR(0);
   100     DISP_WR(1);
   101     DISP_OUT(w);
   102     DISP_WR(0);
   103     DISP_WR(1);
   104    }WHILE;
   105   }
   106  #else
   107   DO setPixel(w); WHILE;
   108  #endif
   109  #undef DO
   110  #undef WHILE
   111  }
   112  
   113  void UTFT::writeCW(byte b,word w) {
   114   writeC(b);
   115  #ifdef DISP_CMD16
   116   writeW(w);
   117  #else
   118   writeB(w>>8);
   119   writeB(w);
   120  #endif
   121  }
   122  
   123  void UTFT::writeCWW(byte b,word x,word y) {
   124   writeC(b);
   125  #ifdef DISP_CMD16
   126   writeW(x);
   127   writeW(y);
   128  #else
   129   writeB(x>>8);
   130   writeB(x);
   131   writeB(y>>8);
   132   writeB(y);
   133  #endif
   134  }
   135  
   136  void UTFT::writeCBList(const byte*z) {
   137   for(byte len;len=pgm_read_byte(z++);) {
   138    UTFT::writeC(pgm_read_byte(z++));
   139    while (--len) UTFT::writeB(pgm_read_byte(z++));
   140   };
   141  }
   142  
   143  /*************************************
   144   * Hardware-dependent initialization *
   145   *************************************/
   146  void UTFT::InitLCD(byte orientation) {
   147   orient=orientation;
   148   flags=0;
   149   align=0;
   150   clrClip();
   151   clrOrg();
   152   //clrScale();
   153   DISP_INIT();
   154  #ifdef DISP_DDR
   155   DISP_DDR(1);	// data port is output port
   156  #endif
   157  #ifdef DISP_RST
   158   DISP_RST(1);
   159   _delay_ms(5); 
   160   DISP_RST(0);
   161   _delay_ms(15);
   162   DISP_RST(1);
   163   _delay_ms(15);
   164  #endif
   165   DISP_CS(0);
   166  #ifdef DISP_ILI9325D
   167   static const struct {byte a;word b;} pairs[] PROGMEM={
   168    {0xE5,0x78F0},	// set SRAM internal timing
   169    {0x01,0},	// set Driver Output Control, bit 8 reflects X counting
   170    {0x02,0x0200},	// set 1 line inversion  
   171    {0x03,0x1030},
   172    {0x04,0},	// Resize register  
   173  //  {0x08,0x0207},	// set the back porch and front porch  
   174  //  {0x09,0},	// set non-display area refresh cycle ISC[3:0]  
   175  //  {0x0A,0},	// FMARK function  
   176  //  {0x0C,0},	// RGB interface setting  
   177  //  {0x0D,0},	// Frame marker Position  
   178  //  {0x0F,0},	// RGB interface polarity  
   179  	//*************Power On sequence ****************//  
   180    {0x10,0},	// SAP, BT[3:0], AP, DSTB, SLP, STB  
   181    {0x11,0x0007}, // DC1[2:0], DC0[2:0], VC[2:0]  
   182    {0x12,0},	// VREG1OUT voltage  
   183    {0x13,0},	// VDV[4:0] for VCOM amplitude  
   184    {0x07,0x0001},
   185    {0xFF,200},	// Dis-charge capacitor power voltage  
   186    {0x10,0x1690},	// SAP, BT[3:0], AP, DSTB, SLP, STB  
   187    {0x11,0x0227},	// Set DC1[2:0], DC0[2:0], VC[2:0]  
   188    {0xFF,50},
   189    {0x12,0x000D},
   190    {0xFF,50},
   191    {0x13,0x1200}, // VDV[4:0] for VCOM amplitude  
   192    {0x29,0x000A}, // 04  VCM[5:0] for VCOMH  
   193  //  {0x2B,0x000D}, // Set Frame Rate  
   194    {0xFF,50},
   195  	// ----------- Adjust the Gamma Curve ----------//  
   196    {0x30,0},
   197    {0x31,0x0700},
   198    {0x32,0x0707},
   199    {0x35,0},
   200    {0x36,0x000F},
   201    {0x37,0x0707},
   202    {0x38,0x0007},
   203    {0x39,0},
   204    {0x3C,0},
   205    {0x3D,0x0F00},
   206  	//------------------ Set GRAM area ---------------//
   207    {0xFE,0},
   208    {0x60,0x2700},	// Gate Scan Line, bit 15 reflects Y counting
   209    {0x61,0x0003}, // NDL,VLE, REV   
   210  //  {0x6A,0},	// set scrolling line  
   211  	//-------------- Partial Display Control ---------//  
   212  //  {0x80,0},
   213  //  {0x81,0},
   214  //  {0x82,0},
   215  //  {0x83,0},
   216  //  {0x84,0},
   217  //  {0x85,0},
   218  	//-------------- Panel Control -------------------//  
   219    {0x90,0x0010},  
   220    {0x92,0},
   221    {0x07,0x0133}}; // 262K color and display ON
   222  
   223   for (char*z=(char*)pairs; z<(char*)pairs+sizeof pairs;) {
   224    byte a=pgm_read_byte(z++);
   225    word b=pgm_read_word(z); z+=2;
   226    switch (a) {
   227     case 1: b|=orient<<7&0x0100; break;	//bit 8 reflects X counting
   228     case 0xFF: _delay_ms(200); continue;
   229     case 0xFE: unsetWindow(); continue;
   230     case 0x60: b|=orient<<13&0x8000; break;	// bit 15 reflects Y counting
   231    }
   232    writeCW(a,b);
   233   }
   234  #elif defined(DISP_ILI9341)
   235   PROGMEM static const byte data_init[]={	// Kette von Pascal-Strings
   236     6,0xCB,0x39,0x2C,0x00,0x34,0x02,
   237     4,0xCF,0x00,0XC1,0X30,
   238     4,0xE8,0x85,0x00,0x78,
   239     3,0xEA,0x00,0x00,
   240     5,0xED,0x64,0x03,0X12,0X81,
   241     2,0xF7,0x20,
   242     2,0xC0,0x23,		//VRH[5:0] 	//Power control 
   243     2,0xC1,0x10,		//SAP[2:0];BT[3:0]
   244     3,0xC5,0x3e,0x28,	//Contrast	//VCM control
   245     2,0xC7,0x86,		//--
   246     2,0x3A,0x55,		// RGB16
   247     3,0xB1,0x00,0x18,	// DIVA[1:0]=0	// RTNA[4:0]=24 = 79 Hz	// Frame Control
   248     5,0xB6,0x0A,0x82,0x27,0x00,	// PTG = Interval Scan, PT = Source Output: GND	// Display Function Control 
   249     2,0xF2,0x00,	// 3Gamma Function Disable 
   250     2,0x26,0x01,	//Gamma curve selected 
   251    16,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,
   252       0x0E,0x09,0x00,	//Set Gamma 
   253    16,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,
   254       0x31,0x36,0x0F,
   255     1,0x11,		//Exit Sleep
   256     0};
   257   writeCBList(data_init);
   258   _delay_ms(120); 
   259   PROGMEM static const byte data_dispon[]={
   260      1,0x29,		//Display on
   261      2,0x36,0x48,	// Memory Access Control	// MY=0, MX=0, MV=0, ML=0, BGR=1, MH=0, -=0, -=0
   262      0};
   263   writeCBList(data_dispon);
   264  //    writeC(0x2c); 
   265  #elif defined(DISP_SPFD5408)	// September 2016
   266  
   267  #define ILI9341_SOFTRESET          0x01
   268  #define ILI9341_SLEEPIN            0x10
   269  #define ILI9341_SLEEPOUT           0x11
   270  #define ILI9341_NORMALDISP         0x13
   271  #define ILI9341_INVERTOFF          0x20
   272  #define ILI9341_INVERTON           0x21
   273  #define ILI9341_GAMMASET           0x26
   274  #define ILI9341_DISPLAYOFF         0x28
   275  #define ILI9341_DISPLAYON          0x29
   276  #define ILI9341_COLADDRSET         0x2A
   277  #define ILI9341_PAGEADDRSET        0x2B
   278  #define ILI9341_MEMORYWRITE        0x2C
   279  #define ILI9341_PIXELFORMAT        0x3A
   280  #define ILI9341_FRAMECONTROL       0xB1
   281  #define ILI9341_DISPLAYFUNC        0xB6
   282  #define ILI9341_ENTRYMODE          0xB7
   283  #define ILI9341_POWERCONTROL1      0xC0
   284  #define ILI9341_POWERCONTROL2      0xC1
   285  #define ILI9341_VCOMCONTROL1      0xC5
   286  #define ILI9341_VCOMCONTROL2      0xC7
   287  #define ILI9341_MEMCONTROL      0x36
   288  #define ILI9341_MADCTL  0x36
   289  
   290  #define ILI9341_MADCTL_MY  0x80
   291  #define ILI9341_MADCTL_MX  0x40
   292  #define ILI9341_MADCTL_MV  0x20
   293  #define ILI9341_MADCTL_ML  0x10
   294  #define ILI9341_MADCTL_RGB 0x00
   295  #define ILI9341_MADCTL_BGR 0x08
   296  #define ILI9341_MADCTL_MH  0x04 
   297  
   298  #define writeRegister8(a,b) writeC(a);writeB(b)
   299  #define writeRegister16(a,b) writeC(a);writeB((b)>>8);writeB((b)&0xFF)
   300  
   301      writeRegister8(0x01, 0);
   302      _delay_ms(50);
   303      writeRegister8(0x28, 0);
   304  
   305      writeRegister8(0xC0, 0x23);
   306      writeRegister8(0xC1, 0x10);
   307      writeRegister16(0xC5, 0x2B2B);
   308      writeRegister8(0xC7, 0xC0);
   309      writeRegister8(0x36, 0x88);
   310      writeRegister8(0x3A, 0x55);
   311      writeRegister16(0xB1, 0x001B);
   312      
   313      writeRegister8(0xB7, 0x07);
   314      /* writeRegister32(0xB6, 0x0A822700);*/
   315  
   316      writeRegister8(0x11, 0);
   317      _delay_ms(150);
   318      writeRegister8(0x29, 0);
   319      _delay_ms(500);
   320  	// *** SPFD5408 change -- Begin
   321  	// Not tested yet
   322  	//writeRegister8(0x20, 0);
   323  	//delay(500);
   324      // *** SPFD5408 change -- End
   325  //    setAddrWindow(0, 0, 240-1, 320-1); 
   326  #elif defined(DISP_S6D04H0)
   327  // PowerOn
   328   _delay_ms(50);
   329  // Init
   330   PROGMEM static const byte data_init[]={	// Kette von Pascal-Strings
   331      3,0xF0,0x5A,0x5A,
   332      3,0xFC,0x5A,0x5A,
   333     12,0xFD,0x00,0x00,0x10,0x14,0x12,0x00,0x04,0x48,0x40,0x16,0x16,
   334      1,0x35,
   335      2,0x36,0x48,
   336      2,0x3A,0x55,
   337     18,0xF2,0x28,0x5B,0x7F,0x08,0x08,0x00,0x00,0x15,0x48,0x04,0x07,0x01,
   338        0x00,0x00,0x63,0x08,0x08,
   339      5,0xF7,0x01,0x00,0x10,0x00,
   340      4,0xF8,0x33,0x00,0x00,
   341      0};
   342   writeCBList(data_init);
   343   PROGMEM static const byte data_power[]={
   344     10,0xF6,0x01,0x01,0x07,0x00,0x01,0x0C,0x03,0x0C,0x03,
   345     13,0xF5,0x00,0x2E,0x40,0x00,0x00,0x01,0x00,0x00,0x0D,0x0D,0x00,0x00,
   346     21,0xF4,0x07,0x00,0x00,0x00,0x22,0x64,0x01,0x02,0x2A,0x4D,0x06,0x2A,
   347        0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
   348      2,0xF3,0x01,
   349      0};
   350   writeCBList(data_power);
   351   PROGMEM static const byte data_gamma[]={
   352     13,0xFA,0x0A,0x04,0x0C,0x19,0x25,0x33,0x2D,0x27,0x22,0x1E,0x1A,0x00,
   353     13,0xFB,0x0C,0x04,0x19,0x1E,0x20,0x23,0x18,0x3D,0x25,0x19,0x0B,0x00,
   354     0};
   355   for (byte i=4; i; i>>=1) {
   356    writeC(0xF9); writeB(i);	// Gamma Red-green-blue
   357    writeCBList(data_gamma);
   358   }
   359   writeC(0x11);
   360   _delay_ms(120);
   361   PROGMEM static const byte data_dispon[]={
   362      3,0xF0,0xA5,0xA5,
   363      3,0xFC,0xA5,0xA5,
   364      1,0x29,
   365      0};
   366   writeCBList(data_dispon);
   367  #elif defined(DISP_ILI9481)
   368   writeC(0x11);
   369   _delay_ms(20);
   370   PROGMEM static const byte data_init[]={ 
   371     4,0xD0,0x07,0x42,0x18,
   372     4,0xD1,0x00,0x07,0x10,
   373     3,0xD2,0x01,0x02,
   374     6,0xC0,0x10,0x3B,0x00,0x02,0x11,
   375     2,0xC5,0x03,
   376    13,0xC8,0x00,0x32,0x36,0x45,0x06,0x16,0x37,0x75,0x77,0x54,0x0C,0x00,
   377     2,0x36,0x0A,
   378     2,0x3A,0x55,
   379     5,0x2A,0x00,0x00,0x01,0x3F,
   380     5,0x2B,0x00,0x00,0x01,0xE0,
   381     0};
   382   writeCBList(data_init);
   383   _delay_ms(120);
   384   writeC(0x29);
   385  #else
   386  # error Add code here!
   387  #endif
   388   DISP_CS(1);
   389   setColor(COLOR_BLACK);
   390   setBackColor(COLOR_WHITE);
   391  }
   392  
   393  void UTFT::lcdOff() {
   394  #ifdef DISP_PCF8833
   395   DISP_CS(0);
   396   writeC(0x28);
   397   DISP_CS(1);
   398  #elif defined(DISP_CPLD)
   399   DISP_CS(0);
   400   writeCW(0x01,0x0000);
   401   writeC(0x0F);   
   402   DISP_CS(1);
   403  #endif
   404  }
   405  
   406  void UTFT::lcdOn() {
   407  #ifdef DISP_PCF8833
   408   DISP_CS(0);
   409   writeC(0x29);
   410   DISP_CS(1);
   411  #elif defined(DISP_CPLD)
   412   DISP_CS(0);
   413   writeCW(0x01,0x0010);
   414   writeC(0x0F);
   415   DISP_CS(1);
   416  #endif
   417  }
   418  
   419  void UTFT::setContrast(char c) {
   420  #ifdef DISP_PCF8833
   421   DISP_CS(0);
   422   if (c>64) c=64;
   423   writeC(0x25);
   424   writeB(c);
   425   DISP_CS(1);
   426  #endif
   427  }
   428  
   429  void UTFT::setBrightness(byte br) {
   430  #ifdef DISP_CPLD
   431   DISP_CS(0);
   432   if (br>16) br=16;
   433   writeCW(0x01,br);
   434   writeC(0x0F);
   435   DISP_CS(1);
   436  #endif
   437  }
   438  
   439  void UTFT::setDisplayPage(byte page) {
   440  #ifdef DISP_CPLD
   441   DISP_CS(0);
   442   if (page>7) page=7;
   443   writeCW(0x04,page);
   444   writeC(0x0F);
   445   DISP_CS(1);
   446  #endif
   447  }
   448  
   449  void UTFT::setWritePage(byte page) {
   450  #ifdef DISP_CPLD
   451   DISP_CS(0);
   452   if (page>7) page=7;
   453   writeCW(0x05,page);
   454   writeC(0x0F);
   455   DISP_CS(1);
   456  #endif
   457  }
   458  
   459  // UTF-8 string processing helpers
   460  // No error checking!
   461  // 2-byte UTF-8 (110x xxxx 10xx xxxx)
   462  // 3-byte UTF-8 (1110 xxxx 10xx xxxx 10xx xxxx)
   463  wchar_t UTFT::take_wchar(const char*&s) {
   464   wchar_t ret=*s++;
   465   if (ret&0x80) {
   466    if (ret&0x20) {
   467     ret=ret<<12|(*s++&0x3F)<<6;
   468    }else ret=ret<<6&0x07C0;
   469    ret|=*s++&0x3F;
   470   }
   471   return ret; 
   472  }
   473  
   474  wchar_t UTFT::take_wchar(const __FlashString*&h) {
   475   const char*&s=reinterpret_cast<const char*&>(h);
   476   wchar_t ret=pgm_read_byte(s++);
   477   if (ret&0x80) {
   478    if (ret&0x20) {
   479     ret=ret<<12|(pgm_read_byte(s++)&0x3F)<<6;
   480    }else ret=ret<<6&0x07C0;
   481    ret|=pgm_read_byte(s++)&0x3F;
   482   }
   483   return ret;
   484  }
   485  
   486  /**********************************************
   487   * Speed-optimized setpixel + bitblt routines *
   488   **********************************************/
   489  
   490  void UTFT::setXY(int X, int Y, bool swap) {
   491  #if defined(DISP_ILI9325D)
   492   writeCW(0x20^swap,X);
   493   writeCW(0x21^swap,Y);
   494   writeC(0x22);		// prepare pixel value output
   495  #elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
   496   writeCWW(0x2A,X,X);	// Column Address Set
   497   writeCWW(0x2B,Y,Y);	// Page Address Set
   498   writeC(0x2C); 		// Memory write
   499  #else
   500  # error Add code here!
   501  #endif
   502  }
   503  
   504  void UTFT::setWindow(byte o) {
   505   byte ori=orient&1;
   506  #if defined(DISP_ILI9325D)
   507   if (o&0x80) {
   508    if (ori) o=o&0xF9 | o<<1&4 | o>>1&2;	// irgendwie müssen die Bits getauscht werden, hm...
   509    writeCW(0x03,0x1030^(o&7^ori)<<3);
   510   }
   511   if (o&0x40) {
   512    ori<<=1;
   513    writeCW(0x50^ori,L);
   514    writeCW(0x52^ori,T);
   515    writeCW(0x51^ori,R);
   516    writeCW(0x53^ori,B);
   517    ori>>=1;
   518   }
   519   if (o&0x10) setXY(X,Y,ori);		// set pixel address
   520  #elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
   521   if (o&0x80) {
   522    writeC(0x36);		// Memory Access Control
   523    writeB((o^ori)<<5|0x08|orient&0x04|orient<<3&0x10|1
   524  # ifndef DISP_ILI9481
   525  							^0x40
   526  # endif
   527  								);
   528   }
   529   if (o&0x40) {
   530    writeCWW(0x2A,L,R);	// Column Address Set
   531    writeCWW(0x2B,T,B);	// Page Address Set
   532    writeC(0x2C); 	// Memory write
   533   }else if (o&0x10) setXY(X,Y,ori);		// set pixel address
   534  #else
   535  # error Add code here!
   536  #endif
   537  }
   538  
   539  void UTFT::scroll(int v) {
   540   DISP_CS(0);
   541  #if defined(DISP_ILI9325D)
   542   writeCW(0x6A,v);
   543  #elif defined(DISP_ILI9341) || defined(DISP_SPFD5408) || defined(DISP_S6D04H0) || defined(DISP_ILI9481)
   544   writeCW(0x37,v);	// Vertical Scrolling Start Address
   545  #else
   546  # error Add code here!
   547  #endif
   548   DISP_CS(1);
   549  }
   550  
   551  void UTFT::setPixel() {
   552   if (clipOk()) {setWindow(0x30); writeW(fc);}
   553  }
   554  
   555  // Skips unset pixels for transparent bitblt:
   556  // Calculates the new horizontal and vertical GRAM address
   557  // x and y are _reversed_ _source_ coordinates
   558  void UTFT::advance(int x,int y) {
   559   byte o=orient>>3;
   560   if (o&1) {
   561    x-=H;
   562    y-=W;
   563    if (o&2) x+=B; else x=T-x;
   564    if (o&4) y+=R; else y=L-y;
   565   }else{
   566    x-=W;		// W-x = current positive x, therefore, x is now 0 or negative
   567    y-=H;
   568    if (o&2) x+=R; else x=L-x;
   569    if (o&4) y+=B; else y=T-y;
   570   }
   571  #ifdef DISP_SETXY
   572   setXY(x,y,(o^orient)&1);	// don't touch current position here!!
   573  #else
   574  #endif
   575  }
   576  
   577  void UTFT::advance() {
   578   byte o=orient;
   579   if (o&0x40) Y=o&0x80?(Y<<1)-YE:YE;	// escapement: advance current position
   580   else X=o&0x80?(X<<1)-XE:XE;
   581  }
   582  
   583  // Schwarzweiß-Version, vom Flash-Speicher, MSBfirst
   584  // startbit = 0..7 (0 = MSB, 7 = LSB)
   585  // Can work with very dense bitmaps (for bitmap fonts!)
   586  // startbit is not limited to 0..7, can be any bit number
   587  void UTFT::bitblt(const byte*data, int bitsperline, int startbit) {
   588   if (clipX() && clipY()) {
   589    int x=XC;
   590    int y=YC;
   591    if (orient&8) SWAP(x,y);
   592    startbit+=y*bitsperline+x;
   593    data+=startbit>>3;		// correct source address
   594    startbit&=7;
   595    x=W;
   596    y=H;
   597    if (orient&8) SWAP(x,y);
   598    bitsperline-=x;		// now: bits at end of line to skip
   599    bool skip=false;
   600    DISP_CS(0);
   601    setWindow(0xF0|orient>>3&7);	// make clipped window current
   602    do{
   603     byte b=pgm_read_byte(data);	// load first byte (possible multiple times!)
   604     byte m=1<<(~startbit&7);	// make first bit mask
   605     for (int xx=x;;) {
   606      if (flags&TRANS) {
   607       if (b&m) {
   608        if (skip) advance(xx,y);	// set new address only at non-contiguous pixels (for more speed)
   609        skip=false;
   610        writeW(fc);		// set pixel to foreground color at X/Y
   611       }else skip=true;
   612      }else writeW(b&m?fc:bc);	// set pixel (always)
   613      startbit++;			// track bit where we are
   614      if (!--xx) break;		// end of line
   615      m>>=1;			// next bit in mask
   616      if (!m) {			// if emptied...
   617       b=pgm_read_byte(++data);	// load next byte
   618       m=0x80;			// set next mask bit (MSB)
   619       startbit-=8;		// should be 0
   620      }
   621     }
   622     startbit+=bitsperline;	// startbit can be 0..8 inclusive(!) at loop exit
   623     data+=startbit>>3;		// prepate for next line
   624     startbit&=7;
   625  #ifndef DISP_SETXY
   626     skip=true;
   627  #endif
   628    }while(--y);
   629    unsetWindow();
   630    DISP_CS(1);
   631   }//else drawCircle(100,100,80);
   632   advance();
   633  }
   634  
   635  // HiColor-Version, vom Massenspeicher (Live-JPG-Dekompressor?)
   636  void UTFT::bitblt(FILE*f, int wordsperline) {
   637   if (clipX() && clipY()) {
   638    int x=XC;
   639    int y=YC;
   640    if (x||y) {
   641     if (orient&8) SWAP(x,y);
   642     myseek(f,y*wordsperline+x<<1);	// correct source pointer
   643    }
   644    x=W;
   645    y=H;
   646    if (orient&8) SWAP(x,y);
   647    wordsperline-=x;		// now: skip words at end (should be >=0!)
   648    wordsperline<<=1;		// now: skip bytes at end
   649    bool skip=false;
   650    DISP_CS(0);
   651    setWindow(0xF0|orient>>3&7);	// make clipped window current
   652    do{		// iterate over source's y (lines)
   653     int xx=x;
   654     do{		// iterate over source's x (pixels)
   655      word w=mygetw(f);		// cannot handle EOF here
   656      if (flags&TRANS) {
   657       if (w==bc) skip=true;
   658       else{
   659        if (skip) advance(xx,y);	// set new address _only_ at non-contiguous pixels (for more speed)
   660        skip=false;
   661        goto w;
   662       }
   663      }else w: writeW(w);		// set pixel (always)
   664     }while(--xx);
   665     if (wordsperline) myseek(f,wordsperline);	// next line
   666    }while(--y);
   667    unsetWindow();
   668    DISP_CS(1);
   669   }//else drawCircle(120,120,80);
   670   advance();
   671  }
   672  
   673  void UTFT::bitblt(const word*w, int wordsperline) {
   674   FILE f;
   675   fdev_setup_stream(&f,0,0,_FDEV_SETUP_READ|__SSTR|__SPGM);
   676   f.len=(int)w;
   677   bitblt(&f,wordsperline);
   678  }
   679  
   680  /*********************************
   681   * Hardware-independent graphics *
   682   *********************************/
   683   
   684  /*==== clipping ====*/
   685  
   686  void UTFT::setClip(int l, int t, int r, int b) {
   687   if (flags&MOVE) {
   688    l+=XO; t+=YO; r+=XO; b+=YO;
   689    flags&=~MOVE;
   690   }
   691   if (l<0) l=0;
   692   if (t<0) t=0;
   693   int e=getDisplayXSize()-1;
   694   if (r>e) r=e;
   695   e=getDisplayYSize()-1;
   696   if (b>e) b=e;
   697   clip.L=l; clip.T=t; clip.R=r; clip.B=b;
   698  }
   699  
   700  bool UTFT::clipX() {
   701   int o=clip.L-L;
   702   XC=0;
   703   if (o>0) {L=clip.L; XC=o;}
   704   if (R>clip.R) R=clip.R;
   705   return (W=R-L+1)>0;	// new width, return true when not empty
   706  }
   707  
   708  bool UTFT::clipOk() const{	// checks point inside clipping area
   709   return clip.L<=X && X<=clip.R && clip.T<=Y && Y<=clip.B;
   710  }
   711  
   712  /*==== position calculation ====*/
   713  
   714  void UTFT::setOrg(int x, int y) {
   715   if (flags&MOVE) {
   716    XO+=x; YO+=y;
   717    flags&=~MOVE;		// one-time flag!
   718   }else XO=x, YO=y;
   719  }
   720  
   721  void UTFT::gotoXY(int x,int y) {
   722   if (flags&MOVE) {
   723    X+=x;
   724    Y+=y;
   725    flags&=~MOVE;		// one-time flag!
   726   }else X=x+XO, Y=y+YO;
   727  }
   728  
   729  void UTFT::targetXY(int x,int y) {
   730   if (flags&MOVE) {
   731    XE=X+x;
   732    YE=Y+y;
   733    flags&=~MOVE;		// one-time flag!
   734   }else XE=x+XO, YE=y+YO;
   735  }
   736  
   737  void UTFT::calcRectX() {
   738   int w=XE-X;
   739   R=(w<0?(L=XE)+(W=-w):(L=X)+(W=w))-1; // W never negative
   740  }
   741  
   742  // remove a limiting bitblt window; CS must be 0
   743  void UTFT::unsetWindow() {
   744   L=clip.L; T=clip.T; R=clip.R; B=clip.B;
   745  #ifdef DISP_SETXY
   746   setWindow(0xC0);
   747  #endif
   748  }
   749  
   750  /*==== points and lines ====*/
   751  
   752  void UTFT::drawPixel() {
   753   DISP_CS(0);
   754   setPixel();
   755   DISP_CS(1);
   756  }
   757  
   758  void UTFT::lineTo(int x, int y) {
   759   targetXY(x,y);
   760   calcRect();	// calculate W and H
   761   if (!W) {
   762    R=L; B+=flags&ENDPIX; goto fr;
   763   }else if (!H) {
   764    B=T; R+=flags&ENDPIX; fr:
   765    fillRect();	// clip and draw
   766    X=XE;
   767    Y=YE;
   768   }else{
   769    int xs=XE<X?-1:1;
   770    int ys=YE<Y?-1:1;
   771    int err=W-H;
   772    DISP_CS(0);
   773    for(;X!=XE || Y!=YE;) {
   774     setPixel();		// clip and draw using DISPLAY X/Y coordinate
   775     int e2=err<<1;
   776     if (e2+H>0) err-=H, X+=xs;
   777     if (e2<W)   err+=W, Y+=ys;
   778    }
   779    if (flags&ENDPIX) setPixel();
   780    DISP_CS(1);
   781   }
   782  }
   783  
   784  /*==== outline figures ====*/
   785  
   786  void UTFT::drawRect(int x1, int y1, int x2, int y2, int w) {
   787   if (x1>x2) SWAP(x1,x2);
   788   if (y1>y2) SWAP(y1,y2);
   789   flags&=~MOVE;
   790   if (x1+w+w>=x2 || y1+w+w>=y2) {
   791    fillRect(x1,y1,x2,y2);	// nicht offen
   792   }else{
   793    fillRect(x1,y1,x1+w,y2-w);	// links
   794    fillRect(x1+w,y1,x2,y1+w);	// oben
   795    fillRect(x2-w,y1+w,x2,y2);	// rechts
   796    fillRect(x1,y2-w,x2-w,y2);	// unten
   797   }
   798  }
   799  
   800  void UTFT::drawRoundRect(int x1, int y1, int x2, int y2, int) {
   801   if (x1>x2) SWAP(x1,x2);
   802   if (y1>y2) SWAP(y1,y2);
   803   int w=x2-x1;	// stets >=0
   804   int h=y2-y1;
   805   if ((unsigned)w>=4 && (unsigned)h>=4) {
   806    drawPixel(x1+1,y1+1);
   807    drawPixel(x2-2,y1+1);
   808    drawPixel(x1+1,y2-2);
   809    drawPixel(x2-2,y2-2);
   810    drawHLine(x1+2,y1,w-4);
   811    drawHLine(x1+2,y2-1,w-4);
   812    drawVLine(x1,y1+2,h-4);
   813    drawVLine(x2-1,y1+2,h-4);
   814   }
   815  }
   816  
   817  void UTFT::drawCircle(int x, int y, int radius) {
   818   int f = 1 - radius;
   819   int ddF_x = 1;
   820   int ddF_y = -2 * radius;
   821   int x1 = 0;
   822   int y1 = radius;
   823   
   824   DISP_CS(0);
   825   flags&=~MOVE;
   826   setPixel(x,y+radius);
   827   setPixel(x,y-radius);
   828   setPixel(x+radius,y);
   829   setPixel(x-radius,y);
   830   
   831   while(x1 < y1) {
   832    if (f>=0) {
   833     y1--;
   834     ddF_y += 2;
   835     f += ddF_y;
   836    }
   837    x1++;
   838    ddF_x += 2;
   839    f += ddF_x;    
   840    setPixel(x+x1,y+y1);
   841    setPixel(x-x1,y+y1);
   842    setPixel(x+x1,y-y1);
   843    setPixel(x-x1,y-y1);
   844    setPixel(x+y1,y+x1);
   845    setPixel(x-y1,y+x1);
   846    setPixel(x+y1,y-x1);
   847    setPixel(x-y1,y-x1);
   848   }
   849   DISP_CS(1);
   850  }
   851  
   852  void UTFT::drawPoly(const POINT*p,int n) {
   853   gotoXY(p[n-1].x,p[n-1].y);
   854   for (int i=0; i<n; i++) lineTo(p[i].x,p[i].y);
   855  }
   856  
   857  /*==== filled figures ====*/
   858  
   859  void UTFT::fillRect() {
   860   if (clipX() && clipY()) {
   861    DISP_CS(0);
   862    setWindow(0xF0);	// no specific fill direction
   863    fillW(fc,W,H);
   864    unsetWindow();
   865    DISP_CS(1);
   866   }
   867  }
   868  
   869  void UTFT::fillRoundRect(int x1, int y1, int x2, int y2, int) {
   870   if (x1>x2) SWAP(x1,x2);
   871   if (y1>y2) SWAP(y1,y2);
   872   int w=x2-x1;	// stets >=0
   873   int h=y2-y1;
   874   if ((unsigned)w>=4 && (unsigned)h>=4) {
   875    drawHLine(x1+2,y1,w-4);
   876    drawHLine(x1+1,y1+1,w-2);
   877    fillRectW(x1,y1+2,w,h-4);
   878    drawHLine(x1+1,y2-2,w-2);
   879    drawHLine(x1+2,y2-1,w-4);
   880   }
   881  }
   882  
   883  void UTFT::fillCircle(int x, int y, int radius) {
   884   flags&=~MOVE;
   885   for (int y1=-radius; y1<=0; y1++) 
   886     for (int x1=-radius; x1<=0; x1++)
   887     if (x1*x1+y1*y1 <= radius*radius) {
   888    drawHLine(x+x1, y+y1, 2*(-x1));
   889    drawHLine(x+x1, y-y1, 2*(-x1));
   890    break;
   891   }
   892  }
   893  
   894  void UTFT::fillScr(word color) {
   895   DISP_CS(0);
   896   unsetWindow();
   897   setWindow(0xF0);
   898  // setXY(L,T,orient);
   899   fillW(color,DISP_X_SIZE,DISP_Y_SIZE);
   900   DISP_CS(1);
   901  }
   902  
   903  /*==== character output ====*/
   904  
   905  const wchar_t*wcschr_P(const wchar_t*p,wchar_t c) {
   906   for(;;p++) {
   907    wchar_t v=pgm_read_word(p);
   908    if (v==c) return p;
   909    if (!v) return 0;
   910   }
   911  }
   912  
   913  static wchar_t uni2cp1252(wchar_t c) {
   914  // Generiert die Kodepositionen 0x80..0x9F
   915   static const PROGMEM wchar_t codes[]=
   916     L"€ ‚ƒ„…†‡ˆ‰Š‹Œ Ž "
   917     L" ‘’“”•–—˜™š›œ žŸ";
   918   if (c>128) {
   919    const wchar_t*p=wcschr_P(codes,c);
   920    if (p) c=0x80+p-codes;
   921   }
   922   return c;
   923  }
   924  
   925  void UTFT::print(wchar_t c) {
   926   if (flags&COOKED) {
   927    if (c=='\n') {
   928     byte o=orient;
   929     o^=o>>3;	// include font rotation and character direction
   930     o^=o>>5&6;	// include string escapement
   931     if (o&1) {	// rotated screen ^ rotated font
   932      Y=YO;
   933      if (o&2) X-=cfont.cy; else X+=cfont.cy;
   934     }else{
   935      X=XO;
   936      if (o&4) Y-=cfont.cy; else Y+=cfont.cy;
   937     }
   938     return;
   939    }
   940   }
   941   c=uni2cp1252(c);
   942   if (c<cfont.first || c>=cfont.first+cfont.count) c='?';
   943   c-=cfont.first;
   944   int bitsperline=0;
   945   int startbit=0;
   946   char cx=cfont.cx;
   947   char cy=cfont.cy;
   948   const byte*addr=cfont.bits;
   949   if (cx<=0) {			// propotional font
   950    char w=0;
   951    if (cx==-16) {
   952     for (wchar_t i=0;i<cfont.count;i++) {
   953      byte n=pgm_read_byte(addr++); // width of this character
   954      if (i==c) {
   955       startbit=bitsperline;	// take that snapshot
   956       w=n;
   957      }
   958      bitsperline+=n;		// sum all widths
   959     }
   960    }else{
   961     for (wchar_t i=0;;) {
   962      byte b=pgm_read_byte(addr++);
   963      for (byte m=0; m<2; m++) {
   964       byte n=(b&15)-cx;		// width of this character
   965       if (i==c) {
   966        startbit=bitsperline;	// take that snapshot
   967        w=n;
   968       }
   969       bitsperline+=n;		// sum the widths
   970       b>>=4;
   971       if (++i==cfont.count) goto exi;
   972      }
   973     }
   974    }
   975  exi: cx=w;
   976  #ifdef DEBUG
   977    deb1=w;
   978    deb2=bitsperline;
   979  #endif
   980   }else{
   981    bitsperline=cfont.cx+7&~7;
   982    addr+=(byte)c*((byte)bitsperline>>3)*cy;
   983   }
   984   if (orient&8) SWAP(cx,cy);	// rotate target character cell (more precisely, flip on main diagonal)
   985   if (orient&16) cx=-cx;	// reflect character cell towards left
   986   if (orient&32) cy=-cy;	// reflect character cell towards top
   987   targetWH(cx,cy);
   988   calcRect();			// generate character cell
   989   bitblt(addr,bitsperline,startbit);
   990  }
   991  
   992  void UTFT::realign(int textlen) {
   993   if (align&0x0F) {		// horizontal
   994    if (align&2) textlen>>=1;	// zentrieren
   995    if (orient&8) {		// TODO: Operationen prüfen/korrigieren
   996     if (orient&0x20) Y+=textlen; else Y-=textlen;
   997    }else{
   998     if (orient&0x10) X+=textlen; else X-=textlen;
   999    }
  1000   }
  1001  }
  1002  
  1003  void UTFT::print(const char *s) {
  1004   realign(align&0x0F?getTextExtent(s):0);
  1005   for(;;) {
  1006    wchar_t c=take_wchar(s);
  1007    if (!c) break;
  1008    print(c);
  1009   }
  1010  }
  1011  void UTFT::print(const __FlashString*s) {
  1012   realign(align&0x0F?getTextExtent(s):0);
  1013   for(;;) {
  1014    wchar_t c=take_wchar(s);
  1015    if (!c) break;
  1016    print(c);
  1017   }
  1018  }
  1019  
  1020  int UTFT::getTextExtent(wchar_t c) {
  1021   int ext=cfont.cx;
  1022   if (ext>0) return ext;	// return constant for monospaced font
  1023   if (c<cfont.first || c+cfont.first>=cfont.count) c='?';
  1024   c-=cfont.first;
  1025   if (ext==-16) {	// Byte-Angaben
  1026    return pgm_read_byte(cfont.bits+c);
  1027   }else{			// Nibble-Angaben
  1028    byte b=pgm_read_byte(cfont.bits+(c>>1));
  1029    if (c&1) b>>=4;	// use high nibble
  1030    return (b&15)-ext;	// "add" the minimum character width
  1031   }
  1032  }
  1033  int UTFT::getTextExtent(const char *s) {
  1034   int ext=0;
  1035   for(;;) {
  1036    wchar_t c=take_wchar(s);
  1037    if (!c) break;
  1038    ext+=getTextExtent(c);
  1039   }
  1040   return ext;
  1041  }
  1042  int UTFT::getTextExtent(const __FlashString*s) {
  1043   int ext=0;
  1044   for(;;) {
  1045    wchar_t c=take_wchar(s);
  1046    if (!c) break;
  1047    ext+=getTextExtent(c);
  1048   }
  1049   return ext;
  1050  }
  1051  #ifdef DISP_PRINTF
  1052  int UTFT::sendByte(char b, FILE*f) {
  1053   return reinterpret_cast<UTFT*>(f->get)->print(b),0;
  1054  }
  1055  void UTFT::vprintf(const char*fmt,va_list args) {
  1056   FILE f;
  1057   fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
  1058   vfprintf(&f,fmt,args);
  1059  }
  1060  void UTFT::printf(const char*fmt,...) {
  1061   va_list va;
  1062   va_start(va,fmt);
  1063   vprintf(fmt,va);
  1064   va_end(va);
  1065  }
  1066  void UTFT::vprintf(const __FlashString*fmt,va_list args) {
  1067   FILE f;
  1068   fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
  1069   vfprintf_P(&f,reinterpret_cast<const char*>(fmt),args);
  1070  }
  1071  void UTFT::printf(const __FlashString*fmt,...) {
  1072   va_list va;
  1073   va_start(va,fmt);
  1074   vprintf(fmt,va);
  1075   va_end(va);
  1076  }
  1077  #endif
  1078  
  1079  void UTFT::setFont(const byte*font) {
  1080   cfont.cx=pgm_read_byte(font++);
  1081   cfont.cy=pgm_read_byte(font++);
  1082   cfont.first=pgm_read_byte(font++);
  1083   cfont.count=pgm_read_byte(font++);
  1084   cfont.bits=font;
  1085  }
  1086  
Detected encoding: UTF-80