diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 8bf8b992c..0d7b9657e 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -32,13 +32,10 @@ void LogoController::viewWillAppear() { } else { m_didPerformTests = true; m_previousLEDColor = PowerOnSelfTest::Perform(); - /* If EPSILON_ONBOARDING_APP == 1, the backlight is not initialized in - * Ion::Device::Board::initPeripherals, so that the LCD test is not visible to - * the user. We thus need to initialize the backlight after the test. Before, - * we push a white rect on the display to hide redrawing glitches. */ - Ion::Display::pushRectUniform(KDRect(KDPointZero, Ion::Display::Width, Ion::Display::Height), KDColorWhite); - Ion::Timing::msleep(50); } + /* If EPSILON_ONBOARDING_APP == 1, the backlight is not initialized in + * Ion::Device::Board::initPeripherals, so that the LCD test is not visible to + * the user. We thus need to initialize the backlight after the test.*/ if (!backlightInitialized) { Ion::Backlight::init(); } diff --git a/apps/on_boarding/power_on_self_test.cpp b/apps/on_boarding/power_on_self_test.cpp index 7bb3efa1c..3306d453f 100644 --- a/apps/on_boarding/power_on_self_test.cpp +++ b/apps/on_boarding/power_on_self_test.cpp @@ -13,7 +13,7 @@ KDColor PowerOnSelfTest::Perform() { /* If VBlank test fails, we end up in an infinite loop and the LED will be * lit up in blue. */ if (Shared::POSTAndHardwareTests::VBlankOK() - && Shared::POSTAndHardwareTests::LCDDataOK()) + && Shared::POSTAndHardwareTests::FastLCDDataOK()) { Ion::LED::setColor(KDColorGreen); } diff --git a/apps/shared/post_and_hardware_tests.cpp b/apps/shared/post_and_hardware_tests.cpp index 94fc3751e..c1b6a7092 100644 --- a/apps/shared/post_and_hardware_tests.cpp +++ b/apps/shared/post_and_hardware_tests.cpp @@ -11,19 +11,39 @@ bool POSTAndHardwareTests::BatteryOK() { } bool POSTAndHardwareTests::VBlankOK() { - for (int i=0; i<6; i++) { + for (int i=0; i<3; i++) { Ion::Display::waitForVBlank(); } return true; } +bool POSTAndHardwareTests::FastLCDDataOK() { + /* We separate TestDisplayColorTiling and TestDisplayColorUniform so that + * errors in TestDisplayColorUniform do not disappear just because the + * previous screen was all white. */ + if (!TestDisplayColorTiling(KDColorWhite)) { + return false; + } + bool result = TestDisplayMulticolor(); + // We end with a white screen so that the test is invisible for the user. + return TestDisplayColorUniform(KDColorWhite) && result; +} + bool POSTAndHardwareTests::LCDDataOK() { KDColor testColors[] = { KDColorRed, KDColorGreen, KDColorBlue, KDColor::RGB24(0xFFFF00), KDColor::RGB24(0xFF00FF), KDColor::RGB24(0x00FFFF), KDColorWhite, KDColorBlack}; for (KDColor c : testColors) { - if (!TestDisplayColor(c)) { + if (!TestDisplayColorTiling(c)) { + return false; + } + } + /* We separate TestDisplayColorTiling and TestDisplayColorUniform so that + * errors in TestDisplayColorUniform do not disappear just because the + * previous screen was with the same color. */ + for (KDColor c : testColors) { + if (!TestDisplayColorUniform(c)) { return false; } } @@ -36,7 +56,7 @@ void POSTAndHardwareTests::ColorPixelBuffer(KDColor * pixels, int numberOfPixels } } -bool POSTAndHardwareTests::TestDisplayColor(KDColor c) { +bool POSTAndHardwareTests::TestDisplayColorTiling(KDColor c) { constexpr int stampHeight = 10; constexpr int stampWidth = 10; static_assert(Ion::Display::Width % stampWidth == 0, "Stamps must tesselate the display"); @@ -52,16 +72,19 @@ bool POSTAndHardwareTests::TestDisplayColor(KDColor c) { Ion::Display::pushRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); } } - if (NumberOfNonColoredPixels(c) > k_invalidPixelsLimit) { - return false; - } + return NumberOfNonColoredPixels(c) <= k_invalidPixelsLimit; +} + +bool POSTAndHardwareTests::TestDisplayColorUniform(KDColor c) { + constexpr int stampHeight = 10; + constexpr int stampWidth = 10; + static_assert(Ion::Display::Width % stampWidth == 0, "Stamps must tesselate the display"); + static_assert(Ion::Display::Height % stampHeight == 0, "Stamps must tesselate the display"); + static_assert(stampHeight % 2 == 0 || stampWidth % 2 == 0, "Even number of XOR needed."); // Test with pushRectUniform Ion::Display::pushRectUniform(KDRect(KDPointZero, Ion::Display::Width, Ion::Display::Height), c); - if (NumberOfNonColoredPixels(c) > k_invalidPixelsLimit) { - return false; - } - return true; + return NumberOfNonColoredPixels(c) < k_invalidPixelsLimit; } int POSTAndHardwareTests::NumberOfNonColoredPixels(KDColor wantedColor) { @@ -109,4 +132,51 @@ bool POSTAndHardwareTests::TestDisplayBlackWhite() { return numberOfInvalidPixels <= k_invalidPixelsLimit; } +KDColor colorSequence(bool reset) { + static uint16_t currentColor = 0; + if (reset) { + currentColor = 0; + } + return KDColor::RGB16(currentColor--); +} + +bool POSTAndHardwareTests::TestDisplayMulticolor() { + constexpr int stampHeight = 10; + constexpr int stampWidth = 10; + static_assert(Ion::Display::Width % stampWidth == 0, "Stamps must tesselate the display"); + static_assert(Ion::Display::Height % stampHeight == 0, "Stamps must tesselate the display"); + static_assert(stampHeight % 2 == 0 || stampWidth % 2 == 0, "Even number of XOR needed."); + + constexpr int numberOfPixels = stampWidth*stampHeight; + KDColor stamp[numberOfPixels]; + + colorSequence(true); + // Multi-colouring of the display + for (int i = 0; i < Ion::Display::Width / stampWidth; i++) { + for (int j = 0; j < Ion::Display::Height / stampHeight; j++) { + for (int k = 0; k < numberOfPixels; k++) { + stamp[k] = colorSequence(false); + } + Ion::Display::pushRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); + } + } + // Check the data is ok + colorSequence(true); + int numberOfInvalidPixels = 0; + for (int i = 0; i < Ion::Display::Width / stampWidth; i++) { + for (int j = 0; j < Ion::Display::Height / stampHeight; j++) { + Ion::Display::pullRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); + for (int k = 0; k < numberOfPixels; k++) { + if (stamp[k] != colorSequence(false)) { + numberOfInvalidPixels++; + if (numberOfInvalidPixels > k_invalidPixelsLimit) { + return false; + } + } + } + } + } + return true; +} + } diff --git a/apps/shared/post_and_hardware_tests.h b/apps/shared/post_and_hardware_tests.h index f412dc2b0..69ae3e0dd 100644 --- a/apps/shared/post_and_hardware_tests.h +++ b/apps/shared/post_and_hardware_tests.h @@ -9,14 +9,16 @@ class POSTAndHardwareTests { public: static bool BatteryOK(); static bool VBlankOK(); + static bool FastLCDDataOK(); static bool LCDDataOK(); - private: constexpr static int k_invalidPixelsLimit = 2; - static bool TestDisplayColor(KDColor c); + static void ColorPixelBuffer(KDColor * pixels, int numberOfPixels, KDColor c); + static bool TestDisplayColorTiling(KDColor c); + static bool TestDisplayColorUniform(KDColor c); static int NumberOfNonColoredPixels(KDColor wantedColor); static bool TestDisplayBlackWhite(); - static void ColorPixelBuffer(KDColor * pixels, int numberOfPixels, KDColor c); + static bool TestDisplayMulticolor(); }; }