M enabled_unittests => enabled_unittests +4 -0
@@ 212,6 212,10 @@ TESTS_LIST["catch2-service-evtmgr"]="
ScreenLightControlFunctions;
"
#---------
+TESTS_LIST["catch2-PowerManager"]="
+ Power Manager CPU sentinels governor test;
+"
+#---------
TESTS_LIST["catch2-StatefulController-tests"]="
Given StatefulController when turn on then turned on;
Given StatefulController when error during device registration then turned off;
M module-bsp/board/linux/lpm/LinuxLPM.cpp => module-bsp/board/linux/lpm/LinuxLPM.cpp +7 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
//
@@ 20,11 20,16 @@ namespace bsp
return 0;
}
- void LinuxLPM::SetCpuFrequency(bsp::LowPowerMode::CpuFrequency freq)
+ void LinuxLPM::SetCpuFrequency(bsp::CpuFrequencyHz freq)
{
currentFrequency = freq;
}
+ uint32_t LinuxLPM::GetCpuFrequency() const noexcept
+ {
+ return 0;
+ }
+
void LinuxLPM::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
{
currentOscSource = source;
M module-bsp/board/linux/lpm/LinuxLPM.h => module-bsp/board/linux/lpm/LinuxLPM.h +2 -1
@@ 14,7 14,8 @@ namespace bsp
public:
int32_t PowerOff() override final;
int32_t Reboot() override final;
- void SetCpuFrequency(CpuFrequency freq) final;
+ void SetCpuFrequency(CpuFrequencyHz freq) final;
+ [[nodiscard]] uint32_t GetCpuFrequency() const noexcept final;
void SwitchOscillatorSource(OscillatorSource source) final;
};
M module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp +13 -8
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RT1051LPM.hpp"
@@ 45,32 45,37 @@ namespace bsp
return 0;
}
- void RT1051LPM::SetCpuFrequency(bsp::LowPowerMode::CpuFrequency freq)
+ void RT1051LPM::SetCpuFrequency(bsp::CpuFrequencyHz freq)
{
currentFrequency = freq;
switch (freq) {
- case bsp::LowPowerMode::CpuFrequency::Level_1:
+ case bsp::CpuFrequencyHz::Level_1:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_12_Mhz);
break;
- case bsp::LowPowerMode::CpuFrequency::Level_2:
+ case bsp::CpuFrequencyHz::Level_2:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_24_Mhz);
break;
- case bsp::LowPowerMode::CpuFrequency::Level_3:
+ case bsp::CpuFrequencyHz::Level_3:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_66_Mhz);
break;
- case bsp::LowPowerMode::CpuFrequency::Level_4:
+ case bsp::CpuFrequencyHz::Level_4:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_132_Mhz);
break;
- case bsp::LowPowerMode::CpuFrequency::Level_5:
+ case bsp::CpuFrequencyHz::Level_5:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_264_Mhz);
break;
- case bsp::LowPowerMode::CpuFrequency::Level_6:
+ case bsp::CpuFrequencyHz::Level_6:
CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_528_Mhz);
break;
}
LOG_INFO("CPU frequency changed to %lu", CLOCK_GetFreq(kCLOCK_CpuClk));
}
+ uint32_t RT1051LPM::GetCpuFrequency() const noexcept
+ {
+ return CLOCK_GetCpuClkFreq();
+ }
+
void RT1051LPM::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
{
if (source == bsp::LowPowerMode::OscillatorSource::Internal) {
M module-bsp/board/rt1051/bsp/lpm/RT1051LPM.hpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPM.hpp +3 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#ifndef PUREPHONE_RT1051LPM_HPP
@@ 18,7 18,8 @@ namespace bsp
RT1051LPM();
int32_t PowerOff() override final;
int32_t Reboot() override final;
- void SetCpuFrequency(CpuFrequency freq) final;
+ void SetCpuFrequency(CpuFrequencyHz freq) final;
+ [[nodiscard]] uint32_t GetCpuFrequency() const noexcept final;
void SwitchOscillatorSource(OscillatorSource source) final;
private:
M module-bsp/bsp/common.hpp => module-bsp/bsp/common.hpp +14 -0
@@ 1,3 1,6 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
#pragma once
//TODO maybe move KeyEvents to keyboard.hpp
@@ 15,6 18,17 @@ namespace bsp
};
+ /// CPU frequency is dependent on the clock settings.
+ /// Only a few thresholds are available in the current configuration
+ enum class CpuFrequencyHz
+ {
+ Level_1 = 12000000,
+ Level_2 = 24000000,
+ Level_3 = 66000000,
+ Level_4 = 132000000,
+ Level_5 = 264000000,
+ Level_6 = 528000000
+ };
enum class Board{
T3,
M module-bsp/bsp/lpm/bsp_lpm.cpp => module-bsp/bsp/lpm/bsp_lpm.cpp +4 -1
@@ 1,3 1,6 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
#include "bsp_lpm.hpp"
@@ 26,7 29,7 @@ namespace bsp{
return inst;
}
- LowPowerMode::CpuFrequency LowPowerMode::GetCurrentFrequency() const noexcept
+ CpuFrequencyHz LowPowerMode::GetCurrentFrequencyLevel() const noexcept
{
return currentFrequency;
}
M module-bsp/bsp/lpm/bsp_lpm.hpp => module-bsp/bsp/lpm/bsp_lpm.hpp +9 -15
@@ 1,23 1,17 @@
-#ifndef PUREPHONE_BSP_LPM_HPP
-#define PUREPHONE_BSP_LPM_HPP
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
#include <optional>
#include <memory>
+#include <bsp/common.hpp>
namespace bsp {
class LowPowerMode
{
public:
- enum class CpuFrequency
- {
- Level_1, // 12 MHz
- Level_2, // 24 MHz
- Level_3, // 66 MHz
- Level_4, // 132 MHz
- Level_5, // 264 MHz
- Level_6 // 528 MHz
- };
enum class OscillatorSource
{
External,
@@ 32,16 26,16 @@ namespace bsp {
virtual int32_t PowerOff() = 0;
virtual int32_t Reboot() = 0;
- virtual void SetCpuFrequency(CpuFrequency freq) = 0;
- [[nodiscard]] CpuFrequency GetCurrentFrequency() const noexcept;
+ virtual void SetCpuFrequency(CpuFrequencyHz freq) = 0;
+ [[nodiscard]] CpuFrequencyHz GetCurrentFrequencyLevel() const noexcept;
+ [[nodiscard]] virtual uint32_t GetCpuFrequency() const noexcept = 0;
virtual void SwitchOscillatorSource(OscillatorSource source) = 0;
[[nodiscard]] OscillatorSource GetCurrentOscillatorSource() const noexcept;
protected:
- CpuFrequency currentFrequency = CpuFrequency::Level_6;
+ CpuFrequencyHz currentFrequency = CpuFrequencyHz::Level_6;
OscillatorSource currentOscSource = OscillatorSource::External;
};
} // namespace bsp
-#endif //PUREPHONE_BSP_LPM_HPP
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +10 -0
@@ 14,6 14,7 @@
#include "NetworkSettings.hpp"
#include "service-cellular/RequestFactory.hpp"
#include "service-cellular/CellularRequestHandler.hpp"
+#include "SystemManager/messages/SentinelRegistrationMessage.hpp"
#include <Audio/AudioCommon.hpp>
#include <BaseInterface.hpp>
@@ 246,6 247,15 @@ sys::ReturnCodes ServiceCellular::InitHandler()
[this](const std::string &value) { apnListChanged(value); },
::settings::SettingsScope::Global);
+ cpuSentinel = std::make_shared<sys::CpuSentinel>(serviceName, this);
+
+ auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(cpuSentinel);
+ bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager);
+
+ // temporarily limit the minimum CPU frequency
+ // due to problems with the UART of the GSM modem
+ cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyHz::Level_4);
+
return sys::ReturnCodes::Success;
}
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +2 -0
@@ 19,6 19,7 @@
#include <Service/Common.hpp>
#include <Service/Message.hpp>
#include <Service/Service.hpp>
+#include <Service/CpuSentinel.hpp>
#include <bsp/common.hpp>
#include <utf8/UTF8.hpp>
#include <optional> // for optional
@@ 159,6 160,7 @@ class ServiceCellular : public sys::Service
private:
std::unique_ptr<TS0710> cmux = std::make_unique<TS0710>(PortSpeed_e::PS460800, this);
+ std::shared_ptr<sys::CpuSentinel> cpuSentinel;
// used for polling for call state
std::unique_ptr<sys::Timer> callStateTimer;
M module-services/service-eink/ServiceEink.cpp => module-services/service-eink/ServiceEink.cpp +12 -0
@@ 12,6 12,7 @@
#include <messages/EinkMessage.hpp>
#include <messages/ImageMessage.hpp>
#include <SystemManager/messages/DeviceRegistrationMessage.hpp>
+#include <SystemManager/messages/SentinelRegistrationMessage.hpp>
#include <SystemManager/Constants.hpp>
#include <cstring>
@@ 59,6 60,13 @@ namespace service::eink
auto deviceRegistrationMsg = std::make_shared<sys::DeviceRegistrationMessage>(display.getDevice());
bus.sendUnicast(deviceRegistrationMsg, service::name::system_manager);
+ cpuSentinel = std::make_shared<sys::CpuSentinel>(name::eink, this, [this](bsp::CpuFrequencyHz newFrequency) {
+ updateResourcesAfterCpuFrequencyChange(newFrequency);
+ });
+
+ auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(cpuSentinel);
+ bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager);
+
display.powerOn();
auto msg = std::make_shared<service::gui::EinkInitialized>(display.getSize());
@@ 200,4 208,8 @@ namespace service::eink
{
return currentState == state;
}
+
+ void ServiceEink::updateResourcesAfterCpuFrequencyChange(bsp::CpuFrequencyHz newFrequency)
+ {}
+
} // namespace service::eink
M module-services/service-eink/ServiceEink.hpp => module-services/service-eink/ServiceEink.hpp +7 -0
@@ 7,6 7,7 @@
#include <Service/Message.hpp>
#include <Service/Service.hpp>
#include <Service/Timer.hpp>
+#include <Service/CpuSentinel.hpp>
#include "EinkDisplay.hpp"
@@ 54,6 55,11 @@ namespace service::eink
EinkStatus_e refreshDisplay(::gui::RefreshModes refreshMode);
EinkStatus_e updateDisplay(uint8_t *frameBuffer, ::gui::RefreshModes refreshMode);
+ // function called from the PowerManager context
+ // to update resources immediately
+ // critical section or mutex support necessary
+ void updateResourcesAfterCpuFrequencyChange(bsp::CpuFrequencyHz newFrequency);
+
sys::MessagePointer handleEinkModeChangedMessage(sys::Message *message);
sys::MessagePointer handleImageMessage(sys::Message *message);
sys::MessagePointer handlePrepareEarlyRequest(sys::Message *message);
@@ 61,6 67,7 @@ namespace service::eink
EinkDisplay display;
State currentState;
std::unique_ptr<sys::Timer> displayPowerOffTimer;
+ std::shared_ptr<sys::CpuSentinel> cpuSentinel;
};
} // namespace service::eink
M module-sys/CMakeLists.txt => module-sys/CMakeLists.txt +2 -0
@@ 13,11 13,13 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Service/Message.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Service/Service.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Service/Timer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Service/CpuSentinel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/SystemManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/DependencyGraph.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/PowerManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/CpuStatistics.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/DeviceManager.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/CpuGovernor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/graph/TopologicalSort.cpp
)
A module-sys/Service/CpuSentinel.cpp => module-sys/Service/CpuSentinel.cpp +34 -0
@@ 0,0 1,34 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "CpuSentinel.hpp"
+#include "SystemManager/messages/RequestCpuFrequencyMessage.hpp"
+#include "SystemManager/Constants.hpp"
+#include <memory>
+
+namespace sys
+{
+
+ CpuSentinel::CpuSentinel(std::string name, sys::Service *service, std::function<void(bsp::CpuFrequencyHz)> callback)
+ : name(name), owner(service), callback(callback)
+ {}
+
+ [[nodiscard]] auto CpuSentinel::GetName() const noexcept -> std::string
+ {
+ return name;
+ }
+
+ void CpuSentinel::HoldMinimumFrequency(bsp::CpuFrequencyHz frequencyToHold)
+ {
+ auto msg = std::make_shared<sys::RequestCpuFrequencyMessage>(GetName(), frequencyToHold);
+ owner->bus.sendUnicast(msg, service::name::system_manager);
+ }
+
+ void CpuSentinel::CpuFrequencyHasChanged(bsp::CpuFrequencyHz newFrequency)
+ {
+ if (callback) {
+ callback(newFrequency);
+ }
+ }
+
+} // namespace sys
A module-sys/Service/CpuSentinel.hpp => module-sys/Service/CpuSentinel.hpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <string>
+#include <functional>
+#include <bsp/common.hpp>
+#include "Service.hpp"
+
+namespace sys
+{
+ /// Each sentinel manages the requests, i.e. when it is needed it sends messages to CpuGovernor with the required
+ /// minimum CPU frequency to perform the task (e.g. screen redraw). Furthermore, every sentinel is informed
+ /// immediately after changing the frequency. This allows it to invoke a callback to the service to update their
+ /// resources (e.g. PWM filling). Every sentinel must register itself on startup to CpuGovernor by sending
+ /// "SentinelRegistrationMessage".
+ class CpuSentinel
+ {
+ public:
+ explicit CpuSentinel(std::string name,
+ sys::Service *service,
+ std::function<void(bsp::CpuFrequencyHz)> callback = nullptr);
+ ~CpuSentinel() = default;
+
+ [[nodiscard]] auto GetName() const noexcept -> std::string;
+ void HoldMinimumFrequency(bsp::CpuFrequencyHz frequencyToHold);
+ void CpuFrequencyHasChanged(bsp::CpuFrequencyHz newFrequency);
+
+ protected:
+ const std::string name;
+ sys::Service *owner{nullptr};
+
+ /// function called from the PowerManager context
+ /// to update resources immediately
+ /// critical section or mutex support necessary
+ std::function<void(bsp::CpuFrequencyHz)> callback;
+ };
+
+} // namespace sys
A module-sys/SystemManager/CpuGovernor.cpp => module-sys/SystemManager/CpuGovernor.cpp +118 -0
@@ 0,0 1,118 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "CpuGovernor.hpp"
+#include <algorithm>
+#include <log/log.hpp>
+
+namespace sys
+{
+
+ GovernorSentinel::GovernorSentinel(std::shared_ptr<CpuSentinel> newSentinel)
+ : sentinelPtr(newSentinel), requestedFrequency(bsp::CpuFrequencyHz::Level_1)
+ {}
+
+ [[nodiscard]] auto GovernorSentinel::GetSentinel() const noexcept -> SentinelPointer
+ {
+ return sentinelPtr;
+ }
+
+ [[nodiscard]] auto GovernorSentinel::GetRequestedFrequency() const noexcept -> bsp::CpuFrequencyHz
+ {
+ return requestedFrequency;
+ }
+
+ void GovernorSentinel::SetRequestedFrequency(bsp::CpuFrequencyHz newFrequency)
+ {
+ requestedFrequency = newFrequency;
+ }
+
+ void CpuGovernor::RegisterNewSentinel(std::shared_ptr<CpuSentinel> newSentinel)
+ {
+ if (newSentinel) {
+ auto isNewSentinelAlreadyRegistered = false;
+
+ for (auto &sentinel : sentinels) {
+ auto sentinelWeakPointer = sentinel->GetSentinel();
+ if (!sentinelWeakPointer.expired()) {
+ std::shared_ptr<CpuSentinel> sharedResource = sentinelWeakPointer.lock();
+ if (sharedResource->GetName() == newSentinel->GetName()) {
+ isNewSentinelAlreadyRegistered = true;
+ break;
+ }
+ }
+ }
+
+ if (!isNewSentinelAlreadyRegistered) {
+ sentinels.push_back(std::make_unique<GovernorSentinel>(newSentinel));
+ }
+ else {
+ LOG_WARN("New sentinel %s is already registered", newSentinel->GetName().c_str());
+ }
+ }
+ }
+
+ [[nodiscard]] auto CpuGovernor::GetNumberOfRegisteredSentinels() const noexcept -> uint32_t
+ {
+ return sentinels.size();
+ }
+
+ void CpuGovernor::PrintAllSentinels() const noexcept
+ {
+ std::for_each(std::begin(sentinels), std::end(sentinels), PrintName);
+ }
+
+ void CpuGovernor::SetCpuFrequencyRequest(std::string sentinelName, bsp::CpuFrequencyHz request)
+ {
+ for (auto &sentinel : sentinels) {
+ auto sentinelWeakPointer = sentinel->GetSentinel();
+ if (!sentinelWeakPointer.expired()) {
+ std::shared_ptr<CpuSentinel> sharedResource = sentinelWeakPointer.lock();
+ if (sharedResource->GetName() == sentinelName) {
+ sentinel->SetRequestedFrequency(request);
+ }
+ }
+ }
+ }
+
+ void CpuGovernor::ResetCpuFrequencyRequest(std::string sentinelName)
+ {
+ SetCpuFrequencyRequest(sentinelName, bsp::CpuFrequencyHz::Level_1);
+ }
+
+ [[nodiscard]] auto CpuGovernor::GetMinimumFrequencyRequested() const noexcept -> bsp::CpuFrequencyHz
+ {
+ bsp::CpuFrequencyHz minFrequency = bsp::CpuFrequencyHz::Level_1;
+
+ for (auto &sentinel : sentinels) {
+ const auto sentinelFrequency = sentinel->GetRequestedFrequency();
+
+ if (sentinelFrequency > minFrequency) {
+ minFrequency = sentinelFrequency;
+ }
+ }
+
+ return minFrequency;
+ }
+
+ void CpuGovernor::InformSentinelsAboutCpuFrequencyChange(bsp::CpuFrequencyHz newFrequency) const noexcept
+ {
+ for (auto &sentinel : sentinels) {
+ auto sentinelWeakPointer = sentinel->GetSentinel();
+ if (!sentinelWeakPointer.expired()) {
+ std::shared_ptr<CpuSentinel> sharedResource = sentinelWeakPointer.lock();
+ sharedResource->CpuFrequencyHasChanged(newFrequency);
+ }
+ }
+ }
+
+ void CpuGovernor::PrintName(const GovernorSentinelPointer &element)
+ {
+ auto sentinelWeakPointer = element->GetSentinel();
+ if (!sentinelWeakPointer.expired()) {
+ std::shared_ptr<CpuSentinel> sharedResource = sentinelWeakPointer.lock();
+ LOG_INFO("Sentinel %s", sharedResource->GetName().c_str());
+ }
+ }
+
+} // namespace sys
A module-sys/SystemManager/CpuGovernor.hpp => module-sys/SystemManager/CpuGovernor.hpp +52 -0
@@ 0,0 1,52 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include "Service/CpuSentinel.hpp"
+
+namespace sys
+{
+ using SentinelPointer = std::weak_ptr<CpuSentinel>;
+
+ class GovernorSentinel
+ {
+ public:
+ explicit GovernorSentinel(std::shared_ptr<CpuSentinel> newSentinel);
+ [[nodiscard]] auto GetSentinel() const noexcept -> SentinelPointer;
+ [[nodiscard]] auto GetRequestedFrequency() const noexcept -> bsp::CpuFrequencyHz;
+ void SetRequestedFrequency(bsp::CpuFrequencyHz newFrequency);
+
+ private:
+ SentinelPointer sentinelPtr;
+ bsp::CpuFrequencyHz requestedFrequency;
+ };
+
+ using GovernorSentinelPointer = std::unique_ptr<GovernorSentinel>;
+ using GovernorSentinelsVector = std::vector<GovernorSentinelPointer>;
+
+ /// CpuGovernor manages all sentinels in the system and has CPU frequency requests from them (e.g. eInkSentinel).
+ /// It is also responsible for informing all sentinels that the CPU frequency has changed.
+ class CpuGovernor
+ {
+
+ public:
+ void RegisterNewSentinel(std::shared_ptr<CpuSentinel> newSentinel);
+ [[nodiscard]] auto GetNumberOfRegisteredSentinels() const noexcept -> uint32_t;
+ void PrintAllSentinels() const noexcept;
+
+ void SetCpuFrequencyRequest(std::string sentinelName, bsp::CpuFrequencyHz request);
+ void ResetCpuFrequencyRequest(std::string sentinelName);
+
+ [[nodiscard]] auto GetMinimumFrequencyRequested() const noexcept -> bsp::CpuFrequencyHz;
+ void InformSentinelsAboutCpuFrequencyChange(bsp::CpuFrequencyHz newFrequency) const noexcept;
+
+ private:
+ static void PrintName(const GovernorSentinelPointer &element);
+
+ GovernorSentinelsVector sentinels;
+ };
+
+} // namespace sys
M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +51 -22
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <log/log.hpp>
@@ 11,6 11,7 @@ namespace sys
{
lowPowerControl = bsp::LowPowerMode::Create().value_or(nullptr);
driverSEMC = drivers::DriverSEMC::Create("ExternalRAM");
+ cpuGovernor = std::make_unique<CpuGovernor>();
}
PowerManager::~PowerManager()
@@ 28,13 29,14 @@ namespace sys
void PowerManager::UpdateCpuFrequency(uint32_t cpuLoad)
{
- const auto freq = lowPowerControl->GetCurrentFrequency();
+ const auto currentCpuFreq = lowPowerControl->GetCurrentFrequencyLevel();
+ const auto minFrequencyRequested = cpuGovernor->GetMinimumFrequencyRequested();
- if (cpuLoad > frequencyShiftUpperThreshold && freq < bsp::LowPowerMode::CpuFrequency::Level_6) {
+ if (cpuLoad > frequencyShiftUpperThreshold && currentCpuFreq < bsp::CpuFrequencyHz::Level_6) {
aboveThresholdCounter++;
belowThresholdCounter = 0;
}
- else if (cpuLoad < frequencyShiftLowerThreshold && freq > bsp::LowPowerMode::CpuFrequency::Level_1) {
+ else if (cpuLoad < frequencyShiftLowerThreshold && currentCpuFreq > bsp::CpuFrequencyHz::Level_1) {
belowThresholdCounter++;
aboveThresholdCounter = 0;
}
@@ 42,22 44,24 @@ namespace sys
ResetFrequencyShiftCounter();
}
- if (aboveThresholdCounter >= maxAboveThresholdCount) {
+ if (aboveThresholdCounter >= maxAboveThresholdCount || minFrequencyRequested > currentCpuFreq) {
ResetFrequencyShiftCounter();
IncreaseCpuFrequency();
}
- if (belowThresholdCounter >= maxBelowThresholdCount) {
- ResetFrequencyShiftCounter();
- DecreaseCpuFrequency();
+ else {
+ if (belowThresholdCounter >= maxBelowThresholdCount && currentCpuFreq > minFrequencyRequested) {
+ ResetFrequencyShiftCounter();
+ DecreaseCpuFrequency();
+ }
}
}
void PowerManager::IncreaseCpuFrequency() const
{
- const auto freq = lowPowerControl->GetCurrentFrequency();
+ const auto freq = lowPowerControl->GetCurrentFrequencyLevel();
const auto oscSource = lowPowerControl->GetCurrentOscillatorSource();
- if (freq == bsp::LowPowerMode::CpuFrequency::Level_1) {
+ if (freq == bsp::CpuFrequencyHz::Level_1) {
// switch osc source first
if (oscSource == bsp::LowPowerMode::OscillatorSource::Internal) {
lowPowerControl->SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource::External);
@@ 70,33 74,42 @@ namespace sys
}
// and increase frequency
- if (freq < bsp::LowPowerMode::CpuFrequency::Level_6) {
- lowPowerControl->SetCpuFrequency(bsp::LowPowerMode::CpuFrequency::Level_6);
+ if (freq < bsp::CpuFrequencyHz::Level_6) {
+ SetCpuFrequency(bsp::CpuFrequencyHz::Level_6);
}
}
void PowerManager::DecreaseCpuFrequency() const
{
- const auto freq = lowPowerControl->GetCurrentFrequency();
- auto level = bsp::LowPowerMode::CpuFrequency::Level_1;
+ const auto freq = lowPowerControl->GetCurrentFrequencyLevel();
+ auto level = bsp::CpuFrequencyHz::Level_1;
- // We temporarily limit the minimum CPU frequency
- // due to problems with the UART of the GSM modem
switch (freq) {
- case bsp::LowPowerMode::CpuFrequency::Level_6:
- level = bsp::LowPowerMode::CpuFrequency::Level_5;
+ case bsp::CpuFrequencyHz::Level_6:
+ level = bsp::CpuFrequencyHz::Level_5;
+ break;
+ case bsp::CpuFrequencyHz::Level_5:
+ level = bsp::CpuFrequencyHz::Level_4;
break;
- default:
- level = bsp::LowPowerMode::CpuFrequency::Level_4;
+ case bsp::CpuFrequencyHz::Level_4:
+ level = bsp::CpuFrequencyHz::Level_3;
+ break;
+ case bsp::CpuFrequencyHz::Level_3:
+ level = bsp::CpuFrequencyHz::Level_2;
+ break;
+ case bsp::CpuFrequencyHz::Level_2:
+ level = bsp::CpuFrequencyHz::Level_1;
+ break;
+ case bsp::CpuFrequencyHz::Level_1:
break;
}
// decrease frequency first
if (level != freq) {
- lowPowerControl->SetCpuFrequency(level);
+ SetCpuFrequency(level);
}
- if (level == bsp::LowPowerMode::CpuFrequency::Level_1) {
+ if (level == bsp::CpuFrequencyHz::Level_1) {
const auto oscSource = lowPowerControl->GetCurrentOscillatorSource();
// then switch osc source
@@ 111,6 124,22 @@ namespace sys
}
}
+ void PowerManager::RegisterNewSentinel(std::shared_ptr<CpuSentinel> newSentinel) const
+ {
+ cpuGovernor->RegisterNewSentinel(newSentinel);
+ }
+
+ void PowerManager::SetCpuFrequencyRequest(std::string sentinelName, bsp::CpuFrequencyHz request) const
+ {
+ cpuGovernor->SetCpuFrequencyRequest(sentinelName, request);
+ }
+
+ void PowerManager::SetCpuFrequency(bsp::CpuFrequencyHz freq) const
+ {
+ lowPowerControl->SetCpuFrequency(freq);
+ cpuGovernor->InformSentinelsAboutCpuFrequencyChange(freq);
+ }
+
void PowerManager::ResetFrequencyShiftCounter()
{
aboveThresholdCounter = 0;
M module-sys/SystemManager/PowerManager.hpp => module-sys/SystemManager/PowerManager.hpp +7 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#ifndef PUREPHONE_POWERMANAGER_HPP
@@ 8,6 8,7 @@
#include "bsp/lpm/bsp_lpm.hpp"
#include "drivers/semc/DriverSEMC.hpp"
+#include "CpuGovernor.hpp"
namespace sys
{
@@ 45,14 46,19 @@ namespace sys
[[nodiscard]] auto getExternalRamDevice() const noexcept -> std::shared_ptr<devices::Device>;
+ void RegisterNewSentinel(std::shared_ptr<CpuSentinel> newSentinel) const;
+ void SetCpuFrequencyRequest(std::string sentinelName, bsp::CpuFrequencyHz request) const;
+
private:
void ResetFrequencyShiftCounter();
+ void SetCpuFrequency(bsp::CpuFrequencyHz freq) const;
uint32_t belowThresholdCounter{0};
uint32_t aboveThresholdCounter{0};
std::unique_ptr<bsp::LowPowerMode> lowPowerControl;
std::shared_ptr<drivers::DriverSEMC> driverSEMC;
+ std::unique_ptr<CpuGovernor> cpuGovernor;
};
} // namespace sys
M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +16 -0
@@ 23,6 23,8 @@
#include <service-appmgr/service-appmgr/Controller.hpp>
#include "messages/CpuFrequencyMessage.hpp"
#include "messages/DeviceRegistrationMessage.hpp"
+#include "messages/SentinelRegistrationMessage.hpp"
+#include "messages/RequestCpuFrequencyMessage.hpp"
#include <time/ScopedTime.hpp>
const inline size_t systemManagerStack = 4096 * 2;
@@ 354,6 356,20 @@ namespace sys
return sys::MessageNone{};
});
+ connect(typeid(sys::SentinelRegistrationMessage), [this](sys::Message *message) -> sys::MessagePointer {
+ auto msg = static_cast<sys::SentinelRegistrationMessage *>(message);
+ powerManager->RegisterNewSentinel(msg->getSentinel());
+
+ return sys::MessageNone{};
+ });
+
+ connect(typeid(sys::RequestCpuFrequencyMessage), [this](sys::Message *message) -> sys::MessagePointer {
+ auto msg = static_cast<sys::RequestCpuFrequencyMessage *>(message);
+ powerManager->SetCpuFrequencyRequest(msg->getName(), msg->getRequest());
+
+ return sys::MessageNone{};
+ });
+
deviceManager->RegisterNewDevice(powerManager->getExternalRamDevice());
return ReturnCodes::Success;
A module-sys/SystemManager/messages/RequestCpuFrequencyMessage.hpp => module-sys/SystemManager/messages/RequestCpuFrequencyMessage.hpp +35 -0
@@ 0,0 1,35 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <Service/Message.hpp>
+#include <bsp/common.hpp>
+
+namespace sys
+{
+
+ class RequestCpuFrequencyMessage : public sys::DataMessage
+ {
+ public:
+ RequestCpuFrequencyMessage(std::string sentinelName, bsp::CpuFrequencyHz request)
+ : sys::DataMessage(MessageType::SystemManagerCpuFrequency), sentinelName(sentinelName),
+ frequencyRequested(request)
+ {}
+
+ [[nodiscard]] auto getRequest() const noexcept
+ {
+ return frequencyRequested;
+ };
+
+ [[nodiscard]] auto getName() const noexcept
+ {
+ return sentinelName;
+ };
+
+ private:
+ std::string sentinelName;
+ bsp::CpuFrequencyHz frequencyRequested = bsp::CpuFrequencyHz::Level_1;
+ };
+
+} // namespace sys
A module-sys/SystemManager/messages/SentinelRegistrationMessage.hpp => module-sys/SystemManager/messages/SentinelRegistrationMessage.hpp +26 -0
@@ 0,0 1,26 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <Service/Message.hpp>
+#include "Service/CpuSentinel.hpp"
+
+namespace sys
+{
+ class SentinelRegistrationMessage : public sys::DataMessage
+ {
+ public:
+ SentinelRegistrationMessage(std::shared_ptr<CpuSentinel> sentinelPtr)
+ : sys::DataMessage(MessageType::SystemManagerRegistration), sentinel(sentinelPtr)
+ {}
+
+ [[nodiscard]] auto getSentinel() const noexcept -> std::shared_ptr<CpuSentinel>
+ {
+ return sentinel;
+ };
+
+ private:
+ std::shared_ptr<CpuSentinel> sentinel;
+ };
+} // namespace sys
M module-sys/SystemManager/tests/CMakeLists.txt => module-sys/SystemManager/tests/CMakeLists.txt +9 -0
@@ 7,3 7,12 @@ add_catch2_executable(
LIBS
module-sys
)
+
+add_catch2_executable(
+ NAME
+ PowerManager
+ SRCS
+ unittest_CpuSentinelsGovernor.cpp
+ LIBS
+ module-sys
+)<
\ No newline at end of file
A module-sys/SystemManager/tests/unittest_CpuSentinelsGovernor.cpp => module-sys/SystemManager/tests/unittest_CpuSentinelsGovernor.cpp +62 -0
@@ 0,0 1,62 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+#include <SystemManager/CpuGovernor.hpp>
+#include <Service/CpuSentinel.hpp>
+
+TEST_CASE("Power Manager CPU sentinels governor test")
+{
+ using namespace sys;
+ std::shared_ptr<CpuSentinel> testSentinel_0 = nullptr;
+ auto testSentinel_1 = std::make_shared<CpuSentinel>("testSentinel_1", nullptr);
+ auto testSentinel_2 = std::make_shared<CpuSentinel>("testSentinel_2", nullptr);
+ auto testSentinel_3 = std::make_shared<CpuSentinel>("testSentinel_1", nullptr);
+
+ SECTION("Sentinel registration")
+ {
+ auto governor = std::make_unique<CpuGovernor>();
+ REQUIRE(governor->GetNumberOfRegisteredSentinels() == 0);
+
+ governor->RegisterNewSentinel(testSentinel_0);
+ REQUIRE(governor->GetNumberOfRegisteredSentinels() == 0);
+
+ governor->RegisterNewSentinel(testSentinel_1);
+ REQUIRE(governor->GetNumberOfRegisteredSentinels() == 1);
+
+ governor->RegisterNewSentinel(testSentinel_2);
+ REQUIRE(governor->GetNumberOfRegisteredSentinels() == 2);
+
+ governor->RegisterNewSentinel(testSentinel_3);
+ REQUIRE(governor->GetNumberOfRegisteredSentinels() == 2);
+ }
+
+ SECTION("Sentinel demands")
+ {
+ auto governor = std::make_unique<CpuGovernor>();
+ governor->RegisterNewSentinel(testSentinel_1);
+ governor->RegisterNewSentinel(testSentinel_2);
+
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_1);
+
+ governor->SetCpuFrequencyRequest("testSentinel_1", bsp::CpuFrequencyHz::Level_4);
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_4);
+
+ governor->SetCpuFrequencyRequest("testSentinel_2", bsp::CpuFrequencyHz::Level_6);
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_6);
+
+ governor->SetCpuFrequencyRequest("testSentinel_1", bsp::CpuFrequencyHz::Level_2);
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_6);
+
+ governor->ResetCpuFrequencyRequest("testSentinel_2");
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_2);
+
+ governor->SetCpuFrequencyRequest("bedNameSentinel", bsp::CpuFrequencyHz::Level_6);
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_2);
+
+ governor->ResetCpuFrequencyRequest("testSentinel_1");
+ REQUIRE(governor->GetMinimumFrequencyRequested() == bsp::CpuFrequencyHz::Level_1);
+ }
+}
M source/MessageType.hpp => source/MessageType.hpp +5 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#ifndef SOURCE_MESSAGETYPE_HPP_
@@ 169,6 169,10 @@ enum class MessageType
// System manager
DeviceRegistration,
+ // System manager
+ SystemManagerCpuFrequency,
+ SystemManagerRegistration,
+
// battery charger messages
EVMBatteryLevel,
EVMChargerPlugged,