// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "BatteryState.hpp" #include #include namespace { namespace sml = boost::sml; using State = BatteryState::ChargingState; namespace events { struct Check { const float soc; const BatteryState::ChargingState state; const float criticalThreshold; const float shutdownThreshold; }; } // namespace events // guards struct isNormal { bool operator()(const events::Check &e) const { return e.soc >= e.criticalThreshold; } } isNormal; struct isCriticalNotCharging { bool operator()(const events::Check &e) const { return e.soc < e.criticalThreshold && e.state != State::Charging && e.state != State::ChargingDone; } } isCriticalNotCharging; struct isCriticalCharging { bool operator()(const events::Check &e) const { return e.soc < e.criticalThreshold && (e.state == State::Charging || e.state == State::ChargingDone); } } isCriticalCharging; struct isShutdown { bool operator()(const events::Check &e) const { return e.soc < e.shutdownThreshold; } } isShutdown; // actions struct setCriticalNotCharging { void operator()(BatteryState::NotifyStateChangedCallback ¬ifier) { notifier(BatteryState::State::CriticalNotCharging); } } setCriticalNotCharging; struct setCriticalCharging { void operator()(BatteryState::NotifyStateChangedCallback ¬ifier) { notifier(BatteryState::State::CriticalCharging); } } setCriticalCharging; struct setNormal { void operator()(BatteryState::NotifyStateChangedCallback ¬ifier) { notifier(BatteryState::State::Normal); } } setNormal; struct setShutdown { void operator()(BatteryState::NotifyStateChangedCallback ¬ifier) { notifier(BatteryState::State::Shutdown); } } setShutdown; struct StateMachine { auto operator()() const { using namespace sml; // clang-format off return make_transition_table( *"InitialCheck"_s + event [ isCriticalNotCharging && !isShutdown ] = "LevelCriticalNotCharging"_s, "InitialCheck"_s + event [ isCriticalNotCharging && isShutdown ] = "Shutdown"_s, "InitialCheck"_s + event [ isCriticalCharging ] = "LevelCriticalCharging"_s, "InitialCheck"_s + event [ isNormal ] = "LevelNormal"_s, "LevelNormal"_s + sml::on_entry<_> / setNormal, "LevelNormal"_s + event [ isCriticalNotCharging && !isShutdown ] = "LevelCriticalNotCharging"_s, "LevelNormal"_s + event [ isCriticalNotCharging && isShutdown ] = "Shutdown"_s, "LevelNormal"_s + event [ isCriticalCharging ] = "LevelCriticalCharging"_s, "LevelCriticalNotCharging"_s + sml::on_entry<_> / setCriticalNotCharging, "LevelCriticalNotCharging"_s + event [ isNormal ] = "LevelNormal"_s, "LevelCriticalNotCharging"_s + event [ isCriticalCharging ] = "LevelCriticalCharging"_s, "LevelCriticalNotCharging"_s + event [ isShutdown ] = "Shutdown"_s, "LevelCriticalCharging"_s + sml::on_entry<_> / setCriticalCharging, "LevelCriticalCharging"_s + event [ isCriticalNotCharging && !isShutdown ] = "LevelCriticalNotCharging"_s, "LevelCriticalCharging"_s + event [ isNormal ] = "LevelNormal"_s, "LevelCriticalCharging"_s + event [ isCriticalNotCharging && isShutdown ] = "Shutdown"_s, "Shutdown"_s + sml::on_entry<_> / setShutdown ); // clang-format on } }; std::unique_ptr> sm; } // namespace class BatteryState::Pimpl { friend BatteryState; public: explicit Pimpl(NotifyStateChangedCallback notifyCallback) : notifyCallback{std::move(notifyCallback)} {} private: NotifyStateChangedCallback notifyCallback; sml::sm sm{notifyCallback}; static constexpr auto criticalThreshold = 10; // % static constexpr auto shutdownThreshold = 1; // % }; void BatteryState::check(const ChargingState state, const float soc) { pimpl->sm.process_event(events::Check{soc, state, Pimpl::criticalThreshold, Pimpl::shutdownThreshold}); } BatteryState::BatteryState(sys::Service *service, NotifyStateChangedCallback notifyCallback) : pimpl{std::make_shared(notifyCallback)} {}