~aleteoryx/muditaos

e338b69fabdaff2c885d517b559bb13a155241b4 — Paweł Joński 4 years ago 2061952
[BH-642] Handle alarm messages in service-time

Handle basic alarm messages in service-time
M module-services/service-time/AlarmEventsDBRepository.cpp => module-services/service-time/AlarmEventsDBRepository.cpp +2 -2
@@ 13,7 13,7 @@
#include <module-db/queries/alarm_events/QueryAlarmEventsGetRecurringBetweenDates.hpp>
#include <module-db/queries/alarm_events/QueryAlarmEventsRemove.hpp>

namespace alarmEvents
namespace alarms
{
    AlarmEventsDBRepository::AlarmEventsDBRepository(sys::Service *service) : service{service}
    {}


@@ 108,4 108,4 @@ namespace alarmEvents
        DBServiceAPI::GetQuery(service, db::Interface::Name::AlarmEvents, std::move(query));
    }

} // namespace alarmEvents
} // namespace alarms

M module-services/service-time/AlarmEventsDBRepository.hpp => module-services/service-time/AlarmEventsDBRepository.hpp +4 -2
@@ 1,12 1,14 @@
// 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 "AlarmRepository.hpp"

#include <Service/Service.hpp>
#include <time/dateCommon.hpp>

namespace alarmEvents
namespace alarms
{
    class AlarmEventsDBRepository : public AbstractAlarmEventsRepository
    {


@@ 41,4 43,4 @@ namespace alarmEvents
        template <typename requestT, typename responseT, typename callbackT, typename... Types>
        void sendQueryWithCallback(const callbackT &callback, Types... queryArgs);
    };
} // namespace alarmEvents
} // namespace alarms

A module-services/service-time/AlarmMessageHandler.cpp => module-services/service-time/AlarmMessageHandler.cpp +98 -0
@@ 0,0 1,98 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AlarmMessageHandler.hpp"
#include "ServiceTime.hpp"

#include <module-db/Interface/AlarmEventRecord.hpp>
#include <module-db/Interface/EventRecord.hpp>

#include <service-time/AlarmMessage.hpp>

namespace alarms
{

    AlarmMessageHandler::AlarmMessageHandler(stm::ServiceTime *service,
                                             std::unique_ptr<IAlarmOperations> &&alarmOperations)
        : service{service}, alarmOperations{std::move(alarmOperations)} {};

    auto AlarmMessageHandler::handleGetAlarm(AlarmGetRequestMessage *request)
        -> std::shared_ptr<AlarmGetResponseMessage>
    {
        return handleWithCallback<AlarmGetRequestMessage, AlarmGetResponseMessage, AlarmEventRecord>(
            request, [&](AlarmGetRequestMessage *request, IAlarmOperations::OnGetAlarmProcessed callback) {
                alarmOperations->getAlarm(request->id, callback);
            });
    }

    auto AlarmMessageHandler::handleAddAlarm(AlarmAddRequestMessage *request)
        -> std::shared_ptr<AlarmAddResponseMessage>
    {
        return handleWithCallback<AlarmAddRequestMessage, AlarmAddResponseMessage, bool>(
            request, [&](AlarmAddRequestMessage *request, IAlarmOperations::OnAddAlarmProcessed callback) {
                alarmOperations->addAlarm(request->alarmEvent, callback);
            });
    }

    auto AlarmMessageHandler::handleUpdateAlarm(AlarmUpdateRequestMessage *request)
        -> std::shared_ptr<AlarmUpdateResponseMessage>
    {
        return handleWithCallback<AlarmUpdateRequestMessage, AlarmUpdateResponseMessage, bool>(
            request, [&](AlarmUpdateRequestMessage *request, IAlarmOperations::OnUpdateAlarmProcessed callback) {
                alarmOperations->updateAlarm(request->alarmEvent, callback);
            });
    }

    auto AlarmMessageHandler::handleRemoveAlarm(AlarmRemoveRequestMessage *request)
        -> std::shared_ptr<AlarmRemoveResponseMessage>
    {
        return handleWithCallback<AlarmRemoveRequestMessage, AlarmRemoveResponseMessage, bool>(
            request, [&](AlarmRemoveRequestMessage *request, IAlarmOperations::OnRemoveAlarmProcessed callback) {
                alarmOperations->removeAlarm(request->id, callback);
            });
    }

