~aleteoryx/muditaos

2cbadc6a00dc51fee7f2257bb57f756dee3ebc57 — Dawid Wojtas 2 years ago c2cdfb3
[BH-1630] Turn off the device for low voltage

The system closes only if the SoC is 0%, but
it doesn't react if the voltage has low level.
The new implementation invokes the close
procedure if the voltage is less than 3.4V.
This solution should avoid possiblity to
hang the MCU.
M module-bsp/board/linux/hal/battery_charger/BatteryCharger.cpp => module-bsp/board/linux/hal/battery_charger/BatteryCharger.cpp +12 -3
@@ 19,11 19,11 @@ namespace hal::battery
        constexpr auto queueTimeoutTicks    = 100;
        constexpr auto taskDelay            = 50;

        constexpr auto dummyBatteryVoltageLevel = 3700;

        constexpr auto chargerPlugStateChange = 'p';
        constexpr auto batteryLevelUp         = ']';
        constexpr auto batteryLevelDown       = '[';
        constexpr auto batteryVoltageUp       = '=';
        constexpr auto batteryVoltageDown     = '-';
        constexpr auto chargerTypeDcdSDP      = 'l';
        constexpr auto chargerTypeDcdCDP      = ';';
        constexpr auto chargerTypeDcdDCP      = '\'';


@@ 47,6 47,7 @@ namespace hal::battery
        xQueueHandle notificationChannel = nullptr;
        TaskHandle_t batteryWorkerHandle = nullptr;
        unsigned batteryLevel            = 100;
        unsigned batteryVoltageLevel     = 3700;
        bool isPlugged                   = false;
        bool shouldRun                   = true;
    };


@@ 76,7 77,7 @@ namespace hal::battery

    std::optional<AbstractBatteryCharger::Voltage> BatteryCharger::getBatteryVoltage() const
    {
        return dummyBatteryVoltageLevel;
        return batteryVoltageLevel;
    }

    std::optional<AbstractBatteryCharger::SOC> BatteryCharger::getSOC() const


@@ 127,6 128,14 @@ namespace hal::battery
                    batteryLevel--;
                    evt = Events::SOC;
                    break;
                case batteryVoltageUp:
                    batteryVoltageLevel += 10;
                    evt = Events::SOC;
                    break;
                case batteryVoltageDown:
                    batteryVoltageLevel -= 10;
                    evt = Events::SOC;
                    break;
                case chargerTypeDcdSDP:
                case chargerTypeDcdCDP:
                case chargerTypeDcdDCP:

M module-services/service-eink/board/linux/renderer/src/RWindow.cpp => module-services/service-eink/board/linux/renderer/src/RWindow.cpp +3 -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

#include "RWindow.hpp"


