~aleteoryx/muditaos

3408fafa8f590114bb8e042283f5114c9750f608 — Przemyslaw Brudny 4 years ago 99e2118
[EGD-6066] Removed Message default constructor

Forced each message to have declared type as parts of Bus logic
depends on it and previously we encountered undefined
behaviours. Added tests and messages validators.
M enabled_unittests => enabled_unittests +9 -0
@@ 133,6 133,15 @@ TESTS_LIST["catch2-db-initializer"]="
    Database initialization scripts;
"
#---------
TESTS_LIST["catch2-system_messages-tests"]="
    Test basic messages constructors;
    Test message MessageUID provider class;
    Test message transmission required fields validators - response;
    Test message transmission required fields validators - unicast;
    Test message transmission required fields validators - broadcast;
    Test message transmission required fields validators - multicast;
"
#---------
TESTS_LIST["catch2-dependency-graph-tests"]="
    Given Dependency Graph When topological sort empty graph then verify if result is empty;
    Given Dependency Graph When topological sort without dependencies then verify order;

M module-audio/Audio/AudioCommon.hpp => module-audio/Audio/AudioCommon.hpp +4 -4
@@ 273,7 273,7 @@ namespace audio

namespace AudioServiceMessage
{
    class EndOfFile : public sys::Message
    class EndOfFile : public sys::DataMessage
    {
      public:
        explicit EndOfFile(audio::Token &token) : token(token)


@@ 287,7 287,7 @@ namespace AudioServiceMessage
        audio::Token token = audio::Token::MakeBadToken();
    };

    class FileSystemNoSpace : public sys::Message
    class FileSystemNoSpace : public sys::DataMessage
    {
      public:
        explicit FileSystemNoSpace(audio::Token &token) : token(token)


@@ 301,7 301,7 @@ namespace AudioServiceMessage
        audio::Token token = audio::Token::MakeBadToken();
    };

    class DbRequest : public sys::Message
    class DbRequest : public sys::DataMessage
    {
      public:
        explicit DbRequest(const audio::Setting &setting,


@@ 315,7 315,7 @@ namespace AudioServiceMessage
        const audio::PlaybackType playback;
    };

    class AudioDeviceCreated : public sys::Message
    class AudioDeviceCreated : public sys::DataMessage
    {
      public:
        explicit AudioDeviceCreated(std::shared_ptr<audio::AudioDevice> device, audio::AudioDevice::Type type)

M module-services/service-appmgr/service-appmgr/messages/DateAndTimeChangeRequest.hpp => module-services/service-appmgr/service-appmgr/messages/DateAndTimeChangeRequest.hpp +1 -1
@@ 8,7 8,7 @@

namespace app::manager
{
    class DateAndTimeChangeRequest : public sys::Message
    class DateAndTimeChangeRequest : public sys::DataMessage
    {};

    class AutomaticDateAndTimeIsOnChangeRequest : public DateAndTimeChangeRequest

M module-services/service-appmgr/service-appmgr/messages/GetCurrentDisplayLanguageRequest.hpp => module-services/service-appmgr/service-appmgr/messages/GetCurrentDisplayLanguageRequest.hpp +1 -1
@@ 7,6 7,6 @@

namespace app::manager
{
    class GetCurrentDisplayLanguageRequest : public sys::Message
    class GetCurrentDisplayLanguageRequest : public sys::DataMessage
    {};
} // namespace app::manager

M module-services/service-appmgr/service-appmgr/messages/UserPowerDownRequest.hpp => module-services/service-appmgr/service-appmgr/messages/UserPowerDownRequest.hpp +1 -2
@@ 7,7 7,6 @@

namespace app
{
    class UserPowerDownRequest : public sys::Message
    class UserPowerDownRequest : public sys::DataMessage
    {};

} // namespace app

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +0 -1
@@ 108,7 108,6 @@ void ServiceBluetooth::ProcessCloseReason(sys::CloseReason closeReason)
sys::MessagePointer ServiceBluetooth::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msg,
                                                          [[maybe_unused]] sys::ResponseMessage *resp)
{
    LOG_ERROR("Unhandled message: %s", typeid(msg).name());
    return std::make_shared<sys::ResponseMessage>();
}


M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +5 -14
@@ 118,12 118,8 @@ class CellularGetCurrentOperatorMessage : public CellularMessage
    {}
};

class CellularSetOperatorAutoSelectMessage : public sys::Message
{
  public:
    CellularSetOperatorAutoSelectMessage()
    {}
};
class CellularSetOperatorAutoSelectMessage : public sys::DataMessage
{};

class CellularGetCurrentOperatorResponse : public CellularMessage
{


@@ 139,7 135,7 @@ class CellularGetCurrentOperatorResponse : public CellularMessage
        return currentOperatorName;
    }
};
class CellularSetOperatorMessage : public sys::Message
class CellularSetOperatorMessage : public sys::DataMessage
{
    at::response::cops::CopsMode mode;
    at::response::cops::NameFormat format;


@@ 696,7 692,6 @@ class CellularMMIResultMessage : public CellularMMIResult, public app::manager::
        : CellularMMIResult(result, std::move(customResult))
    {}