    auto AlarmMessageHandler::handleGetAlarmsInRange(AlarmsGetInRangeRequestMessage *request)
        -> std::shared_ptr<AlarmsGetInRangeResponseMessage>
    {
        return handleWithCallback<AlarmsGetInRangeRequestMessage,
                                  AlarmsGetInRangeResponseMessage,
                                  std::vector<AlarmEventRecord>>(
            request,
            [&](AlarmsGetInRangeRequestMessage *request, IAlarmOperations::OnGetAlarmsInRangeProcessed callback) {
                alarmOperations->getAlarmsInRange(
                    request->start, request->end, request->offset, request->limit, callback);
            });
    }

    auto AlarmMessageHandler::handleGetNextSingleEvents(AlarmGetNextSingleEventsRequestMessage *request)
        -> std::shared_ptr<AlarmGetNextSingleEventsResponseMessage>
    {
        return handleWithCallback<AlarmGetNextSingleEventsRequestMessage,
                                  AlarmGetNextSingleEventsResponseMessage,
                                  std::vector<SingleEventRecord>>(
            request,
            [&](AlarmGetNextSingleEventsRequestMessage *request, IAlarmOperations::OnGetNextSingleProcessed callback) {
                alarmOperations->getNextSingleEvents(TimePointNow(), callback);
            });
    }

    template <class RequestType, class ResponseType, class CallbackParamType>
    auto AlarmMessageHandler::handleWithCallback(
        RequestType *request,
        const std::function<void(RequestType *request, std::function<void(CallbackParamType)>)>
            &alarmOperationsCallback) -> std::shared_ptr<ResponseType>
    {
        auto uniID    = request->uniID;
        auto sender   = request->sender;
        auto callback = [&, uniID, sender](CallbackParamType param) {
            auto response   = std::make_shared<ResponseType>(param);
            response->uniID = uniID;
            service->bus.sendUnicast(response, sender);
        };

        alarmOperationsCallback(request, callback);
        return sys::MessageNone{};
    }

} // namespace alarms

A module-services/service-time/AlarmMessageHandler.hpp => module-services/service-time/AlarmMessageHandler.hpp +42 -0
@@ 0,0 1,42 @@
// 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 "AlarmOperations.hpp"

#include <service-time/AlarmMessage.hpp>

#include <Service/Service.hpp>

namespace stm
{
    class ServiceTime;
}

namespace alarms
{
    class AlarmMessageHandler
    {
      public:
        AlarmMessageHandler(stm::ServiceTime *service, std::unique_ptr<IAlarmOperations> &&alarmOperations);

        auto handleGetAlarm(AlarmGetRequestMessage *request) -> std::shared_ptr<AlarmGetResponseMessage>;
        auto handleAddAlarm(AlarmAddRequestMessage *request) -> std::shared_ptr<AlarmAddResponseMessage>;
        auto handleUpdateAlarm(AlarmUpdateRequestMessage *request) -> std::shared_ptr<AlarmUpdateResponseMessage>;
        auto handleRemoveAlarm(AlarmRemoveRequestMessage *request) -> std::shared_ptr<AlarmRemoveResponseMessage>;
        auto handleGetAlarmsInRange(AlarmsGetInRangeRequestMessage *request)
            -> std::shared_ptr<AlarmsGetInRangeResponseMessage>;
        auto handleGetNextSingleEvents(AlarmGetNextSingleEventsRequestMessage *request)
            -> std::shared_ptr<AlarmGetNextSingleEventsResponseMessage>;

      private:
        stm::ServiceTime *service = nullptr;
        std::unique_ptr<IAlarmOperations> alarmOperations;

        template <class RequestType, class ResponseType, class CallbackParamType>
        auto handleWithCallback(RequestType *request,
                                const std::function<void(RequestType *request, std::function<void(CallbackParamType)>)>
                                    &alarmOperationsCallback) -> std::shared_ptr<ResponseType>;
    };
} // namespace alarms

A module-services/service-time/AlarmOperations.cpp => module-services/service-time/AlarmOperations.cpp +107 -0
@@ 0,0 1,107 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AlarmOperations.hpp"

