diff --git a/apps/hardware_test/Makefile b/apps/hardware_test/Makefile index de664ad2c..f072f3df0 100644 --- a/apps/hardware_test/Makefile +++ b/apps/hardware_test/Makefile @@ -5,6 +5,7 @@ app_src += $(addprefix apps/hardware_test/,\ code_128b_view.cpp \ keyboard_test_controller.cpp \ keyboard_view.cpp \ + lcd_data_test_controller.cpp \ led_test_controller.cpp \ pattern.cpp \ pattern_view.cpp \ diff --git a/apps/hardware_test/app.cpp b/apps/hardware_test/app.cpp index 97452b2c2..116c0206d 100644 --- a/apps/hardware_test/app.cpp +++ b/apps/hardware_test/app.cpp @@ -26,6 +26,7 @@ App::WizardViewController::WizardViewController(Responder * parentResponder) : BankViewController(parentResponder), m_keyboardController(this), m_screenTestController(this), + m_lcdDataTestController(this), m_ledTestController(this), m_batteryTestController(this), m_serialNumberController(this), @@ -34,12 +35,13 @@ App::WizardViewController::WizardViewController(Responder * parentResponder) : } int App::WizardViewController::numberOfChildren() { - return 6; + return 7; } ViewController * App::WizardViewController::childAtIndex(int i) { ViewController * children[] = { &m_vBlankTestController, + &m_lcdDataTestController, &m_keyboardController, &m_screenTestController, &m_ledTestController, diff --git a/apps/hardware_test/app.h b/apps/hardware_test/app.h index 58a88cdd7..933ca64d5 100644 --- a/apps/hardware_test/app.h +++ b/apps/hardware_test/app.h @@ -4,6 +4,7 @@ #include #include "keyboard_test_controller.h" #include "screen_test_controller.h" +#include "lcd_data_test_controller.h" #include "led_test_controller.h" #include "battery_test_controller.h" #include "serial_number_controller.h" @@ -30,6 +31,7 @@ private: private: KeyboardTestController m_keyboardController; ScreenTestController m_screenTestController; + LCDDataTestController m_lcdDataTestController; LEDTestController m_ledTestController; BatteryTestController m_batteryTestController; SerialNumberController m_serialNumberController; diff --git a/apps/hardware_test/lcd_data_test_controller.cpp b/apps/hardware_test/lcd_data_test_controller.cpp new file mode 100644 index 000000000..a561cb226 --- /dev/null +++ b/apps/hardware_test/lcd_data_test_controller.cpp @@ -0,0 +1,133 @@ +#include "lcd_data_test_controller.h" +#include + +using namespace Poincare; + +namespace HardwareTest { + +bool LCDDataTestController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::OK && strcmp(m_view.lcdDataStateTextView()->text(), k_lcdDataOKText) == 0) { + // Handled in WizardViewController + return false; + } + return true; +} + +void LCDDataTestController::viewWillAppear() { + bool testOK = test(); + m_view.lcdDataStateTextView()->setText(testOK ? k_lcdDataOKText : k_lcdDataFailTest); + m_view.setColor(testOK ? KDColorGreen : KDColorRed); +} + +LCDDataTestController::ContentView::ContentView() : + SolidColorView(KDColorWhite), + m_lcdDataStateView(KDFont::LargeFont) +{ +} + +void LCDDataTestController::ContentView::setColor(KDColor color) { + SolidColorView::setColor(color); + m_lcdDataStateView.setBackgroundColor(color); +} + +void LCDDataTestController::ContentView::layoutSubviews() { + m_lcdDataStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); +} + + +void colorPixelBuffer(KDColor * pixels, int numberOfPixels, KDColor c) { + for (int i = 0; i < numberOfPixels; i++) { + pixels[i] = c; + } +} +bool LCDDataTestController::test() { + 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(); +} + +bool LCDDataTestController::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]; + + // 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) > invalidPixelsLimit) { + return false; + } + + // Test with pushRectUniform + Ion::Display::pushRectUniform(KDRect(KDPointZero, Ion::Display::Width, Ion::Display::Height), c); + if (numberOfNonColoredPixels(c) > invalidPixelsLimit) { + return false; + } + return true; +} + +int LCDDataTestController::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 LCDDataTestController::testDisplayBlackWhite() { + Ion::Device::Display::HardwareTestPushBlackWhite(); + 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."); +#warning LCD_DATA_hardware_test + // Test the following algo one we have a good screen + KDColor stamp[stampWidth*stampHeight]; + int numberOfInvalidPixels = 0; + for (int i = 0; i < Ion::Display::Width; i++) { + for (int j = 0; j < Ion::Display::Height; j++) { + colorPixelBuffer(stamp, stampWidth * stampHeight, KDColorBlack); + Ion::Display::pullRect(KDRect(i * stampWidth, j * stampHeight, stampWidth, stampHeight), stamp); + for (int k = 0; k < stampWidth * stampHeight; k++) { + if (stamp[k] != (k%2 == 0 ? KDColorBlack : KDColorWhite)) { + numberOfInvalidPixels++; + } + } + } + } + return numberOfInvalidPixels <= invalidPixelsLimit; +} + +} diff --git a/apps/hardware_test/lcd_data_test_controller.h b/apps/hardware_test/lcd_data_test_controller.h new file mode 100644 index 000000000..9643068d9 --- /dev/null +++ b/apps/hardware_test/lcd_data_test_controller.h @@ -0,0 +1,48 @@ +#ifndef LCD_DATA_TEST_CONTROLLER_H +#define LCD_DATA_TEST_CONTROLLER_H + +#include +#include + +namespace HardwareTest { + +class LCDDataTestController : public ViewController { +public: + LCDDataTestController(Responder * parentResponder) : + ViewController(parentResponder), + m_view() + {} + View * view() override { return &m_view; } + bool handleEvent(Ion::Events::Event event) override; + void viewWillAppear() override; +private: + class ContentView : public SolidColorView { + public: + ContentView(); + BufferTextView * lcdDataStateTextView() { return &m_lcdDataStateView; } + void setColor(KDColor color) override; + private: + void layoutSubviews() override; + int numberOfSubviews() const override { return 1; } + View * subviewAtIndex(int index) override { + assert(index == 0); + return &m_lcdDataStateView; + } + BufferTextView m_lcdDataStateView; + }; + constexpr static const char * k_lcdDataOKText = "LCD DATA: OK"; + constexpr static const char * k_lcdDataFailTest = "LCD DATA: FAIL"; + constexpr static int invalidPixelsLimit = 2; + + bool test(); + bool testDisplayColor(KDColor c); + int numberOfNonColoredPixels(KDColor wantedColor); + bool testDisplayBlackWhite(); + + ContentView m_view; +}; + +} + +#endif + diff --git a/ion/src/device/shared/drivers/display.cpp b/ion/src/device/shared/drivers/display.cpp index 7ba1a93cd..fde47ea4a 100644 --- a/ion/src/device/shared/drivers/display.cpp +++ b/ion/src/device/shared/drivers/display.cpp @@ -381,6 +381,15 @@ 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); + send_command(Command::MemoryWrite); + int numberOfPixels = Ion::Display::Width * Ion::Display::Height; + while (numberOfPixels--) { + send_data(numberOfPixels % 2 == 0 ? KDColorBlack : KDColorWhite); + } +} + } } } diff --git a/ion/src/device/shared/drivers/display.h b/ion/src/device/shared/drivers/display.h index bb06cf2db..21d8269a6 100644 --- a/ion/src/device/shared/drivers/display.h +++ b/ion/src/device/shared/drivers/display.h @@ -62,6 +62,9 @@ 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(); + } } }