M module-services/service-time/AlarmOperations.cpp => module-services/service-time/AlarmOperations.cpp +30 -17
@@ 11,6 11,7 @@
namespace alarms
{
std::unique_ptr<IAlarmOperations> CommonAlarmOperationsFactory::create(
+ [[maybe_unused]] sys::Service *service,
std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
IAlarmOperations::GetCurrentTime getCurrentTimeCallback) const
{
@@ 223,8 224,12 @@ namespace alarms
auto AlarmOperationsCommon::minuteUpdated(TimePoint now) -> void
{
- auto isHandlingInProgress = !ongoingSingleEvents.empty();
+ processEvents(now);
+ }
+ void AlarmOperationsCommon::processEvents(TimePoint now)
+ {
+ const auto isHandlingInProgress = !ongoingSingleEvents.empty();
if (!nextSingleEvents.empty()) {
processNextEventsQueue(now);
}
@@ 246,28 251,36 @@ namespace alarms
void AlarmOperationsCommon::switchAlarmExecution(const SingleEventRecord &singleAlarmEvent, bool newStateOn)
{
- alarms::AlarmType alarmType = alarms::AlarmType::None;
- if (typeid(*(singleAlarmEvent.parent)) == typeid(AlarmEventRecord)) {
- alarmType = alarms::AlarmType::Clock;
- }
-
- auto alarmEventPtr = std::dynamic_pointer_cast<AlarmEventRecord>(singleAlarmEvent.parent);
- if (alarmEventPtr) {
- auto handler = alarmHandlerFactory.getHandler(alarmType);
- if (handler) {
- if (newStateOn) {
- handler->handle(*alarmEventPtr);
- }
- else {
- handler->handleOff(*alarmEventPtr);
- }
- }
+ if (auto alarmEventPtr = std::dynamic_pointer_cast<AlarmEventRecord>(singleAlarmEvent.parent); alarmEventPtr) {
+ handleAlarmEvent(alarmEventPtr, getAlarmEventType(singleAlarmEvent), newStateOn);
}
else {
LOG_WARN("Parent type is not AlarmEventRecord!");
}
}
+ alarms::AlarmType AlarmOperationsCommon::getAlarmEventType(const SingleEventRecord &event)
+ {
+ if (typeid(*(event.parent)) == typeid(AlarmEventRecord)) {
+ return alarms::AlarmType::Clock;
+ }
+ return alarms::AlarmType::None;
+ }
+
+ void AlarmOperationsCommon::handleAlarmEvent(const std::shared_ptr<AlarmEventRecord> &event,
+ alarms::AlarmType alarmType,
+ bool newStateOn)
+ {
+ if (auto handler = alarmHandlerFactory.getHandler(alarmType); handler) {
+ if (newStateOn) {
+ handler->handle(*event);
+ }
+ else {
+ handler->handleOff(*event);
+ }
+ }
+ }
+
auto AlarmOperationsCommon::processNextEventsQueue(const TimePoint now) -> void
{
if (nextSingleEvents.front()->startDate <= now) {
M module-services/service-time/AlarmOperations.hpp => module-services/service-time/AlarmOperations.hpp +14 -4
@@ 10,9 10,10 @@
#include <module-db/Interface/AlarmEventRecord.hpp>
+#include <Service/Service.hpp>
+
namespace alarms
{
-
class IAlarmOperations
{
public:
@@ 56,6 57,7 @@ namespace alarms
virtual ~IAlarmOperationsFactory() noexcept = default;
virtual std::unique_ptr<IAlarmOperations> create(
+ sys::Service *service,
std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
IAlarmOperations::GetCurrentTime getCurrentTimeCallback) const = 0;
};
@@ 63,8 65,8 @@ namespace alarms
class AlarmOperationsCommon : public IAlarmOperations
{
public:
- explicit AlarmOperationsCommon(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
- GetCurrentTime getCurrentTimeCallback);
+ AlarmOperationsCommon(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
+ GetCurrentTime getCurrentTimeCallback);
void updateEventsCache(TimePoint now) override;
@@ 86,7 88,7 @@ namespace alarms
void addAlarmExecutionHandler(const alarms::AlarmType type,
const std::shared_ptr<alarms::AlarmHandler> handler) override;
- private:
+ protected:
std::unique_ptr<AbstractAlarmEventsRepository> alarmEventsRepo;
AlarmHandlerFactory alarmHandlerFactory;
@@ 95,6 97,12 @@ namespace alarms
std::vector<std::unique_ptr<SingleEventRecord>> ongoingSingleEvents;
std::vector<std::unique_ptr<SnoozedAlarmEventRecord>> snoozedSingleEvents;
+ alarms::AlarmType getAlarmEventType(const SingleEventRecord &event);
+ void handleAlarmEvent(const std::shared_ptr<AlarmEventRecord> &event,
+ alarms::AlarmType alarmType,
+ bool newStateOn);
+
+ private:
GetCurrentTime getCurrentTimeCallback;
// Max 100 alarms for one minute seems reasonable, next events will be dropped
@@ 113,6 121,7 @@ namespace alarms
void checkAndUpdateCache(AlarmEventRecord record);
void switchAlarmExecution(const SingleEventRecord &singleAlarmEvent, bool newStateOn);
+ void processEvents(TimePoint now);
void processNextEventsQueue(const TimePoint now);
void processSnoozedEventsQueue(const TimePoint now);
@@ 123,6 132,7 @@ namespace alarms
{
public:
std::unique_ptr<IAlarmOperations> create(
+ sys::Service *service,
std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
IAlarmOperations::GetCurrentTime getCurrentTimeCallback) const override;
};
M module-services/service-time/ServiceTime.cpp => module-services/service-time/ServiceTime.cpp +3 -4
@@ 35,15 35,14 @@ namespace stm
constexpr auto automaticTimezoneRules = "UTC0";
ServiceTime::ServiceTime(const alarms::IAlarmOperationsFactory &alarmOperationsFactory)
- : sys::Service(service::name::service_time, "", StackDepth)
+ : sys::Service(service::name::service_time, "", StackDepth), timeManager{std::make_unique<TimeManager>(
+ std::make_unique<RTCCommand>(this))}
{
LOG_INFO("[ServiceTime] Initializing");
bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);
- timeManager = std::make_unique<TimeManager>(std::make_unique<RTCCommand>(this));
-
auto alarmEventsRepo = std::make_unique<alarms::AlarmEventsDBRepository>(this);
- auto alarmOperations = alarmOperationsFactory.create(std::move(alarmEventsRepo), TimePointNow);
+ auto alarmOperations = alarmOperationsFactory.create(this, std::move(alarmEventsRepo), TimePointNow);
alarmOperations->updateEventsCache(TimePointNow());
alarmMessageHandler = std::make_unique<alarms::AlarmMessageHandler>(this, std::move(alarmOperations));
}
M module-services/service-time/include/service-time/AlarmHandler.hpp => module-services/service-time/include/service-time/AlarmHandler.hpp +2 -0
@@ 12,6 12,8 @@ namespace alarms
Clock,
Calendar,
EveningReminder,
+ PreWakeUpChime,
+ PreWakeUpFrontlight,
None
};
M module-services/service-time/tests/tests-AlarmOperations.cpp => module-services/service-time/tests/tests-AlarmOperations.cpp +1 -1
@@ 113,7 113,7 @@ class AlarmOperationsFixture : public ::testing::Test
protected:
auto getMockedAlarmOperations(std::unique_ptr<MockAlarmEventsRepository> &alarmRepo)
{
- return std::make_unique<alarms::AlarmOperations>(std::move(alarmRepo), timeInjector);
+ return std::make_unique<alarms::AlarmOperationsCommon>(std::move(alarmRepo), timeInjector);
}
};
M products/BellHybrid/BellHybridMain.cpp => products/BellHybrid/BellHybridMain.cpp +1 -1
@@ 66,7 66,7 @@ int main()
systemServices.emplace_back(sys::CreatorFor<ServiceDB>());
systemServices.emplace_back(sys::CreatorFor<ServiceAudio>());
systemServices.emplace_back(sys::CreatorFor<ServiceDesktop>());
- systemServices.emplace_back(sys::CreatorFor<stm::ServiceTime>(alarms::AlarmOperationsFactory{}));
+ systemServices.emplace_back(sys::CreatorFor<stm::ServiceTime>());
systemServices.emplace_back(sys::CreatorFor<service::eink::ServiceEink>());
systemServices.emplace_back(sys::CreatorFor<service::gui::ServiceGUI>());
M products/BellHybrid/alarms/BellAlarmHandler.cpp => products/BellHybrid/alarms/BellAlarmHandler.cpp +29 -0
@@ 51,4 51,33 @@ namespace alarms
return true;
}
+ PreWakeUpChimeHandler::PreWakeUpChimeHandler(sys::Service *service) : service{service}
+ {}
+
+ auto PreWakeUpChimeHandler::handle(const AlarmEventRecord &record) -> bool
+ {
+ LOG_INFO("PreWakeUpChimeHandler::handle");
+ return true;
+ }
+
+ auto PreWakeUpChimeHandler::handleOff(const AlarmEventRecord &record) -> bool
+ {
+ LOG_INFO("PreWakeUpChimeHandler::handleOff");
+ return true;
+ }
+
+ PreWakeUpFrontlightHandler::PreWakeUpFrontlightHandler(sys::Service *service) : service{service}
+ {}
+
+ auto PreWakeUpFrontlightHandler::handle(const AlarmEventRecord &record) -> bool
+ {
+ LOG_INFO("PreWakeUpFrontlightHandler::handle");
+ return true;
+ }
+
+ auto PreWakeUpFrontlightHandler::handleOff(const AlarmEventRecord &record) -> bool
+ {
+ LOG_INFO("PreWakeUpFrontlightHandler::handleOff");
+ return true;
+ }
} // namespace alarms
M products/BellHybrid/alarms/include/BellAlarmHandler.hpp => products/BellHybrid/alarms/include/BellAlarmHandler.hpp +26 -0
@@ 29,4 29,30 @@ namespace alarms
auto handle(const AlarmEventRecord &record) -> bool;
auto handleOff(const AlarmEventRecord &record) -> bool;
};
+
+ class PreWakeUpChimeHandler : public AlarmHandler
+ {
+ public:
+ explicit PreWakeUpChimeHandler(sys::Service *service);
+ auto handle(const AlarmEventRecord &record) -> bool;
+ auto handleOff(const AlarmEventRecord &record) -> bool;
+
+ static constexpr auto name = "PreWakeUpChimeHandler";
+
+ private:
+ sys::Service *service{};
+ };
+
+ class PreWakeUpFrontlightHandler : public AlarmHandler
+ {
+ public:
+ explicit PreWakeUpFrontlightHandler(sys::Service *service);
+ auto handle(const AlarmEventRecord &record) -> bool;
+ auto handleOff(const AlarmEventRecord &record) -> bool;
+
+ static constexpr auto name = "PreWakeUpFrontlightHandler";
+
+ private:
+ sys::Service *service{};
+ };
} // namespace alarms
M products/BellHybrid/services/time/AlarmOperations.cpp => products/BellHybrid/services/time/AlarmOperations.cpp +92 -1
@@ 3,12 3,103 @@
#include <time/AlarmOperations.hpp>
+#include <BellAlarmHandler.hpp>
+
namespace alarms
{
+ namespace
+ {
+ class MockedPreWakeUpSettingsProvider : public PreWakeUpSettingsProvider
+ {
+ public:
+ auto getChimeSettings() -> Settings override
+ {
+ return {true, std::chrono::minutes{5}};
+ }
+
+ auto getFrontlightSettings() -> Settings override
+ {
+ return {true, std::chrono::minutes{5}};
+ }
+ };
+ } // namespace
+
std::unique_ptr<IAlarmOperations> AlarmOperationsFactory::create(
+ sys::Service *service,
std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
IAlarmOperations::GetCurrentTime getCurrentTimeCallback) const
{
- return std::make_unique<AlarmOperations>(std::move(alarmEventsRepo), getCurrentTimeCallback);
+ auto settingsProvider = std::make_unique<MockedPreWakeUpSettingsProvider>();
+ auto alarmOperations = std::make_unique<AlarmOperations>(
+ std::move(alarmEventsRepo), getCurrentTimeCallback, std::move(settingsProvider));
+ alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::PreWakeUpChime,
+ std::make_shared<alarms::PreWakeUpChimeHandler>(service));
+ alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::PreWakeUpFrontlight,
+ std::make_shared<alarms::PreWakeUpFrontlightHandler>(service));
+ return alarmOperations;
+ }
+
+ AlarmOperations::AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
+ GetCurrentTime getCurrentTimeCallback,
+ std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider)
+ : AlarmOperationsCommon{std::move(alarmEventsRepo), std::move(getCurrentTimeCallback)},
+ settingsProvider{std::move(settingsProvider)}
+ {}
+
+ void AlarmOperations::minuteUpdated(TimePoint now)
+ {
+ AlarmOperationsCommon::minuteUpdated(now);
+ processPreWakeUpEvents(now);
+ }
+
+ void AlarmOperations::processPreWakeUpEvents(TimePoint now)
+ {
+ if (nextSingleEvents.empty()) {
+ return;
+ }
+
+ auto nextEvent = *(nextSingleEvents.front());
+ if (getAlarmEventType(nextEvent) != alarms::AlarmType::Clock) {
+ return;
+ }
+
+ PreWakeUpHandler handler{settingsProvider.get()};
+ preWakeUp(nextEvent, handler.handle(now, nextEvent));
+ }
+
+ void AlarmOperations::preWakeUp(const SingleEventRecord &event, PreWakeUpHandler::Result handleResult)
+ {
+ if (!handleResult.timeForChime && !handleResult.timeForFrontlight) {
+ return;
+ }
+
+ if (auto alarmEventPtr = std::dynamic_pointer_cast<AlarmEventRecord>(event.parent); alarmEventPtr) {
+ if (handleResult.timeForChime) {
+ handleAlarmEvent(alarmEventPtr, alarms::AlarmType::PreWakeUpChime, true);
+ }
+ if (handleResult.timeForFrontlight) {
+ handleAlarmEvent(alarmEventPtr, alarms::AlarmType::PreWakeUpFrontlight, true);
+ }
+ }
+ }
+
+ PreWakeUpHandler::PreWakeUpHandler(PreWakeUpSettingsProvider *settingsProvider) : settingsProvider{settingsProvider}
+ {}
+
+ auto PreWakeUpHandler::handle(TimePoint now, const SingleEventRecord &event) -> Result
+ {
+ const auto chimeSettings = settingsProvider->getChimeSettings();
+ const auto frontlightSettings = settingsProvider->getFrontlightSettings();
+ const auto isTimeForChime = isTimeForPreWakeUp(now, event, chimeSettings);
+ const auto isTimeForFrontlight = isTimeForPreWakeUp(now, event, frontlightSettings);
+ return {isTimeForChime, isTimeForFrontlight};
+ }
+
+ auto PreWakeUpHandler::isTimeForPreWakeUp(TimePoint now,
+ const SingleEventRecord &event,
+ PreWakeUpSettingsProvider::Settings settings) -> bool
+ {
+ const auto expectedAlarmStart = std::chrono::floor<std::chrono::minutes>(now) + settings.timeBeforeAlarm;
+ return settings.enabled && std::chrono::floor<std::chrono::minutes>(event.startDate) == expectedAlarmStart;
}
} // namespace alarms
M products/BellHybrid/services/time/CMakeLists.txt => products/BellHybrid/services/time/CMakeLists.txt +1 -0
@@ 18,6 18,7 @@ target_include_directories(bell-time
target_link_libraries(bell-time
PRIVATE
module-sys
+ bell::alarms
PUBLIC
service-time
)
M products/BellHybrid/services/time/include/time/AlarmOperations.hpp => products/BellHybrid/services/time/include/time/AlarmOperations.hpp +46 -1
@@ 11,13 11,58 @@ namespace alarms
{
public:
std::unique_ptr<IAlarmOperations> create(
+ sys::Service *service,
std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
IAlarmOperations::GetCurrentTime getCurrentTimeCallback) const override;
};
+ class PreWakeUpSettingsProvider
+ {
+ public:
+ struct Settings
+ {
+ bool enabled{false};
+ std::chrono::minutes timeBeforeAlarm{std::chrono::minutes::zero()};
+ };
+
+ virtual ~PreWakeUpSettingsProvider() noexcept = default;
+ virtual auto getChimeSettings() -> Settings = 0;
+ virtual auto getFrontlightSettings() -> Settings = 0;
+ };
+
+ class PreWakeUpHandler
+ {
+ public:
+ struct Result
+ {
+ bool timeForChime;
+ bool timeForFrontlight;
+ };
+
+ explicit PreWakeUpHandler(PreWakeUpSettingsProvider *settingsProvider);
+ auto handle(TimePoint now, const SingleEventRecord &event) -> Result;
+
+ private:
+ auto isTimeForPreWakeUp(TimePoint now,
+ const SingleEventRecord &event,
+ PreWakeUpSettingsProvider::Settings settings) -> bool;
+
+ PreWakeUpSettingsProvider *settingsProvider;
+ };
+
class AlarmOperations : public AlarmOperationsCommon
{
public:
- using AlarmOperationsCommon::AlarmOperationsCommon;
+ AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo,
+ GetCurrentTime getCurrentTimeCallback,
+ std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider);
+
+ void minuteUpdated(TimePoint now) override;
+
+ private:
+ void processPreWakeUpEvents(TimePoint now);
+ void preWakeUp(const SingleEventRecord &event, PreWakeUpHandler::Result handleResult);
+
+ std::unique_ptr<PreWakeUpSettingsProvider> settingsProvider;
};
} // namespace alarms