@@ 69,6 69,8 @@ void RWindow::keyMapInit(void)
    batteryKeyMap.insert(std::pair<int8_t, uint32_t>('l', 3));
    batteryKeyMap.insert(std::pair<int8_t, uint32_t>(';', 4));
    batteryKeyMap.insert(std::pair<int8_t, uint32_t>('\'', 5));
    batteryKeyMap.insert(std::pair<int8_t, uint32_t>('-', 6));
    batteryKeyMap.insert(std::pair<int8_t, uint32_t>('=', 7));
}
void RWindow::updateDrawBuffer()
{

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +0 -5
@@ 193,11 193,6 @@ sys::ReturnCodes EventManagerCommon::InitHandler()
void EventManagerCommon::initProductEvents()
{}

auto EventManagerCommon::createEventWorker() -> std::unique_ptr<WorkerEventCommon>
{
    return std::make_unique<WorkerEventCommon>(this);
}

sys::ReturnCodes EventManagerCommon::DeinitHandler()
{
    settings->deinit();

M module-services/service-evtmgr/WorkerEventCommon.cpp => module-services/service-evtmgr/WorkerEventCommon.cpp +1 -1
@@ 112,7 112,7 @@ bool WorkerEventCommon::initCommonHardwareComponents(EventManagerParams params)
    keyInput->init(queues[static_cast<int32_t>(WorkerEventQueues::queueKeyboardIRQ)]->GetQueueHandle());
    auto queueBatteryHandle = queues[static_cast<int32_t>(WorkerEventQueues::queueBatteryController)]->GetQueueHandle();

    batteryController = std::make_shared<sevm::battery::BatteryController>(service, queueBatteryHandle, params.battery);
    batteryController = std::make_shared<sevm::battery::BatteryController>(service, queueBatteryHandle, params);
    bsp::rtc::init(queues[static_cast<int32_t>(WorkerEventQueues::queueRTC)]->GetQueueHandle());

    time_t timestamp;

M module-services/service-evtmgr/battery/BatteryBrownoutDetector.cpp => module-services/service-evtmgr/battery/BatteryBrownoutDetector.cpp +60 -29
@@ 1,55 1,86 @@
// 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

#include "BatteryBrownoutDetector.hpp"

#include <service-evtmgr/BatteryMessages.hpp>
#include <system/Constants.hpp>
#include <Timers/TimerFactory.hpp>
#include <log/log.hpp>
#include <utility>

namespace
{
    constexpr std::chrono::milliseconds measurementTickTime{1000};
    constexpr auto measurementTickName     = "BrtownoutDetectorTick";
    constexpr unsigned measurementMaxCount = 5;
    constexpr auto brownoutLevelVoltage    = 3600; // mV
    constexpr auto measurementTickName = "BrownoutDetectorTick";
} // namespace

BatteryBrownoutDetector::BatteryBrownoutDetector(sys::Service *service, hal::battery::AbstractBatteryCharger &charger)
    : parentService(service), charger{charger},
BatteryBrownoutDetector::BatteryBrownoutDetector(sys::Service *service,
                                                 hal::battery::AbstractBatteryCharger &charger,
                                                 Thresholds voltage,
                                                 Callback callback)
    : charger{charger}, voltage{voltage}, callback{std::move(callback)},
      measurementTick{sys::TimerFactory::createSingleShotTimer(
          service, measurementTickName, measurementTickTime, [this](sys::Timer &) { checkBrownout(); })}
          service, measurementTickName, measurementTickTime, [this](auto &) { tick(); })}
{}