namespace alarms
{
    AlarmOperations::AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo)
        : alarmEventsRepo{std::move(alarmEventsRepo)} {};

    void AlarmOperations::getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback)
    {
        OnGetAlarmEventCallback repoCallback = [callback](AlarmEventRecord record) { callback(record); };
        alarmEventsRepo->getAlarmEvent(alarmId, repoCallback);
    }

    void AlarmOperations::addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback)
    {
        OnAddAlarmEventCallback repoCallback = [callback](bool success) { callback(success); };
        alarmEventsRepo->addAlarmEvent(record, repoCallback);
    }
    void AlarmOperations::updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback)
    {
        OnUpdateAlarmEventCallback repoCallback = [callback](bool success) { callback(success); };
        alarmEventsRepo->updateAlarmEvent(record, repoCallback);
    }

    void AlarmOperations::removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback)
    {
        OnRemoveAlarmEventCallback repoCallback = [callback](bool success) { callback(success); };
        alarmEventsRepo->removeAlarmEvent(alarmId, repoCallback);
    }

    void AlarmOperations::getAlarmsInRange(
        TimePoint start, TimePoint end, std::uint32_t offset, std::uint32_t limit, OnGetAlarmsInRangeProcessed callback)
    {
        OnGetAlarmEventsInRangeCallback repoCallback = [callback](std::vector<AlarmEventRecord> records) {
            callback(records);
        };
        alarmEventsRepo->getAlarmEventsInRange(start, end, offset, limit, repoCallback);
    }

    void AlarmOperations::getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback)
    {
        auto nextEvents = std::make_shared<std::vector<AlarmEventRecord>>();

        OnGetAlarmEventsRecurringInRange repoGetRecurringCallback =
            [&, callback, nextEvents, start](std::vector<AlarmEventRecord> records) {
                onRepoGetRecurringInRangeResponse(callback, nextEvents, start, records);
            };

        OnGetNextCallback repoGetNextCallback =
            [&, callback, nextEvents, start, repoGetRecurringCallback](std::vector<AlarmEventRecord> records) {
                onRepoGetNextResponse(callback, nextEvents, start, repoGetRecurringCallback, records);
            };

        alarmEventsRepo->getNext(start, getNextSingleEventsOffset, getNextSingleEventsLimit, repoGetNextCallback);
    }

    void AlarmOperations::onRepoGetNextResponse(OnGetNextSingleProcessed handledCallback,
                                                std::shared_ptr<std::vector<AlarmEventRecord>> nextEvents,
                                                TimePoint start,
                                                OnGetAlarmEventsRecurringInRange recurringCallback,
                                                std::vector<AlarmEventRecord> records)
    {
        if (records.empty()) {
            handledCallback({});
        }
        else {
            *nextEvents              = std::move(records);
            auto firstEventTimePoint = (*nextEvents)[0].startDate;
            nextEvents->erase(std::remove_if(nextEvents->begin(),
                                             nextEvents->end(),
                                             [](AlarmEventRecord rec) { return !rec.rruleText.empty(); }),
                              nextEvents->end());
            alarmEventsRepo->getAlarmEventsRecurringInRange(
                start, firstEventTimePoint, getNextSingleEventsOffset, getNextSingleEventsLimit, recurringCallback);
        }
    }

    void AlarmOperations::onRepoGetRecurringInRangeResponse(OnGetNextSingleProcessed handledCallback,
                                                            std::shared_ptr<std::vector<AlarmEventRecord>> nextEvents,
                                                            TimePoint start,
                                                            std::vector<AlarmEventRecord> records)
    {
        std::vector<SingleEventRecord> outEvents;
        if (!records.empty()) {
            (*nextEvents)
                .insert(nextEvents->end(),
                        std::make_move_iterator(records.begin()),
                        std::make_move_iterator(records.end()));
        }
        TimePoint nearestTimePoint = TIME_POINT_MAX;
        for (auto &event : (*nextEvents)) {
            auto newSingle = event.getNextSingleEvent(start);
            if (newSingle.startDate == nearestTimePoint) {
                outEvents.push_back(newSingle);
            }
            else if (newSingle.startDate < nearestTimePoint) {
                nearestTimePoint = newSingle.startDate;
                outEvents.clear();
                outEvents.push_back(newSingle);
            }
        }
        handledCallback(outEvents);
    }
} // namespace alarms

A module-services/service-time/AlarmOperations.hpp => module-services/service-time/AlarmOperations.hpp +68 -0
@@ 0,0 1,68 @@
// 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 "AlarmRepository.hpp"

#include <module-db/Interface/AlarmEventRecord.hpp>

namespace alarms
{

