~aleteoryx/muditaos

f79313e397d254e2a0a2fbd2245f622327e83b0f — Lefucjusz 2 years ago 476235d
[BH-1661] E-ink display power management tweaks

Tweaks and changes required to optimize
power consumption for Harmony.
M harmony_changelog.md => harmony_changelog.md +2 -1
@@ 21,10 21,11 @@
* Added error handling for incorrect audio formats and corrupted files inside Relaxation app
* Added error message when files limit is exceeded in Relaxation app

### Changed
### Changed / Improved

* Added new field to deviceInfo endpoint
* Changed order in which files are displayed in Relaxation
* Optimized E-Ink energy consumption

## [1.9.0 2023-04-03]


M module-bsp/board/rt1051/bellpx/CMakeLists.txt => module-bsp/board/rt1051/bellpx/CMakeLists.txt +1 -1
@@ 17,7 17,7 @@ target_sources(
        bsp/audio/AW8898driver.cpp
        bsp/audio/CodecAW8898.cpp

        bsp/eink/eink_pin_config.cpp
        bsp/eink/eink_gpio.cpp
        bsp/lpm/PowerProfile.cpp
        bsp/lpm/RT1051LPM.cpp
        bsp/rotary_encoder/rotary_encoder.cpp

A module-bsp/board/rt1051/bellpx/bsp/eink/eink_gpio.cpp => module-bsp/board/rt1051/bellpx/bsp/eink/eink_gpio.cpp +63 -0
@@ 0,0 1,63 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "drivers/gpio/DriverGPIO.hpp"
#include "board/BoardDefinitions.hpp"

namespace bsp::eink
{
    using namespace drivers;

    namespace
    {
        constexpr auto LogicLow  = 0;
        constexpr auto LogicHigh = 1;
    } // namespace

    void eink_gpio_configure()
    {
        const auto gpio_pwren =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_BELL_PWR_GPIO), DriverGPIOParams{});

        gpio_pwren->ConfPin(
            DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                .defLogic = LogicHigh,
                                .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_BELL_PWR_PIN)});

        const auto gpio =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_GPIO), DriverGPIOParams{});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = LogicHigh,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_CS_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = LogicLow,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_RESET_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingEdge,
                                          .defLogic = LogicLow,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN)});

        gpio->ClearPortInterrupts(1 << static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
        gpio->DisableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    }

    void eink_gpio_power_on()
    {
        const auto gpio_pwren =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_BELL_PWR_GPIO), DriverGPIOParams{});
        gpio_pwren->WritePin(static_cast<std::uint32_t>(BoardDefinitions::EINK_BELL_PWR_PIN), LogicHigh);
    }

    void eink_gpio_power_off()
    {
        const auto gpio_pwren =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_BELL_PWR_GPIO), DriverGPIOParams{});
        gpio_pwren->WritePin(static_cast<std::uint32_t>(BoardDefinitions::EINK_BELL_PWR_PIN), LogicLow);
    }
} // namespace bsp::eink

R module-bsp/board/rt1051/bellpx/bsp/eink/eink_pin_config.hpp => module-bsp/board/rt1051/bellpx/bsp/eink/eink_gpio.hpp +20 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 6,10 6,27 @@
namespace bsp::eink
{
    /**
     * eink_configure_gpio_pins
     * eink_gpio_configure
     *
     * This method initializes all GPIO pins needed for eInk handling.
     */

    void eink_configure_gpio_pins();
    void eink_gpio_configure();

    /**
     * eink_gpio_power_on
     *
     * This method physically turns on display power.
     */

    void eink_gpio_power_on();

    /**
     * eink_gpio_power_off
     *
     * This method physically turns off display power.
     */

    void eink_gpio_power_off();

} // namespace bsp::eink

D module-bsp/board/rt1051/bellpx/bsp/eink/eink_pin_config.cpp => module-bsp/board/rt1051/bellpx/bsp/eink/eink_pin_config.cpp +0 -42
@@ 1,42 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "drivers/gpio/DriverGPIO.hpp"
#include "board/BoardDefinitions.hpp"

namespace bsp::eink
{