    [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>
    {
        return std::make_unique<app::manager::ActionRequest>(


@@ 774,12 769,8 @@ class CellularChangeVoLTEDataMessage : public CellularVoLTEDataMessage
    {}
};

class CellularCheckIfStartAllowedMessage : public sys::Message
{
  public:
    CellularCheckIfStartAllowedMessage() : sys::Message()
    {}
};
class CellularCheckIfStartAllowedMessage : public sys::DataMessage
{};

class CellularNoSimNotification : public CellularResponseMessage, public app::manager::actions::ConvertibleToAction
{

M module-services/service-db/test/test-settings/test-service-db-settings-testapps.hpp => module-services/service-db/test/test-settings/test-service-db-settings-testapps.hpp +2 -2
@@ 1,9 1,9 @@
// 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

namespace app
{
    class UserPowerDownRequest : public sys::Message
    class UserPowerDownRequest : public sys::DataMessage
    {};
} // namespace app
namespace settings

M module-services/service-evtmgr/CMakeLists.txt => module-services/service-evtmgr/CMakeLists.txt +0 -1
@@ 5,7 5,6 @@ set(SOURCES
        EventManager.cpp
        WorkerEvent.cpp
        api/EventManagerServiceAPI.cpp
        messages/Message.cpp
        battery-level-check/BatteryLevelCheck.cpp
        screen-light-control/ControlFunctions.cpp
        screen-light-control/ScreenLightControl.cpp

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

#include <service-evtmgr/Message.hpp>

#include <MessageType.hpp>
#include <Service/Message.hpp>

namespace sevm
{
    Message::Message(MessageType messageType) : DataMessage(messageType)
    {}

    Message::Message() = default;
} // namespace sevm

M module-services/service-evtmgr/service-evtmgr/BatteryMessages.hpp => module-services/service-evtmgr/service-evtmgr/BatteryMessages.hpp +5 -5
@@ 3,16 3,16 @@

#pragma once

#include "Message.hpp"
#include "module-sys/Service/Message.hpp"

#include <module-bsp/bsp/torch/torch.hpp>

namespace sevm
{
    class BatteryStatusChangeMessage : public Message
    class BatteryStatusChangeMessage : public sys::DataMessage
    {};

    class BatterySetCriticalLevel : public Message
    class BatterySetCriticalLevel : public sys::DataMessage
    {
      public:
        BatterySetCriticalLevel(std::uint8_t level) : criticalLevel(level)


@@ 20,10 20,10 @@ namespace sevm
        const unsigned int criticalLevel = 0;
    };

    class BatteryStateChangeMessage : public Message
    class BatteryStateChangeMessage : public sys::DataMessage
    {};

    class BatteryBrownoutMessage : public Message
    class BatteryBrownoutMessage : public sys::DataMessage
    {};

} // namespace sevm

M module-services/service-evtmgr/service-evtmgr/EVMessages.hpp => module-services/service-evtmgr/service-evtmgr/EVMessages.hpp +19 -26
@@ 23,26 23,24 @@ namespace sevm
{
    namespace message
    {
        class GPIO : public Message
        class GPIO : public sys::DataMessage
        {
          public:
            GPIO() : Message(MessageType::EVM_GPIO)
            GPIO() : DataMessage(MessageType::EVM_GPIO)
            {}
            uint32_t num = 0, port = 0, state = 0;
        };
    } // namespace message

    class RtcMinuteAlarmMessage : public Message
    class RtcMinuteAlarmMessage : public sys::DataMessage
    {
      public:
        RtcMinuteAlarmMessage(MessageType messageType) : Message(messageType)
        {
            type = Type::Data;
        }
        RtcMinuteAlarmMessage(MessageType messageType) : DataMessage(messageType)
        {}
        uint32_t timestamp = 0;
    };

    class RtcUpdateTimeMessage : public sys::Message
    class RtcUpdateTimeMessage : public sys::DataMessage
    {
      public:
        explicit RtcUpdateTimeMessage(time_t time) : time(time)


@@ 60,9 58,7 @@ namespace sevm
    {
      public:
        SIMMessage() : DataMessage(MessageType::SIMTrayEvent)
        {
            type = Type::Data;
        }
        {}
    };

    /*


@@ 112,23 108,21 @@ namespace sevm
        bsp::Board board = bsp::Board::none;
    };

    class StatusStateMessage : public Message
    class StatusStateMessage : public sys::DataMessage
    {
      public:
        StatusStateMessage(MessageType messageType) : Message(messageType)
        {
            type = Type::Data;
        }
        explicit StatusStateMessage(MessageType messageType) : DataMessage(messageType)
        {}
        bsp::cellular::status::value state = bsp::cellular::status::value::INACTIVE;
    };

    class ToggleTorchOnOffMessage : public Message
    class ToggleTorchOnOffMessage : public sys::DataMessage
    {};

    class ToggleTorchColorMessage : public Message
    class ToggleTorchColorMessage : public sys::DataMessage
    {};

    class KeypadBacklightMessage : public Message
    class KeypadBacklightMessage : public sys::DataMessage
    {
      public:
        explicit KeypadBacklightMessage(bsp::keypad_backlight::Action action) : action(action)


@@ 137,20 131,19 @@ namespace sevm
        bsp::keypad_backlight::Action action;
    };

    class KeypadBacklightResponseMessage : public Message
    class KeypadBacklightResponseMessage : public sys::DataMessage
    {
      public:
        KeypadBacklightResponseMessage()
        {}
        bool success;
    };

    class VibraMessage : public Message
    class VibraMessage : public sys::DataMessage
    {
      public:
        VibraMessage(bsp::vibrator::Action act,
                     std::chrono::milliseconds rptTime = std::chrono::milliseconds{bsp::vibrator::defaultVibraPauseMs})
            : Message(MessageType::VibraPulseMessage), action(act), repetitionTime(rptTime)
        explicit VibraMessage(
            bsp::vibrator::Action act,
            std::chrono::milliseconds rptTime = std::chrono::milliseconds{bsp::vibrator::defaultVibraPauseMs})
            : DataMessage(MessageType::VibraPulseMessage), action(act), repetitionTime(rptTime)
        {}

        bsp::vibrator::Action action;

M module-services/service-evtmgr/service-evtmgr/KbdMessage.hpp => module-services/service-evtmgr/service-evtmgr/KbdMessage.hpp +5 -7
@@ 1,21 1,19 @@
// 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

#pragma once

#include "Message.hpp"
#include "module-sys/Service/Message.hpp"

#include <common_data/RawKey.hpp>

namespace sevm
{
    class KbdMessage : public Message
    class KbdMessage : public sys::DataMessage
    {
      public:
        KbdMessage() : Message(MessageType::KBDKeyEvent)
        {
            type = Type::Data;
        }
        KbdMessage() : DataMessage(MessageType::KBDKeyEvent)
        {}
        RawKey key = {};
    };
} // namespace sevm

D module-services/service-evtmgr/service-evtmgr/Message.hpp => module-services/service-evtmgr/service-evtmgr/Message.hpp +0 -16
@@ 1,16 0,0 @@
// 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 <MessageType.hpp>
#include <Service/Message.hpp>

namespace sevm
{
    struct Message : public sys::DataMessage
    {
        Message(MessageType messageType);
        Message();
    };
}; // namespace sevm

M module-sys/CMakeLists.txt => module-sys/CMakeLists.txt +1 -0
@@ 78,4 78,5 @@ target_include_directories(${PROJECT_NAME}

if (${ENABLE_TESTS})
    add_subdirectory(SystemManager/tests)
    add_subdirectory(Service/tests)
endif()

M module-sys/Service/Common.hpp => module-sys/Service/Common.hpp +3 -0
@@ 11,6 11,7 @@ namespace sys

    enum class BusChannel
    {
        Unknown,
        System,
        SystemManagerRequests,
        PowerManagerRequests,


@@ 85,6 86,8 @@ inline const char *c_str(sys::ServicePowerMode code)
inline const char *c_str(sys::BusChannel channel)
{
    switch (channel) {
    case sys::BusChannel::Unknown:
        return "Unknown";
    case sys::BusChannel::System:
        return "System";
    case sys::BusChannel::SystemManagerRequests:

M module-sys/Service/Message.cpp => module-sys/Service/Message.cpp +59 -24
@@ 11,7 11,23 @@ namespace sys
        return std::make_pair(retCode, msg);
    }

    Message::Message(BusChannel channel) : channel{channel}
    MessageUIDType MessageUID::get() const noexcept
    {
        return value;
    }

    MessageUIDType MessageUID::getNext() noexcept
    {
        if (value == invalidMessageUid) {
            value = 0;
        }
        return value++;
    }

    Message::Message(Type type) : type(type)
    {}

    Message::Message(Type type, BusChannel channel) : type(type), channel{channel}
    {}

    MessagePointer Message::Execute(Service *service)


@@ 19,54 35,73 @@ namespace sys
        return Proxy::handleMessage(service, this);
    }

    SystemMessage::SystemMessage(SystemMessageType systemMessageType, ServicePowerMode pwrMode)
        : Message(BusChannel::System), systemMessageType(systemMessageType), powerMode(pwrMode)
    bool Message::ValidateMessage() const noexcept
    {
        type = Type::System;
        return !(id == invalidMessageUid || type == Message::Type::Unspecified || sender == "Unknown");
    }

    MessagePointer SystemMessage::Execute(Service *service)
    void Message::ValidateUnicastMessage() const
    {
        return Proxy::handleSystemMessage(service, this);
        if (!ValidateMessage() || uniID == invalidMessageUid || transType != Message::TransmissionType::Unicast) {
            throw std::runtime_error("Message unicast lack essential fields");
        }
    }

    ServiceCloseReasonMessage::ServiceCloseReasonMessage(CloseReason closeReason) : closeReason(closeReason)
    {}

    MessagePointer ServiceCloseReasonMessage::Execute(Service *service)
    void Message::ValidateResponseMessage() const
    {
        Proxy::handleCloseReasonMessage(service, this);
        return MessageNone{};
        if (!ValidateMessage()) {
            throw std::runtime_error("Message response lack essential fields");
        }
    }

    CloseReason ServiceCloseReasonMessage::getCloseReason() const noexcept
    void Message::ValidateBroadcastMessage() const
    {
        return closeReason;
        if (!ValidateMessage() || transType != Message::TransmissionType::Broadcast) {
            throw std::runtime_error("Message broadcast lack essential fields");
        }
    }

    DataMessage::DataMessage(MessageType messageType) : messageType{messageType}
    void Message::ValidateMulticastMessage() const
    {
        type = Type::Data;
        if (!ValidateMessage() || channel == BusChannel::Unknown || transType != Message::TransmissionType::Multicast) {
            throw std::runtime_error("Message multicast lack essential fields");
        }
    }

    DataMessage::DataMessage(BusChannel channel) : Message(channel)
    SystemMessage::SystemMessage(SystemMessageType systemMessageType, ServicePowerMode pwrMode)
        : Message(Type::System, BusChannel::System), systemMessageType(systemMessageType), powerMode(pwrMode)
    {}

    MessagePointer SystemMessage::Execute(Service *service)
    {
        type = Type::Data;
        return Proxy::handleSystemMessage(service, this);
    }

    DataMessage::DataMessage() : Message()
    ServiceCloseReasonMessage::ServiceCloseReasonMessage(CloseReason closeReason)
        : SystemMessage(SystemMessageType::ServiceCloseReason), closeReason(closeReason)
    {}

    CloseReason ServiceCloseReasonMessage::getCloseReason() const noexcept
    {
        type = Type::Data;
        return closeReason;
    }

    DataMessage::DataMessage(MessageType messageType) : Message(Type::Data), messageType{messageType}
    {}

    DataMessage::DataMessage(BusChannel channel) : Message(Type::Data, channel)
    {}

    DataMessage::DataMessage() : Message(Type::Data)
    {}

    ResponseMessage::ResponseMessage(ReturnCodes retCode, MessageType responseTo)
        : retCode(retCode), responseTo(responseTo)
    {
        type = Type::Response;
    }
        : Message(Type::Response), retCode(retCode), responseTo(responseTo)
    {}

    MessagePointer ResponseMessage::Execute(Service *service)
    {
        return Proxy::handleMessage(service, nullptr, this);
    }

} // namespace sys

M module-sys/Service/Message.hpp => module-sys/Service/Message.hpp +72 -17
@@ 3,6 3,7 @@

#pragma once

#include <module-utils/magic_enum/include/magic_enum.hpp>
#include "Common.hpp"
#include "MessageType.hpp"
#include "MessageForward.hpp"


@@ 15,39 16,94 @@ namespace sys
{
    SendResult CreateSendResult(ReturnCodes retCode, MessagePointer msg);

    inline constexpr std::uint64_t invalidMessageUid = std::numeric_limits<uint64_t>().max();

    using MessageUIDType = std::uint64_t;

    class MessageUID
    {
      protected:
        MessageUIDType value = 0;

      public:
        [[nodiscard]] MessageUIDType get() const noexcept;
        [[nodiscard]] MessageUIDType getNext() noexcept;
    };

    class Message
    {
      public:
        enum class TransmissionType
        {
            Unspecified,
            Unicast,
            Multicast,
            Broadcast
        };

        enum class Type
        {
            Unspecified,
            System,
            Data,
            Response
        };

        Message() = default;
        explicit Message(BusChannel channel);
        explicit Message(Type type);
        Message(Type type, BusChannel channel);
        virtual ~Message() noexcept = default;

        virtual MessagePointer Execute(Service *service);

        virtual operator std::string() const
        virtual explicit operator std::string() const
        {
            return {"{}"};
        }

        std::uint64_t id;
        std::uint64_t uniID;
        Type type;
        TransmissionType transType;
        BusChannel channel;
        std::string sender;
        MessageUIDType id          = invalidMessageUid;
        MessageUIDType uniID       = invalidMessageUid;
        Type type                  = Type::Unspecified;
        TransmissionType transType = TransmissionType::Unspecified;
        BusChannel channel         = BusChannel::Unknown;
        std::string sender         = "Unknown";

        [[nodiscard]] std::string to_string() const
        {
            return "| ID:" + std::to_string(id) + " | uniID: " + std::to_string(uniID) +
                   " | Type: " + std::string(magic_enum::enum_name(type)) +
                   " | TransmissionType: " + std::string(magic_enum::enum_name(transType)) +
                   " | Channel: " + std::string(magic_enum::enum_name(channel)) + " | Sender: " + sender + " |";
        }

        /**
         * Validate base message have all essential fields set.
         * @return Return validation result.
         */
        [[nodiscard]] bool ValidateMessage() const noexcept;

        /**
         * Validate if response message have all essential fields set.
         * @return Return validation result.
         */
        void ValidateResponseMessage() const;

        /**
         * Validate if message sent via Unicast have all essential fields set.
         * @return Return validation result.
         */
        void ValidateUnicastMessage() const;

        /**
         * Validate if message sent via Broadcast have all essential fields set.
         * @return Return validation result.
         */
        void ValidateBroadcastMessage() const;

        /**
         * Validate if message sent via Multicast have all essential fields set.
         * @return Return validation result.
         */
        void ValidateMulticastMessage() const;
    };

    enum class SystemMessageType


@@ 56,7 112,8 @@ namespace sys
        SwitchPowerMode,
        Start,
        Timer,
        Exit
        Exit,
        ServiceCloseReason
    };

    class SystemMessage : public Message


@@ 71,22 128,17 @@ namespace sys
        ServicePowerMode powerMode;
    };

    class ServiceCloseReasonMessage : public Message
    class ServiceCloseReasonMessage : public SystemMessage
    {
      public:
        explicit ServiceCloseReasonMessage(CloseReason closeReason);

        MessagePointer Execute(Service *service) final;

        CloseReason getCloseReason() const noexcept;
        [[nodiscard]] CloseReason getCloseReason() const noexcept;

      private:
        const CloseReason closeReason;
    };

    class ReadyToCloseMessage : public Message
    {};

    class DataMessage : public Message
    {
      public:


@@ 98,6 150,9 @@ namespace sys
        MessageType messageType = MessageType::MessageTypeUninitialized;
    };

    class ReadyToCloseMessage : public DataMessage
    {};

    class ResponseMessage : public Message
    {
      public:

M module-sys/Service/Service.cpp => module-sys/Service/Service.cpp +3 -5
@@ 278,13 278,11 @@ namespace sys
                service->isReady = true;
            }
            break;
        case SystemMessageType::ServiceCloseReason:
            service->ProcessCloseReason(static_cast<ServiceCloseReasonMessage *>(message)->getCloseReason());
            break;
        }
        return std::make_shared<ResponseMessage>(ret);
    }

    auto Proxy::handleCloseReasonMessage(Service *service, ServiceCloseReasonMessage *message) -> void
    {
        service->ProcessCloseReason(message->getCloseReason());
    }

} // namespace sys

M module-sys/Service/Service.hpp => module-sys/Service/Service.hpp +0 -1
@@ 153,6 153,5 @@ namespace sys
        static auto handleMessage(Service *service, Message *message, ResponseMessage *response = nullptr)
            -> MessagePointer;
        static auto handleSystemMessage(Service *service, SystemMessage *message) -> MessagePointer;
        static auto handleCloseReasonMessage(Service *service, ServiceCloseReasonMessage *message) -> void;
    };
} // namespace sys

