Sun, 24 Nov 2019 16:44:00 +0100
Version 0.3.7. The WiFi task uses the new event handlers. Cooling temperature top is now 45 instead of 30 degreees for pitching Kveik. One extra cosmetic message during OTA update.
0 | 1 | /* TFT module |
2 | * | |
3 | * Author: LoBo (loboris@gmail.com, loboris.github) | |
4 | * | |
5 | * Module supporting SPI TFT displays based on ILI9341 & ILI9488 controllers | |
6 | */ | |
7 | ||
8 | #include <stdio.h> | |
9 | #include <errno.h> | |
10 | #include <sys/stat.h> | |
11 | #include <string.h> | |
12 | #include "freertos/FreeRTOS.h" | |
13 | #include "freertos/task.h" | |
14 | #include "esp_system.h" | |
15 | #include "tft.h" | |
16 | #include "time.h" | |
17 | #include <math.h> | |
38
537ffe280775
Removed the noVNC code and web pages.
Michiel Broek <mbroek@mbse.eu>
parents:
29
diff
changeset
|
18 | #include "esp32/rom/tjpgd.h" |
0 | 19 | #include "esp_heap_caps.h" |
20 | #include "tftspi.h" | |
21 | ||
22 | #define DEG_TO_RAD 0.01745329252 | |
23 | #define RAD_TO_DEG 57.295779513 | |
24 | #define deg_to_rad 0.01745329252 + 3.14159265359 | |
25 | #define swap(a, b) { int16_t t = a; a = b; b = t; } | |
26 | #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) | |
27 | #if !defined(max) | |
28 | #define max(A,B) ( (A) > (B) ? (A):(B)) | |
29 | #endif | |
30 | #if !defined(min) | |
31 | #define min(A,B) ( (A) < (B) ? (A):(B)) | |
32 | #endif | |
33 | ||
34 | // Embedded fonts | |
35 | extern uint8_t tft_SmallFont[]; | |
36 | extern uint8_t tft_DefaultFont[]; | |
37 | extern uint8_t tft_Dejavu18[]; | |
38 | extern uint8_t tft_Dejavu24[]; | |
39 | extern uint8_t tft_Ubuntu16[]; | |
40 | extern uint8_t tft_Comic24[]; | |
41 | extern uint8_t tft_minya24[]; | |
42 | extern uint8_t tft_tooney32[]; | |
43 | extern uint8_t tft_def_small[]; | |
44 | ||
45 | // ==== Color definitions constants ============== | |
29 | 46 | const color_t TFT_BLACK = { 0, 0, 0 }; ///< Black |
47 | const color_t TFT_NAVY = { 0, 0, 128 }; ///< Navy blue | |
48 | const color_t TFT_DARKGREEN = { 0, 128, 0 }; ///< Dark green | |
49 | const color_t TFT_DARKCYAN = { 0, 128, 128 }; ///< Dark cyan | |
50 | const color_t TFT_MAROON = { 128, 0, 0 }; ///< Maroon red | |
51 | const color_t TFT_PURPLE = { 128, 0, 128 }; ///< Purple | |
52 | const color_t TFT_OLIVE = { 128, 128, 0 }; ///< Olive | |
53 | const color_t TFT_LIGHTGREY = { 192, 192, 192 }; ///< Light gray | |
54 | const color_t TFT_DARKGREY = { 128, 128, 128 }; ///< Dark gray | |
55 | const color_t TFT_BLUE = { 0, 0, 255 }; ///< Blue | |
56 | const color_t TFT_GREEN = { 0, 255, 0 }; ///< Green | |
57 | const color_t TFT_CYAN = { 0, 255, 255 }; ///< Cyan | |
58 | const color_t TFT_RED = { 255, 0, 0 }; ///< Red | |
59 | const color_t TFT_MAGENTA = { 255, 0, 255 }; ///< Magenta | |
60 | const color_t TFT_YELLOW = { 255, 255, 0 }; ///< Yellow | |
61 | const color_t TFT_WHITE = { 255, 255, 255 }; ///< White | |
62 | const color_t TFT_ORANGE = { 255, 164, 0 }; ///< Orange | |
63 | const color_t TFT_GREENYELLOW = { 172, 255, 44 }; ///< Green-yellow | |
64 | const color_t TFT_PINK = { 255, 192, 202 }; ///< Pink | |
0 | 65 | // =============================================== |
66 | ||
67 | // ============================================================== | |
68 | // ==== Set default values of global variables ================== | |
69 | uint8_t orientation = LANDSCAPE;// screen orientation | |
70 | uint16_t font_rotate = 0; // font rotation | |
71 | uint8_t font_transparent = 0; | |
72 | uint8_t font_forceFixed = 0; | |
73 | uint8_t text_wrap = 0; // character wrapping to new line | |
74 | color_t _fg = { 0, 255, 0}; | |
75 | color_t _bg = { 0, 0, 0}; | |
76 | uint8_t image_debug = 0; | |
77 | ||
78 | float _angleOffset = DEFAULT_ANGLE_OFFSET; | |
79 | ||
80 | int TFT_X = 0; | |
81 | int TFT_Y = 0; | |
82 | ||
83 | uint16_t tp_xleft = 300; | |
84 | uint16_t tp_xright = 3550; | |
85 | uint16_t tp_ytop = 3800; | |
86 | uint16_t tp_ybottom = 300; | |
87 | ||
88 | dispWin_t dispWin = { | |
89 | .x1 = 0, | |
90 | .y1 = 0, | |
91 | .x2 = DEFAULT_TFT_DISPLAY_WIDTH -1, | |
92 | .y2 = DEFAULT_TFT_DISPLAY_HEIGHT -1, | |
93 | }; | |
94 | ||
95 | Font cfont = { | |
96 | .font = tft_DefaultFont, | |
97 | .x_size = 0, | |
98 | .y_size = 0x0B, | |
99 | .offset = 0, | |
100 | .numchars = 95, | |
101 | .bitmap = 1, | |
102 | }; | |
103 | ||
104 | uint8_t font_buffered_char = 1; | |
105 | uint8_t font_line_space = 0; | |
106 | // ============================================================== | |
107 | ||
108 | ||
109 | typedef struct { | |
110 | uint8_t charCode; | |
111 | int adjYOffset; | |
112 | int width; | |
113 | int height; | |
114 | int xOffset; | |
115 | int xDelta; | |
116 | uint16_t dataPtr; | |
117 | } propFont; | |
118 | ||
119 | static dispWin_t dispWinTemp; | |
120 | ||
121 | static uint8_t *userfont = NULL; | |
122 | static int TFT_OFFSET = 0; | |
123 | static propFont fontChar; | |
124 | ||
125 | ||
126 | // ========================================================================= | |
127 | // ** All drawings are clipped to 'dispWin' ** | |
128 | // ** All x,y coordinates in public functions are relative to clip window ** | |
129 | // =========== : Public functions | |
130 | // ----------- : Local functions | |
131 | // ========================================================================= | |
132 | ||
133 | ||
134 | // draw color pixel on screen | |
135 | //------------------------------------------------------------------------ | |
136 | static void _drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { | |
137 | ||
138 | if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; | |
139 | drawPixel(x, y, color, sel); | |
140 | } | |
141 | ||
142 | //==================================================================== | |
143 | void TFT_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { | |
144 | ||
145 | _drawPixel(x+dispWin.x1, y+dispWin.y1, color, sel); | |
146 | } | |
147 | ||
148 | //=========================================== | |
149 | color_t TFT_readPixel(int16_t x, int16_t y) { | |
150 | ||
151 | if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return TFT_BLACK; | |
152 | ||
153 | return readPixel(x, y); | |
154 | } | |
155 | ||
156 | //-------------------------------------------------------------------------- | |
157 | static void _drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { | |
158 | // clipping | |
159 | if ((x < dispWin.x1) || (x > dispWin.x2) || (y > dispWin.y2)) return; | |
160 | if (y < dispWin.y1) { | |
161 | h -= (dispWin.y1 - y); | |
162 | y = dispWin.y1; | |
163 | } | |
164 | if (h < 0) h = 0; | |
165 | if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; | |
166 | if (h == 0) h = 1; | |
167 | TFT_pushColorRep(x, y, x, y+h-1, color, (uint32_t)h); | |
168 | } | |
169 | ||
170 | //-------------------------------------------------------------------------- | |
171 | static void _drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { | |
172 | // clipping | |
173 | if ((y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; | |
174 | if (x < dispWin.x1) { | |
175 | w -= (dispWin.x1 - x); | |
176 | x = dispWin.x1; | |
177 | } | |
178 | if (w < 0) w = 0; | |
179 | if ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1; | |
180 | if (w == 0) w = 1; | |
181 | ||
182 | TFT_pushColorRep(x, y, x+w-1, y, color, (uint32_t)w); | |
183 | } | |
184 | ||
185 | //====================================================================== | |
186 | void TFT_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { | |
187 | _drawFastVLine(x+dispWin.x1, y+dispWin.y1, h, color); | |
188 | } | |
189 | ||
190 | //====================================================================== | |
191 | void TFT_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { | |
192 | _drawFastHLine(x+dispWin.x1, y+dispWin.y1, w, color); | |
193 | } | |
194 | ||
195 | // Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer this uses | |
196 | // the eficient FastH/V Line draw routine for segments of 2 pixels or more | |
197 | //---------------------------------------------------------------------------------- | |
198 | static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) | |
199 | { | |
200 | if (x0 == x1) { | |
201 | if (y0 <= y1) _drawFastVLine(x0, y0, y1-y0, color); | |
202 | else _drawFastVLine(x0, y1, y0-y1, color); | |
203 | return; | |
204 | } | |
205 | if (y0 == y1) { | |
206 | if (x0 <= x1) _drawFastHLine(x0, y0, x1-x0, color); | |
207 | else _drawFastHLine(x1, y0, x0-x1, color); | |
208 | return; | |
209 | } | |
210 | ||
211 | int steep = 0; | |
212 | if (abs(y1 - y0) > abs(x1 - x0)) steep = 1; | |
213 | if (steep) { | |
214 | swap(x0, y0); | |
215 | swap(x1, y1); | |
216 | } | |
217 | if (x0 > x1) { | |
218 | swap(x0, x1); | |
219 | swap(y0, y1); | |
220 | } | |
221 | ||
222 | int16_t dx = x1 - x0, dy = abs(y1 - y0); | |
223 | int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0; | |
224 | ||
225 | if (y0 < y1) ystep = 1; | |
226 | ||
227 | // Split into steep and not steep for FastH/V separation | |
228 | if (steep) { | |
229 | for (; x0 <= x1; x0++) { | |
230 | dlen++; | |
231 | err -= dy; | |
232 | if (err < 0) { | |
233 | err += dx; | |
234 | if (dlen == 1) _drawPixel(y0, xs, color, 1); | |
235 | else _drawFastVLine(y0, xs, dlen, color); | |
236 | dlen = 0; y0 += ystep; xs = x0 + 1; | |
237 | } | |
238 | } | |
239 | if (dlen) _drawFastVLine(y0, xs, dlen, color); | |
240 | } | |
241 | else | |
242 | { | |
243 | for (; x0 <= x1; x0++) { | |
244 | dlen++; | |
245 | err -= dy; | |
246 | if (err < 0) { | |
247 | err += dx; | |
248 | if (dlen == 1) _drawPixel(xs, y0, color, 1); | |
249 | else _drawFastHLine(xs, y0, dlen, color); | |
250 | dlen = 0; y0 += ystep; xs = x0 + 1; | |
251 | } | |
252 | } | |
253 | if (dlen) _drawFastHLine(xs, y0, dlen, color); | |
254 | } | |
255 | } | |
256 | ||
257 | //============================================================================== | |
258 | void TFT_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) | |
259 | { | |
260 | _drawLine(x0+dispWin.x1, y0+dispWin.y1, x1+dispWin.x1, y1+dispWin.y1, color); | |
261 | } | |
262 | ||
263 | // fill a rectangle | |
264 | //-------------------------------------------------------------------------------- | |
265 | static void _fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { | |
266 | // clipping | |
267 | if ((x >= dispWin.x2) || (y > dispWin.y2)) return; | |
268 | ||
269 | if (x < dispWin.x1) { | |
270 | w -= (dispWin.x1 - x); | |
271 | x = dispWin.x1; | |
272 | } | |
273 | if (y < dispWin.y1) { | |
274 | h -= (dispWin.y1 - y); | |
275 | y = dispWin.y1; | |
276 | } | |
277 | if (w < 0) w = 0; | |
278 | if (h < 0) h = 0; | |
279 | ||
280 | if ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1; | |
281 | if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; | |
282 | if (w == 0) w = 1; | |
283 | if (h == 0) h = 1; | |
284 | TFT_pushColorRep(x, y, x+w-1, y+h-1, color, (uint32_t)(h*w)); | |
285 | } | |
286 | ||
287 | //============================================================================ | |
288 | void TFT_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { | |
289 | _fillRect(x+dispWin.x1, y+dispWin.y1, w, h, color); | |
290 | } | |
291 | ||
292 | //================================== | |
293 | void TFT_fillScreen(color_t color) { | |
294 | TFT_pushColorRep(0, 0, _width-1, _height-1, color, (uint32_t)(_height*_width)); | |
295 | } | |
296 | ||
297 | //================================== | |
298 | void TFT_fillWindow(color_t color) { | |
299 | TFT_pushColorRep(dispWin.x1, dispWin.y1, dispWin.x2, dispWin.y2, | |
300 | color, (uint32_t)((dispWin.x2-dispWin.x1+1) * (dispWin.y2-dispWin.y1+1))); | |
301 | } | |
302 | ||
303 | // ^^^============= Basics drawing functions ================================^^^ | |
304 | ||
305 | ||
306 | // ================ Graphics drawing functions ================================== | |
307 | ||
308 | //----------------------------------------------------------------------------------- | |
309 | static void _drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { | |
310 | _drawFastHLine(x1,y1,w, color); | |
311 | _drawFastVLine(x1+w-1,y1,h, color); | |
312 | _drawFastHLine(x1,y1+h-1,w, color); | |
313 | _drawFastVLine(x1,y1,h, color); | |
314 | } | |
315 | ||
316 | //=============================================================================== | |
317 | void TFT_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { | |
318 | _drawRect(x1+dispWin.x1, y1+dispWin.y1, w, h, color); | |
319 | } | |
320 | ||
321 | //------------------------------------------------------------------------------------------------- | |
322 | static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, color_t color) | |
323 | { | |
324 | int16_t f = 1 - r; | |
325 | int16_t ddF_x = 1; | |
326 | int16_t ddF_y = -2 * r; | |
327 | int16_t x = 0; | |
328 | int16_t y = r; | |
329 | ||
330 | disp_select(); | |
331 | while (x < y) { | |
332 | if (f >= 0) { | |
333 | y--; | |
334 | ddF_y += 2; | |
335 | f += ddF_y; | |
336 | } | |
337 | x++; | |
338 | ddF_x += 2; | |
339 | f += ddF_x; | |
340 | if (cornername & 0x4) { | |
341 | _drawPixel(x0 + x, y0 + y, color, 0); | |
342 | _drawPixel(x0 + y, y0 + x, color, 0); | |
343 | } | |
344 | if (cornername & 0x2) { | |
345 | _drawPixel(x0 + x, y0 - y, color, 0); | |
346 | _drawPixel(x0 + y, y0 - x, color, 0); | |
347 | } | |
348 | if (cornername & 0x8) { | |
349 | _drawPixel(x0 - y, y0 + x, color, 0); | |
350 | _drawPixel(x0 - x, y0 + y, color, 0); | |
351 | } | |
352 | if (cornername & 0x1) { | |
353 | _drawPixel(x0 - y, y0 - x, color, 0); | |
354 | _drawPixel(x0 - x, y0 - y, color, 0); | |
355 | } | |
356 | } | |
357 | disp_deselect(); | |
358 | } | |
359 | ||
360 | // Used to do circles and roundrects | |
361 | //---------------------------------------------------------------------------------------------------------------- | |
362 | static void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, color_t color) | |
363 | { | |
364 | int16_t f = 1 - r; | |
365 | int16_t ddF_x = 1; | |
366 | int16_t ddF_y = -2 * r; | |
367 | int16_t x = 0; | |
368 | int16_t y = r; | |
369 | int16_t ylm = x0 - r; | |
370 | ||
371 | while (x < y) { | |
372 | if (f >= 0) { | |
373 | if (cornername & 0x1) _drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color); | |
374 | if (cornername & 0x2) _drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color); | |
375 | ylm = x0 - y; | |
376 | y--; | |
377 | ddF_y += 2; | |
378 | f += ddF_y; | |
379 | } | |
380 | x++; | |
381 | ddF_x += 2; | |
382 | f += ddF_x; | |
383 | ||
384 | if ((x0 - x) > ylm) { | |
385 | if (cornername & 0x1) _drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color); | |
386 | if (cornername & 0x2) _drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color); | |
387 | } | |
388 | } | |
389 | } | |
390 | ||
391 | // Draw a rounded rectangle | |
392 | //============================================================================================= | |
393 | void TFT_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) | |
394 | { | |
395 | x += dispWin.x1; | |
396 | y += dispWin.y1; | |
397 | ||
398 | // smarter version | |
399 | _drawFastHLine(x + r, y, w - 2 * r, color); // Top | |
400 | _drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom | |
401 | _drawFastVLine(x, y + r, h - 2 * r, color); // Left | |
402 | _drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right | |
403 | ||
404 | // draw four corners | |
405 | drawCircleHelper(x + r, y + r, r, 1, color); | |
406 | drawCircleHelper(x + w - r - 1, y + r, r, 2, color); | |
407 | drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); | |
408 | drawCircleHelper(x + r, y + h - r - 1, r, 8, color); | |
409 | } | |
410 | ||
411 | // Fill a rounded rectangle | |
412 | //============================================================================================= | |
413 | void TFT_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) | |
414 | { | |
415 | x += dispWin.x1; | |
416 | y += dispWin.y1; | |
417 | ||
418 | // smarter version | |
419 | _fillRect(x + r, y, w - 2 * r, h, color); | |
420 | ||
421 | // draw four corners | |
422 | fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); | |
423 | fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); | |
424 | } | |
425 | ||
426 | ||
427 | ||
428 | ||
429 | //----------------------------------------------------------------------------------------------- | |
430 | ||
431 | // Draw a triangle | |
432 | //-------------------------------------------------------------------------------------------------------------------- | |
433 | static void _drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) | |
434 | { | |
435 | _drawLine(x0, y0, x1, y1, color); | |
436 | _drawLine(x1, y1, x2, y2, color); | |
437 | _drawLine(x2, y2, x0, y0, color); | |
438 | } | |
439 | ||
440 | // Fill a triangle | |
441 | //-------------------------------------------------------------------------------------------------------------------- | |
442 | static void _fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) | |
443 | { | |
444 | int16_t a, b, y, last; | |
445 | ||
446 | // Sort coordinates by Y order (y2 >= y1 >= y0) | |
447 | if (y0 > y1) { | |
448 | swap(y0, y1); swap(x0, x1); | |
449 | } | |
450 | if (y1 > y2) { | |
451 | swap(y2, y1); swap(x2, x1); | |
452 | } | |
453 | if (y0 > y1) { | |
454 | swap(y0, y1); swap(x0, x1); | |
455 | } | |
456 | ||
457 | if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing | |
458 | a = b = x0; | |
459 | if(x1 < a) a = x1; | |
460 | else if(x1 > b) b = x1; | |
461 | if(x2 < a) a = x2; | |
462 | else if(x2 > b) b = x2; | |
463 | _drawFastHLine(a, y0, b-a+1, color); | |
464 | return; | |
465 | } | |
466 | ||
467 | int16_t | |
468 | dx01 = x1 - x0, | |
469 | dy01 = y1 - y0, | |
470 | dx02 = x2 - x0, | |
471 | dy02 = y2 - y0, | |
472 | dx12 = x2 - x1, | |
473 | dy12 = y2 - y1; | |
474 | int32_t | |
475 | sa = 0, | |
476 | sb = 0; | |
477 | ||
478 | // For upper part of triangle, find scanline crossings for segments | |
479 | // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 | |
480 | // is included here (and second loop will be skipped, avoiding a /0 | |
481 | // error there), otherwise scanline y1 is skipped here and handled | |
482 | // in the second loop...which also avoids a /0 error here if y0=y1 | |
483 | // (flat-topped triangle). | |
484 | if(y1 == y2) last = y1; // Include y1 scanline | |
485 | else last = y1-1; // Skip it | |
486 | ||
487 | for(y=y0; y<=last; y++) { | |
488 | a = x0 + sa / dy01; | |
489 | b = x0 + sb / dy02; | |
490 | sa += dx01; | |
491 | sb += dx02; | |
492 | /* longhand: | |
493 | a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); | |
494 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); | |
495 | */ | |
496 | if(a > b) swap(a,b); | |
497 | _drawFastHLine(a, y, b-a+1, color); | |
498 | } | |
499 | ||
500 | // For lower part of triangle, find scanline crossings for segments | |
501 | // 0-2 and 1-2. This loop is skipped if y1=y2. | |
502 | sa = dx12 * (y - y1); | |
503 | sb = dx02 * (y - y0); | |
504 | for(; y<=y2; y++) { | |
505 | a = x1 + sa / dy12; | |
506 | b = x0 + sb / dy02; | |
507 | sa += dx12; | |
508 | sb += dx02; | |
509 | /* longhand: | |
510 | a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); | |
511 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); | |
512 | */ | |
513 | if(a > b) swap(a,b); | |
514 | _drawFastHLine(a, y, b-a+1, color); | |
515 | } | |
516 | } | |
517 | ||
518 | //==================================================================== | |
519 | void TFT_drawCircle(int16_t x, int16_t y, int radius, color_t color) { | |
520 | x += dispWin.x1; | |
521 | y += dispWin.y1; | |
522 | int f = 1 - radius; | |
523 | int ddF_x = 1; | |
524 | int ddF_y = -2 * radius; | |
525 | int x1 = 0; | |
526 | int y1 = radius; | |
527 | ||
528 | disp_select(); | |
529 | _drawPixel(x, y + radius, color, 0); | |
530 | _drawPixel(x, y - radius, color, 0); | |
531 | _drawPixel(x + radius, y, color, 0); | |
532 | _drawPixel(x - radius, y, color, 0); | |
533 | while(x1 < y1) { | |
534 | if (f >= 0) { | |
535 | y1--; | |
536 | ddF_y += 2; | |
537 | f += ddF_y; | |
538 | } | |
539 | x1++; | |
540 | ddF_x += 2; | |
541 | f += ddF_x; | |
542 | _drawPixel(x + x1, y + y1, color, 0); | |
543 | _drawPixel(x - x1, y + y1, color, 0); | |
544 | _drawPixel(x + x1, y - y1, color, 0); | |
545 | _drawPixel(x - x1, y - y1, color, 0); | |
546 | _drawPixel(x + y1, y + x1, color, 0); | |
547 | _drawPixel(x - y1, y + x1, color, 0); | |
548 | _drawPixel(x + y1, y - x1, color, 0); | |
549 | _drawPixel(x - y1, y - x1, color, 0); | |
550 | } | |
551 | disp_deselect(); | |
552 | } | |
553 | ||
554 | //==================================================================== | |
555 | void TFT_fillCircle(int16_t x, int16_t y, int radius, color_t color) { | |
556 | x += dispWin.x1; | |
557 | y += dispWin.y1; | |
558 | ||
559 | _drawFastVLine(x, y-radius, 2*radius+1, color); | |
560 | fillCircleHelper(x, y, radius, 3, 0, color); | |
561 | } | |
562 | ||
563 | ||
564 | // ================ Font and string functions ================================== | |
565 | ||
566 | //-------------------------------------------------------- | |
567 | static int load_file_font(const char * fontfile, int info) | |
568 | { | |
569 | int err = 0; | |
570 | char err_msg[256] = {'\0'}; | |
571 | ||
572 | if (userfont != NULL) { | |
573 | free(userfont); | |
574 | userfont = NULL; | |
575 | } | |
576 | ||
577 | struct stat sb; | |
578 | ||
579 | // Open the file | |
580 | FILE *fhndl = fopen(fontfile, "r"); | |
581 | if (!fhndl) { | |
582 | sprintf(err_msg, "Error opening font file '%s'", fontfile); | |
583 | err = 1; | |
584 | goto exit; | |
585 | } | |
586 | ||
587 | // Get file size | |
588 | if (stat(fontfile, &sb) != 0) { | |
589 | sprintf(err_msg, "Error getting font file size"); | |
590 | err = 2; | |
591 | goto exit; | |
592 | } | |
593 | int fsize = sb.st_size; | |
594 | if (fsize < 30) { | |
595 | sprintf(err_msg, "Error getting font file size"); | |
596 | err = 3; | |
597 | goto exit; | |
598 | } | |
599 | ||
600 | userfont = malloc(fsize+4); | |
601 | if (userfont == NULL) { | |
602 | sprintf(err_msg, "Font memory allocation error"); | |
603 | fclose(fhndl); | |
604 | err = 4; | |
605 | goto exit; | |
606 | } | |
607 | ||
608 | int read = fread(userfont, 1, fsize, fhndl); | |
609 | ||
610 | fclose(fhndl); | |
611 | ||
612 | if (read != fsize) { | |
613 | sprintf(err_msg, "Font read error"); | |
614 | err = 5; | |
615 | goto exit; | |
616 | } | |
617 | ||
618 | userfont[read] = 0; | |
619 | if (strstr((char *)(userfont+read-8), "RPH_font") == NULL) { | |
620 | sprintf(err_msg, "Font ID not found"); | |
621 | err = 6; | |
622 | goto exit; | |
623 | } | |
624 | ||
625 | // Check size | |
626 | int size = 0; | |
627 | int numchar = 0; | |
628 | int width = userfont[0]; | |
629 | int height = userfont[1]; | |
630 | uint8_t first = 255; | |
631 | uint8_t last = 0; | |
632 | //int offst = 0; | |
633 | int pminwidth = 255; | |
634 | int pmaxwidth = 0; | |
635 | ||
636 | if (width != 0) { | |
637 | // Fixed font | |
638 | numchar = userfont[3]; | |
639 | first = userfont[2]; | |
640 | last = first + numchar - 1; | |
641 | size = ((width * height * numchar) / 8) + 4; | |
642 | } | |
643 | else { | |
644 | // Proportional font | |
645 | size = 4; // point at first char data | |
646 | uint8_t charCode; | |
647 | int charwidth; | |
648 | ||
649 | do { | |
650 | charCode = userfont[size]; | |
651 | charwidth = userfont[size+2]; | |
652 | ||
653 | if (charCode != 0xFF) { | |
654 | numchar++; | |
655 | if (charwidth != 0) size += ((((charwidth * userfont[size+3])-1) / 8) + 7); | |
656 | else size += 6; | |
657 | ||
658 | if (info) { | |
659 | if (charwidth > pmaxwidth) pmaxwidth = charwidth; | |
660 | if (charwidth < pminwidth) pminwidth = charwidth; | |
661 | if (charCode < first) first = charCode; | |
662 | if (charCode > last) last = charCode; | |
663 | } | |
664 | } | |
665 | else size++; | |
666 | } while ((size < (read-8)) && (charCode != 0xFF)); | |
667 | } | |
668 | ||
669 | if (size != (read-8)) { | |
670 | sprintf(err_msg, "Font size error: found %d expected %d)", size, (read-8)); | |
671 | err = 7; | |
672 | goto exit; | |
673 | } | |
674 | ||
675 | if (info) { | |
676 | if (width != 0) { | |
677 | printf("Fixed width font:\r\n size: %d width: %d height: %d characters: %d (%d~%d)\n", | |
678 | size, width, height, numchar, first, last); | |
679 | } | |
680 | else { | |
681 | printf("Proportional font:\r\n size: %d width: %d~%d height: %d characters: %d (%d~%d)\n", | |
682 | size, pminwidth, pmaxwidth, height, numchar, first, last); | |
683 | } | |
684 | } | |
685 | ||
686 | exit: | |
687 | if (err) { | |
688 | if (userfont) { | |
689 | free(userfont); | |
690 | userfont = NULL; | |
691 | } | |
692 | if (info) printf("Error: %d [%s]\r\n", err, err_msg); | |
693 | } | |
694 | return err; | |
695 | } | |
696 | ||
697 | ||
698 | // ----------------------------------------------------------------------------------------- | |
699 | // Individual Proportional Font Character Format: | |
700 | // ----------------------------------------------------------------------------------------- | |
701 | // Character Code | |
702 | // yOffset (start Y of visible pixels) | |
703 | // Width (width of the visible pixels) | |
704 | // Height (height of the visible pixels) | |
705 | // xOffset (start X of visible pixels) | |
706 | // xDelta (the distance to move the cursor. Effective width of the character.) | |
707 | // Data[n] | |
708 | // ----------------------------------------------------------------------------------------- | |
709 | ||
710 | //--------------------------------------------------------------------------------------------- | |
711 | // Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1) | |
712 | // Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) | |
713 | //--------------------------------------------------------------------------------------------- | |
714 | ||
715 | //---------------------------------- | |
716 | ||
717 | // Set max width & height of the proportional font | |
718 | //----------------------------- | |
719 | static void getMaxWidthHeight() | |
720 | { | |
721 | uint16_t tempPtr = 4; // point at first char data | |
722 | uint8_t cc, cw, ch, cd, cy; | |
723 | ||
724 | cfont.numchars = 0; | |
725 | cfont.max_x_size = 0; | |
726 | ||
727 | cc = cfont.font[tempPtr++]; | |
728 | while (cc != 0xFF) { | |
729 | cfont.numchars++; | |
730 | cy = cfont.font[tempPtr++]; | |
731 | cw = cfont.font[tempPtr++]; | |
732 | ch = cfont.font[tempPtr++]; | |
733 | tempPtr++; | |
734 | cd = cfont.font[tempPtr++]; | |
735 | cy += ch; | |
736 | if (cw > cfont.max_x_size) cfont.max_x_size = cw; | |
737 | if (cd > cfont.max_x_size) cfont.max_x_size = cd; | |
738 | if (ch > cfont.y_size) cfont.y_size = ch; | |
739 | if (cy > cfont.y_size) cfont.y_size = cy; | |
740 | if (cw != 0) { | |
741 | // packed bits | |
742 | tempPtr += (((cw * ch)-1) / 8) + 1; | |
743 | } | |
744 | cc = cfont.font[tempPtr++]; | |
745 | } | |
746 | cfont.size = tempPtr; | |
747 | } | |
748 | ||
749 | // Return the Glyph data for an individual character in the proportional font | |
750 | //------------------------------------ | |
751 | static uint8_t getCharPtr(uint8_t c) { | |
752 | uint16_t tempPtr = 4; // point at first char data | |
753 | ||
754 | do { | |
755 | fontChar.charCode = cfont.font[tempPtr++]; | |
756 | if (fontChar.charCode == 0xFF) return 0; | |
757 | ||
758 | fontChar.adjYOffset = cfont.font[tempPtr++]; | |
759 | fontChar.width = cfont.font[tempPtr++]; | |
760 | fontChar.height = cfont.font[tempPtr++]; | |
761 | fontChar.xOffset = cfont.font[tempPtr++]; | |
762 | fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset); | |
763 | fontChar.xDelta = cfont.font[tempPtr++]; | |
764 | ||
765 | if (c != fontChar.charCode && fontChar.charCode != 0xFF) { | |
766 | if (fontChar.width != 0) { | |
767 | // packed bits | |
768 | tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1; | |
769 | } | |
770 | } | |
771 | } while ((c != fontChar.charCode) && (fontChar.charCode != 0xFF)); | |
772 | ||
773 | fontChar.dataPtr = tempPtr; | |
774 | if (c == fontChar.charCode) { | |
775 | if (font_forceFixed > 0) { | |
776 | // fix width & offset for forced fixed width | |
777 | fontChar.xDelta = cfont.max_x_size; | |
778 | fontChar.xOffset = (fontChar.xDelta - fontChar.width) / 2; | |
779 | } | |
780 | } | |
781 | else return 0; | |
782 | ||
783 | return 1; | |
784 | } | |
785 | ||
786 | ||
787 | //=================================================== | |
788 | void TFT_setFont(uint8_t font, const char *font_file) | |
789 | { | |
790 | cfont.font = NULL; | |
791 | ||
792 | if (font == FONT_7SEG) { | |
793 | cfont.bitmap = 2; | |
794 | cfont.x_size = 24; | |
795 | cfont.y_size = 6; | |
796 | cfont.offset = 0; | |
797 | cfont.color = _fg; | |
798 | } else { | |
799 | if (font == USER_FONT) { | |
800 | if (load_file_font(font_file, 0) != 0) | |
801 | cfont.font = tft_DefaultFont; | |
802 | else | |
803 | cfont.font = userfont; | |
804 | } else if (font == DEJAVU18_FONT) | |
805 | cfont.font = tft_Dejavu18; | |
806 | else if (font == DEJAVU24_FONT) | |
807 | cfont.font = tft_Dejavu24; | |
808 | else if (font == UBUNTU16_FONT) | |
809 | cfont.font = tft_Ubuntu16; | |
810 | else if (font == COMIC24_FONT) | |
811 | cfont.font = tft_Comic24; | |
812 | else if (font == MINYA24_FONT) | |
813 | cfont.font = tft_minya24; | |
814 | else if (font == TOONEY32_FONT) | |
815 | cfont.font = tft_tooney32; | |
816 | else if (font == SMALL_FONT) | |
817 | cfont.font = tft_SmallFont; | |
818 | else if (font == DEF_SMALL_FONT) | |
819 | cfont.font = tft_def_small; | |
820 | else | |
821 | cfont.font = tft_DefaultFont; | |
822 | ||
823 | cfont.bitmap = 1; | |
824 | cfont.x_size = cfont.font[0]; | |
825 | cfont.y_size = cfont.font[1]; | |
826 | if (cfont.x_size > 0) { | |
827 | cfont.offset = cfont.font[2]; | |
828 | cfont.numchars = cfont.font[3]; | |
829 | cfont.size = cfont.x_size * cfont.y_size * cfont.numchars; | |
830 | } else { | |
831 | cfont.offset = 4; | |
832 | getMaxWidthHeight(); | |
833 | } | |
834 | //_testFont(); | |
835 | } | |
836 | } | |
837 | ||
838 | ||
839 | ||
840 | // ----------------------------------------------------------------------------------------- | |
841 | // Individual Proportional Font Character Format: | |
842 | // ----------------------------------------------------------------------------------------- | |
843 | // Character Code | |
844 | // yOffset (start Y of visible pixels) | |
845 | // Width (width of the visible pixels) | |
846 | // Height (height of the visible pixels) | |
847 | // xOffset (start X of visible pixels) | |
848 | // xDelta (the distance to move the cursor. Effective width of the character.) | |
849 | // Data[n] | |
850 | // ----------------------------------------------------------------------------------------- | |
851 | //--------------------------------------------------------------------------------------------- | |
852 | // Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1) | |
853 | // Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) | |
854 | //--------------------------------------------------------------------------------------------- | |
855 | ||
856 | // print non-rotated proportional character | |
857 | // character is already in fontChar | |
858 | //---------------------------------------------- | |
859 | static int printProportionalChar(int x, int y) { | |
860 | uint8_t ch = 0; | |
861 | int i, j, char_width; | |
862 | ||
863 | char_width = ((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta); | |
864 | ||
865 | if ((font_buffered_char) && (!font_transparent)) { | |
866 | int len, bufPos; | |
867 | ||
868 | // === buffer Glyph data for faster sending === | |
869 | len = char_width * cfont.y_size; | |
870 | color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); | |
871 | if (color_line) { | |
872 | // fill with background color | |
873 | for (int n = 0; n < len; n++) { | |
874 | color_line[n] = _bg; | |
875 | } | |
876 | // set character pixels to foreground color | |
877 | uint8_t mask = 0x80; | |
878 | for (j = 0; j < fontChar.height; j++) { | |
879 | for (i = 0; i < fontChar.width; i++) { | |
880 | if (((i + (j*fontChar.width)) % 8) == 0) { | |
881 | mask = 0x80; | |
882 | ch = cfont.font[fontChar.dataPtr++]; | |
883 | } | |
884 | if ((ch & mask) != 0) { | |
885 | // visible pixel | |
886 | bufPos = ((j + fontChar.adjYOffset) * char_width) + (fontChar.xOffset + i); // bufY + bufX | |
887 | color_line[bufPos] = _fg; | |
888 | } | |
889 | mask >>= 1; | |
890 | } | |
891 | } | |
892 | // send to display in one transaction | |
893 | disp_select(); | |
894 | send_data(x, y, x+char_width-1, y+cfont.y_size-1, len, color_line); | |
895 | disp_deselect(); | |
896 | free(color_line); | |
897 | ||
898 | return char_width; | |
899 | } | |
900 | } | |
901 | ||
902 | int cx, cy; | |
903 | ||
904 | if (!font_transparent) | |
905 | _fillRect(x, y, char_width+1, cfont.y_size, _bg); | |
906 | ||
907 | // draw Glyph | |
908 | uint8_t mask = 0x80; | |
909 | disp_select(); | |
910 | for (j=0; j < fontChar.height; j++) { | |
911 | for (i=0; i < fontChar.width; i++) { | |
912 | if (((i + (j*fontChar.width)) % 8) == 0) { | |
913 | mask = 0x80; | |
914 | ch = cfont.font[fontChar.dataPtr++]; | |
915 | } | |
916 | ||
917 | if ((ch & mask) !=0) { | |
918 | cx = (uint16_t)(x+fontChar.xOffset+i); | |
919 | cy = (uint16_t)(y+j+fontChar.adjYOffset); | |
920 | _drawPixel(cx, cy, _fg, 0); | |
921 | } | |
922 | mask >>= 1; | |
923 | } | |
924 | } | |
925 | disp_deselect(); | |
926 | ||
927 | return char_width; | |
928 | } | |
929 | ||
930 | ||
931 | ||
932 | // non-rotated fixed width character | |
933 | //---------------------------------------------- | |
934 | static void printChar(uint8_t c, int x, int y) { | |
935 | uint8_t i, j, ch, fz, mask; | |
936 | uint16_t k, temp, cx, cy, len; | |
937 | ||
938 | // fz = bytes per char row | |
939 | fz = cfont.x_size/8; | |
940 | if (cfont.x_size % 8) | |
941 | fz++; | |
942 | ||
943 | // get character position in buffer | |
944 | temp = ((c-cfont.offset)*((fz)*cfont.y_size))+4; | |
945 | ||
946 | if ((font_buffered_char) && (!font_transparent)) { | |
947 | // === buffer Glyph data for faster sending === | |
948 | len = cfont.x_size * cfont.y_size; | |
949 | color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); | |
950 | if (color_line) { | |
951 | // fill with background color | |
952 | for (int n = 0; n < len; n++) { | |
953 | color_line[n] = _bg; | |
954 | } | |
955 | // set character pixels to foreground color | |
956 | for (j = 0; j < cfont.y_size; j++) { | |
957 | for (k = 0; k < fz; k++) { | |
958 | ch = cfont.font[temp + k]; | |
959 | mask = 0x80; | |
960 | for (i = 0; i < 8; i++) { | |
961 | if ((ch & mask) !=0) { | |
962 | color_line[(j*cfont.x_size) + (i+(k*8))] = _fg; | |
963 | } | |
964 | mask >>= 1; | |
965 | } | |
966 | } | |
967 | temp += (fz); | |
968 | } | |
969 | // send to display in one transaction | |
970 | disp_select(); | |
971 | send_data(x, y, x+cfont.x_size-1, y+cfont.y_size-1, len, color_line); | |
972 | disp_deselect(); | |
973 | free(color_line); | |
974 | ||
975 | return; | |
976 | } | |
977 | } | |
978 | ||
979 | if (!font_transparent) | |
980 | _fillRect(x, y, cfont.x_size, cfont.y_size, _bg); | |
981 | ||
982 | disp_select(); | |
983 | for (j = 0; j < cfont.y_size; j++) { | |
984 | for (k = 0; k < fz; k++) { | |
985 | ch = cfont.font[temp + k]; | |
986 | mask = 0x80; | |
987 | for (i = 0; i < 8; i++) { | |
988 | if ((ch & mask) !=0) { | |
989 | cx = (uint16_t)(x+i+(k*8)); | |
990 | cy = (uint16_t)(y+j); | |
991 | _drawPixel(cx, cy, _fg, 0); | |
992 | } | |
993 | mask >>= 1; | |
994 | } | |
995 | } | |
996 | temp += (fz); | |
997 | } | |
998 | disp_deselect(); | |
999 | } | |
1000 | ||
1001 | ||
1002 | ||
1003 | // print rotated proportional character | |
1004 | // character is already in fontChar | |
1005 | //--------------------------------------------------- | |
1006 | static int rotatePropChar(int x, int y, int offset) { | |
1007 | uint8_t ch = 0; | |
1008 | double radian = font_rotate * DEG_TO_RAD; | |
1009 | float cos_radian = cos(radian); | |
1010 | float sin_radian = sin(radian); | |
1011 | ||
1012 | uint8_t mask = 0x80; | |
1013 | disp_select(); | |
1014 | for (int j=0; j < fontChar.height; j++) { | |
1015 | for (int i=0; i < fontChar.width; i++) { | |
1016 | if (((i + (j*fontChar.width)) % 8) == 0) { | |
1017 | mask = 0x80; | |
1018 | ch = cfont.font[fontChar.dataPtr++]; | |
1019 | } | |
1020 | ||
1021 | int newX = (int)(x + (((offset + i) * cos_radian) - ((j+fontChar.adjYOffset)*sin_radian))); | |
1022 | int newY = (int)(y + (((j+fontChar.adjYOffset) * cos_radian) + ((offset + i) * sin_radian))); | |
1023 | ||
1024 | if ((ch & mask) != 0) _drawPixel(newX,newY,_fg, 0); | |
1025 | else if (!font_transparent) _drawPixel(newX,newY,_bg, 0); | |
1026 | ||
1027 | mask >>= 1; | |
1028 | } | |
1029 | } | |
1030 | disp_deselect(); | |
1031 | ||
1032 | return fontChar.xDelta+1; | |
1033 | } | |
1034 | ||
1035 | // rotated fixed width character | |
1036 | //-------------------------------------------------------- | |
1037 | static void rotateChar(uint8_t c, int x, int y, int pos) { | |
1038 | uint8_t i,j,ch,fz,mask; | |
1039 | uint16_t temp; | |
1040 | int newx,newy; | |
1041 | double radian = font_rotate*0.0175; | |
1042 | float cos_radian = cos(radian); | |
1043 | float sin_radian = sin(radian); | |
1044 | int zz; | |
1045 | ||
1046 | if( cfont.x_size < 8 ) fz = cfont.x_size; | |
1047 | else fz = cfont.x_size/8; | |
1048 | temp=((c-cfont.offset)*((fz)*cfont.y_size))+4; | |
1049 | ||
1050 | disp_select(); | |
1051 | for (j=0; j<cfont.y_size; j++) { | |
1052 | for (zz=0; zz<(fz); zz++) { | |
1053 | ch = cfont.font[temp+zz]; | |
1054 | mask = 0x80; | |
1055 | for (i=0; i<8; i++) { | |
1056 | newx=(int)(x+(((i+(zz*8)+(pos*cfont.x_size))*cos_radian)-((j)*sin_radian))); | |
1057 | newy=(int)(y+(((j)*cos_radian)+((i+(zz*8)+(pos*cfont.x_size))*sin_radian))); | |
1058 | ||
1059 | if ((ch & mask) != 0) _drawPixel(newx,newy,_fg, 0); | |
1060 | else if (!font_transparent) _drawPixel(newx,newy,_bg, 0); | |
1061 | mask >>= 1; | |
1062 | } | |
1063 | } | |
1064 | temp+=(fz); | |
1065 | } | |
1066 | disp_deselect(); | |
1067 | // calculate x,y for the next char | |
1068 | TFT_X = (int)(x + ((pos+1) * cfont.x_size * cos_radian)); | |
1069 | TFT_Y = (int)(y + ((pos+1) * cfont.x_size * sin_radian)); | |
1070 | } | |
1071 | ||
1072 | //---------------------- | |
1073 | static int _7seg_width() | |
1074 | { | |
1075 | return (2 * (2 * cfont.y_size + 1)) + cfont.x_size; | |
1076 | } | |
1077 | ||
1078 | //----------------------- | |
1079 | static int _7seg_height() | |
1080 | { | |
1081 | return (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size); | |
1082 | } | |
1083 | ||
1084 | // Returns the string width in pixels. | |
1085 | // Useful for positions strings on the screen. | |
1086 | //=============================== | |
1087 | int TFT_getStringWidth(char* str) | |
1088 | { | |
1089 | int strWidth = 0; | |
1090 | ||
1091 | if (cfont.bitmap == 2) strWidth = ((_7seg_width()+2) * strlen(str)) - 2; // 7-segment font | |
1092 | else if (cfont.x_size != 0) strWidth = strlen(str) * cfont.x_size; // fixed width font | |
1093 | else { | |
1094 | // calculate the width of the string of proportional characters | |
1095 | char* tempStrptr = str; | |
1096 | while (*tempStrptr != 0) { | |
1097 | if (getCharPtr(*tempStrptr++)) { | |
1098 | strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1); | |
1099 | } | |
1100 | } | |
1101 | strWidth--; | |
1102 | } | |
1103 | return strWidth; | |
1104 | } | |
1105 | ||
1106 | //=============================================== | |
1107 | void TFT_clearStringRect(int x, int y, char *str) | |
1108 | { | |
1109 | int w = TFT_getStringWidth(str); | |
1110 | int h = TFT_getfontheight(); | |
1111 | TFT_fillRect(x+dispWin.x1, y+dispWin.y1, w, h, _bg); | |
1112 | } | |
1113 | ||
1114 | //============================================================================== | |
1115 | /** | |
1116 | * bit-encoded bar position of all digits' bcd segments | |
1117 | * | |
1118 | * 6 | |
1119 | * +-----+ | |
1120 | * 3 | . | 2 | |
1121 | * +--5--+ | |
1122 | * 1 | . | 0 | |
1123 | * +--.--+ | |
1124 | * 4 | |
1125 | */ | |
1126 | static const uint16_t font_bcd[] = { | |
1127 | 0x200, // 0010 0000 0000 // - | |
1128 | 0x080, // 0000 1000 0000 // . | |
1129 | 0x06C, // 0100 0110 1100 // /, degree | |
1130 | 0x05f, // 0000 0101 1111, // 0 | |
1131 | 0x005, // 0000 0000 0101, // 1 | |
1132 | 0x076, // 0000 0111 0110, // 2 | |
1133 | 0x075, // 0000 0111 0101, // 3 | |
1134 | 0x02d, // 0000 0010 1101, // 4 | |
1135 | 0x079, // 0000 0111 1001, // 5 | |
1136 | 0x07b, // 0000 0111 1011, // 6 | |
1137 | 0x045, // 0000 0100 0101, // 7 | |
1138 | 0x07f, // 0000 0111 1111, // 8 | |
1139 | 0x07d, // 0000 0111 1101 // 9 | |
1140 | 0x900 // 1001 0000 0000 // : | |
1141 | }; | |
1142 | ||
1143 | //----------------------------------------------------------------------------------------------- | |
1144 | static void barVert(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { | |
1145 | _fillTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, color); | |
1146 | _fillTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, color); | |
1147 | _fillRect(x, y+2*w+1, 2*w+1, l, color); | |
1148 | if (cfont.offset) { | |
1149 | _drawTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, outline); | |
1150 | _drawTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, outline); | |
1151 | _drawRect(x, y+2*w+1, 2*w+1, l, outline); | |
1152 | } | |
1153 | } | |
1154 | ||
1155 | //---------------------------------------------------------------------------------------------- | |
1156 | static void barHor(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { | |
1157 | _fillTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, color); | |
1158 | _fillTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, color); | |
1159 | _fillRect(x+2*w+1, y, l, 2*w+1, color); | |
1160 | if (cfont.offset) { | |
1161 | _drawTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, outline); | |
1162 | _drawTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, outline); | |
1163 | _drawRect(x+2*w+1, y, l, 2*w+1, outline); | |
1164 | } | |
1165 | } | |
1166 | ||
1167 | //-------------------------------------------------------------------------------------------- | |
1168 | static void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, color_t color) { | |
1169 | /* TODO: clipping */ | |
1170 | if (num < 0x2D || num > 0x3A) return; | |
1171 | ||
1172 | int16_t c = font_bcd[num-0x2D]; | |
1173 | int16_t d = 2*w+l+1; | |
1174 | ||
1175 | // === Clear unused segments === | |
1176 | if (!(c & 0x001)) barVert(x+d, y+d, w, l, _bg, _bg); | |
1177 | if (!(c & 0x002)) barVert(x, y+d, w, l, _bg, _bg); | |
1178 | if (!(c & 0x004)) barVert(x+d, y, w, l, _bg, _bg); | |
1179 | if (!(c & 0x008)) barVert(x, y, w, l, _bg, _bg); | |
1180 | if (!(c & 0x010)) barHor(x, y+2*d, w, l, _bg, _bg); | |
1181 | if (!(c & 0x020)) barHor(x, y+d, w, l, _bg, _bg); | |
1182 | if (!(c & 0x040)) barHor(x, y, w, l, _bg, _bg); | |
1183 | ||
1184 | if (!(c & 0x080)) { | |
1185 | // low point | |
1186 | _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg); | |
1187 | if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg); | |
1188 | } | |
1189 | if (!(c & 0x100)) { | |
1190 | // down middle point | |
1191 | _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg); | |
1192 | if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg); | |
1193 | } | |
1194 | if (!(c & 0x800)) { | |
1195 | // up middle point | |
1196 | _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg); | |
1197 | if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg); | |
1198 | } | |
1199 | if (!(c & 0x200)) { | |
1200 | // middle, minus | |
1201 | _fillRect(x+2*w+1, y+d, l, 2*w+1, _bg); | |
1202 | if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, _bg); | |
1203 | } | |
1204 | ||
1205 | // === Draw used segments === | |
1206 | if (c & 0x001) barVert(x+d, y+d, w, l, color, cfont.color); // down right | |
1207 | if (c & 0x002) barVert(x, y+d, w, l, color, cfont.color); // down left | |
1208 | if (c & 0x004) barVert(x+d, y, w, l, color, cfont.color); // up right | |
1209 | if (c & 0x008) barVert(x, y, w, l, color, cfont.color); // up left | |
1210 | if (c & 0x010) barHor(x, y+2*d, w, l, color, cfont.color); // down | |
1211 | if (c & 0x020) barHor(x, y+d, w, l, color, cfont.color); // middle | |
1212 | if (c & 0x040) barHor(x, y, w, l, color, cfont.color); // up | |
1213 | ||
1214 | if (c & 0x080) { | |
1215 | // low point | |
1216 | _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, color); | |
1217 | if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, cfont.color); | |
1218 | } | |
1219 | if (c & 0x100) { | |
1220 | // down middle point | |
1221 | _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, color); | |
1222 | if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, cfont.color); | |
1223 | } | |
1224 | if (c & 0x800) { | |
1225 | // up middle point | |
1226 | _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, color); | |
1227 | if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, cfont.color); | |
1228 | } | |
1229 | if (c & 0x200) { | |
1230 | // middle, minus | |
1231 | _fillRect(x+2*w+1, y+d, l, 2*w+1, color); | |
1232 | if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, cfont.color); | |
1233 | } | |
1234 | } | |
1235 | //============================================================================== | |
1236 | ||
1237 | //====================================== | |
1238 | void TFT_print(char *st, int x, int y) { | |
1239 | int stl, i, tmpw, tmph, fh; | |
1240 | uint8_t ch; | |
1241 | ||
1242 | if (cfont.bitmap == 0) return; // wrong font selected | |
1243 | ||
1244 | // ** Rotated strings cannot be aligned | |
1245 | if ((font_rotate != 0) && ((x <= CENTER) || (y <= CENTER))) return; | |
1246 | ||
1247 | if ((x < LASTX) || (font_rotate == 0)) TFT_OFFSET = 0; | |
1248 | ||
1249 | if ((x >= LASTX) && (x < LASTY)) x = TFT_X + (x-LASTX); | |
1250 | else if (x > CENTER) x += dispWin.x1; | |
1251 | ||
1252 | if (y >= LASTY) y = TFT_Y + (y-LASTY); | |
1253 | else if (y > CENTER) y += dispWin.y1; | |
1254 | ||
1255 | // ** Get number of characters in string to print | |
1256 | stl = strlen(st); | |
1257 | ||
1258 | // ** Calculate CENTER, RIGHT or BOTTOM position | |
1259 | tmpw = TFT_getStringWidth(st); // string width in pixels | |
1260 | fh = cfont.y_size; // font height | |
1261 | if ((cfont.x_size != 0) && (cfont.bitmap == 2)) { | |
1262 | // 7-segment font | |
1263 | fh = (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size); // 7-seg character height | |
1264 | } | |
1265 | ||
1266 | if (x == RIGHT) x = dispWin.x2 - tmpw + dispWin.x1; | |
1267 | else if (x == CENTER) x = (((dispWin.x2 - dispWin.x1 + 1) - tmpw) / 2) + dispWin.x1; | |
1268 | ||
1269 | if (y == BOTTOM) y = dispWin.y2 - fh + dispWin.y1; | |
1270 | else if (y==CENTER) y = (((dispWin.y2 - dispWin.y1 + 1) - (fh/2)) / 2) + dispWin.y1; | |
1271 | ||
1272 | if (x < dispWin.x1) x = dispWin.x1; | |
1273 | if (y < dispWin.y1) y = dispWin.y1; | |
1274 | if ((x > dispWin.x2) || (y > dispWin.y2)) return; | |
1275 | ||
1276 | TFT_X = x; | |
1277 | TFT_Y = y; | |
1278 | ||
1279 | // ** Adjust y position | |
1280 | tmph = cfont.y_size; // font height | |
1281 | // for non-proportional fonts, char width is the same for all chars | |
1282 | tmpw = cfont.x_size; | |
1283 | if (cfont.x_size != 0) { | |
1284 | if (cfont.bitmap == 2) { // 7-segment font | |
1285 | tmpw = _7seg_width(); // character width | |
1286 | tmph = _7seg_height(); // character height | |
1287 | } | |
1288 | } | |
1289 | else TFT_OFFSET = 0; // fixed font; offset not needed | |
1290 | ||
1291 | if ((TFT_Y + tmph - 1) > dispWin.y2) return; | |
1292 | ||
1293 | int offset = TFT_OFFSET; | |
1294 | ||
1295 | for (i=0; i<stl; i++) { | |
1296 | ch = st[i]; // get string character | |
1297 | ||
1298 | if (ch == 0x0D) { // === '\r', erase to eol ==== | |
1299 | if ((!font_transparent) && (font_rotate==0)) _fillRect(TFT_X, TFT_Y, dispWin.x2+1-TFT_X, tmph, _bg); | |
1300 | } | |
1301 | ||
1302 | else if (ch == 0x0A) { // ==== '\n', new line ==== | |
1303 | if (cfont.bitmap == 1) { | |
1304 | TFT_Y += tmph + font_line_space; | |
1305 | if (TFT_Y > (dispWin.y2-tmph)) break; | |
1306 | TFT_X = dispWin.x1; | |
1307 | } | |
1308 | } | |
1309 | ||
1310 | else { // ==== other characters ==== | |
1311 | if (cfont.x_size == 0) { | |
1312 | // for proportional font get character data to 'fontChar' | |
1313 | if (getCharPtr(ch)) tmpw = fontChar.xDelta; | |
1314 | else continue; | |
1315 | } | |
1316 | ||
1317 | // check if character can be displayed in the current line | |
1318 | if ((TFT_X+tmpw) > (dispWin.x2)) { | |
1319 | if (text_wrap == 0) break; | |
1320 | TFT_Y += tmph + font_line_space; | |
1321 | if (TFT_Y > (dispWin.y2-tmph)) break; | |
1322 | TFT_X = dispWin.x1; | |
1323 | } | |
1324 | ||
1325 | // Let's print the character | |
1326 | if (cfont.x_size == 0) { | |
1327 | // == proportional font | |
1328 | if (font_rotate == 0) TFT_X += printProportionalChar(TFT_X, TFT_Y) + 1; | |
1329 | else { | |
1330 | // rotated proportional font | |
1331 | offset += rotatePropChar(x, y, offset); | |
1332 | TFT_OFFSET = offset; | |
1333 | } | |
1334 | } | |
1335 | else { | |
1336 | if (cfont.bitmap == 1) { | |
1337 | // == fixed font | |
1338 | if ((ch < cfont.offset) || ((ch-cfont.offset) > cfont.numchars)) ch = cfont.offset; | |
1339 | if (font_rotate == 0) { | |
1340 | printChar(ch, TFT_X, TFT_Y); | |
1341 | TFT_X += tmpw; | |
1342 | } | |
1343 | else rotateChar(ch, x, y, i); | |
1344 | } | |
1345 | else if (cfont.bitmap == 2) { | |
1346 | // == 7-segment font == | |
1347 | _draw7seg(TFT_X, TFT_Y, ch, cfont.y_size, cfont.x_size, _fg); | |
1348 | TFT_X += (tmpw + 2); | |
1349 | } | |
1350 | } | |
1351 | } | |
1352 | } | |
1353 | } | |
1354 | ||
1355 | ||
1356 | // ================ Service functions ========================================== | |
1357 | ||
1358 | // Change the screen rotation. | |
1359 | // Input: m new rotation value (0 to 3) | |
1360 | //================================= | |
1361 | void TFT_setRotation(uint8_t rot) { | |
1362 | if (rot > 3) { | |
1363 | uint8_t madctl = (rot & 0xF8); // for testing, manually set MADCTL register | |
1364 | if (disp_select() == ESP_OK) { | |
1365 | disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); | |
1366 | disp_deselect(); | |
1367 | } | |
1368 | } | |
1369 | else { | |
1370 | orientation = rot; | |
1371 | _tft_setRotation(rot); | |
1372 | } | |
1373 | ||
1374 | dispWin.x1 = 0; | |
1375 | dispWin.y1 = 0; | |
1376 | dispWin.x2 = _width-1; | |
1377 | dispWin.y2 = _height-1; | |
1378 | ||
1379 | TFT_fillScreen(_bg); | |
1380 | } | |
1381 | ||
1382 | ||
1383 | // Select gamma curve | |
1384 | // Input: gamma = 0~3 | |
1385 | //================================== | |
1386 | void TFT_setGammaCurve(uint8_t gm) { | |
1387 | uint8_t gamma_curve = 1 << (gm & 0x03); | |
1388 | disp_spi_transfer_cmd_data(TFT_CMD_GAMMASET, &gamma_curve, 1); | |
1389 | } | |
1390 | ||
1391 | ||
1392 | //===================================================================== | |
1393 | void TFT_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) | |
1394 | { | |
1395 | dispWin.x1 = x1; | |
1396 | dispWin.y1 = y1; | |
1397 | dispWin.x2 = x2; | |
1398 | dispWin.y2 = y2; | |
1399 | ||
1400 | if (dispWin.x2 >= _width) dispWin.x2 = _width-1; | |
1401 | if (dispWin.y2 >= _height) dispWin.y2 = _height-1; | |
1402 | if (dispWin.x1 > dispWin.x2) dispWin.x1 = dispWin.x2; | |
1403 | if (dispWin.y1 > dispWin.y2) dispWin.y1 = dispWin.y2; | |
1404 | } | |
1405 | ||
1406 | //===================== | |
1407 | void TFT_resetclipwin() | |
1408 | { | |
1409 | dispWin.x2 = _width-1; | |
1410 | dispWin.y2 = _height-1; | |
1411 | dispWin.x1 = 0; | |
1412 | dispWin.y1 = 0; | |
1413 | } | |
1414 | ||
1415 | //========================================================================== | |
1416 | void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color) { | |
1417 | if (cfont.bitmap != 2) return; | |
1418 | ||
1419 | if (l < 6) l = 6; | |
1420 | if (l > 40) l = 40; | |
1421 | if (w < 1) w = 1; | |
1422 | if (w > (l/2)) w = l/2; | |
1423 | if (w > 12) w = 12; | |
1424 | ||
1425 | cfont.x_size = l; | |
1426 | cfont.y_size = w; | |
1427 | cfont.offset = outline; | |
1428 | cfont.color = color; | |
1429 | } | |
1430 | ||
1431 | //========================================== | |
1432 | int TFT_getfontsize(int *width, int* height) | |
1433 | { | |
1434 | if (cfont.bitmap == 1) { | |
1435 | if (cfont.x_size != 0) *width = cfont.x_size; // fixed width font | |
1436 | else *width = cfont.max_x_size; // proportional font | |
1437 | *height = cfont.y_size; | |
1438 | } | |
1439 | else if (cfont.bitmap == 2) { | |
1440 | // 7-segment font | |
1441 | *width = _7seg_width(); | |
1442 | *height = _7seg_height(); | |
1443 | } | |
1444 | else { | |
1445 | *width = 0; | |
1446 | *height = 0; | |
1447 | return 0; | |
1448 | } | |
1449 | return 1; | |
1450 | } | |
1451 | ||
1452 | //===================== | |
1453 | int TFT_getfontheight() | |
1454 | { | |
1455 | if (cfont.bitmap == 1) return cfont.y_size; // Bitmap font | |
1456 | else if (cfont.bitmap == 2) return _7seg_height(); // 7-segment font | |
1457 | return 0; | |
1458 | } | |
1459 | ||
1460 | //==================== | |
1461 | void TFT_saveClipWin() | |
1462 | { | |
1463 | dispWinTemp.x1 = dispWin.x1; | |
1464 | dispWinTemp.y1 = dispWin.y1; | |
1465 | dispWinTemp.x2 = dispWin.x2; | |
1466 | dispWinTemp.y2 = dispWin.y2; | |
1467 | } | |
1468 | ||
1469 | //======================= | |
1470 | void TFT_restoreClipWin() | |
1471 | { | |
1472 | dispWin.x1 = dispWinTemp.x1; | |
1473 | dispWin.y1 = dispWinTemp.y1; | |
1474 | dispWin.x2 = dispWinTemp.x2; | |
1475 | dispWin.y2 = dispWinTemp.y2; | |
1476 | } | |
1477 | ||
1478 | ||
1479 | // ============= Touch panel functions ========================================= | |
1480 | ||
1481 | #if USE_TOUCH == TOUCH_TYPE_XPT2046 | |
1482 | //------------------------------------------------------- | |
1483 | static int tp_get_data_xpt2046(uint8_t type, int samples) | |
1484 | { | |
1485 | if (ts_spi == NULL) return 0; | |
1486 | ||
1487 | int n, result, val = 0; | |
1488 | uint32_t i = 0; | |
1489 | uint32_t vbuf[18]; | |
1490 | uint32_t minval, maxval, dif; | |
1491 | ||
1492 | if (samples < 3) samples = 1; | |
1493 | if (samples > 18) samples = 18; | |
1494 | ||
1495 | // one dummy read | |
1496 | result = touch_get_data(type); | |
1497 | ||
1498 | // read data | |
1499 | while (i < 10) { | |
1500 | minval = 5000; | |
1501 | maxval = 0; | |
1502 | // get values | |
1503 | for (n=0;n<samples;n++) { | |
1504 | result = touch_get_data(type); | |
1505 | if (result < 0) break; | |
1506 | ||
1507 | vbuf[n] = result; | |
1508 | if (result < minval) minval = result; | |
1509 | if (result > maxval) maxval = result; | |
1510 | } | |
1511 | if (result < 0) break; | |
1512 | dif = maxval - minval; | |
1513 | if (dif < 40) break; | |
1514 | i++; | |
1515 | } | |
1516 | if (result < 0) return -1; | |
1517 | ||
1518 | if (samples > 2) { | |
1519 | // remove one min value | |
1520 | for (n = 0; n < samples; n++) { | |
1521 | if (vbuf[n] == minval) { | |
1522 | vbuf[n] = 5000; | |
1523 | break; | |
1524 | } | |
1525 | } | |
1526 | // remove one max value | |
1527 | for (n = 0; n < samples; n++) { | |
1528 | if (vbuf[n] == maxval) { | |
1529 | vbuf[n] = 5000; | |
1530 | break; | |
1531 | } | |
1532 | } | |
1533 | for (n = 0; n < samples; n++) { | |
1534 | if (vbuf[n] < 5000) val += vbuf[n]; | |
1535 | } | |
1536 | val /= (samples-2); | |
1537 | } | |
1538 | else val = vbuf[0]; | |
1539 | ||
1540 | return val; | |
1541 | } | |
1542 | ||
1543 | //----------------------------------------------- | |
1544 | static int TFT_read_touch_xpt2046(int *x, int* y) | |
1545 | { | |
1546 | int res = 0, result = -1; | |
1547 | ||
1548 | if (spi_lobo_device_select(ts_spi, 0) != ESP_OK) | |
1549 | return 0; | |
1550 | ||
1551 | result = tp_get_data_xpt2046(0xB0, 3); // Z; pressure; touch detect | |
1552 | if (result <= 15) goto exit; // Z was 50, but near the origin it's just above 10. | |
1553 | // 26-6-2018 from 10 to 15. | |
1554 | ||
1555 | // touch panel pressed | |
1556 | result = tp_get_data_xpt2046(0xD0, 6); | |
1557 | if (result < 0) goto exit; | |
1558 | *x = result; | |
1559 | ||
1560 | result = tp_get_data_xpt2046(0x90, 6); | |
1561 | if (result < 0) goto exit; | |
1562 | *y = result; | |
1563 | res = 1; | |
1564 | ||
1565 | exit: | |
1566 | spi_lobo_device_deselect(ts_spi); | |
1567 | return res; | |
1568 | } | |
1569 | #endif | |
1570 | ||
1571 | //============================================= | |
1572 | int TFT_read_touch(int *x, int* y, uint8_t raw) | |
1573 | { | |
1574 | *x = 0; | |
1575 | *y = 0; | |
1576 | ||
1577 | if (ts_spi == NULL) | |
1578 | return 0; | |
1579 | #if USE_TOUCH == TOUCH_TYPE_NONE | |
1580 | return 0; | |
1581 | #else | |
1582 | int result = -1; | |
1583 | int X=0, Y=0; | |
1584 | ||
1585 | #if USE_TOUCH == TOUCH_TYPE_XPT2046 | |
1586 | result = TFT_read_touch_xpt2046(&X, &Y); | |
1587 | if (result == 0) | |
1588 | return 0; | |
1589 | #elif USE_TOUCH == TOUCH_TYPE_STMPE610 | |
1590 | uint32_t tp_calx = TP_CALX_STMPE610; | |
1591 | uint32_t tp_caly = TP_CALY_STMPE610; | |
1592 | uint16_t Xx, Yy, Z=0; | |
1593 | result = stmpe610_get_touch(&Xx, &Yy, &Z); | |
1594 | if (result == 0) return 0; | |
1595 | X = Xx; | |
1596 | Y = Yy; | |
1597 | #else | |
1598 | return 0; | |
1599 | #endif | |
1600 | ||
1601 | if (raw) { | |
1602 | *x = X; | |
1603 | *y = Y; | |
1604 | return 1; | |
1605 | } | |
1606 | ||
1607 | // Calibrate the result | |
1608 | int tmp; | |
1609 | int xleft = tp_xleft; //(tp_calx >> 16) & 0x3FFF; | |
1610 | int xright = tp_xright; //tp_calx & 0x3FFF; | |
1611 | int ytop = tp_ytop; //(tp_caly >> 16) & 0x3FFF; | |
1612 | int ybottom = tp_ybottom; //tp_caly & 0x3FFF; | |
1613 | ||
1614 | if (((xright - xleft) <= 0) || ((ytop - ybottom) <= 0)) | |
1615 | return 0; | |
1616 | ||
1617 | #if USE_TOUCH == TOUCH_TYPE_XPT2046 | |
1618 | // printf("Raw %dx%d ", X, Y); | |
1619 | // Received coordinates are always in portrait, origin left bottom. | |
1620 | int width = DEFAULT_TFT_DISPLAY_WIDTH; | |
1621 | int height = DEFAULT_TFT_DISPLAY_HEIGHT; | |
1622 | X = ((X - xleft) * width) / (xright - xleft); | |
1623 | Y = ((Y - ybottom) * height) / (ytop - ybottom); | |
1624 | ||
1625 | if (X < 0) | |
1626 | X = 0; | |
1627 | if (X > width-1) | |
1628 | X = width-1; | |
1629 | if (Y < 0) | |
1630 | Y = 0; | |
1631 | if (Y > height-1) | |
1632 | Y = height-1; | |
1633 | ||
1634 | switch (orientation) { | |
1635 | case PORTRAIT: | |
1636 | Y = height - Y - 1; | |
1637 | break; | |
1638 | case LANDSCAPE: | |
1639 | tmp = X; | |
1640 | X = height - Y - 1; | |
1641 | Y = width - tmp - 1; | |
1642 | break; | |
1643 | case PORTRAIT_FLIP: | |
1644 | X = width - X - 1; | |
1645 | break; | |
1646 | case LANDSCAPE_FLIP: | |
1647 | tmp = X; | |
1648 | X = Y; | |
1649 | Y = tmp; | |
1650 | break; | |
1651 | } | |
1652 | // printf("Cal %dx%d %dx%d XxY %dx%d\n", xleft, ybottom, xright, ytop, X, Y); | |
1653 | #elif USE_TOUCH == TOUCH_TYPE_STMPE610 | |
1654 | int width = _width; | |
1655 | int height = _height; | |
1656 | if (_width > _height) { | |
1657 | width = _height; | |
1658 | height = _width; | |
1659 | } | |
1660 | X = ((X - xleft) * width) / (xright - xleft); | |
1661 | Y = ((Y - ytop) * height) / (ybottom - ytop); | |
1662 | ||
1663 | if (X < 0) X = 0; | |
1664 | if (X > width-1) X = width-1; | |
1665 | if (Y < 0) Y = 0; | |
1666 | if (Y > height-1) Y = height-1; | |
1667 | ||
1668 | switch (orientation) { | |
1669 | case PORTRAIT_FLIP: | |
1670 | X = width - X - 1; | |
1671 | Y = height - Y - 1; | |
1672 | break; | |
1673 | case LANDSCAPE: | |
1674 | tmp = X; | |
1675 | X = Y; | |
1676 | Y = width - tmp -1; | |
1677 | break; | |
1678 | case LANDSCAPE_FLIP: | |
1679 | tmp = X; | |
1680 | X = height - Y -1; | |
1681 | Y = tmp; | |
1682 | break; | |
1683 | } | |
1684 | #endif | |
1685 | *x = X; | |
1686 | *y = Y; | |
1687 | return 1; | |
1688 | #endif | |
1689 | } | |
1690 |