    void eink_configure_gpio_pins()
    {
        using namespace drivers;

        auto gpio_pwren =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_BELL_PWR_GPIO), DriverGPIOParams{});

        gpio_pwren->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                                .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                                .defLogic = 1,
                                                .pin = static_cast<uint32_t>(BoardDefinitions::EINK_BELL_PWR_PIN)});

        auto gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_GPIO), DriverGPIOParams{});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = 1,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_CS_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = 0,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_RESET_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingEdge,
                                          .defLogic = 0,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN)});

        gpio->ClearPortInterrupts(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    }
} // namespace bsp::eink

M module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp => module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp +26 -23
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "dma_config.h"


@@ 62,18 62,13 @@

#define ED028TC1_BUSY_STATE_TIMEOUT_MS 2000 // Time after the display should for sure exit the busy state

#define _delay_ms(ms) vTaskDelay(pdMS_TO_TICKS(ms))

/// This is DMA handle for internal frame buffer memory-to-memory copying operation
static edma_handle_t s_einkMemcpyDma_handle __attribute__((used));

using namespace drivers;
using namespace magic_enum;
static std::shared_ptr<drivers::DriverDMA> dma;
static std::shared_ptr<drivers::DriverDMAMux> dmamux;

/* Internal variable definitions */
static uint8_t s_einkIsPoweredOn = false; //  Variable which contains the state of the power of the EPD display
static bool s_einkIsPoweredOn = false; //  Variable which contains the state of the power of the EPD display

static EinkWaveforms_e s_einkConfiguredWaveform =
    EinkWaveformGC16; //  This variable contains the current waveform set in the display


@@ 533,30 528,38 @@ uint8_t EinkIsPoweredOn()

void EinkPowerOn()
{
    if (!s_einkIsPoweredOn) {
        uint8_t cmd = EinkPowerON; // 0x04
        if (BSP_EinkWriteData(&cmd, sizeof(cmd), SPI_AUTOMATIC_CS) != 0) {
            EinkResetAndInitialize();
            return;
        }
    if (s_einkIsPoweredOn) {
        return;
    }

    BSP_EinkLogicPowerOn();

        BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout));
        s_einkIsPoweredOn = true;
    uint8_t cmd = EinkPowerON; // 0x04
    if (BSP_EinkWriteData(&cmd, sizeof(cmd), SPI_AUTOMATIC_CS) != 0) {
        EinkResetAndInitialize();
        return;
    }
    BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout));

    s_einkIsPoweredOn = true;
}

void EinkPowerOff()
{
    if (s_einkIsPoweredOn) {
        uint8_t cmd = EinkPowerOFF; // 0x02
        if (BSP_EinkWriteData(&cmd, sizeof(cmd), SPI_AUTOMATIC_CS) != 0) {
            EinkResetAndInitialize();
            return;
        }
    if (!s_einkIsPoweredOn) {
        return;
    }

        BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout));
        s_einkIsPoweredOn = false;
    uint8_t cmd = EinkPowerOFF; // 0x02
    if (BSP_EinkWriteData(&cmd, sizeof(cmd), SPI_AUTOMATIC_CS) != 0) {
        EinkResetAndInitialize();
        return;
    }
    BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout));

    BSP_EinkLogicPowerOff();

    s_einkIsPoweredOn = false;
}

void EinkPowerDown(void)

M module-bsp/board/rt1051/bsp/eink/bsp_eink.cpp => module-bsp/board/rt1051/bsp/eink/bsp_eink.cpp +31 -26
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp_eink.h"


@@ 7,7 7,7 @@
#include "fsl_lpspi_edma.h"
#include "fsl_common.h"
#include "dma_config.h"
#include "bsp/eink/eink_pin_config.hpp"
#include "bsp/eink/eink_gpio.hpp"

#include "FreeRTOS.h"
#include "semphr.h"


@@ 180,7 180,7 @@ status_t BSP_EinkInit(bsp_eink_BusyEvent event)

    gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_GPIO), DriverGPIOParams{});

    bsp::eink::eink_configure_gpio_pins();
    bsp::eink::eink_gpio_configure();

    s_eink_lpspi_master_config.baudRate     = BSP_EINK_TRANSFER_WRITE_CLOCK;
    s_eink_lpspi_master_config.bitsPerFrame = 8;


@@ 229,24 229,6 @@ status_t BSP_EinkInit(bsp_eink_BusyEvent event)
    return kStatus_Success;
}