M module-sys/Service/details/bus/Bus.cpp => module-sys/Service/details/bus/Bus.cpp +41 -17
@@ 1,9 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Bus.hpp"

#include "module-sys/Service/Service.hpp"


@@ 20,8 17,8 @@ namespace sys
{
    namespace
    {
        std::uint64_t uniqueMsgId  = 0;
        std::uint64_t unicastMsgId = 0;
        MessageUID uniqueMsgId;
        MessageUID unicastMsgId;

        std::map<BusChannel, std::set<Service *>> channels;
        std::map<std::string, Service *> servicesRegistered;


@@ 54,13 51,27 @@ namespace sys
        assert(request != nullptr);
        assert(sender != nullptr);

        {
            cpp_freertos::CriticalSectionGuard guard;
            response->id    = uniqueMsgId++;
            response->uniID = request->uniID;
        }
        response->sender    = sender->GetName();
        response->transType = Message::TransmissionType::Unicast;

        if (request->transType == Message::TransmissionType::Unicast) {
            {
                cpp_freertos::CriticalSectionGuard guard;
                response->id    = uniqueMsgId.getNext();
                response->uniID = request->uniID;
            }

            response->ValidateUnicastMessage();
        }
        else {
            {
                cpp_freertos::CriticalSectionGuard guard;
                response->id = uniqueMsgId.getNext();
            }

            response->ValidateResponseMessage();
        }

        if (auto it = servicesRegistered.find(request->sender); it != servicesRegistered.end()) {
            const auto targetService = it->second;
            targetService->mailbox.push(response);


@@ 71,12 82,15 @@ namespace sys
    {
        {
            cpp_freertos::CriticalSectionGuard guard;
            message->id    = uniqueMsgId++;
            message->uniID = unicastMsgId++;
            message->id    = uniqueMsgId.getNext();
            message->uniID = unicastMsgId.getNext();
        }

        message->sender    = sender->GetName();
        message->transType = Message::TransmissionType::Unicast;

        message->ValidateUnicastMessage();

        if (auto it = servicesRegistered.find(targetName); it != servicesRegistered.end()) {
            const auto targetService = it->second;
            targetService->mailbox.push(message);


@@ 95,15 109,19 @@ namespace sys
        std::vector<std::shared_ptr<Message>> tempMsg;
        tempMsg.reserve(4); // reserve space for 4 elements to avoid costly memory allocations

        uint64_t unicastID = unicastMsgId;
        MessageUIDType unicastID = unicastMsgId.get();

        {
            cpp_freertos::CriticalSectionGuard guard;
            message->id    = uniqueMsgId++;
            message->uniID = unicastMsgId++;
            message->id    = uniqueMsgId.getNext();
            message->uniID = unicastMsgId.getNext();
        }

        message->sender    = sender->GetName();
        message->transType = Message::TransmissionType ::Unicast;

        message->ValidateUnicastMessage();

        auto ele = servicesRegistered.find(targetName);
        if (ele != servicesRegistered.end()) {
            const auto targetService = servicesRegistered[targetName];


@@ 183,12 201,15 @@ namespace sys
    {
        {
            cpp_freertos::CriticalSectionGuard guard;
            message->id = uniqueMsgId++;
            message->id = uniqueMsgId.getNext();
        }

        message->channel   = channel;
        message->transType = Message::TransmissionType::Multicast;
        message->sender    = sender->GetName();

        message->ValidateMulticastMessage();

        for (const auto &target : channels[channel]) {
            target->mailbox.push(message);
        }


@@ 198,11 219,14 @@ namespace sys
    {
        {
            cpp_freertos::CriticalSectionGuard guard;
            message->id = uniqueMsgId++;
            message->id = uniqueMsgId.getNext();
        }

        message->transType = Message::TransmissionType ::Broadcast;
        message->sender    = sender->GetName();

        message->ValidateBroadcastMessage();

        for (const auto &target : servicesRegistered) {
            const auto targetService = target.second;
            targetService->mailbox.push(message);

A module-sys/Service/tests/CMakeLists.txt => module-sys/Service/tests/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
add_catch2_executable(
    NAME
        system_messages-tests
    SRCS
        tests-main.cpp
        test-system_messages.cpp
    LIBS
        module-sys
)
\ No newline at end of file

A module-sys/Service/tests/test-system_messages.cpp => module-sys/Service/tests/test-system_messages.cpp +110 -0
@@ 0,0 1,110 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include "Service/Message.hpp"

class MockedMessageUID : public sys::MessageUID
{
  public:
    void set(sys::MessageUIDType _value)
    {
        value = _value;
    }
};

TEST_CASE("Test basic messages constructors")
{
    auto dataMsg     = sys::DataMessage();
    auto systemMsg   = sys::SystemMessage(sys::SystemMessageType::Ping);
    auto responseMsg = sys::ResponseMessage();

    REQUIRE(dataMsg.type == sys::Message::Type::Data);
    REQUIRE(
        (systemMsg.type == sys::Message::Type::System && systemMsg.systemMessageType == sys::SystemMessageType::Ping));
    REQUIRE(responseMsg.type == sys::Message::Type::Response);
}

TEST_CASE("Test message MessageUID provider class")
{
    MockedMessageUID uidProvider;

    auto uidReceiver = uidProvider.get();
    REQUIRE(uidReceiver == 0);

    uidReceiver = uidProvider.getNext();
    REQUIRE(uidReceiver == 0);

    uidReceiver = uidProvider.getNext();
    REQUIRE(uidReceiver == 1);

    uidProvider.set(sys::invalidMessageUid);
    REQUIRE(uidProvider.get() == sys::invalidMessageUid);

    uidReceiver = uidProvider.getNext();
    REQUIRE(uidReceiver == 0);

    uidReceiver = uidProvider.getNext();
    REQUIRE(uidReceiver == 1);
}

TEST_CASE("Test message transmission required fields validators - response")
{
    MockedMessageUID uidProvider;

    auto dataMsg = sys::DataMessage();

    REQUIRE_THROWS_AS((dataMsg.ValidateResponseMessage()), std::runtime_error);

    dataMsg.id     = uidProvider.getNext();
    dataMsg.sender = "TestSender";

    REQUIRE_NOTHROW(dataMsg.ValidateResponseMessage());
}

TEST_CASE("Test message transmission required fields validators - unicast")
{
    MockedMessageUID uidProvider;

    auto dataMsg = sys::DataMessage();

    REQUIRE_THROWS_AS((dataMsg.ValidateUnicastMessage()), std::runtime_error);

    dataMsg.id        = uidProvider.getNext();
    dataMsg.uniID     = 0;
    dataMsg.sender    = "TestSender";
    dataMsg.transType = sys::Message::TransmissionType::Unicast;

    REQUIRE_NOTHROW(dataMsg.ValidateUnicastMessage());
}

TEST_CASE("Test message transmission required fields validators - broadcast")
{
    MockedMessageUID uidProvider;

    auto dataMsg = sys::DataMessage();

    REQUIRE_THROWS_AS((dataMsg.ValidateBroadcastMessage()), std::runtime_error);

    dataMsg.id        = uidProvider.getNext();
    dataMsg.sender    = "TestSender";
    dataMsg.transType = sys::Message::TransmissionType::Broadcast;

    REQUIRE_NOTHROW(dataMsg.ValidateBroadcastMessage());
}

TEST_CASE("Test message transmission required fields validators - multicast")
{
    MockedMessageUID uidProvider;

    auto dataMsg = sys::DataMessage();

    REQUIRE_THROWS_AS((dataMsg.ValidateMulticastMessage()), std::runtime_error);

    dataMsg.id        = uidProvider.getNext();
    dataMsg.sender    = "TestSender";
    dataMsg.transType = sys::Message::TransmissionType::Multicast;
    dataMsg.channel   = sys::BusChannel::System;

    REQUIRE_NOTHROW(dataMsg.ValidateMulticastMessage());
}

A module-sys/Service/tests/tests-main.cpp => module-sys/Service/tests/tests-main.cpp +5 -0
@@ 0,0 1,5 @@
// 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 // This tells Catch to provide a main() - only do this in one cpp file
#include <catch2/catch.hpp>

M module-sys/SystemManager/messages/SystemManagerMessage.hpp => module-sys/SystemManager/messages/SystemManagerMessage.hpp +3 -3
@@ 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

#pragma once


@@ 19,11 19,11 @@ namespace sys
        SystemManagerMessage() : sys::DataMessage(MessageType::PMChangePowerMode){};
    };

    class CriticalBatteryLevelNotification : public sys::Message, public app::manager::actions::ConvertibleToAction
    class CriticalBatteryLevelNotification : public sys::DataMessage, public app::manager::actions::ConvertibleToAction
    {
      public:
        explicit CriticalBatteryLevelNotification(bool isActive, bool isCharging = false)
            : sys::Message(), isActive(isActive), isCharging(isCharging)
            : isActive(isActive), isCharging(isCharging)
        {}

        [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>