// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "EinkDisplay.hpp" #include #include #include #include namespace service::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; constexpr auto LUTVersionInterval = 3; constexpr auto LUTSubcritical = 12; constexpr auto LUTCritical = 13; 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; } } // namespace EinkDisplay::EinkDisplay(::gui::Size screenSize) : size{screenSize}, waveformSettings{createDefaultWaveFormSettings(EinkWaveformGC16)}, displayMode{EinkDisplayColorMode_e::EinkDisplayColorModeStandard} {} EinkDisplay::~EinkDisplay() noexcept { delete[] waveformSettings.LUTCData; delete[] waveformSettings.LUTDData; } EinkStatus_e EinkDisplay::resetAndInit() { return EinkResetAndInitialize(); } void EinkDisplay::dither() { EinkDitherDisplay(); } void EinkDisplay::powerOn() { EinkPowerOn(); } void EinkDisplay::powerOff() { EinkPowerOff(); } void EinkDisplay::shutdown() { EinkPowerDown(); } EinkStatus_e EinkDisplay::update(std::uint8_t *displayBuffer) { return EinkUpdateFrame(pointTopLeft.x, pointTopLeft.y, size.width, size.height, displayBuffer, getCurrentBitsPerPixelFormat(), displayMode); } EinkBpp_e EinkDisplay::getCurrentBitsPerPixelFormat() const noexcept { if (waveformSettings.mode == EinkWaveformDU2) { return Eink1Bpp; } return Eink4Bpp; } EinkStatus_e EinkDisplay::refresh(EinkDisplayTimingsMode_e refreshMode) { return EinkRefreshImage(pointTopLeft.x, pointTopLeft.y, size.width, size.height, refreshMode); } bool EinkDisplay::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 EinkDisplay::calculateWaveFormSegment(std::int32_t temperature) const { if (temperature < 38) { return temperature / LUTVersionInterval; } if (temperature < 43) { return LUTSubcritical; } return LUTCritical; } unsigned int EinkDisplay::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: return LUTSTotalSize * (56 + segment); } throw std::invalid_argument{"Invalid waveform mode."}; } void EinkDisplay::resetWaveFormSettings() { delete[] waveformSettings.LUTDData; waveformSettings.LUTDSize = 0; waveformSettings.LUTDData = new std::uint8_t[LUTDSize + 1]; waveformSettings.LUTDData[0] = EinkLUTD; delete[] waveformSettings.LUTCData; waveformSettings.LUTCSize = LUTCSize; waveformSettings.LUTCData = new std::uint8_t[LUTCSize + 1]; waveformSettings.LUTCData[0] = EinkLUTC; } void EinkDisplay::setMode(EinkDisplayColorMode_e mode) noexcept { displayMode = mode; } ::gui::Size EinkDisplay::getSize() const noexcept { return size; } } // namespace service::eink