status_t BSP_EinkChangeSpiFrequency(uint32_t frequencyHz)
{
    uint32_t tcrPrescalerValue = 0;

    LPSPI_Enable(BSP_EINK_LPSPI_BASE, false);
    LPSPI_MasterSetBaudRate(
        BSP_EINK_LPSPI_BASE, frequencyHz, GetPerphSourceClock(PerphClock_LPSPI), &tcrPrescalerValue);

    s_eink_lpspi_master_config.baudRate = frequencyHz;
    BSP_EINK_LPSPI_BASE->TCR =
        LPSPI_TCR_CPOL(s_eink_lpspi_master_config.cpol) | LPSPI_TCR_CPHA(s_eink_lpspi_master_config.cpha) |
        LPSPI_TCR_LSBF(s_eink_lpspi_master_config.direction) |
        LPSPI_TCR_FRAMESZ(s_eink_lpspi_master_config.bitsPerFrame - 1) | LPSPI_TCR_PRESCALE(tcrPrescalerValue) |
        LPSPI_TCR_PCS(s_eink_lpspi_master_config.whichPcs);

    return 0;
}

void BSP_EinkDeinit(void)
{
    LPSPI_Enable(BSP_EINK_LPSPI_BASE, false);


@@ 272,8 254,34 @@ void BSP_EinkDeinit(void)
    gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    gpio->ClearPortInterrupts(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    gpio.reset();
}

void BSP_EinkLogicPowerOn()
{
    bsp::eink::eink_gpio_power_on();
}

    // pll.reset(); TODO:M.P
void BSP_EinkLogicPowerOff()
{
    bsp::eink::eink_gpio_power_off();
}

status_t BSP_EinkChangeSpiFrequency(uint32_t frequencyHz)
{
    uint32_t tcrPrescalerValue = 0;

    LPSPI_Enable(BSP_EINK_LPSPI_BASE, false);
    LPSPI_MasterSetBaudRate(
        BSP_EINK_LPSPI_BASE, frequencyHz, GetPerphSourceClock(PerphClock_LPSPI), &tcrPrescalerValue);

    s_eink_lpspi_master_config.baudRate = frequencyHz;
    BSP_EINK_LPSPI_BASE->TCR =
        LPSPI_TCR_CPOL(s_eink_lpspi_master_config.cpol) | LPSPI_TCR_CPHA(s_eink_lpspi_master_config.cpha) |
        LPSPI_TCR_LSBF(s_eink_lpspi_master_config.direction) |
        LPSPI_TCR_FRAMESZ(s_eink_lpspi_master_config.bitsPerFrame - 1) | LPSPI_TCR_PRESCALE(tcrPrescalerValue) |
        LPSPI_TCR_PCS(s_eink_lpspi_master_config.whichPcs);

    return 0;
}

status_t BSP_EinkWriteData(void *txBuffer, uint32_t len, eink_spi_cs_config_e cs)


@@ 287,7 295,7 @@ status_t BSP_EinkWriteData(void *txBuffer, uint32_t len, eink_spi_cs_config_e cs
        BSP_EinkWriteCS(BSP_Eink_CS_Clr);
    }

    uint8_t loopCnt    = (len / (DMA_MAX_SINGLE_TRANSACTION_PAYLOAD + 1)) + 1;
    const uint8_t loopCnt = (len / (DMA_MAX_SINGLE_TRANSACTION_PAYLOAD + 1)) + 1;
    uint32_t frameSize = 0;
    uint32_t bytesSent = 0;



@@ 453,9 461,6 @@ void BSP_EinkWriteCS(bsp_eink_cs_ctrl_t ctrl)
    else if (ctrl == BSP_Eink_CS_Set) {
        gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::EINK_CS_PIN), 1);
    }
    else {
        return;
    }
}

BaseType_t BSP_EinkBusyPinStateChangeHandler(void)

M module-bsp/board/rt1051/bsp/eink/bsp_eink.h => module-bsp/board/rt1051/bsp/eink/bsp_eink.h +5 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef EINK_BSP_EINK_H_


