From 870250433ad59ca7754bb0bcc95781eae96d9b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jo=C5=84ski?= Date: Tue, 21 Jun 2022 14:36:21 +0200 Subject: [PATCH] [MOS-298] HALize ServiceEink Add HAL to ServiceEink Remove dead code from Linux eink substitute Fix LUTS.bin refresh problems on simulator --- .../application-meditation/CMakeLists.txt | 1 + .../application-onboarding/CMakeLists.txt | 1 + module-bsp/board/linux/CMakeLists.txt | 1 + module-bsp/board/linux/eink/ED028TC1.c | 38 +-- module-bsp/board/linux/eink/ED028TC1.h | 323 +----------------- .../board/linux/eink/LinuxEinkDisplay.cpp | 95 ++++++ .../board/linux/eink/LinuxEinkDisplay.hpp | 32 ++ module-bsp/board/rt1051/CMakeLists.txt | 4 +- module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp | 132 +++---- module-bsp/board/rt1051/bsp/eink/ED028TC1.h | 28 +- .../board/rt1051/bsp/eink}/EinkDisplay.cpp | 220 ++++++++---- .../board/rt1051/bsp/eink/EinkDisplay.hpp | 65 ++++ .../board/rt1051/bsp/eink/eink_dimensions.cpp | 47 +++ .../board/rt1051/bsp/eink/eink_dimensions.hpp | 25 ++ module-bsp/hal/CMakeLists.txt | 1 + .../include/hal/eink/AbstractEinkDisplay.hpp | 80 +++++ module-gui/CMakeLists.txt | 1 + .../service-cellular/call/CMakeLists.txt | 1 + module-services/service-eink/CMakeLists.txt | 7 +- module-services/service-eink/EinkDisplay.hpp | 62 ---- module-services/service-eink/ServiceEink.cpp | 114 +++---- module-services/service-eink/ServiceEink.hpp | 19 +- module-services/service-gui/CMakeLists.txt | 10 +- module-sys/SystemManager/CMakeLists.txt | 1 + .../CMakeLists.txt | 1 + .../application-bell-powernap/CMakeLists.txt | 1 + .../BellHybrid/apps/common/CMakeLists.txt | 1 + .../test/test-settings/CMakeLists.txt | 1 + 28 files changed, 659 insertions(+), 653 deletions(-) create mode 100644 module-bsp/board/linux/eink/LinuxEinkDisplay.cpp create mode 100644 module-bsp/board/linux/eink/LinuxEinkDisplay.hpp rename {module-services/service-eink => module-bsp/board/rt1051/bsp/eink}/EinkDisplay.cpp (51%) create mode 100644 module-bsp/board/rt1051/bsp/eink/EinkDisplay.hpp create mode 100644 module-bsp/board/rt1051/bsp/eink/eink_dimensions.cpp create mode 100644 module-bsp/board/rt1051/bsp/eink/eink_dimensions.hpp create mode 100644 module-bsp/hal/include/hal/eink/AbstractEinkDisplay.hpp delete mode 100644 module-services/service-eink/EinkDisplay.hpp diff --git a/module-apps/application-meditation/CMakeLists.txt b/module-apps/application-meditation/CMakeLists.txt index 980d60063a25f82d0b78344293f9cf39554eba81..46274986e320a82d01f8f65cfc190bdee3da1838 100644 --- a/module-apps/application-meditation/CMakeLists.txt +++ b/module-apps/application-meditation/CMakeLists.txt @@ -47,6 +47,7 @@ target_link_libraries(application-meditation module-vfs service-audio utils-time + Microsoft.GSL::GSL PUBLIC apps-common module-gui diff --git a/module-apps/application-onboarding/CMakeLists.txt b/module-apps/application-onboarding/CMakeLists.txt index 696b2a9fed6c1dbd6675d170e70d0507f1b4d60b..71d109cb4409e8dac12c0841196b00dff1a411ab 100644 --- a/module-apps/application-onboarding/CMakeLists.txt +++ b/module-apps/application-onboarding/CMakeLists.txt @@ -51,6 +51,7 @@ target_link_libraries(application-onboarding i18n log module-gui + Microsoft.GSL::GSL PUBLIC apps-common ) diff --git a/module-bsp/board/linux/CMakeLists.txt b/module-bsp/board/linux/CMakeLists.txt index a0db450761db88a68cb06477196c716a697711ba..168c035eacd34dc772f15b698f50271621a58048 100644 --- a/module-bsp/board/linux/CMakeLists.txt +++ b/module-bsp/board/linux/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(module-bsp eeprom/eeprom.cpp eink_frontlight/eink_frontlight.cpp eink/ED028TC1.c + eink/LinuxEinkDisplay.cpp headset/headset.cpp keypad_backlight/keypad_backlight.cpp light_sensor/light_sensor.cpp diff --git a/module-bsp/board/linux/eink/ED028TC1.c b/module-bsp/board/linux/eink/ED028TC1.c index a24f92fb05cec782d440814e5f0cda8ce330f793..a7f56d628a4ddc784086bdb16d5aacc890e6045b 100644 --- a/module-bsp/board/linux/eink/ED028TC1.c +++ b/module-bsp/board/linux/eink/ED028TC1.c @@ -49,10 +49,6 @@ int shared_fd = 0; static uint8_t s_einkIsPoweredOn = false; // Variable which contains the state of the power of the EPD display -/* Function bodies */ -void EinkChangeDisplayUpdateTimings(EinkDisplayTimingsMode_e timingsMode) -{} - uint8_t EinkIsPoweredOn() { return s_einkIsPoweredOn; @@ -73,11 +69,6 @@ void EinkPowerDown(void) EinkPowerOff(); } -int16_t EinkGetTemperatureInternal() -{ - return 25; -} - static shared_memory_header *createSHMBuffer(const char *name) { if (shared_header != NULL) @@ -128,30 +119,14 @@ EinkStatus_e EinkResetAndInitialize() return EinkOK; } -EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings) -{ - return EinkOK; -} - -EinkStatus_e EinkWaitTillPipelineBusy() -{ - return EinkOK; -} - -EinkStatus_e EinkDitherDisplay() -{ - return EinkOK; -} - -EinkStatus_e EinkUpdateFrame( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, uint8_t *buffer, EinkBpp_e bpp, EinkDisplayColorMode_e invertColors) +EinkStatus_e EinkUpdateFrame(EinkFrame_t frame, uint8_t *buffer) { - uint32_t offset_eink = Y * BOARD_EINK_DISPLAY_RES_X + X; + uint32_t offset_eink = frame.pos_y * BOARD_EINK_DISPLAY_RES_X + frame.pos_x; uint32_t offset_buffer = 0; - for (uint32_t h = 0; h < H; ++h) { - memcpy(shared_buffer + offset_eink, buffer + offset_buffer, W); + for (uint32_t h = 0; h < frame.height; ++h) { + memcpy(shared_buffer + offset_eink, buffer + offset_buffer, frame.width); offset_eink += BOARD_EINK_DISPLAY_RES_X; - offset_buffer += W; + offset_buffer += frame.width; } shared_header->frameCount++; @@ -168,8 +143,7 @@ EinkStatus_e EinkFillScreenWithColor(EinkDisplayColorFilling_e colorFill) return EinkError; } -EinkStatus_e EinkRefreshImage( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, EinkDisplayTimingsMode_e refreshTimingsMode) +EinkStatus_e EinkRefreshImage(EinkFrame_t frame) { return EinkOK; } diff --git a/module-bsp/board/linux/eink/ED028TC1.h b/module-bsp/board/linux/eink/ED028TC1.h index b60100ab7b5f9c629889fcd7213d7eb84c4a2544..caff2db49fd6765bca0c812aba1afaa0e64062c3 100644 --- a/module-bsp/board/linux/eink/ED028TC1.h +++ b/module-bsp/board/linux/eink/ED028TC1.h @@ -22,218 +22,6 @@ extern "C" { #endif /* __cplusplus */ -/* Exported macro ------------------------------------------------------------*/ -/** - * @brief ED028TC1 register definitions - */ -#define EinkPanelSetting (0x00U) -#define EinkPowerSetting (0x01U) -#define EinkPowerOFF (0x02U) -#define EinkPowerOFFSequenceSetting (0x03U) -#define EinkPowerON (0x04U) -#define EinkDPC (0x05U) -#define EinkDSLP (0x06U) -#define EinkBoosterSoftStart (0x07U) - -#define EinkDataStartTransmission1 (0x10U) -#define EinkDisplayRefresh (0x12U) -#define EinkDTM2 (0x13U) -#define EinkAWM1 (0x15U) -#define EinkAWM2 (0x16U) - -#define EinkLUTC (0x20U) -#define EinkLUTD (0x21U) -#define EinkLUTR (0x22U) -#define EinkPowerSaving (0x26U) -#define EinkMISCS (0x27U) - -#define EinkPLLControl (0x30U) - -#define EinkTemperatureSensorCalibration (0x40U) -#define EinkTemperatureSensorSelection (0x41U) - -#define EinkVcomAndDataIntervalSetting (0x50U) -#define EinkLPD (0x51U) - -#define EinkTCONSetting (0x60U) -#define EinkResolutionSetting (0x61U) -#define EinkDAM (0x65U) - -#define EinkREV (0x70U) -#define EinkFLG (0x71U) -#define EinkLUT_COL_FLG (0x72U) -#define EinkLUT_BUSY_FLG (0x73U) - -#define EinkAutoMeasurementVcom (0x80U) -#define EinkReadVcomValue (0x81U) -#define EinkVCM_DCSetting (0x82U) -#define EinkDataStartTransmissionWindow (0x83U) -#define EinkEDS (0x84U) -#define EinkXONS (0x85U) - -#define EinkLEDDS (0x90U) -#define EinkPBC (0x91U) -#define EinkPBCS (0x92U) -#define EinkEXTRS (0x93U) -#define EinkNTRS (0x94U) - -#define EinkGDOrderSetting (0xE0U) - -/** - * @brief ED028TC1 register bit definitions - */ -// PanelSetting -#define XON (1 << 7) -#define RES0 (1 << 6) -#define LUT_SEL (1 << 5) -#define DM (1 << 4) -#define SHL (1 << 2) -#define SPIWM (1 << 1) -#define RST_N (1 << 0) -#define SFT1PX (0 << 0) -#define SFT2PX (1 << 0) -#define SFT3PX (2 << 0) -#define SFT4PX (3 << 0) - -// PowerSetting -#define VSource_EN (1 << 0) -#define VGate_EN (1 << 1) -#define VG_LVL17V (0 << 0) -#define VG_LVL18V (1 << 0) -#define VG_LVL19V (2 << 0) -#define VG_LVL20V (3 << 0) -#define VG_LVL21V (4 << 0) -#define VSLV_LVL (0) // this is: 7-bit 00h=2.4V, 7Fh=15.0V -#define VSL_LVL15V (0 << 2) -#define VSL_LVL14V (1 << 2) -#define VSL_LVL13V (2 << 2) -#define VSL_LVL12V (3 << 2) -#define VSH_LVL15V (0 << 0) -#define VSH_LVL14V (1 << 0) -#define VSH_LVL13V (2 << 0) -#define VSH_LVL12V (3 << 0) - -// PowerOFFSequenceSetting -#define T_VDS_OFF_1F (0 << 4) -#define T_VDS_OFF_2F (1 << 4) -#define T_VDS_OFF_3F (2 << 4) -#define T_VDS_OFF_4F (3 << 4) - -// BoosterSoftStart -#define BTPHx_SSP_10ms (0 << 6) // soft start period of phase A,B -#define BTPHx_SSP_20ms (1 << 6) -#define BTPHx_SSP_30ms (2 << 6) -#define BTPHx_SSP_40ms (3 << 6) -#define BTPHx_DS_1 (0 << 3) // driving strength of phase A,B,C -#define BTPHx_DS_2 (1 << 3) -#define BTPHx_DS_3 (2 << 3) -#define BTPHx_DS_4 (3 << 3) -#define BTPHx_DS_5 (4 << 3) -#define BTPHx_DS_6 (5 << 3) -#define BTPHx_DS_7 (6 << 3) -#define BTPHx_DS_8 (7 << 3) -#define BTPHx_OT_027 (0 << 0) // minimum OFF time setting of phase A,B,C -#define BTPHx_OT_034 (1 << 0) -#define BTPHx_OT_040 (2 << 0) -#define BTPHx_OT_054 (3 << 0) -#define BTPHx_OT_080 (4 << 0) -#define BTPHx_OT_154 (5 << 0) -#define BTPHx_OT_334 (6 << 0) -#define BTPHx_OT_658 (7 << 0) - -#define EINK_TEMPERATURE_SENSOR_USE_INTERNAL (0 << 6) -#define EINK_TEMPERATURE_SENSOR_USE_EXTERNAL (2 << 6) - -// DataStartTransmission1 -#define Cur_BPP1 (0 << 0) -#define Cur_BPP2 (1 << 0) -#define Cur_BPP3 (2 << 0) -#define Cur_BPP4 (3 << 0) - -// DisplayRefresh -#define AC_DCVCOM (1 << 7) -#define WFMode0 (0 << 4) -#define WFMode1 (1 << 4) -#define WFMode2 (2 << 4) -#define WFMode3 (3 << 4) -#define WFMode4 (4 << 4) -#define UPD_CPY_TO_PRE (1 << 3) -#define DN_EN (1 << 2) -#define Regal_EN_DIS (0 << 0) -#define Regal_EN_K (1 << 0) -#define Regal_EN_W (2 << 0) -#define Regal_EN_KW (3 << 0) - -// PLLControl -#define OSC_RATE_SEL2_5 (0 << 1) -#define OSC_RATE_SEL5 (1 << 1) -#define OSC_RATE_SEL8 (2 << 1) -#define OSC_RATE_SEL10 (3 << 1) -#define OSC_RATE_SEL16 (4 << 1) -#define OSC_RATE_SEL18 (5 << 1) -#define OSC_RATE_SEL19 (6 << 1) -#define OSC_RATE_SEL20 (7 << 1) - -// VcomAndDataIntervalSetting -#define VBD_CON (1 << 3) -#define VBD_OT_G0_G0 (0 << 1) -#define VBD_OT_G0_G15 (2 << 1) -#define VBD_OT_G15_G0 (3 << 1) -#define VBD_OT_G15_G15 (4 << 1) -#define DDX (1 << 0) -#define CDI (4) // Vcom data interval: 0h=2hsync -> Fh=32hsync, step=2 -#define DCI (0) // Data to Vcom interval: 0h=1hsync -> Fh=16hsync, step=1 - -// AutoMeasurementVcom -#define VCM_EN (1 << 6) -#define AMVT3s (0 << 4) -#define AMVT5s (1 << 4) -#define AMVT6s (2 << 4) -#define AMVT10s (3 << 4) -#define AMVX (1 << 3) -#define AMVS (1 << 2) -#define AMV (1 << 1) -#define AMVE (1 << 0) - -// GDOrderSetting -#define VBD_EN_SEL (1 << 3) -#define GDOS_M0 (0 << 0) -#define GDOS_M1 (1 << 0) -#define GDOS_M2 (2 << 0) -#define GDOS_M3 (3 << 0) -#define GDOS_M4 (4 << 0) -#define GDOS_M5 (5 << 0) -#define GDOS_M6 (6 << 0) -#define GDOS_M7 (7 << 0) -#define VBD_FN (0) // VBorder frame number seting: 0-VBD disabled, 1-VBD=8, ... 1Fh-VBD=248 - -// Dither -#define EINK_DITHER_START 0x01 -#define EINK_DITHER_4BPP_MODE (0 << 1) -#define EINK_DITHER_2BPP_MODE (1 << 1) - -#define EINK_FLAG_BUSY_N 0x0001 ///< This flag informs that the driver is busy. 0 - busy, 1 - idle -#define EINK_FLAG_POWER_OFF_IN_PROGRESS \ - 0x0002 ///< This flag informs that the Power Off sequence is in progress. 1 - in progress -#define EINK_FLAG_POWER_ON_IN_PROGRESS \ - 0x0004 ///< This flag informs that the Power On sequence is in progress. 1 - in progress -#define EINK_FLAG_ENTIRE_FRAME_RECEIVED \ - 0x0008 ///< This flag informs that the driver received data for entire frame defined in the \ref - ///< EinkDataStartTransmissionWindow command -#define EINK_FLAG_I2C_BUSY 0x0010 ///< This flag informs that the I2C master periph is busy. Active low -#define EINK_FLAG_I2C_ERROR 0x0020 ///< This flag informs that the I2C master acquired an error -#define EINK_FLAG_PIPELINE_COLLISION 0x0040 ///< This flag informs that two frames sent in the pipelin overlap -#define EINK_FLAG_PIPELINE_BUSY 0x0080 ///< This flag informs that pipeline insertion is in progress -#define EINK_FLAG_REAGL_BUSY 0x0100 ///< This flag informs that the REAGLS function processing is in progress -#define EINK_FLAG_DITHER_IN_PROGRESS 0x0200 ///< This flag informs that the Dither process is in progress -#define EINK_FLAG_DISP_REFRESH_IN_PROGRESS \ - 0x0400 ///< This flag informs that the Display Refreshing process is in progress -#define EINK_FLAG_AUTO_MEASURE_VCOM_IN_PROGRESS \ - 0x0800 ///< This flag informs that the auto measurement of the VCOM is in progress -#define EINK_FLAG_EPD_DISCHARGE_IN_PROGRESS 0x1000 ///< This flag informs that the EPD display discharge is in progress -#define EINK_FLAG_BOOST_VOLTAGE_READY 0x4000 ///< This flag informs that the Boost voltage is ready -#define EINK_FLAG_RAM_TEST_FLAG 0x8000 ///< This flag is for internal SRAM memory testing - /* Exported types ------------------------------------------------------------*/ /** * @enum EinkStatus_e @@ -251,64 +39,19 @@ extern "C" EinkWaveformsFileOpenFail, //!< Could not open the file with the waveforms for EPD display } EinkStatus_e; - /** - * @enum EinkBpp_e - */ - typedef enum - { - Eink1Bpp = 1, //!< Eink1Bpp - Eink2Bpp, //!< Eink2Bpp - Eink3Bpp, //!< Eink3Bpp - Eink4Bpp //!< Eink4Bpp - } EinkBpp_e; - - typedef enum - { - EinkWaveformINIT, ///< Clears deeply the display - EinkWaveformA2, ///< Fastest, direct update, no flashing. Severe ghosting effect - EinkWaveformDU2, ///< Fast, direct update, no flashing. Medium ghosting effect - EinkWaveformGLD16, ///< Slow, little flashing. Light ghosting mode - EinkWaveformGC16, ///< Slow, strong flashing. Next to none ghosting - } EinkWaveforms_e; - - typedef enum - { - EinkDisplayTimingsDeepCleanMode, - EinkDisplayTimingsHighContrastMode, - EinkDisplayTimingsFastRefreshMode - } EinkDisplayTimingsMode_e; - typedef enum { EinkDisplayColorBlack = 0, EinkDisplayColorWhite = 0xFF } EinkDisplayColorFilling_e; - typedef enum - { - EinkDisplayColorModeStandard, - EinkDisplayColorModeInverted - } EinkDisplayColorMode_e; - typedef struct { - // type of eink's waveform - EinkWaveforms_e mode; - // temperature of surrounding - int32_t temperature; - // use counter to keep track if need to change - uint32_t useCounter; - // pointer to lookup table for lut c - uint8_t *LUTCData; - // sizeo of lutc data - uint32_t LUTCSize; - // pointer to lookup table for lut d - uint8_t *LUTDData; - // size of lutd data - uint32_t LUTDSize; - } EinkWaveformSettings_t; - - /* Exported constants --------------------------------------------------------*/ + uint16_t pos_x; + uint16_t pos_y; + uint16_t width; + uint16_t height; + } EinkFrame_t; /* Exported functions ------------------------------------------------------- */ @@ -333,52 +76,21 @@ extern "C" */ void EinkPowerDown(void); - /** - * This function measures the ambient temperature using the ED028TC1 display internal temperature sensor. - * @note The display needs to be powered on - * - * @return Ambient temperature in the degrees of Celsius - */ - int16_t EinkGetTemperatureInternal(); - /** * @brief This function resets the eink display and setups the initial configuration */ EinkStatus_e EinkResetAndInitialize(); - /** - * TODO: Fill The doxy when got info what does it do - * @return - */ - EinkStatus_e EinkWaitTillPipelineBusy(); - - /** - * TODO: Fill The doxy when got info what does it do - * @return - */ - EinkStatus_e EinkDitherDisplay(); - /** * @brief This function sends the part of image from the given buffer to the internal memory of the display. It * makes not screen to update. - * @param X [in] - image start position X in pixels - * @param Y [in] - image start position Y in pixels - * @param W [in] - image width in pixels - * @param H [in] - image height in pixels + * @param frame [in] - draw buffer on specified part of screen * @param buffer [in] - pointer to image encoded according to \ref bpp set in initialization - * @param bpp [in] - The format of the \ref buffer (number of the bits per pixel) - * @param invertColors[in] - true if colors of the image are to be inverted, false otherwise * * @return EinkNoMem - Could not allocate the temporary buffer * EinkOK - Part of image send successfully */ - EinkStatus_e EinkUpdateFrame(uint16_t X, - uint16_t Y, - uint16_t W, - uint16_t H, - uint8_t *buffer, - EinkBpp_e bpp, - EinkDisplayColorMode_e invertColors); + EinkStatus_e EinkUpdateFrame(EinkFrame_t frame, uint8_t *buffer); /** * @brief This function sets the waveform to the \ref EinkWaveformINIT to make the display clearing more deep and @@ -399,28 +111,11 @@ extern "C" /** * @brief Refresh window on the screen. E-paper display tends to loose contrast over time. To Keep the image sharp * refresh is needed. - * @param X refresh window position X in pixels - * @param Y refresh window position Y in pixels - * @param W refresh window width in pixels - * @param H refresh window height in pixels - * @param refreshTimingsMode [in] - EinkDisplayTimingsDeepCleanMode - if image is to be cleared precisely - * EinkDisplayTimingsHighContrastMode - if image is displayed in the high contrast - * mode EinkDisplayTimingsFastRefreshMode - if image is to be displayed fast + * @param frame refresh specified part of screen * * @return EinkOK */ - EinkStatus_e EinkRefreshImage( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, EinkDisplayTimingsMode_e refreshTimingsMode); - - /** - * @brief This function sends the proper waveform consisting from the LUTC and LUTD data, - * based on the requested waveform (see \ref Mode) and the given temperature (see \ref temperature) - * @param Mode [in] - type of the waveform - * @param temperature [in] - current ambient temperature in Celsius degrees - * @param LUTCData [in] - Data - * @return - */ - EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings); + EinkStatus_e EinkRefreshImage(EinkFrame_t frame); /** * This function converts the ARGB image to the L4 format diff --git a/module-bsp/board/linux/eink/LinuxEinkDisplay.cpp b/module-bsp/board/linux/eink/LinuxEinkDisplay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee4b6f5941894ef62b0fe89bc3293619e0891b51 --- /dev/null +++ b/module-bsp/board/linux/eink/LinuxEinkDisplay.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include + +#include + +#include +#include + +#include "LinuxEinkDisplay.hpp" +#include "ED028TC1.h" + +namespace hal::eink +{ + EinkStatus translateStatus(const EinkStatus_e status_e) + { + switch (status_e) { + case EinkOK: + return EinkStatus::EinkOK; + case EinkError: + return EinkStatus::EinkError; + case EinkSPIErr: + return EinkStatus::EinkSPIErr; + case EinkSPINotInitializedErr: + return EinkStatus::EinkSPINotInitializedErr; + case EinkDMAErr: + return EinkStatus::EinkDMAErr; + case EinkInitErr: + return EinkStatus::EinkInitErr; + case EinkTimeout: + return EinkStatus::EinkTimeout; + case EinkNoMem: + return EinkStatus::EinkNoMem; + case EinkWaveformsFileOpenFail: + return EinkStatus::EinkWaveformsFileOpenFail; + default: + return EinkStatus::EinkUnknown; + } + } + + LinuxEinkDisplay::LinuxEinkDisplay(FrameSize size) : size{size} + {} + + void LinuxEinkDisplay::setMode(const EinkDisplayColorMode mode) noexcept + { + displayColorMode = mode; + } + + EinkStatus LinuxEinkDisplay::showImage(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode) + { + return translateStatus(EinkUpdateFrame(EinkFrame_t{0, 0, size.width, size.height}, frameBuffer)); + } + + void LinuxEinkDisplay::prepareEarlyRequest([[maybe_unused]] const EinkRefreshMode refreshMode, + [[maybe_unused]] const WaveformTemperature behaviour) + {} + + void LinuxEinkDisplay::dither() + {} + + void LinuxEinkDisplay::powerOn() + { + EinkPowerOn(); + } + + void LinuxEinkDisplay::powerOff() + { + EinkPowerOff(); + } + + void LinuxEinkDisplay::shutdown() + {} + + void LinuxEinkDisplay::wipeOut() + { + EinkFillScreenWithColor(EinkDisplayColorFilling_e::EinkDisplayColorWhite); + } + + EinkStatus LinuxEinkDisplay::resetAndInit() + { + EinkResetAndInitialize(); + return EinkStatus::EinkOK; + } + + [[nodiscard]] auto LinuxEinkDisplay::getDevice() const noexcept -> std::shared_ptr + { + return {}; + } + + std::unique_ptr AbstractEinkDisplay::Factory::create(FrameSize size) + { + return std::make_unique(size); + } +} // namespace hal::eink diff --git a/module-bsp/board/linux/eink/LinuxEinkDisplay.hpp b/module-bsp/board/linux/eink/LinuxEinkDisplay.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6167a4808013a9c75a7599f4cf7781bf6bf04a33 --- /dev/null +++ b/module-bsp/board/linux/eink/LinuxEinkDisplay.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include + +namespace hal::eink +{ + + class LinuxEinkDisplay : public AbstractEinkDisplay + { + public: + explicit LinuxEinkDisplay(FrameSize size); + + private: + void setMode(const EinkDisplayColorMode mode) noexcept override; + EinkStatus showImage(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode) override; + void prepareEarlyRequest(const EinkRefreshMode refreshMode, const WaveformTemperature behaviour) override; + + void dither() override; + void powerOn() override; + void powerOff() override; + void shutdown() override; + void wipeOut() override; + EinkStatus resetAndInit() override; + [[nodiscard]] std::shared_ptr getDevice() const noexcept override; + + FrameSize size; + EinkDisplayColorMode displayColorMode{EinkDisplayColorMode::EinkDisplayColorModeStandard}; + }; +} // namespace hal::eink diff --git a/module-bsp/board/rt1051/CMakeLists.txt b/module-bsp/board/rt1051/CMakeLists.txt index 03343f4438f322d7eae0632b443d471eb4a7746c..551e9b0887055c6d4169d758ab429476fe667b4f 100644 --- a/module-bsp/board/rt1051/CMakeLists.txt +++ b/module-bsp/board/rt1051/CMakeLists.txt @@ -13,7 +13,9 @@ target_sources(module-bsp bsp/eink_frontlight/eink_frontlight.cpp bsp/eink/bsp_eink.cpp bsp/eink/ED028TC1.cpp + bsp/eink/EinkDisplay.cpp bsp/eink/eink_binarization_luts.c + bsp/eink/eink_dimensions.cpp bsp/eMMC/fsl_mmc.c bsp/eMMC/fsl_sdmmc_common.c bsp/eMMC/fsl_sdmmc_event.c @@ -75,7 +77,7 @@ add_subdirectory(common/fsl_drivers) add_subdirectory(os) add_subdirectory(${BOARD}) -target_link_libraries(module-bsp PUBLIC cmsis fsl) +target_link_libraries(module-bsp PUBLIC cmsis fsl Microsoft.GSL::GSL) add_library(system-stats-sink-board) target_sources(system-stats-sink-board diff --git a/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp b/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp index 152260bb549c694a7e0ee38e7e3215130a0916f7..7a61e10ac2056b2550cdfe5a753c7311561e1d7b 100644 --- a/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp +++ b/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp @@ -21,6 +21,7 @@ #include "board.h" #include "eink_binarization_luts.h" #include "macros.h" +#include "eink_dimensions.hpp" #include #include "drivers/pll/DriverPLL.hpp" @@ -54,22 +55,6 @@ #define EPD_BOOSTER_OFF_TIME_GDR_6_58uS 7 #define EPD_BOOSTER_OFF_TIME_GDR_POS 0 -#if defined(EINK_ROTATE_90_CLOCKWISE) -#define EINK_DISPLAY_RES_X (BOARD_EINK_DISPLAY_RES_Y) -#define EINK_DISPLAY_RES_Y (BOARD_EINK_DISPLAY_RES_X) -#define EINK_DISPLAY_X_AXIS (BOARD_EINK_DISPLAY_RES_Y - Y - H) -#define EINK_DISPLAY_Y_AXIS (BOARD_EINK_DISPLAY_RES_X - X - W) -#define EINK_DISPLAY_WINDOW_WIDTH (H) -#define EINK_DISPLAY_WINDOW_HEIGHT (W) -#else -#define EINK_DISPLAY_RES_X (BOARD_EINK_DISPLAY_RES_X) -#define EINK_DISPLAY_RES_Y (BOARD_EINK_DISPLAY_RES_Y) -#define EINK_DISPLAY_X_AXIS (BOARD_EINK_DISPLAY_RES_X - X - W) -#define EINK_DISPLAY_Y_AXIS (BOARD_EINK_DISPLAY_RES_Y - Y - H) -#define EINK_DISPLAY_WINDOW_WIDTH (W) -#define EINK_DISPLAY_WINDOW_HEIGHT (H) -#endif - #define EINK_BLACK_PIXEL_MASK 0x00 // This is the mask for the black pixel value #define EINK_1BPP_WHITE_PIXEL_MASK 0x01 // This is the mask for the white pixel in 1bpp mode #define EINK_2BPP_WHITE_PIXEL_MASK 0x03 // This is the mask for the white pixel in 2bpp mode @@ -814,8 +799,7 @@ EinkStatus_e EinkDitherDisplay() return EinkOK; } -EinkStatus_e EinkUpdateFrame( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, uint8_t *buffer, EinkBpp_e bpp, EinkDisplayColorMode_e invertColors) +EinkStatus_e EinkUpdateFrame(EinkFrame_t frame, uint8_t *buffer, EinkBpp_e bpp, EinkDisplayColorMode_e invertColors) { uint8_t buf[10]; uint8_t pixelsInByte = 8 / bpp; @@ -826,20 +810,24 @@ EinkStatus_e EinkUpdateFrame( if ((s_einkConfiguredWaveform == EinkWaveformA2) || (s_einkConfiguredWaveform == EinkWaveformDU2)) { switch (bpp) { case Eink1Bpp: { - s_EinkTransformAnimationFrameCoordinateSystem_1Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformAnimationFrameCoordinateSystem_1Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink2Bpp: { - s_EinkTransformAnimationFrameCoordinateSystem_2Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformAnimationFrameCoordinateSystem_2Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink3Bpp: { - s_EinkTransformAnimationFrameCoordinateSystem_3Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformAnimationFrameCoordinateSystem_3Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink4Bpp: { #if defined(EINK_ROTATE_90_CLOCKWISE) - s_EinkTransformFrameCoordinateSystem_4Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformFrameCoordinateSystem_4Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); #else s_EinkTransformFrameCoordinateSystemNoRotation_4Bpp( - buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); #endif } break; } @@ -847,49 +835,61 @@ EinkStatus_e EinkUpdateFrame( else { switch (bpp) { case Eink1Bpp: { - s_EinkTransformFrameCoordinateSystem_1Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformFrameCoordinateSystem_1Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink2Bpp: { - s_EinkTransformFrameCoordinateSystem_2Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformFrameCoordinateSystem_2Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink3Bpp: { - s_EinkTransformFrameCoordinateSystem_3Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformFrameCoordinateSystem_3Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); } break; case Eink4Bpp: { #if defined(EINK_ROTATE_90_CLOCKWISE) - s_EinkTransformFrameCoordinateSystem_4Bpp(buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + s_EinkTransformFrameCoordinateSystem_4Bpp( + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); #else s_EinkTransformFrameCoordinateSystemNoRotation_4Bpp( - buffer, W, H, s_einkServiceRotatedBuf + 2, invertColors); + buffer, frame.width, frame.height, s_einkServiceRotatedBuf + 2, invertColors); #endif } break; } } buf[0] = EinkDataStartTransmissionWindow; // set display window - buf[1] = (uint8_t)(EINK_DISPLAY_X_AXIS >> 8); // MSB of the X axis in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[2] = (uint8_t)EINK_DISPLAY_X_AXIS; // LSB of the X axis in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[3] = (uint8_t)(EINK_DISPLAY_Y_AXIS >> 8); // MSB of the Y axis in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[4] = (uint8_t)EINK_DISPLAY_Y_AXIS; // LSB of the Y axis in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[5] = (uint8_t)(EINK_DISPLAY_WINDOW_WIDTH >> 8); // MSB of the window height in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[6] = (uint8_t)EINK_DISPLAY_WINDOW_WIDTH; // LSB of the window height in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[7] = (uint8_t)(EINK_DISPLAY_WINDOW_HEIGHT >> 8); // MSB of the window width in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[8] = (uint8_t)EINK_DISPLAY_WINDOW_HEIGHT; // LSB of the window width in the EPD display. Value converted from + buf[1] = static_cast(hal::eink::getDisplayXAxis(frame) >> + 8); // MSB of the X axis in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[2] = static_cast( + hal::eink::getDisplayXAxis(frame)); // LSB of the X axis in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one + buf[3] = static_cast(hal::eink::getDisplayYAxis(frame) >> + 8); // MSB of the Y axis in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[4] = static_cast( + hal::eink::getDisplayYAxis(frame)); // LSB of the Y axis in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one + buf[5] = static_cast(hal::eink::getDisplayWindowWidth(frame) >> + 8); // MSB of the window height in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[6] = static_cast( + hal::eink::getDisplayWindowWidth(frame)); // LSB of the window height in the EPD display. Value converted from // the standard GUI coords system to the ED028TC1 one + buf[7] = static_cast(hal::eink::getDisplayWindowHeight(frame) >> + 8); // MSB of the window width in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[8] = static_cast( + hal::eink::getDisplayWindowHeight(frame)); // LSB of the window width in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one if (BSP_EinkWriteData(buf, 9, SPI_AUTOMATIC_CS) != 0) { EinkResetAndInitialize(); return EinkSPIErr; } - uint32_t msgSize = 2 + ((uint32_t)W * (uint32_t)H / + uint32_t msgSize = 2 + (static_cast(frame.width) * static_cast(frame.height) / pixelsInByte); // command (1 byte) + bpp (1 byte) + dataSize(W*H/pixelsInByte bytes) // Send the part of the image to the display memory @@ -952,13 +952,13 @@ EinkStatus_e EinkFillScreenWithColor(EinkDisplayColorFilling_e colorFill) BSP_EinkWriteCS(BSP_Eink_CS_Set); - EinkRefreshImage(0, 0, BOARD_EINK_DISPLAY_RES_X, BOARD_EINK_DISPLAY_RES_Y, EinkDisplayTimingsDeepCleanMode); + EinkRefreshImage(EinkFrame_t{0, 0, BOARD_EINK_DISPLAY_RES_X, BOARD_EINK_DISPLAY_RES_Y}, + EinkDisplayTimingsDeepCleanMode); return EinkOK; } -EinkStatus_e EinkRefreshImage( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, EinkDisplayTimingsMode_e refreshTimingsMode) +EinkStatus_e EinkRefreshImage(EinkFrame_t frame, EinkDisplayTimingsMode_e refreshTimingsMode) { EinkChangeDisplayUpdateTimings(refreshTimingsMode); @@ -969,22 +969,30 @@ EinkStatus_e EinkRefreshImage( buf[0] = EinkDisplayRefresh; buf[1] = UPD_CPY_TO_PRE; - buf[2] = (uint8_t)(EINK_DISPLAY_X_AXIS >> 8); // MSB of the X axis in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[3] = (uint8_t)EINK_DISPLAY_X_AXIS; // LSB of the X axis in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[4] = (uint8_t)(EINK_DISPLAY_Y_AXIS >> 8); // MSB of the Y axis in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[5] = (uint8_t)EINK_DISPLAY_Y_AXIS; // LSB of the Y axis in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[6] = (uint8_t)(EINK_DISPLAY_WINDOW_WIDTH >> 8); // MSB of the window height in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[7] = (uint8_t)EINK_DISPLAY_WINDOW_WIDTH; // LSB of the window height in the EPD display. Value converted from - // the standard GUI coords system to the ED028TC1 one - buf[8] = (uint8_t)(EINK_DISPLAY_WINDOW_HEIGHT >> 8); // MSB of the window width in the EPD display. Value converted - // from the standard GUI coords system to the ED028TC1 one - buf[9] = (uint8_t)EINK_DISPLAY_WINDOW_HEIGHT; // LSB of the window width in the EPD display. Value converted from + buf[2] = static_cast(hal::eink::getDisplayXAxis(frame) >> + 8); // MSB of the X axis in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[3] = static_cast( + hal::eink::getDisplayXAxis(frame)); // LSB of the X axis in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one + buf[4] = static_cast(hal::eink::getDisplayYAxis(frame) >> + 8); // MSB of the Y axis in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[5] = static_cast( + hal::eink::getDisplayYAxis(frame)); // LSB of the Y axis in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one + buf[6] = static_cast(hal::eink::getDisplayWindowWidth(frame) >> + 8); // MSB of the window height in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[7] = static_cast( + hal::eink::getDisplayWindowWidth(frame)); // LSB of the window height in the EPD display. Value converted from // the standard GUI coords system to the ED028TC1 one + buf[8] = static_cast(hal::eink::getDisplayWindowHeight(frame) >> + 8); // MSB of the window width in the EPD display. Value converted + // from the standard GUI coords system to the ED028TC1 one + buf[9] = static_cast( + hal::eink::getDisplayWindowHeight(frame)); // LSB of the window width in the EPD display. Value converted from + // the standard GUI coords system to the ED028TC1 one if (BSP_EinkWriteData(buf, sizeof(buf), SPI_AUTOMATIC_CS) != 0) { EinkResetAndInitialize(); diff --git a/module-bsp/board/rt1051/bsp/eink/ED028TC1.h b/module-bsp/board/rt1051/bsp/eink/ED028TC1.h index c949aed555de63b28e9f8b814dc3ea54d80f33f2..ea27a14c245d15816d5556326de5594300787d4e 100644 --- a/module-bsp/board/rt1051/bsp/eink/ED028TC1.h +++ b/module-bsp/board/rt1051/bsp/eink/ED028TC1.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md /** @@ -312,6 +312,14 @@ extern "C" uint32_t LUTDSize; } EinkWaveformSettings_t; + typedef struct + { + uint16_t pos_x; + uint16_t pos_y; + uint16_t width; + uint16_t height; + } EinkFrame_t; + /* Exported constants --------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ @@ -365,10 +373,7 @@ extern "C" /** * @brief This function sends the part of image from the given buffer to the internal memory of the display. It * makes not screen to update. - * @param X [in] - image start position X in pixels - * @param Y [in] - image start position Y in pixels - * @param W [in] - image width in pixels - * @param H [in] - image height in pixels + * @param frame [in] - part of screen on which the image will be written * @param buffer [in] - pointer to image encoded according to \ref bpp set in initialization * @param bpp [in] - The format of the \ref buffer (number of the bits per pixel) * @param invertColors[in] - true if colors of the image are to be inverted, false otherwise @@ -376,10 +381,7 @@ extern "C" * @return EinkNoMem - Could not allocate the temporary buffer * EinkOK - Part of image send successfully */ - EinkStatus_e EinkUpdateFrame(uint16_t X, - uint16_t Y, - uint16_t W, - uint16_t H, + EinkStatus_e EinkUpdateFrame(EinkFrame_t frame, uint8_t *buffer, EinkBpp_e bpp, EinkDisplayColorMode_e invertColors); @@ -403,18 +405,14 @@ extern "C" /** * @brief Refresh window on the screen. E-paper display tends to loose contrast over time. To Keep the image sharp * refresh is needed. - * @param X refresh window position X in pixels - * @param Y refresh window position Y in pixels - * @param W refresh window width in pixels - * @param H refresh window height in pixels + * @param frame - part of screen on which image will be written * @param refreshTimingsMode [in] - EinkDisplayTimingsDeepCleanMode - if image is to be cleared precisely * EinkDisplayTimingsHighContrastMode - if image is displayed in the high contrast * mode EinkDisplayTimingsFastRefreshMode - if image is to be displayed fast * * @return EinkOK */ - EinkStatus_e EinkRefreshImage( - uint16_t X, uint16_t Y, uint16_t W, uint16_t H, EinkDisplayTimingsMode_e refreshTimingsMode); + EinkStatus_e EinkRefreshImage(EinkFrame_t frame, EinkDisplayTimingsMode_e refreshTimingsMode); /** * @brief This function sends the proper waveform consisting from the LUTC and LUTD data, diff --git a/module-services/service-eink/EinkDisplay.cpp b/module-bsp/board/rt1051/bsp/eink/EinkDisplay.cpp similarity index 51% rename from module-services/service-eink/EinkDisplay.cpp rename to module-bsp/board/rt1051/bsp/eink/EinkDisplay.cpp index 118c315b0990ca24a79feeed9e094b77c921bda5..186f5597ffe85afb9e7ce3d4dc93b2b1936bafd6 100644 --- a/module-services/service-eink/EinkDisplay.cpp +++ b/module-bsp/board/rt1051/bsp/eink/EinkDisplay.cpp @@ -3,17 +3,16 @@ #include "EinkDisplay.hpp" -#if defined(TARGET_RT1051) #include -#endif #include -#include + #include +#include #include #include -namespace service::eink +namespace hal::eink { namespace { @@ -44,10 +43,81 @@ namespace service::eink settings.LUTDSize = 0; return settings; } + + unsigned int toWaveformTemperatureOffset(std::int32_t temperature) noexcept + { + if (temperature >= LUTTemperatureCritical) { + return LUTTemperatureOffsetCritical; + } + if (temperature >= LUTTemperatureSubcritical) { + return LUTTemperatureOffsetSubcritical; + } + if (temperature < LUTTemperatureMinimal) { + temperature = LUTTemperatureMinimal; + } + return temperature / LUTTemperatureOffsetInterval; + } + + unsigned int toWaveformOffset(unsigned short LUTbank, unsigned int temperatureOffset) noexcept + { + constexpr auto singleLUTOffset = (LUTTemperatureOffsetCritical + 1); + return LUTSTotalSize * (singleLUTOffset * LUTbank + temperatureOffset); + } + + unsigned int toWaveformOffset(EinkWaveforms_e mode, unsigned int temperatureOffset) + { + switch (mode) { + case EinkWaveformINIT: + return toWaveformOffset(0, temperatureOffset); + case EinkWaveformA2: + return toWaveformOffset(1, temperatureOffset); + case EinkWaveformDU2: + return toWaveformOffset(2, temperatureOffset); + case EinkWaveformGLD16: + return toWaveformOffset(3, temperatureOffset); + case EinkWaveformGC16: + return toWaveformOffset(4, temperatureOffset); + default: + throw std::invalid_argument{"Invalid waveform mode."}; + } + } } // namespace - EinkDisplay::EinkDisplay(::gui::Size screenSize) - : size{screenSize}, currentWaveform{createDefaultWaveFormSettings(EinkWaveformGC16)}, + EinkDisplayColorMode_e translateDisplayColorMode(const EinkDisplayColorMode mode) + { + return mode == EinkDisplayColorMode::EinkDisplayColorModeStandard + ? EinkDisplayColorMode_e::EinkDisplayColorModeStandard + : EinkDisplayColorMode_e::EinkDisplayColorModeInverted; + } + + EinkStatus translateStatus(const EinkStatus_e status_e) + { + switch (status_e) { + case EinkOK: + return EinkStatus::EinkOK; + case EinkError: + return EinkStatus::EinkError; + case EinkSPIErr: + return EinkStatus::EinkSPIErr; + case EinkSPINotInitializedErr: + return EinkStatus::EinkSPINotInitializedErr; + case EinkDMAErr: + return EinkStatus::EinkDMAErr; + case EinkInitErr: + return EinkStatus::EinkInitErr; + case EinkTimeout: + return EinkStatus::EinkTimeout; + case EinkNoMem: + return EinkStatus::EinkNoMem; + case EinkWaveformsFileOpenFail: + return EinkStatus::EinkWaveformsFileOpenFail; + default: + return EinkStatus::EinkUnknown; + } + } + + EinkDisplay::EinkDisplay(FrameSize size) + : size{size}, currentWaveform{createDefaultWaveFormSettings(EinkWaveformGC16)}, displayMode{EinkDisplayColorMode_e::EinkDisplayColorModeStandard} { #if defined(TARGET_RT1051) @@ -62,9 +132,59 @@ namespace service::eink delete[] currentWaveform.LUTDData; } - EinkStatus_e EinkDisplay::resetAndInit() + EinkStatus EinkDisplay::updateDisplay(std::uint8_t *frameBuffer, [[maybe_unused]] const EinkRefreshMode refreshMode) + { + return update(frameBuffer); + } + + EinkStatus EinkDisplay::refreshDisplay(const EinkRefreshMode refreshMode) + { + const auto isDeepRefresh = refreshMode == EinkRefreshMode::REFRESH_DEEP; + return refresh(isDeepRefresh ? EinkDisplayTimingsDeepCleanMode : EinkDisplayTimingsFastRefreshMode); + } + + EinkStatus EinkDisplay::prepareDisplay(const EinkRefreshMode refreshMode, const WaveformTemperature behaviour) { - return EinkResetAndInitialize(); + powerOn(); + + const auto temperature = + behaviour == WaveformTemperature::KEEP_CURRENT ? getLastTemperature() : EinkGetTemperatureInternal(); + + if (refreshMode == EinkRefreshMode::REFRESH_DEEP) { + auto status = setWaveform(EinkWaveforms_e::EinkWaveformGC16, temperature); + if (status == EinkStatus::EinkOK) { + dither(); + } + return status; + } + return setWaveform(EinkWaveforms_e::EinkWaveformDU2, temperature); + } + + EinkStatus EinkDisplay::showImage(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode) + { + if (const auto status = prepareDisplay(refreshMode, WaveformTemperature::KEEP_CURRENT); + status != EinkStatus::EinkOK) { + return status; + } + + if (const auto status = updateDisplay(frameBuffer, refreshMode); status != EinkStatus::EinkOK) { + return status; + } + + if (const auto status = refreshDisplay(refreshMode); status != EinkStatus::EinkOK) { + return status; + } + return EinkStatus::EinkOK; + } + + void EinkDisplay::prepareEarlyRequest(const EinkRefreshMode refreshMode, const WaveformTemperature behaviour) + { + prepareDisplay(refreshMode, behaviour); + } + + EinkStatus EinkDisplay::resetAndInit() + { + return translateStatus(EinkResetAndInitialize()); } void EinkDisplay::dither() @@ -77,9 +197,6 @@ namespace service::eink if (driverLPSPI) { driverLPSPI->Enable(); } - if (eInkSentinel) { - eInkSentinel->HoldMinimumFrequency(); - } EinkPowerOn(); } @@ -89,9 +206,6 @@ namespace service::eink if (driverLPSPI) { driverLPSPI->Disable(); } - if (eInkSentinel) { - eInkSentinel->ReleaseMinimumFrequency(); - } } void EinkDisplay::shutdown() @@ -104,15 +218,12 @@ namespace service::eink EinkFillScreenWithColor(EinkDisplayColorFilling_e::EinkDisplayColorWhite); } - EinkStatus_e EinkDisplay::update(std::uint8_t *displayBuffer) + EinkStatus EinkDisplay::update(std::uint8_t *displayBuffer) { - return EinkUpdateFrame(pointTopLeft.x, - pointTopLeft.y, - size.width, - size.height, - displayBuffer, - getCurrentBitsPerPixelFormat(), - displayMode); + return translateStatus(EinkUpdateFrame(EinkFrame_t{0, 0, size.width, size.height}, + displayBuffer, + getCurrentBitsPerPixelFormat(), + translateDisplayColorMode(displayMode))); } EinkBpp_e EinkDisplay::getCurrentBitsPerPixelFormat() const noexcept @@ -123,13 +234,13 @@ namespace service::eink return Eink4Bpp; } - EinkStatus_e EinkDisplay::refresh(EinkDisplayTimingsMode_e refreshMode) + EinkStatus EinkDisplay::refresh(const EinkDisplayTimingsMode_e refreshMode) { currentWaveform.useCounter += 1; - return EinkRefreshImage(pointTopLeft.x, pointTopLeft.y, size.width, size.height, refreshMode); + return translateStatus(EinkRefreshImage(EinkFrame_t{0, 0, size.width, size.height}, refreshMode)); } - bool EinkDisplay::isNewWaveformNeeded(EinkWaveforms_e newMode, std::int32_t newTemperature) const + bool EinkDisplay::isNewWaveformNeeded(const EinkWaveforms_e newMode, const std::int32_t newTemperature) const { constexpr auto lenientTemperatureUseCounter = 50; // arbitrary. not documented auto alloweLenientTemperature = currentWaveform.useCounter < lenientTemperatureUseCounter; @@ -160,10 +271,10 @@ namespace service::eink return true; } - EinkStatus_e EinkDisplay::setWaveform(EinkWaveforms_e mode, std::int32_t temperature) + EinkStatus EinkDisplay::setWaveform(const EinkWaveforms_e mode, const std::int32_t temperature) { if (!isNewWaveformNeeded(mode, temperature)) { - return EinkOK; + return EinkStatus::EinkOK; } auto currentOffset = @@ -177,13 +288,13 @@ namespace service::eink if (offset == currentOffset) { // current waveform is still the best fit - return EinkOK; + return EinkStatus::EinkOK; } auto file = std::fopen(LutsFileName, "rb"); if (file == nullptr) { LOG_FATAL("Could not find the LUTS.bin file. Returning"); - return EinkWaveformsFileOpenFail; + return EinkStatus::EinkWaveformsFileOpenFail; } auto fileHandlerCleanup = gsl::finally([&file]() { std::fclose(file); }); @@ -201,43 +312,7 @@ namespace service::eink std::fread(¤tWaveform.LUTCData[1], 1, LUTCSize, file); EinkUpdateWaveform(¤tWaveform); - return EinkOK; - } - - unsigned int EinkDisplay::toWaveformTemperatureOffset(std::int32_t temperature) noexcept - { - if (temperature >= LUTTemperatureCritical) - return LUTTemperatureOffsetCritical; - if (temperature >= LUTTemperatureSubcritical) - return LUTTemperatureOffsetSubcritical; - if (temperature < LUTTemperatureMinimal) { - temperature = LUTTemperatureMinimal; - } - return temperature / LUTTemperatureOffsetInterval; - } - - unsigned int EinkDisplay::toWaveformOffset(unsigned short LUTbank, unsigned int temperatureOffset) noexcept - { - constexpr auto singleLUTOffset = (LUTTemperatureOffsetCritical + 1); - return LUTSTotalSize * (singleLUTOffset * LUTbank + temperatureOffset); - } - - unsigned int EinkDisplay::toWaveformOffset(EinkWaveforms_e mode, unsigned int temperatureOffset) - { - switch (mode) { - case EinkWaveformINIT: - return toWaveformOffset(0, temperatureOffset); - case EinkWaveformA2: - return toWaveformOffset(1, temperatureOffset); - case EinkWaveformDU2: - return toWaveformOffset(2, temperatureOffset); - case EinkWaveformGLD16: - return toWaveformOffset(3, temperatureOffset); - case EinkWaveformGC16: - return toWaveformOffset(4, temperatureOffset); - default: - throw std::invalid_argument{"Invalid waveform mode."}; - } + return EinkStatus::EinkOK; } void EinkDisplay::resetWaveformSettings() @@ -253,7 +328,7 @@ namespace service::eink currentWaveform.LUTCData[0] = EinkLUTC; } - void EinkDisplay::setMode(EinkDisplayColorMode_e mode) noexcept + void EinkDisplay::setMode(const EinkDisplayColorMode mode) noexcept { displayMode = mode; } @@ -263,19 +338,14 @@ namespace service::eink return currentWaveform.temperature; } - ::gui::Size EinkDisplay::getSize() const noexcept - { - return size; - } - [[nodiscard]] auto EinkDisplay::getDevice() const noexcept -> std::shared_ptr { return driverLPSPI; } - void EinkDisplay::setEinkSentinel(std::shared_ptr sentinel) + std::unique_ptr AbstractEinkDisplay::Factory::create(FrameSize size) { - eInkSentinel = std::move(sentinel); + return std::make_unique(size); } -} // namespace service::eink +} // namespace hal::eink diff --git a/module-bsp/board/rt1051/bsp/eink/EinkDisplay.hpp b/module-bsp/board/rt1051/bsp/eink/EinkDisplay.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d85f5c2e7f63878bb351deaa5691954c76c2e759 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eink/EinkDisplay.hpp @@ -0,0 +1,65 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include +#include + +#include + +#include "drivers/lpspi/DriverLPSPI.hpp" +#include "ED028TC1.h" + +namespace hal::eink +{ + /** + * Specifies the Eink display. + * Responsible for handling low-level Eink display operations, e.g. switching power modes, updating, refreshing, + * etc. + */ + class EinkDisplay : public AbstractEinkDisplay + { + public: + EinkDisplay(FrameSize size); + + ~EinkDisplay() noexcept; + + void setMode(EinkDisplayColorMode mode) noexcept override; + EinkStatus showImage(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode) override; + void prepareEarlyRequest(EinkRefreshMode refreshMode, const WaveformTemperature behaviour) override; + + EinkStatus resetAndInit() override; + void dither() override; + void powerOn() override; + void powerOff() override; + void shutdown() override; + void wipeOut() override; + + [[nodiscard]] auto getDevice() const noexcept -> std::shared_ptr override; + + private: + bool isNewWaveformNeeded(const EinkWaveforms_e newMode, const int32_t newTemperature) const; + void resetWaveformSettings(); + + EinkBpp_e getCurrentBitsPerPixelFormat() const noexcept; + + EinkStatus setWaveform(const EinkWaveforms_e mode, const std::int32_t temperature); + + std::int32_t getLastTemperature() const noexcept; + + EinkStatus update(std::uint8_t *displayBuffer); + EinkStatus refresh(const EinkDisplayTimingsMode_e refreshMode); + + EinkStatus updateDisplay(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode); + EinkStatus refreshDisplay(const EinkRefreshMode refreshMode); + EinkStatus prepareDisplay(const EinkRefreshMode refreshMode, const WaveformTemperature behaviour); + + FrameSize size; + + EinkWaveformSettings_t currentWaveform; + EinkDisplayColorMode displayMode; + + std::shared_ptr driverLPSPI; + }; +} // namespace hal::eink diff --git a/module-bsp/board/rt1051/bsp/eink/eink_dimensions.cpp b/module-bsp/board/rt1051/bsp/eink/eink_dimensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89a2b98820561242cfd29a5ca14c7bf8214d07c0 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eink/eink_dimensions.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "eink_dimensions.hpp" + +#include + +namespace hal::eink +{ + + std::uint32_t getDisplayXAxis(EinkFrame_t frame) + { +#if defined(EINK_ROTATE_90_CLOCKWISE) + return BOARD_EINK_DISPLAY_RES_Y - frame.pos_y - frame.height; +#else + return BOARD_EINK_DISPLAY_RES_X - frame.pos_x - frame.width; +#endif + } + + std::uint32_t getDisplayYAxis(EinkFrame_t frame) + { +#if defined(EINK_ROTATE_90_CLOCKWISE) + return BOARD_EINK_DISPLAY_RES_X - frame.pos_x - frame.width; +#else + return BOARD_EINK_DISPLAY_RES_Y - frame.pos_y - frame.height; +#endif + } + + std::uint32_t getDisplayWindowWidth(EinkFrame_t frame) + { +#if defined(EINK_ROTATE_90_CLOCKWISE) + return frame.height; +#else + return frame.width; +#endif + } + + std::uint32_t getDisplayWindowHeight(EinkFrame_t frame) + { +#if defined(EINK_ROTATE_90_CLOCKWISE) + return frame.width; +#else + return frame.height; +#endif + } + +} // namespace hal::eink diff --git a/module-bsp/board/rt1051/bsp/eink/eink_dimensions.hpp b/module-bsp/board/rt1051/bsp/eink/eink_dimensions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..15945e4c34af54312bb980f89568b026e81bcb89 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eink/eink_dimensions.hpp @@ -0,0 +1,25 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include + +#include +#include "ED028TC1.h" + +#if defined(EINK_ROTATE_90_CLOCKWISE) +#define EINK_DISPLAY_RES_X (BOARD_EINK_DISPLAY_RES_Y) +#define EINK_DISPLAY_RES_Y (BOARD_EINK_DISPLAY_RES_X) +#else +#define EINK_DISPLAY_RES_X (BOARD_EINK_DISPLAY_RES_X) +#define EINK_DISPLAY_RES_Y (BOARD_EINK_DISPLAY_RES_Y) +#endif + +namespace hal::eink +{ + std::uint32_t getDisplayXAxis(EinkFrame_t frame); + std::uint32_t getDisplayYAxis(EinkFrame_t frame); + std::uint32_t getDisplayWindowWidth(EinkFrame_t frame); + std::uint32_t getDisplayWindowHeight(EinkFrame_t frame); +} // namespace hal::eink diff --git a/module-bsp/hal/CMakeLists.txt b/module-bsp/hal/CMakeLists.txt index 9d21e0e02f476d6a383e6957c76135583b3135d9..99fb56f1ce5b81760fadbe34b59627daacd8b1f2 100644 --- a/module-bsp/hal/CMakeLists.txt +++ b/module-bsp/hal/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(hal include/hal/GenericFactory.hpp include/hal/battery_charger/AbstractBatteryCharger.hpp include/hal/cellular/SIM.hpp + include/hal/eink/AbstractEinkDisplay.hpp include/hal/key_input/RawKey.hpp include/hal/key_input/KeyEventDefinitions.hpp include/hal/key_input/AbstractKeyInput.hpp diff --git a/module-bsp/hal/include/hal/eink/AbstractEinkDisplay.hpp b/module-bsp/hal/include/hal/eink/AbstractEinkDisplay.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e988dc36cbba181dee2990a46d40f58314f4a6c3 --- /dev/null +++ b/module-bsp/hal/include/hal/eink/AbstractEinkDisplay.hpp @@ -0,0 +1,80 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include + +#include + +namespace hal::eink +{ + + enum class EinkDisplayColorMode + { + EinkDisplayColorModeStandard, + EinkDisplayColorModeInverted + }; + + enum class WaveformTemperature + { + KEEP_CURRENT, + MEASURE_NEW, + }; + + enum class EinkRefreshMode + { + REFRESH_NONE, + REFRESH_FAST = 1, + REFRESH_DEEP + }; + + enum class EinkStatus + { + EinkOK, //!< EinkOK + EinkError, + EinkSPIErr, //!< EinkSPIErr + EinkSPINotInitializedErr, //!< EinkSPINotInitializedErr + EinkDMAErr, //!< EinkDMAErr + EinkInitErr, //!< EinkInitErr + EinkTimeout, //!< Timeout occured while waiting for not busy signal from EINK + EinkNoMem, //!< Could not allocate memory + EinkWaveformsFileOpenFail, //!< Could not open the file with the waveforms for EPD display + + EinkUnknown, + }; + + struct FrameSize + { + uint16_t width; + uint16_t height; + }; + + struct EinkFrame + { + uint16_t pos_x; + uint16_t pos_y; + FrameSize size; + }; + + class AbstractEinkDisplay + { + public: + struct Factory + { + static std::unique_ptr create(FrameSize size); + }; + + virtual ~AbstractEinkDisplay() = default; + + virtual void setMode(const EinkDisplayColorMode mode) noexcept = 0; + virtual EinkStatus showImage(std::uint8_t *frameBuffer, const EinkRefreshMode refreshMode) = 0; + virtual void prepareEarlyRequest(EinkRefreshMode refreshMode, const WaveformTemperature behaviour) = 0; + + virtual void dither() = 0; + virtual void powerOn() = 0; + virtual void powerOff() = 0; + virtual void shutdown() = 0; + virtual void wipeOut() = 0; + virtual EinkStatus resetAndInit() = 0; + virtual std::shared_ptr getDevice() const noexcept = 0; + }; +} // namespace hal::eink diff --git a/module-gui/CMakeLists.txt b/module-gui/CMakeLists.txt index 8f9e79954b4095f0ba00116e82f30e3f4450f5fe..811e4a89c1510fec451f09826b4ff2d7dd38c075 100644 --- a/module-gui/CMakeLists.txt +++ b/module-gui/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(${PROJECT_NAME} json::json pugixml::pugixml utils-time + Microsoft.GSL::GSL ) # Board specific compilation definitions,options,include directories and features diff --git a/module-services/service-cellular/call/CMakeLists.txt b/module-services/service-cellular/call/CMakeLists.txt index 945eeb2a441bbd3abff33129b37f994062c442fd..b0481261bcff16fe88abb3588c9b8ba51a699d3e 100644 --- a/module-services/service-cellular/call/CMakeLists.txt +++ b/module-services/service-cellular/call/CMakeLists.txt @@ -25,6 +25,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE + Microsoft.GSL::GSL module-sys sml::utils::logger PUBLIC diff --git a/module-services/service-eink/CMakeLists.txt b/module-services/service-eink/CMakeLists.txt index af26e494abb78090df7b3a86c504eed475eaefcb..84b3a06481dc94f3459a6ba27899f94565240cb0 100644 --- a/module-services/service-eink/CMakeLists.txt +++ b/module-services/service-eink/CMakeLists.txt @@ -3,7 +3,6 @@ message( "${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}" ) set(SOURCES ServiceEink.cpp - EinkDisplay.cpp api/ServiceEinkApi.cpp internal/StaticData.cpp messages/ImageMessage.cpp @@ -14,11 +13,13 @@ add_library(${PROJECT_NAME} STATIC ${SOURCES}) add_board_subdirectory(board) target_link_libraries( ${PROJECT_NAME} - module-utils + PUBLIC module-bsp - Microsoft.GSL::GSL messagetype module-sys + PRIVATE + Microsoft.GSL::GSL + module-utils ) target_include_directories(${PROJECT_NAME} diff --git a/module-services/service-eink/EinkDisplay.hpp b/module-services/service-eink/EinkDisplay.hpp deleted file mode 100644 index b9597ec6653566297e19a5949f4ca995df588927..0000000000000000000000000000000000000000 --- a/module-services/service-eink/EinkDisplay.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. -// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md - -#pragma once - -#include -#include -#include "Common.hpp" - -#include -#include -#include "drivers/lpspi/DriverLPSPI.hpp" -#include "EinkSentinel.hpp" - -namespace service::eink -{ - /** - * Specifies the Eink display. - * Responsible for handling low-level Eink display operations, e.g. switching power modes, updating, refreshing, - * etc. - */ - class EinkDisplay - { - public: - explicit EinkDisplay(::gui::Size screenSize); - ~EinkDisplay() noexcept; - - EinkStatus_e resetAndInit(); - EinkStatus_e update(std::uint8_t *displayBuffer); - EinkStatus_e refresh(EinkDisplayTimingsMode_e refreshMode); - void dither(); - void powerOn(); - void powerOff(); - void shutdown(); - void wipeOut(); - - EinkStatus_e setWaveform(EinkWaveforms_e mode, std::int32_t temperature); - void setMode(EinkDisplayColorMode_e mode) noexcept; - - std::int32_t getLastTemperature() const noexcept; - ::gui::Size getSize() const noexcept; - - [[nodiscard]] auto getDevice() const noexcept -> std::shared_ptr; - void setEinkSentinel(std::shared_ptr sentinel); - - private: - static unsigned int toWaveformTemperatureOffset(std::int32_t temperature) noexcept; - static unsigned int toWaveformOffset(unsigned short LUTbank, unsigned int temperatureOffset) noexcept; - static unsigned int toWaveformOffset(EinkWaveforms_e mode, unsigned int temperatureOffset); - bool isNewWaveformNeeded(EinkWaveforms_e newMode, int32_t newTemperature) const; - void resetWaveformSettings(); - - EinkBpp_e getCurrentBitsPerPixelFormat() const noexcept; - static constexpr ::gui::Point pointTopLeft{0, 0}; - const ::gui::Size size; - EinkWaveformSettings_t currentWaveform; - EinkDisplayColorMode_e displayMode; - - std::shared_ptr driverLPSPI; - std::shared_ptr eInkSentinel; - }; -} // namespace service::eink diff --git a/module-services/service-eink/ServiceEink.cpp b/module-services/service-eink/ServiceEink.cpp index 1c1edf56857d2330f04757306f1e87083b273025..191809e037e6b2e9548c7004464d6b86e1c343ea 100644 --- a/module-services/service-eink/ServiceEink.cpp +++ b/module-services/service-eink/ServiceEink.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include @@ -29,22 +29,38 @@ namespace service::eink constexpr auto ServceEinkStackDepth = 4096U; constexpr std::chrono::milliseconds displayPowerOffTimeout{2000}; - std::string toSettingString(EinkModeMessage::Mode mode) + std::string toSettingString(const EinkModeMessage::Mode mode) { if (mode == EinkModeMessage::Mode::Normal) { return "0"; } return "1"; } + + hal::eink::EinkRefreshMode translateToEinkRefreshMode(const gui::RefreshModes guiRefreshMode) + { + switch (guiRefreshMode) { + case gui::RefreshModes::GUI_REFRESH_DEEP: + return hal::eink::EinkRefreshMode::REFRESH_DEEP; + case gui::RefreshModes::GUI_REFRESH_FAST: + return hal::eink::EinkRefreshMode::REFRESH_FAST; + default: + return hal::eink::EinkRefreshMode::REFRESH_NONE; + } + } } // namespace ServiceEink::ServiceEink(ExitAction exitAction, const std::string &name, std::string parent) - : sys::Service(name, std::move(parent), ServceEinkStackDepth), - exitAction{exitAction}, display{{BOARD_EINK_DISPLAY_RES_X, BOARD_EINK_DISPLAY_RES_Y}}, - currentState{State::Running}, settings{std::make_unique()} + : sys::Service(name, std::move(parent), ServceEinkStackDepth), exitAction{exitAction}, + currentState{State::Running}, display{hal::eink::AbstractEinkDisplay::Factory::create( + hal::eink::FrameSize{BOARD_EINK_DISPLAY_RES_X, BOARD_EINK_DISPLAY_RES_Y})}, + settings{std::make_unique()} { displayPowerOffTimer = sys::TimerFactory::createSingleShotTimer( - this, "einkDisplayPowerOff", displayPowerOffTimeout, [this](sys::Timer &) { display.powerOff(); }); + this, "einkDisplayPowerOff", displayPowerOffTimeout, [this](sys::Timer &) { + display->powerOff(); + eInkSentinel->ReleaseMinimumFrequency(); + }); connect(typeid(EinkModeMessage), [this](sys::Message *message) -> sys::MessagePointer { return handleEinkModeChangedMessage(message); }); @@ -55,7 +71,6 @@ namespace service::eink [this](sys::Message *request) -> sys::MessagePointer { return handlePrepareEarlyRequest(request); }); eInkSentinel = std::make_shared(name::eink, this); - display.setEinkSentinel(eInkSentinel); } sys::MessagePointer ServiceEink::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *response) @@ -66,7 +81,7 @@ namespace service::eink sys::ReturnCodes ServiceEink::InitHandler() { LOG_INFO("Initializing"); - if (const auto status = display.resetAndInit(); status != EinkOK) { + if (const auto status = display->resetAndInit(); status != hal::eink::EinkStatus::EinkOK) { LOG_FATAL("Error: Could not initialize Eink display!"); return sys::ReturnCodes::Failure; } @@ -74,13 +89,14 @@ namespace service::eink settings->init(service::ServiceProxy(shared_from_this())); initStaticData(); - auto deviceRegistrationMsg = std::make_shared(display.getDevice()); + auto deviceRegistrationMsg = std::make_shared(display->getDevice()); bus.sendUnicast(deviceRegistrationMsg, service::name::system_manager); auto sentinelRegistrationMsg = std::make_shared(eInkSentinel); bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager); - display.powerOn(); + display->powerOn(); + eInkSentinel->HoldMinimumFrequency(); return sys::ReturnCodes::Success; } @@ -96,9 +112,9 @@ namespace service::eink sys::ReturnCodes ServiceEink::DeinitHandler() { if (exitAction == ExitAction::WipeOut) { - display.wipeOut(); + display->wipeOut(); } - display.shutdown(); + display->shutdown(); settings->deinit(); return sys::ReturnCodes::Success; } @@ -123,17 +139,19 @@ namespace service::eink { setState(State::Running); - if (const auto status = display.resetAndInit(); status != EinkOK) { + if (const auto status = display->resetAndInit(); status != hal::eink::EinkStatus::EinkOK) { LOG_FATAL("Error: Could not initialize Eink display!"); } - display.powerOn(); - display.powerOff(); + eInkSentinel->HoldMinimumFrequency(); + display->powerOn(); + display->powerOff(); + eInkSentinel->ReleaseMinimumFrequency(); } void ServiceEink::suspend() { setState(State::Suspended); - display.shutdown(); + display->shutdown(); } sys::MessagePointer ServiceEink::handleEinkModeChangedMessage(sys::Message *message) @@ -149,10 +167,10 @@ namespace service::eink { auto invertedModeRequested = mode == EinkModeMessage::Mode::Invert; if (invertedModeRequested) { - display.setMode(EinkDisplayColorMode_e::EinkDisplayColorModeInverted); + display->setMode(hal::eink::EinkDisplayColorMode::EinkDisplayColorModeInverted); } else { - display.setMode(EinkDisplayColorMode_e::EinkDisplayColorModeStandard); + display->setMode(hal::eink::EinkDisplayColorMode::EinkDisplayColorModeStandard); } internal::StaticData::get().setInvertedMode(invertedModeRequested); } @@ -166,70 +184,22 @@ namespace service::eink } utils::time::Scoped measurement("ImageMessage"); - showImage(message->getData(), message->getRefreshMode()); - return std::make_shared(message->getContextId()); - } - - void ServiceEink::showImage(std::uint8_t *frameBuffer, ::gui::RefreshModes refreshMode) - { displayPowerOffTimer.stop(); - auto displayPowerOffTimerReload = gsl::finally([this]() { displayPowerOffTimer.start(); }); - if (const auto status = prepareDisplay(refreshMode, WaveformTemperature::KEEP_CURRENT); - status != EinkStatus_e::EinkOK) { - LOG_FATAL("Failed to prepare frame"); - return; - } - - if (const auto status = updateDisplay(frameBuffer, refreshMode); status != EinkStatus_e::EinkOK) { - LOG_FATAL("Failed to update frame"); - return; + auto status = display->showImage(message->getData(), translateToEinkRefreshMode(message->getRefreshMode())); + if (status != hal::eink::EinkStatus::EinkOK) { + LOG_ERROR("Error during drawing image on eink: %s", magic_enum::enum_name(status).data()); } - if (const auto status = refreshDisplay(refreshMode); status != EinkStatus_e::EinkOK) { - LOG_FATAL("Failed to refresh frame"); - return; - } - } - - EinkStatus_e ServiceEink::updateDisplay(std::uint8_t *frameBuffer, ::gui::RefreshModes refreshMode) - { - return display.update(frameBuffer); - } - - EinkStatus_e ServiceEink::refreshDisplay(::gui::RefreshModes refreshMode) - { - const auto isDeepRefresh = refreshMode == ::gui::RefreshModes::GUI_REFRESH_DEEP; - return display.refresh(isDeepRefresh ? EinkDisplayTimingsDeepCleanMode : EinkDisplayTimingsFastRefreshMode); - } - - EinkStatus_e ServiceEink::prepareDisplay(::gui::RefreshModes refreshMode, WaveformTemperature behaviour) - { - EinkStatus_e status; - - displayPowerOffTimer.stop(); - display.powerOn(); - - const auto temperature = behaviour == WaveformTemperature::KEEP_CURRENT ? display.getLastTemperature() - : EinkGetTemperatureInternal(); - - if (refreshMode == ::gui::RefreshModes::GUI_REFRESH_DEEP) { - status = display.setWaveform(EinkWaveforms_e::EinkWaveformGC16, temperature); - if (status == EinkOK) { - display.dither(); - } - } - else { - status = display.setWaveform(EinkWaveforms_e::EinkWaveformDU2, temperature); - } - return status; + return std::make_shared(message->getContextId()); } sys::MessagePointer ServiceEink::handlePrepareEarlyRequest(sys::Message *message) { const auto waveformUpdateMsg = static_cast(message); - prepareDisplay(waveformUpdateMsg->getRefreshMode(), WaveformTemperature::MEASURE_NEW); + display->prepareEarlyRequest(translateToEinkRefreshMode(waveformUpdateMsg->getRefreshMode()), + hal::eink::WaveformTemperature::MEASURE_NEW); return sys::MessageNone{}; } diff --git a/module-services/service-eink/ServiceEink.hpp b/module-services/service-eink/ServiceEink.hpp index 76dead12358bcdb604fc212ca5111d0dd4f48a4f..6a4f62673624c47823458d245aea28b6012b6b16 100644 --- a/module-services/service-eink/ServiceEink.hpp +++ b/module-services/service-eink/ServiceEink.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -9,7 +9,6 @@ #include #include "EinkSentinel.hpp" -#include "EinkDisplay.hpp" #include #include @@ -18,6 +17,9 @@ #include #include #include +#include + +#include "Common.hpp" namespace service::eink { @@ -46,23 +48,12 @@ namespace service::eink Suspended }; - /// It takes 25ms to get a new measurement - enum class WaveformTemperature - { - KEEP_CURRENT, - MEASURE_NEW, - }; - void setState(State state) noexcept; bool isInState(State state) const noexcept; void enterActiveMode(); void suspend(); - void showImage(std::uint8_t *frameBuffer, ::gui::RefreshModes refreshMode); - EinkStatus_e prepareDisplay(::gui::RefreshModes refreshMode, WaveformTemperature behaviour); - EinkStatus_e refreshDisplay(::gui::RefreshModes refreshMode); - EinkStatus_e updateDisplay(uint8_t *frameBuffer, ::gui::RefreshModes refreshMode); void setDisplayMode(EinkModeMessage::Mode mode); sys::MessagePointer handleEinkModeChangedMessage(sys::Message *message); @@ -72,8 +63,8 @@ namespace service::eink void initStaticData(); ExitAction exitAction; - EinkDisplay display; State currentState; + std::unique_ptr display; sys::TimerHandle displayPowerOffTimer; std::shared_ptr eInkSentinel; std::unique_ptr settings; diff --git a/module-services/service-gui/CMakeLists.txt b/module-services/service-gui/CMakeLists.txt index 80555816b14e8f64b1c7c11caf3dc8dd44cb7188..6e3051ecfd5974cdf5329b04dc2eb9001c0c2b71 100644 --- a/module-services/service-gui/CMakeLists.txt +++ b/module-services/service-gui/CMakeLists.txt @@ -26,9 +26,13 @@ target_sources(service-gui target_link_libraries(service-gui - service-eink - module-gui - module-apps + PUBLIC + service-eink + module-gui + module-apps + PRIVATE + Microsoft.GSL::GSL + ) target_include_directories(service-gui diff --git a/module-sys/SystemManager/CMakeLists.txt b/module-sys/SystemManager/CMakeLists.txt index 914cd96f1c88fcb3eff2566116356b1fa3392b2c..a36319c298d282802297d20e768e7033fb4e853e 100644 --- a/module-sys/SystemManager/CMakeLists.txt +++ b/module-sys/SystemManager/CMakeLists.txt @@ -47,6 +47,7 @@ target_link_libraries(sys-manager service-desktop msgpack11 system-stats-sink + Microsoft.GSL::GSL ) if (${ENABLE_TESTS}) diff --git a/products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt b/products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt index f945aa572a173151c67cc15db408c2d8a6b07f42..a88a524f838f5d23c38c3adbd012136bb4d45e36 100644 --- a/products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt +++ b/products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt @@ -48,6 +48,7 @@ target_link_libraries(application-bell-background-sounds apps-common bell::audio bell::alarms + Microsoft.GSL::GSL PUBLIC module-gui diff --git a/products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt b/products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt index b8cf828784e6e256644e51fecb8fd33611758ef7..edab090c166fc088ec1fb339d3adf52330409d98 100644 --- a/products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt +++ b/products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt @@ -48,6 +48,7 @@ target_link_libraries(application-bell-powernap bell::keymap bell::alarms bell::db + Microsoft.GSL::GSL PUBLIC module-gui diff --git a/products/BellHybrid/apps/common/CMakeLists.txt b/products/BellHybrid/apps/common/CMakeLists.txt index 975e190e9621a848a52e6ca8525676c42e9e4a69..625b4bec38c2ab7bff51d8e401f1c27dfa57c47c 100644 --- a/products/BellHybrid/apps/common/CMakeLists.txt +++ b/products/BellHybrid/apps/common/CMakeLists.txt @@ -127,6 +127,7 @@ target_link_libraries(application-bell-common bell::audio module-gui bell::db + Microsoft.GSL::GSL ) if (${ENABLE_TESTS}) diff --git a/products/PurePhone/test/test-settings/CMakeLists.txt b/products/PurePhone/test/test-settings/CMakeLists.txt index bc7572f7872d71555190e3c86e396035c4891638..f40dd9077f15c32091bc08e14624809d63eeff25 100644 --- a/products/PurePhone/test/test-settings/CMakeLists.txt +++ b/products/PurePhone/test/test-settings/CMakeLists.txt @@ -13,6 +13,7 @@ add_catch2_executable( module-vfs service-audio service-cellular + Microsoft.GSL::GSL DEPS module-sys )