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-8 | 0
|