// 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 "BusProxy.hpp" #include "Common.hpp" // for ReturnCodes, ServicePriority, BusChannels #include "Mailbox.hpp" // for Mailbox #include "Message.hpp" // for MessagePointer #include "ServiceManifest.hpp" #include "Watchdog.hpp" #include "thread.hpp" // for Thread #include // for SystemWatchdog #include // for find, max #include // for uint32_t, uint64_t #include // for function #include // for end #include // for map #include // for allocator, shared_ptr, enable_shared_from_this #include // for string #include // for type_index #include // for pair #include // for vector<>::iterator, vector #include // for connect by type namespace sys { struct Proxy; class Timer; namespace timer { class SystemTimer; } // namespace timer } // namespace sys namespace sys { using MessageHandler = std::function; class Service : public cpp_freertos::Thread, public std::enable_shared_from_this { public: Service(std::string name, std::string parent = "", uint32_t stackDepth = 4096, ServicePriority priority = ServicePriority::Idle, Watchdog &watchdog = SystemWatchdog::getInstance()); ~Service() override; void StartService(); void CloseService(); // Invoked for not processed already messages // override should in in either callback, function or whatever... [[deprecated("Use connect method instead.")]] virtual MessagePointer DataReceivedHandler( DataMessage *msg, ResponseMessage *resp) = 0; // Invoked during initialization virtual ReturnCodes InitHandler() = 0; /** * @brief Handler to gently release system resources, such as worker * threads. All other resources should be freed in a destructor. * * @return ReturnCodes */ virtual ReturnCodes DeinitHandler() = 0; virtual auto ProcessCloseReason(CloseReason closeReason) -> void; virtual ReturnCodes SwitchPowerModeHandler(const ServicePowerMode mode) = 0; /** * @brief Ends stops service's thread and its timers. */ virtual void CloseHandler() final; std::string parent; BusProxy bus; Mailbox> mailbox; Watchdog &watchdog; uint32_t pingTimestamp; bool isReady; std::vector> staleUniqueMsg; /// connect: register message handler bool connect(const std::type_info &type, MessageHandler handler); bool connect(Message *msg, MessageHandler handler); bool connect(Message &&msg, MessageHandler handler); void sendCloseReadyMessage(Service *service); protected: bool enableRunLoop; void Run() override; std::map message_handlers; private: /// first point of enttry on messages - actually used method in run /// First calls message_handlers /// If not - fallback to DataReceivedHandler auto MessageEntry(Message *message, ResponseMessage *response) -> MessagePointer; auto HandleMessage(Message *message) -> MessagePointer; auto HandleResponse(ResponseMessage *message) -> MessagePointer; /// Execute a message handler functor, if found one. /// \param message Request message /// \return A pair of: /// - True if message handler called, false otherwise. /// - A response message on success, nullptr otherwise. auto ExecuteMessageHandler(Message *message) -> std::pair; friend Proxy; class Timers { friend timer::SystemTimer; private: std::vector list; void attach(timer::SystemTimer *timer); void detach(timer::SystemTimer *timer); public: void stop(); [[nodiscard]] auto get(timer::SystemTimer *timer) noexcept -> timer::SystemTimer *; } timers; public: auto getTimers() -> auto & { return timers; } auto TimerHandle(SystemMessage &message) -> ReturnCodes; }; /// proxy has one objective - be friend for Service, so that Message which is not a friend could access /// one and only one entrypoint to messages entrypoint (MessageEntry) /// MessageEntry calls overridable DataReceivedHandler for Service instance and all Calls that are 100% neccessary /// for service struct Proxy { 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