From da5a2d15f74636a2248ce4d178b56085e6c43452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 24 Apr 2019 16:13:07 +0200 Subject: [PATCH] [apps/on_boarding] Power-on self-test POST checks the battery, VBLANK and LCDData --- .../lcd_data_test_controller.cpp | 4 +- apps/on_boarding/Makefile | 1 + apps/on_boarding/logo_controller.cpp | 9 +- apps/on_boarding/logo_controller.h | 2 +- apps/on_boarding/power_on_self_test.cpp | 127 ++++++++++++++++++ apps/on_boarding/power_on_self_test.h | 32 +++++ ion/include/ion/display.h | 3 + ion/src/blackbox/Makefile | 1 + ion/src/device/shared/drivers/display.cpp | 9 +- ion/src/device/shared/drivers/display.h | 4 +- ion/src/emscripten/Makefile | 1 + ion/src/sdl/Makefile | 1 + ion/src/shared/dummy/display.cpp | 4 + ion/src/simulator/Makefile | 1 + 14 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 apps/on_boarding/power_on_self_test.cpp create mode 100644 apps/on_boarding/power_on_self_test.h create mode 100644 ion/src/shared/dummy/display.cpp diff --git a/apps/hardware_test/lcd_data_test_controller.cpp b/apps/hardware_test/lcd_data_test_controller.cpp index 054cb69cd..2474bec79 100644 --- a/apps/hardware_test/lcd_data_test_controller.cpp +++ b/apps/hardware_test/lcd_data_test_controller.cpp @@ -1,5 +1,5 @@ #include "lcd_data_test_controller.h" -#include +#include using namespace Poincare; @@ -106,7 +106,7 @@ int LCDDataTestController::numberOfNonColoredPixels(KDColor wantedColor) { } bool LCDDataTestController::testDisplayBlackWhite() { - Ion::Device::Display::HardwareTestPushBlackWhite(); + Ion::Display::POSTPushBlackWhite(); constexpr int stampHeight = Ion::Display::Height; constexpr int stampWidth = 2; static_assert(Ion::Display::Width % stampWidth == 0, "Stamps must tesselate the display"); diff --git a/apps/on_boarding/Makefile b/apps/on_boarding/Makefile index c013f074e..66e866df9 100644 --- a/apps/on_boarding/Makefile +++ b/apps/on_boarding/Makefile @@ -4,6 +4,7 @@ app_src += $(addprefix apps/on_boarding/,\ logo_controller.cpp \ logo_view.cpp \ pop_up_controller.cpp \ + power_on_self_test.cpp \ ) i18n_files += $(addprefix apps/on_boarding/,\ diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 356fc17c5..9b94cc49e 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -1,6 +1,6 @@ #include "logo_controller.h" +#include "power_on_self_test.h" #include -#include namespace OnBoarding { @@ -12,10 +12,6 @@ LogoController::LogoController() : { } -View * LogoController::view() { - return &m_logoView; -} - bool LogoController::fire() { app()->dismissModalViewController(); return true; @@ -23,8 +19,7 @@ bool LogoController::fire() { void LogoController::viewWillAppear() { ViewController::viewWillAppear(); - m_previousLEDColor = Ion::LED::getColor(); - Ion::LED::setColor(Ion::Battery::level() == Ion::Battery::Charge::FULL ? KDColorGreen : KDColorRed); + m_previousLEDColor = PowerOnSelfTest::Perform(); } void LogoController::viewDidDisappear() { diff --git a/apps/on_boarding/logo_controller.h b/apps/on_boarding/logo_controller.h index 72196e581..47ca7df4d 100644 --- a/apps/on_boarding/logo_controller.h +++ b/apps/on_boarding/logo_controller.h @@ -9,7 +9,7 @@ namespace OnBoarding { class LogoController : public ViewController, public Timer { public: LogoController(); - View * view() override; + View * view() override { return &m_logoView; } void viewWillAppear() override; void viewDidDisappear() override; private: diff --git a/apps/on_boarding/power_on_self_test.cpp b/apps/on_boarding/power_on_self_test.cpp new file mode 100644 index 000000000..483013c17 --- /dev/null +++ b/apps/on_boarding/power_on_self_test.cpp @@ -0,0 +1,127 @@ +#include "power_on_self_test.h" +#include +#include +#include + +namespace OnBoarding { + +KDColor PowerOnSelfTest::Perform() { + KDColor previousLEDColor = Ion::LED::getColor(); + if (!BatteryOK()) { + Ion::LED::setColor(KDColorRed); + } else { + Ion::LED::setColor(KDColorBlue); + /* If VBlank test fails, we end up in an infinite loop and the LED will be + * lit up in blue. */ + if (VBlankOK() && LCDDataOK()) { + Ion::LED::setColor(KDColorGreen); + } + } + return previousLEDColor; +} + +bool PowerOnSelfTest::BatteryOK() { + return Ion::Battery::level() == Ion::Battery::Charge::FULL; +} + +bool PowerOnSelfTest::VBlankOK() { + for (int i=0; i<6; i++) { + Ion::Display::waitForVBlank(); + } + return true; +} + +bool PowerOnSelfTest::LCDDataOK() { + KDColor testColors[] = { + KDColorRed, KDColorGreen, KDColorBlue, + KDColor::RGB24(0xFFFF00), KDColor::RGB24(0xFF00FF), KDColor::RGB24(0x00FFFF), + KDColorWhite, KDColorBlack}; + for (KDColor c : testColors) { + if (!TestDisplayColor(c)) { + return false; + } + } + return TestDisplayBlackWhite(); +} + +void PowerOnSelfTest::ColorPixelBuffer(KDColor * pixels, int numberOfPixels, KDColor c) { + for (int i = 0; i < numberOfPixels; i++) { + pixels[i] = c; + } +} + +bool PowerOnSelfTest::TestDisplayColor(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."); + + KDColor stamp[stampWidth*stampHeight]; + + // Tiling test with pushRect + ColorPixelBuffer(stamp, stampWidth * stampHeight, c); + for (int i = 0; i < Ion::Display::Width / stampWidth; i++) { + for (int j = 0; j < Ion::Display::Height / stampHeight; j++) { + Ion::Display::pushRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); + } + } + if (NumberOfNonColoredPixels(c) > k_invalidPixelsLimit) { + return false; + } + + // Test with pushRectUniform + Ion::Display::pushRectUniform(KDRect(KDPointZero, Ion::Display::Width, Ion::Display::Height), c); + if (NumberOfNonColoredPixels(c) > k_invalidPixelsLimit) { + return false; + } + return true; +} + +int PowerOnSelfTest::NumberOfNonColoredPixels(KDColor wantedColor) { + 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."); + + KDColor stamp[stampWidth*stampHeight]; + + int numberOfInvalidPixels = 0; + for (int i = 0; i < Ion::Display::Width / stampWidth; i++) { + for (int j = 0; j < Ion::Display::Height / stampHeight; j++) { + ColorPixelBuffer(stamp, stampWidth * stampHeight, wantedColor == KDColorBlack ? KDColorRed : KDColorBlack); + Ion::Display::pullRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); + for (int k = 0; k < stampWidth * stampHeight; k++) { + if (stamp[k] != wantedColor) { + numberOfInvalidPixels++; + } + } + } + } + return numberOfInvalidPixels; +} + +bool PowerOnSelfTest::TestDisplayBlackWhite() { + Ion::Display::POSTPushBlackWhite(); + constexpr int stampHeight = Ion::Display::Height; + constexpr int stampWidth = 2; + 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."); + KDColor stamp[stampWidth*stampHeight]; + int numberOfInvalidPixels = 0; + for (int i = 0; i < Ion::Display::Width/stampWidth; i++) { + ColorPixelBuffer(stamp, stampWidth * stampHeight, KDColorRed); + Ion::Display::pullRect(KDRect(i*stampWidth, 0, stampWidth, stampHeight), stamp); + for (int k = 0; k < stampWidth * stampHeight; k++) { + if (stamp[k] != ((k%2 == 0) ? KDColorWhite : KDColorBlack)) { + numberOfInvalidPixels++; + } + } + } + return numberOfInvalidPixels <= k_invalidPixelsLimit; +} + + +} diff --git a/apps/on_boarding/power_on_self_test.h b/apps/on_boarding/power_on_self_test.h new file mode 100644 index 000000000..e22d8d217 --- /dev/null +++ b/apps/on_boarding/power_on_self_test.h @@ -0,0 +1,32 @@ +#ifndef APPS_POWER_ON_SELF_TEST_H +#define APPS_POWER_ON_SELF_TEST_H + +#include + +namespace OnBoarding { + +class PowerOnSelfTest { +public: + /* Performs self tests, lights up the LED to indicate the tests results and + * returns the LED color previous to the tests. */ + static KDColor Perform(); + +private: + constexpr static int k_invalidPixelsLimit = 2; + + // Tests + static bool BatteryOK(); + static bool VBlankOK(); + static bool LCDDataOK(); + + // Test helpers + static bool TestDisplayColor(KDColor c); + static int NumberOfNonColoredPixels(KDColor wantedColor); + static bool TestDisplayBlackWhite(); + static void ColorPixelBuffer(KDColor * pixels, int numberOfPixels, KDColor c); +}; + +} + +#endif + diff --git a/ion/include/ion/display.h b/ion/include/ion/display.h index a43c830cc..88fa48c74 100644 --- a/ion/include/ion/display.h +++ b/ion/include/ion/display.h @@ -23,6 +23,9 @@ void pullRect(KDRect r, KDColor * pixels); void waitForVBlank(); +// For Power On Self Test +void POSTPushBlackWhite(); + constexpr int Width = 320; constexpr int Height = 240; constexpr int WidthInTenthOfMillimeter = 576; diff --git a/ion/src/blackbox/Makefile b/ion/src/blackbox/Makefile index 6835cf65a..9c93b9bf8 100644 --- a/ion/src/blackbox/Makefile +++ b/ion/src/blackbox/Makefile @@ -16,6 +16,7 @@ src += $(addprefix ion/src/shared/, \ timing.cpp \ dummy/backlight.cpp \ dummy/battery.cpp \ + dummy/display.cpp \ dummy/events_modifier.cpp \ dummy/fcc_id.cpp \ dummy/led.cpp \ diff --git a/ion/src/device/shared/drivers/display.cpp b/ion/src/device/shared/drivers/display.cpp index fde47ea4a..a2448c574 100644 --- a/ion/src/device/shared/drivers/display.cpp +++ b/ion/src/device/shared/drivers/display.cpp @@ -55,6 +55,11 @@ void waitForVBlank() { } } +void POSTPushBlackWhite() { + setDrawingArea(KDRect(0,0,Ion::Display::Width, Ion::Display::Height), Orientation::Landscape); + pushBlackWhitePixels(); +} + } } @@ -381,8 +386,7 @@ void pullPixels(KDColor * pixels, size_t numberOfPixels) { send_command(Command::PixelFormatSet, 0x05); } -void HardwareTestPushBlackWhite() { - setDrawingArea(KDRect(0,0,Ion::Display::Width, Ion::Display::Height), Orientation::Landscape); +void pushBlackWhitePixels() { send_command(Command::MemoryWrite); int numberOfPixels = Ion::Display::Width * Ion::Display::Height; while (numberOfPixels--) { @@ -390,6 +394,7 @@ void HardwareTestPushBlackWhite() { } } + } } } diff --git a/ion/src/device/shared/drivers/display.h b/ion/src/device/shared/drivers/display.h index 21d8269a6..516ad3cac 100644 --- a/ion/src/device/shared/drivers/display.h +++ b/ion/src/device/shared/drivers/display.h @@ -62,8 +62,8 @@ constexpr static uint32_t FSMCBankAddress = FSMCBaseAddress + (FSMCMemoryBank-1) static volatile Command * const CommandAddress = (Command *)(FSMCBankAddress); static volatile uint16_t * const DataAddress = (uint16_t *)(FSMCBankAddress | (1<<(FSMCDataCommandAddressBit+1))); -// For hardware test -void HardwareTestPushBlackWhite(); +// For Power On Self tests +void pushBlackWhitePixels(); } } diff --git a/ion/src/emscripten/Makefile b/ion/src/emscripten/Makefile index c697a08cd..950dcb4cb 100644 --- a/ion/src/emscripten/Makefile +++ b/ion/src/emscripten/Makefile @@ -14,6 +14,7 @@ src += $(addprefix ion/src/shared/, \ timing.cpp \ dummy/backlight.cpp \ dummy/battery.cpp \ + dummy/display.cpp \ dummy/fcc_id.cpp \ dummy/led.cpp \ dummy/serial_number.cpp \ diff --git a/ion/src/sdl/Makefile b/ion/src/sdl/Makefile index c54ceca19..ad92e2e34 100644 --- a/ion/src/sdl/Makefile +++ b/ion/src/sdl/Makefile @@ -10,6 +10,7 @@ src += $(addprefix ion/src/shared/, \ timing.cpp \ dummy/backlight.cpp \ dummy/battery.cpp \ + dummy/display.cpp \ dummy/fcc_id.cpp \ dummy/led.cpp \ dummy/serial_number.cpp \ diff --git a/ion/src/shared/dummy/display.cpp b/ion/src/shared/dummy/display.cpp new file mode 100644 index 000000000..62e6e7268 --- /dev/null +++ b/ion/src/shared/dummy/display.cpp @@ -0,0 +1,4 @@ +#include + +void Ion::Display::POSTPushBlackWhite() { +} diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 341258950..748c274bb 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -17,6 +17,7 @@ src += $(addprefix ion/src/shared/, \ timing.cpp \ dummy/backlight.cpp \ dummy/battery.cpp \ + dummy/display.cpp \ dummy/fcc_id.cpp \ dummy/led.cpp \ dummy/serial_number.cpp \