From 402a7416378afb1864120c3aef3854bee610d457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ta=C5=84ski?= Date: Wed, 23 Dec 2020 09:59:57 +0100 Subject: [PATCH] [EGD-5026] Change Eink service code structure Refactor. --- module-gui/gui/Common.hpp | 9 +- .../model/ApplicationManager.cpp | 4 +- module-services/service-eink/CMakeLists.txt | 1 + module-services/service-eink/EinkScreen.cpp | 210 +++++++++ module-services/service-eink/EinkScreen.hpp | 49 ++ module-services/service-eink/ServiceEink.cpp | 425 ++++++------------ module-services/service-eink/ServiceEink.hpp | 104 +++-- 7 files changed, 444 insertions(+), 358 deletions(-) create mode 100644 module-services/service-eink/EinkScreen.cpp create mode 100644 module-services/service-eink/EinkScreen.hpp diff --git a/module-gui/gui/Common.hpp b/module-gui/gui/Common.hpp index f24ad451abb482dbb1bbb022c7ee05d8ea838102..56a8de4ecf54057074f802aa4f95df19fe370c42 100644 --- a/module-gui/gui/Common.hpp +++ b/module-gui/gui/Common.hpp @@ -30,13 +30,16 @@ namespace gui struct Point { Position x = 0, y = 0; - Point(Position x = 0, Position y = 0) : x(x), y(y) + + constexpr Point(Position x = 0, Position y = 0) : x(x), y(y) {} - [[nodiscard]] auto get(Axis axis) const -> Length + + [[nodiscard]] constexpr auto get(Axis axis) -> Length { return Axis::X == axis ? x : y; } - [[nodiscard]] auto isZero() const -> bool + + [[nodiscard]] constexpr auto isZero() -> bool { return 0 == x && 0 == y; } diff --git a/module-services/service-appmgr/model/ApplicationManager.cpp b/module-services/service-appmgr/model/ApplicationManager.cpp index 669ab98cc53aecfd02d0a868c59722e5c2e81aed..001ea34495a977835193495241f03eab720ad909 100644 --- a/module-services/service-appmgr/model/ApplicationManager.cpp +++ b/module-services/service-appmgr/model/ApplicationManager.cpp @@ -139,8 +139,8 @@ namespace app::manager !ret) { LOG_ERROR("Failed to initialize GUI service"); } - if (bool ret = - sys::SystemManager::CreateService(std::make_shared(service::name::eink, GetName()), this); + if (bool ret = sys::SystemManager::CreateService( + std::make_shared(service::name::eink, GetName()), this); !ret) { LOG_ERROR("Failed to initialize EInk service"); } diff --git a/module-services/service-eink/CMakeLists.txt b/module-services/service-eink/CMakeLists.txt index b8b1d8e2c6142beda41c852b648aed27c9e6db67..70d82d0fe37b21cda42829210bc53961157a5d03 100644 --- a/module-services/service-eink/CMakeLists.txt +++ b/module-services/service-eink/CMakeLists.txt @@ -14,6 +14,7 @@ message( "EINK BOARD PATH: ${CMAKE_CURRENT_LIST_DIR}/${EINK_BOARD_PATH}" ) set(SOURCES ServiceEink.cpp + EinkScreen.cpp messages/ImageMessage.cpp ) diff --git a/module-services/service-eink/EinkScreen.cpp b/module-services/service-eink/EinkScreen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31a77b0315d95a2ff5ad7a0c1d383044fec25e3a --- /dev/null +++ b/module-services/service-eink/EinkScreen.cpp @@ -0,0 +1,210 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "EinkScreen.hpp" + +#include +#include + +#include +#include + +namespace eink +{ + namespace + { + constexpr auto DefaultSurroundingTemperature = -1000; + constexpr auto LutsFileName = "Luts.bin"; + constexpr auto LUTDSize = 16385; + constexpr auto LUTCSize = 64; + constexpr auto LUTRSize = 256; ///< Needed due to \ref EINK_LUTS_FILE_PATH structure + constexpr auto LUTSTotalSize = LUTDSize + LUTCSize + LUTRSize; + + EinkWaveFormSettings_t createDefaultWaveFormSettings(EinkWaveforms_e waveformMode) + { + EinkWaveFormSettings_t settings{}; + settings.mode = waveformMode; + settings.temperature = DefaultSurroundingTemperature; + settings.LUTCData = nullptr; + settings.LUTCSize = 0; + settings.LUTDData = nullptr; + settings.LUTDSize = 0; + return settings; + } + + std::unique_ptr allocateScreenBuffer(gui::Size screenSize) + { + return std::make_unique(screenSize.width * screenSize.height); + } + } // namespace + + EinkScreen::EinkScreen(gui::Size screenSize) + : size{screenSize}, screenBuffer{allocateScreenBuffer(screenSize)}, + waveformSettings{createDefaultWaveFormSettings(EinkWaveformGC16)}, + displayMode{EinkDisplayColorMode_e::EinkDisplayColorModeStandard} + {} + + EinkScreen::~EinkScreen() noexcept + { + delete[] waveformSettings.LUTCData; + delete[] waveformSettings.LUTDData; + } + + EinkStatus_e EinkScreen::resetAndInit() + { + return EinkResetAndInitialize(); + } + + void EinkScreen::dither() + { + EinkDitherDisplay(); + } + + void EinkScreen::powerOn() + { + EinkPowerOn(); + } + + void EinkScreen::powerOff() + { + EinkPowerOff(); + } + + void EinkScreen::shutdown() + { + EinkPowerDown(); + } + + void EinkScreen::setScreenBuffer(const std::uint8_t *buffer, std::uint32_t bufferSize) + { + std::memcpy(screenBuffer.get(), buffer, bufferSize); + } + + void EinkScreen::setScreenBuffer(std::uint8_t value, std::uint32_t bufferSize) + { + std::memset(screenBuffer.get(), value, bufferSize); + } + + EinkStatus_e EinkScreen::update() + { + return EinkUpdateFrame( + pointTopLeft.x, pointTopLeft.y, size.width, size.height, screenBuffer.get(), Eink4Bpp, displayMode); + } + + EinkStatus_e EinkScreen::refresh(EinkDisplayTimingsMode_e refreshMode) + { + return EinkRefreshImage(pointTopLeft.x, pointTopLeft.y, size.width, size.height, refreshMode); + } + + bool EinkScreen::deepClear(std::int32_t temperature) + { + const auto waveformMode = waveformSettings.mode; + + powerOn(); + changeWaveform(EinkWaveforms_e::EinkWaveformA2, temperature); + + fillScreen(gui::Color::White); + for (auto i = 0; i < 2; ++i) { + fillScreen(gui::Color::Black); + fillScreen(gui::Color::White); + } + + changeWaveform(waveformMode, temperature); + powerOff(); + return true; + } + + void EinkScreen::fillScreen(std::uint8_t colorIntensity) + { + const auto screenBufferSize = size.width * size.height; + setScreenBuffer(colorIntensity, screenBufferSize); + if (const auto status = update(); status != EinkOK) { + LOG_FATAL("Failed to update frame"); + } + if (const auto status = refresh(EinkDisplayTimingsFastRefreshMode); status != EinkOK) { + LOG_FATAL("Failed to refresh frame"); + } + } + + bool EinkScreen::changeWaveform(EinkWaveforms_e mode, std::int32_t temperature) + { + if (temperature == waveformSettings.temperature && mode == waveformSettings.mode) { + return EinkOK; + } + waveformSettings.temperature = temperature; + waveformSettings.mode = mode; + + const auto segment = calculateWaveFormSegment(temperature); + auto offset = calculateWaveFormOffset(mode, segment); + + auto file = std::fopen(LutsFileName, "rb"); + if (file == nullptr) { + LOG_FATAL("Could not find the LUTS.bin file. Returning"); + return false; + } + auto fileHandlerCleanup = gsl::finally([&file]() { std::fclose(file); }); + + resetWaveFormSettings(); + std::fseek(file, offset, SEEK_SET); + std::fread(&waveformSettings.LUTDData[1], 1, LUTDSize, file); + + // 0x00 - 1 frame, ... , 0x0F - 16 frames + const uint8_t frameCount = waveformSettings.LUTDData[1] + 1; + // (frameCount * 64) - size of actual LUT; (+1) - the byte containing frameCount; (+1) - EinkLUTD command + waveformSettings.LUTDSize = (frameCount * 64) + 1 + 1; + + offset += LUTDSize; + std::fseek(file, offset, SEEK_SET); + std::fread(&waveformSettings.LUTCData[1], 1, LUTCSize, file); + + EinkUpdateWaveform(&waveformSettings); + return true; + } + + unsigned int EinkScreen::calculateWaveFormSegment(std::int32_t temperature) const + { + if (temperature < 38) { + return temperature / 3; + } + if (temperature < 43) { + return 12; + } + return 13; + } + + unsigned int EinkScreen::calculateWaveFormOffset(EinkWaveforms_e mode, unsigned int segment) const + { + switch (mode) { + case EinkWaveformINIT: + return LUTSTotalSize * segment; + case EinkWaveformA2: + return LUTSTotalSize * (14 + segment); + case EinkWaveformDU2: + return LUTSTotalSize * (28 + segment); + case EinkWaveformGLD16: + return LUTSTotalSize * (42 + segment); + case EinkWaveformGC16: + [[fallthrough]]; + default: + return LUTSTotalSize * (56 + segment); + } + } + + void EinkScreen::resetWaveFormSettings() + { + delete[] waveformSettings.LUTDData; + waveformSettings.LUTDSize = 0; + waveformSettings.LUTDData = new uint8_t[LUTDSize + 1]; + waveformSettings.LUTDData[0] = EinkLUTD; + + delete[] waveformSettings.LUTCData; + waveformSettings.LUTCSize = LUTCSize; + waveformSettings.LUTCData = new uint8_t[LUTCSize + 1]; + waveformSettings.LUTCData[0] = EinkLUTC; + } + + void EinkScreen::setDisplayMode(EinkDisplayColorMode_e mode) noexcept + { + displayMode = mode; + } +} // namespace eink diff --git a/module-services/service-eink/EinkScreen.hpp b/module-services/service-eink/EinkScreen.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2758d3543e54e8b07c37cfcf83fbc337b5efacb0 --- /dev/null +++ b/module-services/service-eink/EinkScreen.hpp @@ -0,0 +1,49 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include + +#include + +#include +#include + +namespace eink +{ + class EinkScreen + { + public: + explicit EinkScreen(gui::Size screenSize = {480, 600}); + ~EinkScreen() noexcept; + + EinkStatus_e resetAndInit(); + EinkStatus_e update(); + EinkStatus_e refresh(EinkDisplayTimingsMode_e refreshMode); + void dither(); + void powerOn(); + void powerOff(); + void shutdown(); + + bool deepClear(std::int32_t temperature); + bool changeWaveform(EinkWaveforms_e mode, std::int32_t temperature); + + void setScreenBuffer(const std::uint8_t *buffer, std::uint32_t bufferSize); + void setDisplayMode(EinkDisplayColorMode_e mode) noexcept; + + private: + void fillScreen(std::uint8_t colorIntensity); + void setScreenBuffer(std::uint8_t value, std::uint32_t bufferSize); + unsigned int calculateWaveFormSegment(std::int32_t temperature) const; + unsigned int calculateWaveFormOffset(EinkWaveforms_e mode, unsigned int segment) const; + void resetWaveFormSettings(); + + static constexpr gui::Point pointTopLeft{0, 0}; + + const gui::Size size; + std::unique_ptr screenBuffer; + EinkWaveFormSettings_t waveformSettings; + EinkDisplayColorMode_e displayMode; + }; +} // namespace eink diff --git a/module-services/service-eink/ServiceEink.cpp b/module-services/service-eink/ServiceEink.cpp index af1da143bc981d70a55ffda3a610d0bcff42fb2e..6053bbd4f174f48183c1c91e608e533f96ed2fbc 100644 --- a/module-services/service-eink/ServiceEink.cpp +++ b/module-services/service-eink/ServiceEink.cpp @@ -13,316 +13,140 @@ #include #include #include -#include #include -#include -#include #include #include -enum class EinkWorkerCommands +namespace eink { - Initialize, - Initialized, - Destroy, - CopyImage, - CopyCompleteCallback, - CopyComplete -}; - -ServiceEink::ServiceEink(const std::string &name, std::string parent) - : sys::Service(name, parent, 4096 + 1024), - einkRenderBuffer(std::make_unique(screen.height * screen.width)), selfRefereshTriggerCount{0}, - temperatureMeasurementTriggerCount{0}, powerOffTriggerCount{0}, - powerOffTimer("PwrOffTimer", this, 3000, sys::Timer::Type::SingleShot) -{ - memset(&waveformSettings, 0, sizeof(EinkWaveFormSettings_t)); - waveformSettings.mode = EinkWaveformGC16; - waveformSettings.temperature = -1000; - - connect(typeid(service::eink::EinkModeMessage), [this](sys::Message *message) -> sys::MessagePointer { - auto msg = static_cast(message); - this->displayMode = msg->getMode() == service::eink::EinkModeMessage::Mode::Normal - ? EinkDisplayColorMode_e::EinkDisplayColorModeStandard - : EinkDisplayColorMode_e::EinkDisplayColorModeInverted; - return sys::MessageNone{}; - }); - - connect(typeid(service::eink::EinkDMATransfer), - [&](sys::Message *request) -> sys::MessagePointer { return handleEinkDMATransfer(request); }); - - connect(typeid(service::eink::ImageMessage), - [&](sys::Message *request) -> sys::MessagePointer { return handleImageMessage(request); }); - - connect(typeid(service::eink::StateRequest), - [&](sys::Message *request) -> sys::MessagePointer { return handleStateRequest(request); }); - - connect(typeid(service::eink::TemperatureUpdate), - [&](sys::Message *request) -> sys::MessagePointer { return handleTemperatureUpdate(request); }); -} - -ServiceEink::~ServiceEink() -{ - if (waveformSettings.LUTCData != nullptr) - delete[] waveformSettings.LUTCData; - if (waveformSettings.LUTDData != nullptr) - delete[] waveformSettings.LUTDData; - waveformSettings.temperature = -1000; -} - -sys::MessagePointer ServiceEink::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) -{ - return std::make_shared(); -} - -sys::ReturnCodes ServiceEink::InitHandler() -{ - - LOG_INFO("[ServiceEink] Initializing"); - - EinkStatus_e einkStatus = EinkResetAndInitialize(); - - if (einkStatus != EinkOK) { - LOG_FATAL("Error: Could not initialize Eink display!\n"); + namespace + { + constexpr auto ServceEinkStackDepth = 4096 + 1024; + } // namespace + + ServiceEink::ServiceEink(const std::string &name, std::string parent) + : sys::Service(name, parent, ServceEinkStackDepth), selfRefereshTriggerCount{0}, + temperatureMeasurementTriggerCount{0}, powerOffTriggerCount{0}, + powerOffTimer("PwrOffTimer", this, 3000, sys::Timer::Type::SingleShot) + { + connect(typeid(service::eink::EinkModeMessage), + [this](sys::Message *message) -> sys::MessagePointer { return handleEinkModeChangedMessage(message); }); + + connect(typeid(service::eink::EinkDMATransfer), + [this](sys::Message *request) -> sys::MessagePointer { return handleEinkDMATransfer(request); }); + + connect(typeid(service::eink::ImageMessage), + [this](sys::Message *request) -> sys::MessagePointer { return handleImageMessage(request); }); + + connect(typeid(service::eink::StateRequest), + [this](sys::Message *request) -> sys::MessagePointer { return handleStateRequest(request); }); + + connect(typeid(service::eink::TemperatureUpdate), + [this](sys::Message *request) -> sys::MessagePointer { return handleTemperatureUpdate(request); }); } - EinkPowerOn(); - - auto msg = std::make_shared(suspendInProgress, shutdownInProgress); - sys::Bus::SendUnicast(msg, service::name::gui, this); - - return sys::ReturnCodes::Success; -} - -sys::ReturnCodes ServiceEink::DeinitHandler() -{ - EinkPowerDown(); - return sys::ReturnCodes::Success; -} - -sys::ReturnCodes ServiceEink::SwitchPowerModeHandler(const sys::ServicePowerMode mode) -{ - LOG_FATAL("[ServiceEink] PowerModeHandler: %s", c_str(mode)); - - switch (mode) { - case sys::ServicePowerMode ::Active: { - suspended = false; - EinkStatus_e einkStatus = EinkResetAndInitialize(); + sys::MessagePointer ServiceEink::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) + { + return std::make_shared(); + } - if (einkStatus != EinkOK) { + sys::ReturnCodes ServiceEink::InitHandler() + { + LOG_INFO("[ServiceEink] Initializing"); + if (const auto status = screen.resetAndInit(); status != EinkOK) { LOG_FATAL("Error: Could not initialize Eink display!\n"); + return sys::ReturnCodes::Failure; } + screen.powerOn(); - EinkPowerOn(); - EinkPowerOff(); - } break; - case sys::ServicePowerMode ::SuspendToRAM: - case sys::ServicePowerMode ::SuspendToNVM: - suspended = true; - powerOffTimer.stop(); - EinkPowerDown(); - break; + auto msg = std::make_shared(suspendInProgress, shutdownInProgress); + sys::Bus::SendUnicast(msg, service::name::gui, this); + return sys::ReturnCodes::Success; } - return sys::ReturnCodes::Success; -} - -bool ServiceEink::changeWaveform(EinkWaveforms_e mode, const int32_t temperature) -{ - - if ((temperature == waveformSettings.temperature) && (mode == waveformSettings.mode)) { - return EinkOK; + sys::ReturnCodes ServiceEink::DeinitHandler() + { + screen.shutdown(); + return sys::ReturnCodes::Success; } - const uint32_t LUTD_SIZE = 16385; - const uint32_t LUTC_SIZE = 64; - const uint32_t LUTR_SIZE = 256; ///< Needed due to \ref EINK_LUTS_FILE_PATH structure - - const uint32_t LUTS_TOTAL_SIZE = LUTD_SIZE + LUTC_SIZE + LUTR_SIZE; - - waveformSettings.temperature = temperature; - waveformSettings.mode = mode; - - unsigned int segment = 0; - - if (temperature < 38) { - segment = temperature / 3; - } - else { - if (temperature < 43) { - segment = 12; - } - else { - segment = 13; + sys::ReturnCodes ServiceEink::SwitchPowerModeHandler(const sys::ServicePowerMode mode) + { + LOG_FATAL("[ServiceEink] PowerModeHandler: %s", c_str(mode)); + + switch (mode) { + case sys::ServicePowerMode::Active: + enterActiveMode(); + break; + case sys::ServicePowerMode::SuspendToRAM: + [[fallthrough]]; + case sys::ServicePowerMode::SuspendToNVM: + suspend(); + break; } + return sys::ReturnCodes::Success; } - uint32_t offset = 0; - - switch (mode) { - case EinkWaveformINIT: - offset = LUTS_TOTAL_SIZE * segment; - break; - - case EinkWaveformA2: - offset = LUTS_TOTAL_SIZE * (14 + segment); - break; - - case EinkWaveformDU2: - offset = LUTS_TOTAL_SIZE * (28 + segment); - break; - - case EinkWaveformGLD16: - offset = LUTS_TOTAL_SIZE * (42 + segment); - break; - - case EinkWaveformGC16: - default: - offset = LUTS_TOTAL_SIZE * (56 + segment); - break; - } - - auto file = std::fopen("Luts.bin", "rb"); - if (file == nullptr) { - LOG_FATAL("Could not find the LUTS.bin file. Returning"); - return false; - } - - if (waveformSettings.LUTDData != nullptr) - delete[] waveformSettings.LUTDData; - - waveformSettings.LUTDSize = 0; - waveformSettings.LUTDData = new uint8_t[LUTD_SIZE + 1]; + void ServiceEink::enterActiveMode() + { + suspended = false; - if (waveformSettings.LUTDData == nullptr) { - LOG_ERROR("Could not allocate memory for the LUTD array"); - std::fclose(file); - return false; + if (const auto status = screen.resetAndInit(); status != EinkOK) { + LOG_FATAL("Error: Could not initialize Eink display!\n"); + } + screen.powerOn(); + screen.powerOff(); } - if (waveformSettings.LUTCData != nullptr) - delete[] waveformSettings.LUTCData; + void ServiceEink::suspend() + { + suspended = true; - waveformSettings.LUTCSize = LUTC_SIZE; - waveformSettings.LUTCData = new uint8_t[LUTC_SIZE + 1]; - if (waveformSettings.LUTCData == nullptr) { - LOG_ERROR("Could not allocate memory for the LUTC array"); - std::fclose(file); - return false; + powerOffTimer.stop(); + screen.shutdown(); } - waveformSettings.LUTDData[0] = EinkLUTD; - waveformSettings.LUTCData[0] = EinkLUTC; - - std::fseek(file, offset, SEEK_SET); - std::fread(&waveformSettings.LUTDData[1], 1, LUTD_SIZE, file); - - uint8_t frameCount = waveformSettings.LUTDData[1] + 1; // 0x00 - 1 frame, ... , 0x0F - 16 frames - waveformSettings.LUTDSize = - frameCount * 64 + 1 + - 1; // (frameCount * 64) - size of actual LUT; (+1) - the byte containing frameCount; (+1) - EinkLUTD command - - offset += LUTD_SIZE; - std::fseek(file, offset, SEEK_SET); - std::fread(&waveformSettings.LUTCData[1], 1, LUTC_SIZE, file); - - std::fclose(file); - - EinkUpdateWaveform(&waveformSettings); - - return true; -} - -bool ServiceEink::deepClearScreen(int8_t temperature) -{ - EinkWaveforms_e wv = waveformSettings.mode; - - EinkPowerOn(); - changeWaveform(EinkWaveforms_e::EinkWaveformA2, temperature); - - EinkStatus_e ret; - memset(einkRenderBuffer.get(), 15, screen.width * screen.height); - ret = EinkUpdateFrame( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, einkRenderBuffer.get(), Eink4Bpp, displayMode); - if (ret != EinkOK) - LOG_FATAL("Failed to update frame"); - ret = EinkRefreshImage( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, EinkDisplayTimingsFastRefreshMode); - if (ret != EinkOK) - LOG_FATAL("Failed to refresh frame"); - - for (uint32_t i = 0; i < 2; i++) { - memset(einkRenderBuffer.get(), 0, screen.width * screen.height); - ret = EinkUpdateFrame( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, einkRenderBuffer.get(), Eink4Bpp, displayMode); - if (ret != EinkOK) - LOG_FATAL("Failed to update frame"); - ret = EinkRefreshImage( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, EinkDisplayTimingsFastRefreshMode); - if (ret != EinkOK) - LOG_FATAL("Failed to refresh frame"); - - memset(einkRenderBuffer.get(), 15, screen.width * screen.height); - ret = EinkUpdateFrame( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, einkRenderBuffer.get(), Eink4Bpp, displayMode); - if (ret != EinkOK) - LOG_FATAL("Failed to update frame"); - ret = EinkRefreshImage( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, EinkDisplayTimingsFastRefreshMode); - if (ret != EinkOK) - LOG_FATAL("Failed to refresh frame"); + sys::MessagePointer ServiceEink::handleEinkModeChangedMessage(sys::Message *message) + { + const auto msg = static_cast(message); + const auto displayMode = msg->getMode() == service::eink::EinkModeMessage::Mode::Normal + ? EinkDisplayColorMode_e::EinkDisplayColorModeStandard + : EinkDisplayColorMode_e::EinkDisplayColorModeInverted; + screen.setDisplayMode(displayMode); + return sys::MessageNone{}; } - changeWaveform(wv, temperature); - - EinkPowerOff(); - - return true; -} - -sys::MessagePointer ServiceEink::handleEinkDMATransfer(sys::Message *message) -{ - utils::time::Scoped scopedtimming("EinkDMATransfer"); - - if (suspended) { - if (suspendInProgress) { - LOG_ERROR("drawing before suspend failed"); - suspendInProgress = false; + sys::MessagePointer ServiceEink::handleEinkDMATransfer(sys::Message *message) + { + utils::time::Scoped measurement("EinkDMATransfer"); + + if (suspended) { + if (suspendInProgress) { + LOG_ERROR("drawing before suspend failed"); + suspendInProgress = false; + } + LOG_INFO("[ServiceEink] Received image while suspended, ignoring"); + return sys::MessageNone{}; } - LOG_INFO("[ServiceEink] Received image while suspended, ignoring"); - } - else { - EinkPowerOn(); - - int32_t temperature = EinkGetTemperatureInternal(); - - EinkStatus_e ret; - if (deepRefresh) { - changeWaveform(EinkWaveforms_e::EinkWaveformGC16, temperature); - EinkDitherDisplay(); + screen.powerOn(); + if (const auto temperature = EinkGetTemperatureInternal(); deepRefresh) { + screen.changeWaveform(EinkWaveforms_e::EinkWaveformGC16, temperature); + screen.dither(); } else { - changeWaveform(EinkWaveforms_e::EinkWaveformDU2, temperature); + screen.changeWaveform(EinkWaveforms_e::EinkWaveformDU2, temperature); } - ret = EinkUpdateFrame( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, einkRenderBuffer.get(), Eink4Bpp, displayMode); - if (ret != EinkOK) + if (const auto status = screen.update(); status != EinkOK) { LOG_FATAL("Failed to update frame"); - - if (deepRefresh) { - ret = EinkRefreshImage( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, EinkDisplayTimingsDeepCleanMode); } - else { - ret = EinkRefreshImage( - pointTopLeft.x, pointTopLeft.y, screen.width, screen.height, EinkDisplayTimingsFastRefreshMode); - } - - if (ret != EinkOK) + if (const auto status = + screen.refresh(deepRefresh ? EinkDisplayTimingsDeepCleanMode : EinkDisplayTimingsFastRefreshMode); + status != EinkOK) { LOG_FATAL("Failed to refresh frame"); + } powerOffTimer.reload(); @@ -330,35 +154,38 @@ sys::MessagePointer ServiceEink::handleEinkDMATransfer(sys::Message *message) suspendInProgress = false; shutdownInProgress = false; sys::Bus::SendUnicast(msg, service::name::gui, this); + + return sys::MessageNone{}; } - return nullptr; -} -sys::MessagePointer ServiceEink::handleImageMessage(sys::Message *request) -{ - auto message = static_cast(request); + sys::MessagePointer ServiceEink::handleImageMessage(sys::Message *request) + { + auto message = static_cast(request); - powerOffTimer.stop(); - memcpy(einkRenderBuffer.get(), message->getData(), message->getSize()); - deepRefresh = message->getDeepRefresh(); + powerOffTimer.stop(); + screen.setScreenBuffer(message->getData(), message->getSize()); + deepRefresh = message->getDeepRefresh(); - shutdownInProgress = message->getShutdown(); - if (shutdownInProgress) - LOG_DEBUG("Shutdown In Progress"); + shutdownInProgress = message->getShutdown(); + if (shutdownInProgress) { + LOG_DEBUG("Shutdown In Progress"); + } + suspendInProgress = message->getSuspend(); + if (suspendInProgress) { + LOG_DEBUG("Suspend In Progress"); + } - suspendInProgress = message->getSuspend(); - if (suspendInProgress) - LOG_DEBUG("Suspend In Progress"); - sys::Bus::SendUnicast(std::make_shared(), GetName(), this); - return std::make_shared(); -} + sys::Bus::SendUnicast(std::make_shared(), GetName(), this); + return std::make_shared(); + } -sys::MessagePointer ServiceEink::handleStateRequest(sys::Message *) -{ - return std::make_shared(suspendInProgress, shutdownInProgress); -} + sys::MessagePointer ServiceEink::handleStateRequest(sys::Message *) + { + return std::make_shared(suspendInProgress, shutdownInProgress); + } -sys::MessagePointer ServiceEink::handleTemperatureUpdate(sys::Message *) -{ - return nullptr; -} + sys::MessagePointer ServiceEink::handleTemperatureUpdate(sys::Message *) + { + return nullptr; + } +} // namespace eink diff --git a/module-services/service-eink/ServiceEink.hpp b/module-services/service-eink/ServiceEink.hpp index efc00bbbbdebb3a1836176c29da6dfe7da131a06..e19745cf92043a34a6e7fb0a2c99510f4065372d 100644 --- a/module-services/service-eink/ServiceEink.hpp +++ b/module-services/service-eink/ServiceEink.hpp @@ -13,58 +13,54 @@ #include #include -class ServiceEink : public sys::Service -{ - gui::Size screen = {480, 600}; - gui::Point pointTopLeft = {0, 0}; - std::unique_ptr einkRenderBuffer; - - protected: - // counts timer triggers from last self refresh - uint32_t selfRefereshTriggerCount; - // counts timer events from last temperature measurement - uint32_t temperatureMeasurementTriggerCount; - // counts trigger counts from last action that required eink to be powered on - uint32_t powerOffTriggerCount; - - // number of timer triggers required to execute self refresh handler - const uint32_t selfRefereshTriggerValue = 60; - // number of timer triggers required to execute temperature measurement handler - const uint32_t temperatureMeasurementTriggerValue = 5 * 60; - // number of timer triggers from last action requiring power on eink to power down eink. - const uint32_t powerOffTriggerValue = 3; - - // structure with recently loaded waveformdata - EinkWaveFormSettings_t waveformSettings; - - EinkDisplayColorMode_e displayMode = EinkDisplayColorMode_e::EinkDisplayColorModeStandard; - - bool suspended = false; - - bool suspendInProgress = false; - bool shutdownInProgress = false; +#include "EinkScreen.hpp" - bool changeWaveform(EinkWaveforms_e Mode, const int32_t temperature); - - bool deepClearScreen(int8_t temperature); - - bool deepRefresh = false; - - sys::ms powerOffTime = 3000; - sys::Timer powerOffTimer; - - public: - ServiceEink(const std::string &name, std::string parent = ""); - ~ServiceEink() override; - - sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override; - sys::ReturnCodes InitHandler() override; - sys::ReturnCodes DeinitHandler() override; - sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override final; - - private: - sys::MessagePointer handleEinkDMATransfer(sys::Message *message); - sys::MessagePointer handleImageMessage(sys::Message *message); - sys::MessagePointer handleStateRequest(sys::Message *messge); - sys::MessagePointer handleTemperatureUpdate(sys::Message *); -}; +namespace eink +{ + class ServiceEink : public sys::Service + { + protected: + EinkScreen screen; + + // counts timer triggers from last self refresh + uint32_t selfRefereshTriggerCount; + // counts timer events from last temperature measurement + uint32_t temperatureMeasurementTriggerCount; + // counts trigger counts from last action that required eink to be powered on + uint32_t powerOffTriggerCount; + + // number of timer triggers required to execute self refresh handler + const uint32_t selfRefereshTriggerValue = 60; + // number of timer triggers required to execute temperature measurement handler + const uint32_t temperatureMeasurementTriggerValue = 5 * 60; + // number of timer triggers from last action requiring power on eink to power down eink. + const uint32_t powerOffTriggerValue = 3; + + bool suspended = false; + + bool suspendInProgress = false; + bool shutdownInProgress = false; + bool deepRefresh = false; + + sys::ms powerOffTime = 3000; + sys::Timer powerOffTimer; + + public: + explicit ServiceEink(const std::string &name, std::string parent = {}); + + sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override; + sys::ReturnCodes InitHandler() override; + sys::ReturnCodes DeinitHandler() override; + sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override final; + + private: + void enterActiveMode(); + void suspend(); + + sys::MessagePointer handleEinkModeChangedMessage(sys::Message *message); + sys::MessagePointer handleEinkDMATransfer(sys::Message *message); + sys::MessagePointer handleImageMessage(sys::Message *message); + sys::MessagePointer handleStateRequest(sys::Message *messge); + sys::MessagePointer handleTemperatureUpdate(sys::Message *); + }; +} // namespace eink