    class IAlarmOperations
    {
      public:
        using OnGetAlarmProcessed         = std::function<void(AlarmEventRecord)>;
        using OnGetAlarmsInRangeProcessed = std::function<void(std::vector<AlarmEventRecord>)>;
        using OnAddAlarmProcessed         = std::function<void(bool)>;
        using OnUpdateAlarmProcessed      = std::function<void(bool)>;
        using OnRemoveAlarmProcessed      = std::function<void(bool)>;
        using OnGetNextSingleProcessed    = std::function<void(std::vector<SingleEventRecord>)>;

        virtual void getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback)       = 0;
        virtual void addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback)           = 0;
        virtual void updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback)     = 0;
        virtual void removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) = 0;
        virtual void getAlarmsInRange(TimePoint start,
                                      TimePoint end,
                                      std::uint32_t offset,
                                      std::uint32_t limit,
                                      OnGetAlarmsInRangeProcessed callback)                    = 0;
        virtual void getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback)   = 0;
    };

    class AlarmOperations : public IAlarmOperations
    {
      public:
        explicit AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo);

        void getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback) override;
        void addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) override;
        void updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback) override;
        void removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) override;
        void getAlarmsInRange(TimePoint start,
                              TimePoint end,
                              std::uint32_t offset,
                              std::uint32_t limit,
                              OnGetAlarmsInRangeProcessed callback) override;
        void getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback) override;

      private:
        std::unique_ptr<AbstractAlarmEventsRepository> alarmEventsRepo;

        // Max 100 alarms for one minute seems reasonable, next events will be dropped
        constexpr static auto getNextSingleEventsOffset = 0;
        constexpr static auto getNextSingleEventsLimit  = 100;

        void onRepoGetNextResponse(OnGetNextSingleProcessed handledCallback,
                                   std::shared_ptr<std::vector<AlarmEventRecord>> nextEvents,
                                   TimePoint start,
                                   OnGetAlarmEventsRecurringInRange recurringCallback,
                                   std::vector<AlarmEventRecord> records);
        void onRepoGetRecurringInRangeResponse(OnGetNextSingleProcessed handledCallback,
                                               std::shared_ptr<std::vector<AlarmEventRecord>> nextEvents,
                                               TimePoint start,
                                               std::vector<AlarmEventRecord> records);
    };
} // namespace alarms

M module-services/service-time/AlarmRepository.hpp => module-services/service-time/AlarmRepository.hpp +10 -13
@@ 3,7 3,6 @@

#pragma once

#include <service-time/AlarmMessage.hpp>

#include <module-sys/Service/Service.hpp>
#include <time/dateCommon.hpp>


@@ 18,22 17,20 @@ class AlarmEventRecord;
/**
 * @brief Basic interface alarm API
 */
namespace alarmEvents
namespace alarms
{
    using OnGetAlarmEventCallback          = std::function<void(AlarmEventRecord)>;
    using OnGetAlarmEventsCallback         = std::function<void(std::vector<AlarmEventRecord>)>;
    using OnGetAlarmEventsInRangeCallback  = std::function<void(std::vector<AlarmEventRecord>)>;
    using OnAddAlarmEventCallback          = std::function<void(bool)>;
    using OnUpdateAlarmEventCallback       = std::function<void(bool)>;
    using OnRemoveAlarmEventCallback       = std::function<void(bool)>;
    using OnGetNextCallback                = std::function<void(std::vector<AlarmEventRecord>)>;
    using OnGetAlarmEventsRecurringInRange = std::function<void(std::vector<AlarmEventRecord>)>;

    class AbstractAlarmEventsRepository
    {
      public:
        using OnGetAlarmEventCallback          = std::function<void(AlarmEventRecord)>;
        using OnGetAlarmEventsCallback         = std::function<void(std::vector<AlarmEventRecord>)>;
        using OnGetAlarmEventsInRangeCallback  = std::function<void(std::vector<AlarmEventRecord>)>;
        using OnAddAlarmEventCallback          = std::function<void(bool)>;
        using OnUpdateAlarmEventCallback       = std::function<void(bool)>;
        using OnRemoveAlarmEventCallback       = std::function<void(bool)>;
        using OnGetNextCallback                = std::function<void(std::vector<AlarmEventRecord>)>;
        using OnGetAlarmEventsRecurringInRange = std::function<void(std::vector<AlarmEventRecord>)>;

      public:
        /**
         * Default destructor
         */


@@ 112,4 109,4 @@ namespace alarmEvents
                                                    std::uint32_t limit,
                                                    const OnGetAlarmEventsRecurringInRange &callback) = 0;
    };
} // namespace alarmEvents
} // namespace alarms

