x9e with horus bt module (#5214)
[opentx.git] / radio / src / tests / lcd.cpp
blob195879fd89bf9069ab8fc001d396f67607be3ccc
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include <QtCore/QDir>
22 #include <QtCore/QDebug>
23 #include <QApplication>
24 #include <QPainter>
25 #include <math.h>
26 #include <gtest/gtest.h>
28 #define SWAP_DEFINED
29 #include "opentx.h"
30 #include "location.h"
31 #include "targets/simu/simulcd.h"
33 void doPaint(QPainter & p)
35 QRgb rgb = qRgb(161, 161, 161);
37 p.setBackground(QBrush(rgb));
38 p.eraseRect(0, 0, LCD_W, LCD_H);
40 if (1) {
41 #if LCD_W < 212
42 rgb = qRgb(0, 0, 0);
43 p.setPen(rgb);
44 p.setBrush(QBrush(rgb));
45 #endif
47 #if LCD_W >= 212
48 unsigned int previousDepth = 0xFF;
49 #endif
51 for (int y=0; y<LCD_H; y++) {
52 #if LCD_W >= 212
53 unsigned int idx = (y/2) * LCD_W;
54 #else
55 unsigned int idx = (y/8) * LCD_W;
56 unsigned int mask = (1 << (y%8));
57 #endif
58 for (int x=0; x<LCD_W; x++, idx++) {
59 #if LCD_W < 212
60 if (simuLcdBuf[idx] & mask) {
61 p.drawPoint(x, y);
63 #else
64 unsigned int z = (y & 1) ? (simuLcdBuf[idx] >> 4) : (simuLcdBuf[idx] & 0x0F);
65 if (z) {
66 if (z != previousDepth) {
67 previousDepth = z;
68 rgb = qRgb(161-(z*161)/15, 161-(z*161)/15, 161-(z*161)/15);
69 p.setPen(rgb);
70 p.setBrush(QBrush(rgb));
72 p.drawPoint(x, y);
74 #endif
80 bool checkScreenshot(const QString & test)
82 lcdRefresh();
83 QImage buffer(LCD_W, LCD_H, QImage::Format_RGB32);
84 QPainter p(&buffer);
85 doPaint(p);
86 QString filename(QString("%1_%2x%3.png").arg(test).arg(LCD_W).arg(LCD_H));
87 QImage reference(TESTS_PATH "/tests/" + filename);
89 if (buffer == reference) {
90 return true;
92 else {
93 QString filename(QString("%1_%2x%3.png").arg(test).arg(LCD_W).arg(LCD_H));
94 buffer.save("/tmp/" + filename);
95 return false;
99 #if defined(COLORLCD)
100 // TODO
101 #else
102 #if defined(PCBTARANIS) && LCD_W >= 212
103 TEST(outdezNAtt, test_unsigned)
105 lcdClear();
106 lcdDrawNumber(0, 0, 65530, LEFT);
107 EXPECT_TRUE(checkScreenshot("unsigned")) << "Unsigned numbers will be bad displayed";
109 #elif defined(CPUARM) && LCD_W <= 128
110 TEST(outdezNAtt, test_unsigned)
112 lcdClear();
113 lcdDrawNumber(0, 0, 65530, LEFT|UNSIGN);
114 EXPECT_TRUE(checkScreenshot("arm_unsigned")) << "Unsigned numbers will be bad displayed";
116 #else
117 TEST(outdezNAtt, test_unsigned)
119 lcdClear();
120 lcdDrawNumber(0, 0, 65530, LEFT|UNSIGN);
121 EXPECT_TRUE(checkScreenshot("unsigned")) << "Unsigned numbers will be bad displayed";
123 #endif
125 #if defined(CPUARM)
126 TEST(outdezNAtt, testBigNumbers)
128 lcdClear();
129 lcdDrawNumber(0, 0, 1234567, LEFT);
130 lcdDrawNumber(0, FH, -1234567, LEFT);
131 EXPECT_TRUE(checkScreenshot("big_numbers"));
133 #endif // #if defined(CPUARM)
135 TEST(Lcd, Invers_0_0)
137 lcdClear();
138 lcdDrawText(0, 0, "Test", INVERS);
139 EXPECT_TRUE(checkScreenshot("invers_0_0"));
142 TEST(Lcd, Invers_0_1)
144 lcdClear();
145 lcdDrawText(0, 1, "Test", INVERS);
146 EXPECT_TRUE(checkScreenshot("invers_0_1"));
149 TEST(Lcd, Prec2_Left)
151 lcdClear();
152 lcdDrawNumber(0, 0, 2, PREC2|LEFT);
153 EXPECT_TRUE(checkScreenshot("prec2_left"));
156 TEST(Lcd, Prec2_Right)
158 lcdClear();
159 lcdDrawNumber(LCD_W, LCD_H-FH, 2, PREC2|RIGHT);
160 EXPECT_TRUE(checkScreenshot("prec2_right"));
163 #if defined(CPUARM)
164 TEST(Lcd, Prec1_Dblsize_Invers)
166 lcdClear();
167 lcdDrawNumber(LCD_W, 10, 51, PREC1|DBLSIZE|INVERS|RIGHT);
168 EXPECT_TRUE(checkScreenshot("prec1_dblsize_invers"));
170 #endif
172 TEST(Lcd, Line_Wrap)
174 lcdClear();
175 lcdDrawText(LCD_W-10, 0, "TEST");
176 EXPECT_TRUE(checkScreenshot("line_wrap"));
179 TEST(Lcd, DblsizeBottomRight)
181 lcdClear();
182 lcdDrawText(LCD_W-20, LCD_H-16, "TEST", DBLSIZE);
183 EXPECT_TRUE(checkScreenshot("dblsize_bottom_right"));
186 #if defined(CPUARM)
187 TEST(Lcd, Smlsize_drawStringWithIndex)
189 lcdClear();
190 drawStringWithIndex(0, 0, "FM", 0, SMLSIZE);
191 EXPECT_TRUE(checkScreenshot("smlsize_drawstringwithindex"));
193 #endif
195 TEST(Lcd, vline)
197 lcdClear();
198 for (int x=0; x<100; x+=2) {
199 lcdDrawSolidVerticalLine(x, x/2, 12);
201 EXPECT_TRUE(checkScreenshot("vline"));
204 #if defined(CPUARM)
205 TEST(Lcd, vline_x_lt0)
207 lcdClear();
208 lcdDrawSolidVerticalLine(50, -10, 12);
209 lcdDrawSolidVerticalLine(100, -10, 1);
210 EXPECT_TRUE(checkScreenshot("vline_lt0"));
212 #endif
214 #if defined(CPUARM)
215 TEST(Lcd, Smlsize)
217 lcdClear();
218 lcdDrawText(0, 0, "TESTgy,", SMLSIZE);
219 lcdDrawText(10, 22, "TESTgy,", SMLSIZE|INVERS);
220 lcdDrawSolidFilledRect(8, 40, 100, 20);
221 lcdDrawText(10, 42, "TESTgy,", SMLSIZE);
223 bool invert = false;
224 for(int i=0; i<3; i++) {
225 lcdDrawText(40+(4*i), 0+(4*i), "ABC", SMLSIZE|(invert?INVERS:0));
226 invert = !invert;
229 EXPECT_TRUE(checkScreenshot("smlsize"));
232 TEST(Lcd, Stdsize)
234 lcdClear();
235 lcdDrawText(0, 0, "TEST", 0);
236 lcdDrawText(10, 22, "TEST", INVERS);
237 lcdDrawSolidFilledRect(8, 40, 100, 20);
238 lcdDrawText(10, 42, "TEST", 0);
240 bool invert = false;
241 for(int i=0; i<3; i++) {
242 lcdDrawText(40+(4*i), 0+(4*i), "ABC", (invert?INVERS:0));
243 invert = !invert;
246 EXPECT_TRUE(checkScreenshot("stdsize"));
249 TEST(Lcd, Midsize)
251 lcdClear();
252 lcdDrawText(0, 0, "TEST", MIDSIZE);
253 lcdDrawText(10, 22, "TEST", MIDSIZE|INVERS);
254 lcdDrawSolidFilledRect(8, 40, 100, 20);
255 lcdDrawText(10, 42, "TEST", MIDSIZE);
257 bool invert = false;
258 for(int i=0; i<3; i++) {
259 lcdDrawText(40+(4*i), 0+(4*i), "ABC", MIDSIZE|(invert?INVERS:0));
260 invert = !invert;
263 EXPECT_TRUE(checkScreenshot("midsize"));
266 TEST(Lcd, Dblsize)
268 lcdClear();
269 lcdDrawText(2, 10, "TST", DBLSIZE);
270 lcdDrawText(42, 10, "TST", DBLSIZE|INVERS);
271 lcdDrawSolidFilledRect(80, 8, 46, 24);
272 lcdDrawText(82, 10, "TST", DBLSIZE);
274 bool invert = false;
275 for(int i=0; i<3; i++) {
276 lcdDrawText(10+(4*i), 30+(4*i), "ABC", DBLSIZE|(invert?INVERS:0));
277 invert = !invert;
280 EXPECT_TRUE(checkScreenshot("dblsize"));
282 #endif
284 #if defined(PCBTARANIS) && LCD_W >= 212
285 TEST(Lcd, DrawSwitch)
287 lcdClear();
288 drawSwitch(0, 10, SWSRC_SA0, 0);
289 drawSwitch(30, 10, SWSRC_SA0, SMLSIZE);
290 // drawSwitch(60, 10, SWSRC_SA0, MIDSIZE); missing arrows in this font
291 drawSwitch(90, 10, SWSRC_SA0, DBLSIZE);
292 EXPECT_TRUE(checkScreenshot("drawswitch"));
294 #endif
296 #if defined(PCBTARANIS) && LCD_W >= 212
297 TEST(Lcd, BMPWrapping)
299 lcdClear();
300 uint8_t bitmap[2+40*40/2];
301 lcdLoadBitmap(bitmap, TESTS_PATH "/tests/plane.bmp", 40, 40);
302 lcdDrawBitmap(200, 0, bitmap);
303 lcdDrawBitmap(200, 60, bitmap);
304 lcdDrawBitmap(240, 60, bitmap); // x too big
305 lcdDrawBitmap(20, 200, bitmap); // y too big
306 EXPECT_TRUE(checkScreenshot("bmpwrapping"));
308 #endif
310 #if defined(PCBTARANIS) && LCD_W >= 212
311 TEST(Lcd, lcdDrawHorizontalLine)
313 lcdClear();
314 lcdDrawHorizontalLine(0, 10, LCD_W, DOTTED);
315 lcdDrawHorizontalLine(0, 20, LCD_W, SOLID);
316 lcdDrawHorizontalLine(50, 30, LCD_W, 0xEE); //too wide
317 lcdDrawHorizontalLine(50, LCD_H + 10, 20, SOLID); //too low
318 lcdDrawHorizontalLine(250, 30, LCD_W, SOLID); //x outside display
319 EXPECT_TRUE(checkScreenshot("lcdDrawHorizontalLine"));
321 #endif
323 #if defined(PCBTARANIS) && LCD_W >= 212
324 TEST(Lcd, lcdDrawVerticalLine)
326 lcdClear();
327 lcdDrawVerticalLine(10, 0, LCD_H, DOTTED);
328 lcdDrawVerticalLine(20, 0, LCD_H, SOLID);
329 lcdDrawVerticalLine(30, 30, LCD_H, 0xEE); //too high
330 lcdDrawVerticalLine(40, LCD_H + 10, 20, SOLID); //too low
331 lcdDrawVerticalLine(250, LCD_H + 10, LCD_H, SOLID); //x outside display
332 EXPECT_TRUE(checkScreenshot("lcdDrawVerticalLine"));
334 #endif
336 template <int padding> class TestBuffer
338 private:
339 uint8_t * buf;
340 uint32_t size;
341 public:
342 TestBuffer(uint32_t size) : buf(0), size(size) {
343 buf = new uint8_t[size + padding * 2];
344 memset(buf, 0xA5, padding);
345 memset(buf+padding, 0x00, size);
346 memset(buf+padding+size, 0x5A, padding);
348 ~TestBuffer() { if (buf) delete[] buf; };
349 uint8_t * buffer() { return buf + padding; };
350 void leakCheck() const {
351 uint8_t paddingCompareBuf[padding];
352 memset(paddingCompareBuf, 0xA5, padding);
353 if (memcmp(buf, paddingCompareBuf, padding) != 0) {
354 ADD_FAILURE() << "buffer leaked low";
356 memset(paddingCompareBuf, 0x5A, padding);
357 if (memcmp(buf+padding+size, paddingCompareBuf, padding) != 0) {
358 ADD_FAILURE() << "buffer leaked high";
363 #if defined(PCBTARANIS) && LCD_W >= 212
364 TEST(Lcd, lcdDrawBitmapLoadAndDisplay)
366 lcdClear();
367 // Test proper BMP files, they should display correctly
369 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(7, 32));
370 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_7x32.bmp", 7, 32) != NULL);
371 bitmap.leakCheck();
372 lcdDrawBitmap(10, 2, bitmap.buffer());
375 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(6, 32));
376 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_6x32.bmp", 6, 32) != NULL);
377 bitmap.leakCheck();
378 lcdDrawBitmap(20, 2, bitmap.buffer());
381 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(31, 31));
382 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_31x31.bmp", 31, 31) != NULL);
383 bitmap.leakCheck();
384 lcdDrawBitmap(30, 2, bitmap.buffer());
387 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(39, 32));
388 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 39, 32) != NULL);
389 bitmap.leakCheck();
390 lcdDrawBitmap(70, 2, bitmap.buffer());
393 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(20, 20));
394 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_20x20.bmp", 20, 20) != NULL);
395 bitmap.leakCheck();
396 lcdDrawBitmap(120, 2, bitmap.buffer());
398 EXPECT_TRUE(checkScreenshot("lcdDrawBitmapLoadAndDisplay"));
400 // Test various bad BMP files, they should not display
402 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(LCD_W+1, 32));
403 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), "", LCD_W+1, 32) == NULL) << "to wide";
404 bitmap.leakCheck();
407 TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(10, 10));
408 EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 10, 10) == NULL) << "to small buffer";
409 bitmap.leakCheck();
412 #endif
414 #if defined(PCBTARANIS)
416 void drawDiamond(int x, int y, int size)
418 int x1 = x - size;
419 int x2 = x;
420 int x3 = x + size;
422 int y1 = y - size;
423 int y2 = y;
424 int y3 = y + size;
426 lcdDrawLine( x1, y2, x2, y1, SOLID, FORCE);
427 lcdDrawLine( x2, y1, x3, y2, SOLID, FORCE);
428 lcdDrawLine( x3, y2, x2, y3, SOLID, FORCE);
429 lcdDrawLine( x2, y3, x1, y2, SOLID, FORCE);
432 TEST(Lcd, lcdDrawLine)
434 int start, length, xOffset;
435 uint8_t pattern;
437 lcdClear();
439 start = 2;
440 pattern = SOLID;
441 length = 40;
442 xOffset = 0;
443 lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0);
444 lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0);
446 start = 4;
447 pattern = DOTTED;
448 length = 40;
449 xOffset = 0;
450 lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0);
451 lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0);
453 start = 56;
454 pattern = SOLID;
455 length = -40;
456 xOffset = 65;
457 lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0);
458 lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0);
460 start = 54;
461 pattern = DOTTED;
462 length = -40;
463 xOffset = 65;
464 lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0);
465 lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0);
467 // 45 deg lines
468 lcdDrawLine( 25, 30, 35, 30, SOLID, FORCE );
469 lcdDrawLine( 30, 25, 30, 35, SOLID, FORCE );
471 drawDiamond(30, 30, 10);
472 drawDiamond(30, 30, 20);
474 // slanted lines
475 lcdDrawLine( 60, 10, 100, 10, SOLID, FORCE );
476 lcdDrawLine( 60, 10, 100, 20, SOLID, FORCE );
477 lcdDrawLine( 60, 10, 100, 30, SOLID, FORCE );
478 lcdDrawLine( 60, 10, 100, 40, SOLID, FORCE );
479 lcdDrawLine( 60, 10, 100, 50, SOLID, FORCE );
481 lcdDrawLine( 60, 10, 100, 50, SOLID, FORCE );
482 lcdDrawLine( 60, 10, 90, 50, SOLID, FORCE );
483 lcdDrawLine( 60, 10, 80, 50, SOLID, FORCE );
484 lcdDrawLine( 60, 10, 70, 50, SOLID, FORCE );
485 lcdDrawLine( 60, 10, 60, 50, SOLID, FORCE );
487 EXPECT_TRUE(checkScreenshot("lcdDrawLine"));
489 #endif
490 #endif