@@ 31,6 31,10 @@ extern "C"

    status_t BSP_EinkInit(bsp_eink_BusyEvent event);
    void BSP_EinkDeinit(void);

    void BSP_EinkLogicPowerOn();
    void BSP_EinkLogicPowerOff();

    void BSP_EinkWriteCS(bsp_eink_cs_ctrl_t ctrl);
    uint8_t BSP_EinkWaitUntilDisplayBusy(uint32_t timeout);
    void BSP_EinkResetDisplayController(void);

M module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.cpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.cpp +2 -2
@@ 78,8 78,9 @@ namespace bsp
                driverSEMC->SwitchToPLL2ClockSource();
            }
            // Add intermediate step in frequency
            if (newFrequency > CpuFrequencyMHz::Level_4)
            if (newFrequency > CpuFrequencyMHz::Level_4) {
                return CpuFrequencyMHz::Level_4;
            }
        }
        return newFrequency;
    }


@@ 200,5 201,4 @@ namespace bsp
        PMU->REG_1P1 |= PMU_REG_1P1_ENABLE_WEAK_LINREG_MASK;
        PMU->REG_1P1 &= ~PMU_REG_1P1_ENABLE_LINREG_MASK;
    }

} // namespace bsp

M module-bsp/board/rt1051/puretx/CMakeLists.txt => module-bsp/board/rt1051/puretx/CMakeLists.txt +1 -1
@@ 14,7 14,7 @@ target_sources(
        hal/battery_charger/CurrentMeasurementScope.cpp
        hal/key_input/KeyInput.cpp
        bsp/battery_charger/battery_charger.cpp
        bsp/eink/eink_pin_config.cpp
        bsp/eink/eink_gpio.cpp
        bsp/keyboard/keyboard.cpp
        bsp/lpm/PowerProfile.cpp
        bsp/lpm/RT1051LPM.cpp

A module-bsp/board/rt1051/puretx/bsp/eink/eink_gpio.cpp => module-bsp/board/rt1051/puretx/bsp/eink/eink_gpio.cpp +50 -0
@@ 0,0 1,50 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "drivers/gpio/DriverGPIO.hpp"
#include "board/BoardDefinitions.hpp"

namespace bsp::eink
{
    using namespace drivers;

    namespace
    {
        constexpr auto LogicLow  = 0;
        constexpr auto LogicHigh = 1;
    } // namespace

    void eink_gpio_configure()
    {
        const auto gpio =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_GPIO), DriverGPIOParams{});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = LogicHigh,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_CS_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = LogicLow,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_RESET_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingEdge,
                                          .defLogic = LogicLow,
                                          .pin      = static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN)});

        gpio->ClearPortInterrupts(1 << static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
        gpio->DisableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    }

    void eink_gpio_power_on()
    {
        // Pure's hardware does not support physical power control of the display
    }

    void eink_gpio_power_off()
    {
        // Pure's hardware does not support physical power control of the display
    }
} // namespace bsp::eink

R module-bsp/board/rt1051/puretx/bsp/eink/eink_pin_config.hpp => module-bsp/board/rt1051/puretx/bsp/eink/eink_gpio.hpp +20 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 6,10 6,27 @@
namespace bsp::eink
{
    /**
     * eink_configure_gpio_pins
     * eink_gpio_configure
     *
     * This method initializes all GPIO pins needed for eInk handling.
     */

    void eink_configure_gpio_pins();
    void eink_gpio_configure();

    /**
     * eink_gpio_power_on
     *
     * This method physically turns on display power.
     */

    void eink_gpio_power_on();

    /**
     * eink_gpio_power_off
     *
     * This method physically turns off display power.
     */

    void eink_gpio_power_off();

} // namespace bsp::eink

D module-bsp/board/rt1051/puretx/bsp/eink/eink_pin_config.cpp => module-bsp/board/rt1051/puretx/bsp/eink/eink_pin_config.cpp +0 -34
@@ 1,34 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "drivers/gpio/DriverGPIO.hpp"
#include "board/BoardDefinitions.hpp"

namespace bsp::eink
{

    void eink_configure_gpio_pins()
    {
        using namespace drivers;

        auto gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::EINK_GPIO), DriverGPIOParams{});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = 1,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_CS_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                          .defLogic = 0,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_RESET_PIN)});

        gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                          .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingEdge,
                                          .defLogic = 0,
                                          .pin      = static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN)});

        gpio->ClearPortInterrupts(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::EINK_BUSY_PIN));
    }
} // namespace bsp::eink