M module-services/service-time/CMakeLists.txt => module-services/service-time/CMakeLists.txt +8 -0
@@ 4,11 4,18 @@ message( "${PROJECT_NAME}  ${CMAKE_CURRENT_SOURCE_DIR}" )
set(SOURCES
    AlarmHandlerFactory.cpp
    AlarmEventsDBRepository.cpp
    AlarmMessageHandler.cpp
    AlarmOperations.cpp
    ServiceTime.cpp
    TimeManager.cpp
    RTCcommand.cpp
    TimezoneHandler.cpp
    internal/StaticData.cpp

    include/service-time/AlarmHandler.hpp
    include/service-time/AlarmHandlerFactory.hpp
    include/service-time/AlarmMessage.hpp
    include/service-time/AlarmServiceAPI.hpp
)

add_library(${PROJECT_NAME} STATIC ${SOURCES})


@@ 21,6 28,7 @@ target_include_directories(${PROJECT_NAME}

target_link_libraries(${PROJECT_NAME}
    PRIVATE
        module-db
        time
        service-db
        service-time-api

M module-services/service-time/ServiceTime.cpp => module-services/service-time/ServiceTime.cpp +32 -3
@@ 1,17 1,20 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AlarmMessageHandler.hpp"
#include "ServiceTime.hpp"
#include "service-time/TimeMessage.hpp"
#include "service-time/RTCCommand.hpp"
#include <service-time/AlarmMessage.hpp>
#include <service-time/internal/StaticData.hpp>
#include <service-time/RTCCommand.hpp>
#include <service-time/TimeMessage.hpp>
#include <service-time/TimeSettings.hpp>
#include <service-time/TimezoneHandler.hpp>

#include <BaseInterface.hpp>
#include <Common/Query.hpp>
#include <MessageType.hpp>
#include <log.hpp>
#include <MessageType.hpp>
#include <module-db/Interface/EventRecord.hpp>
#include <service-db/DBNotificationMessage.hpp>
#include <service-db/QueryMessage.hpp>
#include <service-cellular/service-cellular/CellularMessage.hpp>


@@ 37,6 40,10 @@ namespace stm
        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 = std::make_unique<alarms::AlarmOperations>(std::move(alarmEventsRepo));
        alarmMessageHandler  = std::make_unique<alarms::AlarmMessageHandler>(this, std::move(alarmOperations));
    }

    ServiceTime::~ServiceTime()


@@ 105,6 112,28 @@ namespace stm
        });
        connect(typeid(stm::message::GetAutomaticDateAndTimeRequest),
                [&](sys::Message *request) -> sys::MessagePointer { return handleGetAutomaticDateAndTimeRequest(); });

        connect(typeid(alarms::AlarmGetRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleGetAlarm(static_cast<alarms::AlarmGetRequestMessage *>(request));
        });
        connect(typeid(alarms::AlarmAddRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleAddAlarm(static_cast<alarms::AlarmAddRequestMessage *>(request));
        });
        connect(typeid(alarms::AlarmUpdateRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleUpdateAlarm(static_cast<alarms::AlarmUpdateRequestMessage *>(request));
        });
        connect(typeid(alarms::AlarmRemoveRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleRemoveAlarm(static_cast<alarms::AlarmRemoveRequestMessage *>(request));
        });
        connect(typeid(alarms::AlarmsGetInRangeRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleGetAlarmsInRange(
                static_cast<alarms::AlarmsGetInRangeRequestMessage *>(request));
        });
        connect(typeid(alarms::AlarmGetNextSingleEventsRequestMessage),
                [&](sys::Message *request) -> sys::MessagePointer {
                    return alarmMessageHandler->handleGetNextSingleEvents(
                        static_cast<alarms::AlarmGetNextSingleEventsRequestMessage *>(request));
                });
    }

    auto ServiceTime::handleSetAutomaticDateAndTimeRequest(sys::Message *request)

M module-services/service-time/ServiceTime.hpp => module-services/service-time/ServiceTime.hpp +5 -0
@@ 3,6 3,8 @@

#pragma once

#include "AlarmEventsDBRepository.hpp"
#include "AlarmMessageHandler.hpp"
#include "Constants.hpp"
#include "service-time/TimeManager.hpp"
#include "service-time/ServiceTime.hpp"