void BatteryBrownoutDetector::startDetection()
bool BatteryBrownoutDetector::isVoltageThresholdExceeded()
{
    if (detectionOngoing) {
        return;
    return charger.getBatteryVoltage() < voltage.shutdown;
}

void BatteryBrownoutDetector::tick()
{
    if (isVoltageThresholdExceeded()) {
        if (isTimerExpired()) {
            brownoutDetected();
        }
    }
    else {
        brownoutNotDetected();
    }
    LOG_DEBUG("Battery Brownout detection window start");
    detectionOngoing = true;
    measurementCount = 0;
    checkBrownout();
}

void BatteryBrownoutDetector::checkBrownout()
bool BatteryBrownoutDetector::isTimerExpired()
{
    if (charger.getBatteryVoltage() < brownoutLevelVoltage) {
        LOG_DEBUG("Battery Brownout detected");
    if (++measurementBrownoutCount < voltage.measurementMaxCount) {
        measurementTick.start();
        return false;
    }
    return true;
}

        auto messageBrownout = std::make_shared<sevm::BatteryBrownoutMessage>();
        parentService->bus.sendUnicast(std::move(messageBrownout), service::name::system_manager);
void BatteryBrownoutDetector::brownoutDetected()
{
    callback(DetectionResult::eventDetected);
    clearDetection();
}

        return;
void BatteryBrownoutDetector::brownoutNotDetected()
{
    // If count is > 0 it means that detection started but didn't finish
    if (measurementBrownoutCount > 0) {
        callback(DetectionResult::detectionNegative);
    }
    clearDetection();
}

    measurementCount++;
    if (measurementCount <= measurementMaxCount) {
        measurementTick.start();
void BatteryBrownoutDetector::poll()
{
    if (eventDetectionOngoing) {
        return;
    }
    else {
        LOG_DEBUG("Battery Brownout detection window finish with negative result");
        detectionOngoing = false;
    if (isVoltageThresholdExceeded()) {
        triggerDetection();
    }
}

void BatteryBrownoutDetector::clearDetection()
{
    measurementBrownoutCount = 0;
    eventDetectionOngoing    = false;
}

void BatteryBrownoutDetector::triggerDetection()
{
    eventDetectionOngoing    = true;
    measurementBrownoutCount = 0;
    measurementTick.start();
}

M module-services/service-evtmgr/battery/BatteryBrownoutDetector.hpp => module-services/service-evtmgr/battery/BatteryBrownoutDetector.hpp +32 -10
@@ 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


@@ 7,8 7,6 @@
#include <Service/Service.hpp>
#include <Timers/TimerHandle.hpp>

#include <memory>

namespace sys
{
    class Service;


@@ 17,16 15,40 @@ namespace sys
class BatteryBrownoutDetector
{
  public:
    BatteryBrownoutDetector(sys::Service *service, hal::battery::AbstractBatteryCharger &charger);
    void startDetection();
    struct Thresholds
    {
        units::Voltage shutdown;
        std::uint8_t measurementMaxCount;
    };

  private:
    void checkBrownout();
    enum class DetectionResult : std::uint8_t
    {
        eventDetected,
        detectionNegative
    };

    using Callback = std::function<void(DetectionResult result)>;

    sys::Service *parentService;
    BatteryBrownoutDetector(sys::Service *service,
                            hal::battery::AbstractBatteryCharger &charger,
                            Thresholds voltage,
                            Callback callback);

    void poll();

  private:
    void tick();
    bool isTimerExpired();
    bool isVoltageThresholdExceeded();
    void brownoutDetected();
    void brownoutNotDetected();
    void clearDetection();
    void triggerDetection();
    hal::battery::AbstractBatteryCharger &charger;

    bool detectionOngoing     = false;
    unsigned measurementCount = 0;
    bool eventDetectionOngoing        = false;
    unsigned measurementBrownoutCount = 0;
    Thresholds voltage;
    Callback callback;
    sys::TimerHandle measurementTick;
};

M module-services/service-evtmgr/battery/BatteryController.cpp => module-services/service-evtmgr/battery/BatteryController.cpp +25 -9
@@ 75,11 75,26 @@ namespace
    }
} // namespace

BatteryController::BatteryController(sys::Service *service,
                                     xQueueHandle notificationChannel,
                                     BatteryState::Thresholds thresholds)
BatteryController::BatteryController(sys::Service *service, xQueueHandle notificationChannel, EventManagerParams params)
    : service{service}, charger{hal::battery::AbstractBatteryCharger::Factory::create(notificationChannel)},
      brownoutDetector(service, *charger),
      brownoutDetector(
          service,
          *charger,
          params.voltage,
          [this](BatteryBrownoutDetector::DetectionResult result) {
              using Brownout = BatteryBrownoutDetector::DetectionResult;
              switch (result) {
              case Brownout::eventDetected: {
                  auto messageBrownout = std::make_shared<sevm::BatteryBrownoutMessage>();
                  this->service->bus.sendUnicast(std::move(messageBrownout), service::name::system_manager);
                  LOG_INFO("Battery brownout %s. Sending message...", magic_enum::enum_name(result).data());
              } break;
              case Brownout::detectionNegative:
              default:
                  LOG_INFO("Battery brownout detection window finish with negative result");
                  break;
              }
          }),
      batteryState{service,
                   [this](const auto state) {
                       Store::Battery::modify().levelState = transformBatteryState(state);


@@ 87,9 102,9 @@ BatteryController::BatteryController(sys::Service *service,
                       this->service->bus.sendMulticast(std::move(stateChangeMessage),
                                                        sys::BusChannel::ServiceEvtmgrNotifications);
                   },
                   thresholds}
                   params.battery}
{
    updateSoC();
    updateSoc();
    Store::Battery::modify().state = transformChargingState(charger->getChargingStatus());
    batteryState.check(transformChargingState(Store::Battery::modify().state), Store::Battery::modify().level);



@@ 111,7 126,7 @@ void sevm::battery::BatteryController::handleNotification(Events evt)
        update();
        break;
    case Events::Brownout:
        brownoutDetector.startDetection();
        brownoutDetector.poll();
        break;
    }
}


@@ 119,6 134,7 @@ void sevm::battery::BatteryController::handleNotification(Events evt)
void sevm::battery::BatteryController::poll()
{
    update();
    brownoutDetector.poll();
}
void sevm::battery::BatteryController::printCurrentState()
{


@@ 133,7 149,7 @@ void sevm::battery::BatteryController::update()
    const auto lastSoc   = Store::Battery::get().level;
    const auto lastState = Store::Battery::get().state;

    updateSoC();
    updateSoc();
    Store::Battery::modify().state = transformChargingState(charger->getChargingStatus());

    const auto currentSoc   = Store::Battery::get().level;


@@ 150,7 166,7 @@ void sevm::battery::BatteryController::update()
    printCurrentState();
}

void sevm::battery::BatteryController::updateSoC()
void sevm::battery::BatteryController::updateSoc()
{
    const auto batteryLevel = charger->getSOC();
    if (batteryLevel) {

M module-services/service-evtmgr/battery/BatteryController.hpp => module-services/service-evtmgr/battery/BatteryController.hpp +4 -4
@@ 4,6 4,7 @@
#pragma once

#include <hal/battery_charger/AbstractBatteryCharger.hpp>
#include "EventManagerParams.hpp"
#include "BatteryBrownoutDetector.hpp"
#include "BatteryState.hpp"



@@ 20,16 21,15 @@ namespace sevm::battery
      public:
        using Events          = hal::battery::AbstractBatteryCharger::Events;
        using ChargerPresence = hal::battery::AbstractBatteryCharger::ChargerPresence;
        BatteryController(sys::Service *service, xQueueHandle notificationChannel, BatteryState::Thresholds thresholds);

        void poll();
        BatteryController(sys::Service *service, xQueueHandle notificationChannel, EventManagerParams params);

        /// Handler for incoming async notifications from the back-end
        void handleNotification(Events);
        void poll();

      private:
        void update();
        void updateSoC();
        void updateSoc();
        void printCurrentState();
        void checkChargerPresence();
        units::Voltage getVoltage();

M module-services/service-evtmgr/service-evtmgr/EventManagerCommon.hpp => module-services/service-evtmgr/service-evtmgr/EventManagerCommon.hpp +1 -1
@@ 70,7 70,7 @@ class EventManagerCommon : public sys::Service
    std::function<void(const time_t)> onMinuteTick;
    virtual void handleKeyEvent(sys::Message *msg);
    virtual void initProductEvents();
    virtual auto createEventWorker() -> std::unique_ptr<WorkerEventCommon>;
    virtual auto createEventWorker() -> std::unique_ptr<WorkerEventCommon> = 0;

    std::shared_ptr<settings::Settings> settings;
    std::unique_ptr<WorkerEventCommon> EventWorker;

M module-services/service-evtmgr/service-evtmgr/WorkerEventCommon.hpp => module-services/service-evtmgr/service-evtmgr/WorkerEventCommon.hpp +0 -1
@@ 44,7 44,6 @@ class WorkerEventCommon : public sys::Worker
  protected:
    virtual void addProductQueues(std::list<sys::WorkerQueueInfo> &queueList);
    virtual void initProductHardware();

    virtual void processKeyEvent(bsp::KeyEvents event, bsp::KeyCodes code);

    sys::Service *service = nullptr;

M module-services/service-evtmgr/service-evtmgr/include/EventManagerParams.hpp => module-services/service-evtmgr/service-evtmgr/include/EventManagerParams.hpp +3 -1
@@ 3,9 3,11 @@

#pragma once

#include <battery/BatteryController.hpp>
#include <battery/BatteryState.hpp>
#include <battery/BatteryBrownoutDetector.hpp>

struct EventManagerParams
{
    BatteryState::Thresholds battery;
    BatteryBrownoutDetector::Thresholds voltage;
};

M module-utils/EventStore/EventStore.hpp => module-utils/EventStore/EventStore.hpp +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

#pragma once

M products/BellHybrid/services/evtmgr/EventManager.cpp => products/BellHybrid/services/evtmgr/EventManager.cpp +3 -1
@@ 40,7 40,9 @@ namespace

EventManager::EventManager(LogDumpFunction logDumpFunction, const std::string &name)
    : EventManagerCommon(logDumpFunction,
                         {.battery{.critical = constants::criticalThreshold, .shutdown = constants::shutdownThreshold}},
                         {.battery{.critical = constants::criticalThreshold, .shutdown = constants::shutdownThreshold},
                          .voltage{.shutdown            = constants::shutdownVoltageThreshold,
                                   .measurementMaxCount = constants::measurementThreshold}},
                         name),
      backlightHandler(settings, this), userActivityHandler(std::make_shared<sys::CpuSentinel>(name, this), this)
{

M products/BellHybrid/services/evtmgr/WorkerEvent.cpp => products/BellHybrid/services/evtmgr/WorkerEvent.cpp +1 -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

#include "WorkerEvent.hpp"

M products/BellHybrid/services/evtmgr/WorkerEvent.hpp => products/BellHybrid/services/evtmgr/WorkerEvent.hpp +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

#pragma once

M products/BellHybrid/services/evtmgr/include/evtmgr/battery/Thresholds.hpp => products/BellHybrid/services/evtmgr/include/evtmgr/battery/Thresholds.hpp +3 -0
@@ 9,4 9,7 @@ namespace constants
{
    static constexpr units::Percent criticalThreshold = 1;
    static constexpr units::Percent shutdownThreshold = 1;

    static constexpr units::Voltage shutdownVoltageThreshold = 3400;
    static constexpr std::uint8_t measurementThreshold       = 0;
} // namespace constants

M products/PurePhone/services/evtmgr/WorkerEvent.cpp => products/PurePhone/services/evtmgr/WorkerEvent.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 "WorkerEvent.hpp"

M products/PurePhone/services/evtmgr/WorkerEvent.hpp => products/PurePhone/services/evtmgr/WorkerEvent.hpp +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

#pragma once

M products/PurePhone/services/evtmgr/include/evtmgr/EventManager.hpp => products/PurePhone/services/evtmgr/include/evtmgr/EventManager.hpp +3 -1
@@ 17,7 17,9 @@ class EventManager : public EventManagerCommon
                          const std::string &name         = service::name::evt_manager)
        : EventManagerCommon(
              logDumpFunction,
              {.battery{.critical = constants::criticalThreshold, .shutdown = constants::shutdownThreshold}},
              {.battery{.critical = constants::criticalThreshold, .shutdown = constants::shutdownThreshold},
               .voltage{.shutdown            = constants::shutdownVoltageThreshold,
                        .measurementMaxCount = constants::measurementThreshold}},
              name),
          vibrator(std::make_unique<vibra_handle::Vibra>(this)), backlightHandler(settings, this),
          userActivityHandler(std::make_shared<sys::CpuSentinel>(name, this), this)

M products/PurePhone/services/evtmgr/include/evtmgr/battery/Thresholds.hpp => products/PurePhone/services/evtmgr/include/evtmgr/battery/Thresholds.hpp +3 -0
@@ 9,4 9,7 @@ namespace constants
{
    static constexpr units::Percent criticalThreshold = 10;
    static constexpr units::Percent shutdownThreshold = 1;

    static constexpr units::Voltage shutdownVoltageThreshold = 3600;
    static constexpr std::uint8_t measurementThreshold       = 5;
} // namespace constants