M module-bsp/bsp/lpm/bsp_lpm.hpp => module-bsp/bsp/lpm/bsp_lpm.hpp +0 -1
@@ 31,7 31,6 @@ namespace bsp
            GoToRecoveryRecovery,     //! Goto to recovery into recovery mode
            GoToRecoveryBackup,       //! Goto to recovery into backup mode
            GoToRecoveryRestore       //! Goto to recovery into restore mode

        };

        LowPowerMode()          = default;

M module-services/service-eink/ServiceEink.cpp => module-services/service-eink/ServiceEink.cpp +30 -20
@@ 18,15 18,14 @@

#include <cstring>
#include <memory>
#include <gsl/util>
#include "Utils.hpp"

namespace service::eink
{
    namespace
    {
        constexpr auto ServceEinkStackDepth = 4096U;
        constexpr std::chrono::milliseconds displayPowerOffTimeout{2000};
        constexpr auto ServiceEinkStackDepth = 1024 * 4;
        constexpr std::chrono::milliseconds displayPowerOffTimeout{200};

        std::string toSettingString(const EinkModeMessage::Mode mode)
        {


@@ 50,7 49,7 @@ namespace service::eink
    } // namespace

    ServiceEink::ServiceEink(ExitAction exitAction, const std::string &name, std::string parent)
        : sys::Service(name, std::move(parent), ServceEinkStackDepth), exitAction{exitAction},
        : sys::Service(name, std::move(parent), ServiceEinkStackDepth), 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<settings::Settings>()}


@@ 78,14 77,15 @@ namespace service::eink
        eInkSentinel = std::make_shared<EinkSentinel>(name::eink, this);
    }

    sys::MessagePointer ServiceEink::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *response)
    sys::MessagePointer ServiceEink::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msgl,
                                                         [[maybe_unused]] sys::ResponseMessage *response)
    {
        return std::make_shared<sys::ResponseMessage>();
    }

    sys::ReturnCodes ServiceEink::InitHandler()
    {
        LOG_INFO("Initializing");
        LOG_INFO("Initializing Eink");
        if (const auto status = display->resetAndInit(); status != hal::eink::EinkStatus::EinkOK) {
            LOG_FATAL("Error: Could not initialize Eink display!");
            return sys::ReturnCodes::Failure;


@@ 94,10 94,10 @@ namespace service::eink
        settings->init(service::ServiceProxy(shared_from_this()));
        initStaticData();

        auto deviceRegistrationMsg = std::make_shared<sys::DeviceRegistrationMessage>(display->getDevice());
        const auto deviceRegistrationMsg = std::make_shared<sys::DeviceRegistrationMessage>(display->getDevice());
        bus.sendUnicast(deviceRegistrationMsg, service::name::system_manager);

        auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(eInkSentinel);
        const auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(eInkSentinel);
        bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager);

        display->powerOn();


@@ 110,7 110,7 @@ namespace service::eink
    {
        const auto invertedModeSetting   = settings->getValue(settings::Display::invertedMode);
        const auto isInvertedModeEnabled = utils::toNumeric(invertedModeSetting);
        const auto mode = isInvertedModeEnabled == 0 ? EinkModeMessage::Mode::Normal : EinkModeMessage::Mode::Invert;
        const auto mode = (isInvertedModeEnabled == 0) ? EinkModeMessage::Mode::Normal : EinkModeMessage::Mode::Invert;
        setDisplayMode(mode);
    }



@@ 150,7 150,6 @@ namespace service::eink
            enterActiveMode();
            break;
        case sys::ServicePowerMode::SuspendToRAM:
            [[fallthrough]];
        case sys::ServicePowerMode::SuspendToNVM:
            suspend();
            break;


@@ 188,7 187,7 @@ namespace service::eink

    void ServiceEink::setDisplayMode(EinkModeMessage::Mode mode)
    {
        auto invertedModeRequested = mode == EinkModeMessage::Mode::Invert;
        const auto invertedModeRequested = (mode == EinkModeMessage::Mode::Invert);
        if (invertedModeRequested) {
            display->setMode(hal::eink::EinkDisplayColorMode::EinkDisplayColorModeInverted);
        }


@@ 229,8 228,9 @@ namespace service::eink
    inline auto mergeBoundingBoxes(const BoxesContainer &boxes, std::uint16_t gapThreshold)
    {
        std::vector<gui::BoundingBox> mergedBoxes;
        if (boxes.empty())
        if (boxes.empty()) {
            return mergedBoxes;
        }
        mergedBoxes.reserve(boxes.size());
        gui::BoundingBox merged = boxes.front();
        for (std::size_t i = 1; i < boxes.size(); ++i) {


@@ 253,8 253,9 @@ namespace service::eink
    inline auto makeAlignedFrames(const BoxesContainer &boxes, std::uint16_t alignment)
    {
        std::vector<hal::eink::EinkFrame> frames;
        if (boxes.empty())
        if (boxes.empty()) {
            return frames;
        }
        frames.reserve(boxes.size());
        auto a = alignment;
        for (const auto &bb : boxes) {


@@ 322,9 323,6 @@ namespace service::eink
            return sys::MessageNone{};
        }

        displayPowerOffTimer.stop();
        auto displayPowerOffTimerReload = gsl::finally([this]() { displayPowerOffTimer.start(); });

        const gui::Context &ctx = *message->getContext();
        auto refreshMode        = translateToEinkRefreshMode(message->getRefreshMode());



@@ 365,7 363,7 @@ namespace service::eink

            eInkSentinel->HoldMinimumFrequency();

            auto status = display->showImageUpdate(updateFrames, ctx.getData());
            const auto status = display->showImageUpdate(updateFrames, ctx.getData());
            if (status == hal::eink::EinkStatus::EinkOK) {
                isImageUpdated = true;
            }


@@ 400,13 398,15 @@ namespace service::eink
                expandFrame(refreshFramesSum, refreshFrame);
            }
            einkDisplayState = EinkDisplayState::NeedRefresh;
            auto msg         = std::make_shared<service::eink::RefreshMessage>(
            const auto msg   = std::make_shared<service::eink::RefreshMessage>(
                message->getContextId(), refreshFrame, refreshMode, message->sender);
            bus.sendUnicast(msg, this->GetName());

            return sys::MessageNone{};
        }
        else {
            einkDisplayState = EinkDisplayState::Idle;
            restartDisplayPowerOffTimer();
            return std::make_shared<service::eink::ImageDisplayedNotification>(message->getContextId());
        }
    }


@@ 437,7 437,9 @@ namespace service::eink
        LOG_INFO("Time to refresh: %d", (int)(tick3 - tick1));
#endif

        auto msg = std::make_shared<service::eink::ImageDisplayedNotification>(message->getContextId());
        restartDisplayPowerOffTimer();

        const auto msg = std::make_shared<service::eink::ImageDisplayedNotification>(message->getContextId());
        bus.sendUnicast(msg, message->getOriginalSender());

        return sys::MessageNone{};


@@ 449,8 451,9 @@ namespace service::eink
        LOG_INFO("Refresh cancel");
#endif

        if (einkDisplayState == EinkDisplayState::NeedRefresh)
        if (einkDisplayState == EinkDisplayState::NeedRefresh) {
            einkDisplayState = EinkDisplayState::Canceled;
        }
        return sys::MessageNone{};
    }



@@ 472,4 475,11 @@ namespace service::eink
        return currentState == state;
    }

    void ServiceEink::restartDisplayPowerOffTimer()
    {
        if (displayPowerOffTimer.isActive()) {
            displayPowerOffTimer.stop();
        }
        displayPowerOffTimer.start();
    }
} // namespace service::eink

M module-services/service-eink/ServiceEink.hpp => module-services/service-eink/ServiceEink.hpp +1 -0
@@ 60,6 60,7 @@ namespace service::eink

        void setState(State state) noexcept;
        bool isInState(State state) const noexcept;
        void restartDisplayPowerOffTimer();

        void enterActiveMode();
        void suspend();

M products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.cpp => products/BellHybrid/apps/application-bell-main/presenters/HomeScreenPresenter.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-bell-main/presenters/HomeScreenPresenter.hpp"

M pure_changelog.md => pure_changelog.md +1 -0
@@ 14,6 14,7 @@
* Updated Bluetooth stack
* Unified GUI flow for adding contact with number already present in another contact
* Decrease critical battery level from 10% to 5%
* Optimized E-Ink energy consumption

### Fixed