@@ 33,6 35,8 @@ namespace stm

        std::unique_ptr<settings::Settings> settings;

        std::unique_ptr<alarms::AlarmMessageHandler> alarmMessageHandler;

        void registerMessageHandlers();
        auto handleSetAutomaticDateAndTimeRequest(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;
        auto handleSetTimeFormatRequest(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;


@@ 40,6 44,7 @@ namespace stm
        auto handleSetTimezoneRequest(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;
        auto handleCellularTimeNotificationMessage(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;
        auto handleGetAutomaticDateAndTimeRequest() -> std::shared_ptr<sys::ResponseMessage>;

        void initStaticData();

      public:

M module-services/service-time/include/service-time/AlarmMessage.hpp => module-services/service-time/include/service-time/AlarmMessage.hpp +18 -15
@@ 25,29 25,28 @@ namespace alarms
    {
      public:
        AlarmGetRequestMessage(const unsigned int id = 1) : id(id){};
        unsigned int id;
        const unsigned int id;
    };

    class AlarmGetResponseMessage : public AlarmMessage
    {
      public:
        AlarmGetResponseMessage(const std::vector<AlarmEventRecord> alarms = std::vector<AlarmEventRecord>())
            : alarms(alarms){};
        std::vector<AlarmEventRecord> alarms;
        AlarmGetResponseMessage(const AlarmEventRecord alarm = AlarmEventRecord{}) : alarm(alarm){};
        const AlarmEventRecord alarm;
    };

    class AlarmAddRequestMessage : public AlarmMessage
    {
      public:
        AlarmAddRequestMessage(const AlarmEventRecord &alarmEvent = AlarmEventRecord()) : alarmEvent(alarmEvent){};
        AlarmEventRecord alarmEvent;
        const AlarmEventRecord alarmEvent;
    };

    class AlarmAddResponseMessage : public AlarmMessage
    {
      public:
        AlarmAddResponseMessage(const AlarmEventRecord &alarmEvent = AlarmEventRecord()) : alarmEvent(alarmEvent){};
        AlarmEventRecord alarmEvent;
        AlarmAddResponseMessage(const bool success = false) : success(success){};
        const bool success;
    };

    class AlarmUpdateRequestMessage : public AlarmMessage


@@ 60,22 59,22 @@ namespace alarms
    class AlarmUpdateResponseMessage : public AlarmMessage
    {
      public:
        AlarmUpdateResponseMessage(const AlarmEventRecord &alarmEvent = AlarmEventRecord()) : alarmEvent(alarmEvent){};
        AlarmEventRecord alarmEvent;
        AlarmUpdateResponseMessage(const bool success = false) : success(success){};
        const bool success;
    };

    class AlarmRemoveRequestMessage : public AlarmMessage
    {
      public:
        AlarmRemoveRequestMessage(const unsigned int id = 0) : id(id){};
        unsigned int id;
        const unsigned int id;
    };

    class AlarmRemoveResponseMessage : public AlarmMessage
    {
      public:
        AlarmRemoveResponseMessage(const bool success = false) : success(success){};
        bool success;
        const bool success;
    };

    class AlarmsGetInRangeRequestMessage : public AlarmMessage


@@ 83,10 82,14 @@ namespace alarms
      public:
        AlarmsGetInRangeRequestMessage(
            const std::chrono::time_point<std::chrono::system_clock> start = TIME_POINT_INVALID,
            const std::chrono::time_point<std::chrono::system_clock> end   = TIME_POINT_INVALID)
            : start(start), end(end){};
        std::chrono::time_point<std::chrono::system_clock> start;
        std::chrono::time_point<std::chrono::system_clock> end;
            const std::chrono::time_point<std::chrono::system_clock> end   = TIME_POINT_INVALID,
            std::uint32_t offset                                           = 0,
            std::uint32_t limit                                            = 0)
            : start(start), end(end), offset(offset), limit(limit){};
        const std::chrono::time_point<std::chrono::system_clock> start;
        const std::chrono::time_point<std::chrono::system_clock> end;
        const std::uint32_t offset;
        const std::uint32_t limit;
    };

    class AlarmsGetInRangeResponseMessage : public AlarmMessage

M module-services/service-time/tests/CMakeLists.txt => module-services/service-time/tests/CMakeLists.txt +12 -0
@@ 19,3 19,15 @@ add_catch2_executable(
        service-time
        module-db
)

add_gtest_executable(
    NAME 
        service-time-alarm-operations
    SRCS
        tests-AlarmOperations.cpp
    LIBS
        module-sys
        service-time
    INCLUDE
        $<TARGET_PROPERTY:service-time,INCLUDE_DIRECTORIES>
)

A module-services/service-time/tests/tests-AlarmOperations.cpp => module-services/service-time/tests/tests-AlarmOperations.cpp +368 -0
@@ 0,0 1,368 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <AlarmOperations.hpp>
#include <AlarmRepository.hpp>
#include <module-db/Interface/AlarmEventRecord.hpp>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

class MockAlarmEventsRepository : public alarms::AbstractAlarmEventsRepository
{
  public:
    std::vector<AlarmEventRecord> nextRecords;
    std::vector<AlarmEventRecord> recurringRecords;

    MOCK_METHOD(void,
                getAlarmEvent,
                (const std::uint32_t alarmId, const alarms::OnGetAlarmEventCallback &callback),
                ());
    MOCK_METHOD(void,
                getAlarmEvents,
                (std::uint32_t offset, std::uint32_t limit, const alarms::OnGetAlarmEventsCallback &callback),
                ());
    MOCK_METHOD(void,
                getAlarmEventsInRange,
                (TimePoint start,
                 TimePoint end,
                 std::uint32_t offset,
                 std::uint32_t limit,
                 const alarms::OnGetAlarmEventsInRangeCallback &callback),
                ());
    MOCK_METHOD(void,
                addAlarmEvent,
                (const AlarmEventRecord &alarmEvent, const alarms::OnAddAlarmEventCallback &callback),
                ());
    MOCK_METHOD(void,
                updateAlarmEvent,
                (const AlarmEventRecord &alarmEvent, const alarms::OnUpdateAlarmEventCallback &callback),
                ());
    MOCK_METHOD(void,
                removeAlarmEvent,
                (const std::uint32_t id, const alarms::OnRemoveAlarmEventCallback &callback),
                ());
    void getAlarmEventsRecurringInRange(TimePoint start,
                                        TimePoint end,
                                        std::uint32_t offset,
                                        std::uint32_t limit,
                                        const alarms::OnGetAlarmEventsRecurringInRange &callback)
    {
        callback({recurringRecords});
    }

    void getNext(TimePoint start, std::uint32_t offset, std::uint32_t limit, const alarms::OnGetNextCallback &callback)
    {
        callback({nextRecords});
    }

    void addSingleEvent(const AlarmEventRecord record)
    {
        nextRecords.push_back(record);
    }

    void addRecurringEvent(const AlarmEventRecord record)
    {
        addSingleEvent(record);
        recurringRecords.push_back(record);
    }
};

class AlarmOperationsFixture : public ::testing::Test
{
  protected:
    auto getMockedAlarmOperations(std::unique_ptr<MockAlarmEventsRepository> &alarmRepo)
    {
        return std::make_unique<alarms::AlarmOperations>(std::move(alarmRepo));
    }
};

constexpr auto defName     = "";
constexpr auto defDuration = 60;
constexpr auto defAllDay   = false;
constexpr auto defRRule    = "";
constexpr auto defMusic    = "";
constexpr auto defEnabled  = true;
constexpr auto defSnooze   = 15;

TEST_F(AlarmOperationsFixture, getNextOneEvent)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-11-11 09:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1,
                                                          defName,
                                                          TimePointFromString("2022-11-11 09:00:00"),
                                                          defDuration,
                                                          defAllDay,
                                                          defRRule,
                                                          defMusic,
                                                          defEnabled,
                                                          defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2020-01-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextTwoEvents)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-11-11 09:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->addSingleEvent(AlarmEventRecord(1,
                                                   defName,
                                                   TimePointFromString("2022-11-11 09:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    alarmRepoMock->addSingleEvent(AlarmEventRecord(2,
                                                   defName,
                                                   TimePointFromString("2022-12-11 02:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2020-01-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextTwoEventsReversedOrder)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-11-11 09:00:00"));
        EXPECT_EQ(records[0].parent->ID, 2);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->addSingleEvent(AlarmEventRecord(1,
                                                   defName,
                                                   TimePointFromString("2022-12-11 02:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    alarmRepoMock->addSingleEvent(AlarmEventRecord(2,
                                                   defName,
                                                   TimePointFromString("2022-11-11 09:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2020-01-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextWithRecursiveFirst)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-01-11 02:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();

    alarmRepoMock->addRecurringEvent(AlarmEventRecord(1,
                                                      defName,
                                                      TimePointFromString("2022-01-11 02:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=DAILY",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));
    alarmRepoMock->addSingleEvent(AlarmEventRecord(2,
                                                   defName,
                                                   TimePointFromString("2022-11-11 09:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2020-01-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextWithRecursiveBeforeRange)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-10-01 02:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();

    alarmRepoMock->addRecurringEvent(AlarmEventRecord(1,
                                                      defName,
                                                      TimePointFromString("2022-01-11 02:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=DAILY",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));

    alarmRepoMock->addSingleEvent(AlarmEventRecord(2,
                                                   defName,
                                                   TimePointFromString("2022-11-11 09:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2022-10-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextWithTwoRecursive)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback1 = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-10-01 09:00:00"));
        EXPECT_EQ(records[0].parent->ID, 2);
    };
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback2 = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 1);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-10-02 02:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->addRecurringEvent(AlarmEventRecord(1,
                                                      defName,
                                                      TimePointFromString("2022-01-11 02:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=DAILY",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));
    alarmRepoMock->addRecurringEvent(AlarmEventRecord(2,
                                                      defName,
                                                      TimePointFromString("2022-01-11 09:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=DAILY",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2022-10-01 03:00:00"), callback1);
    alarmOperations->getNextSingleEvents(TimePointFromString("2022-10-01 17:00:00"), callback2);
}

TEST_F(AlarmOperationsFixture, getNextMultipleEvents)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 2);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-01-01 02:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
        EXPECT_EQ(records[1].startDate, TimePointFromString("2022-01-01 02:00:00"));
        EXPECT_EQ(records[1].parent->ID, 3);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->addSingleEvent(AlarmEventRecord(1,
                                                   defName,
                                                   TimePointFromString("2022-01-01 02:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    alarmRepoMock->addSingleEvent(AlarmEventRecord(2,
                                                   defName,
                                                   TimePointFromString("2022-11-11 09:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));
    alarmRepoMock->addSingleEvent(AlarmEventRecord(3,
                                                   defName,
                                                   TimePointFromString("2022-01-01 02:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2020-01-01 00:00:00"), callback);
}

TEST_F(AlarmOperationsFixture, getNextMultipleEventsWithRecursive)
{
    alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) {
        EXPECT_EQ(records.size(), 2);
        EXPECT_EQ(records[0].startDate, TimePointFromString("2022-01-01 02:00:00"));
        EXPECT_EQ(records[0].parent->ID, 1);
        EXPECT_EQ(records[1].startDate, TimePointFromString("2022-01-01 02:00:00"));
        EXPECT_EQ(records[1].parent->ID, 3);
    };

    auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>();
    alarmRepoMock->addSingleEvent(AlarmEventRecord(1,
                                                   defName,
                                                   TimePointFromString("2022-01-01 02:00:00"),
                                                   defDuration,
                                                   defAllDay,
                                                   defRRule,
                                                   defMusic,
                                                   defEnabled,
                                                   defSnooze));

    alarmRepoMock->addRecurringEvent(AlarmEventRecord(2,
                                                      defName,
                                                      TimePointFromString("2021-01-01 09:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=MONTHLY;BYMONTHDAY=1;INTERVAL=1",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));
    alarmRepoMock->addRecurringEvent(AlarmEventRecord(3,
                                                      defName,
                                                      TimePointFromString("2021-01-01 02:00:00"),
                                                      defDuration,
                                                      defAllDay,
                                                      "FREQ=MONTHLY;BYMONTHDAY=1;INTERVAL=1",
                                                      defMusic,
                                                      defEnabled,
                                                      defSnooze));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    alarmOperations->getNextSingleEvents(TimePointFromString("2022-01-01 00:00:00"), callback);
}

M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +1 -0
@@ 51,6 51,7 @@ target_link_libraries(BellHybrid
        service-bluetooth
        service-desktop
        service-lwip
        service-time
        sys
        platform
        ${LWIP_LIBRARIES}

M products/PurePhone/CMakeLists.txt => products/PurePhone/CMakeLists.txt +1 -0
@@ 67,6 67,7 @@ target_link_libraries(PurePhone
        service-bluetooth
        service-desktop
        service-lwip
        service-time
        sys
        ${LWIP_LIBRARIES}
        "$<$<STREQUAL:${PROJECT_TARGET},TARGET_Linux>:iosyscalls>"