#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* GENERIC MOUNT REFERENCE IMPLEMENTATION */ #include "mcc_generics.h" namespace mcc { enum class MccGenericMountErrorCode : int { ERROR_OK, ERROR_HW_INIT, ERROR_HW_STOP, ERROR_HW_GETSTATE }; } // namespace mcc namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace mcc { template class MccGenericMount : public HardwareT, public TelemetryT, public PZoneContT, public SlewModelT, public TrackModelT, public GuidingModelT, public LoggerT { public: typedef std::error_code error_t; using LoggerT::logDebug; using LoggerT::logError; using LoggerT::logInfo; using LoggerT::logWarn; using typename GuidingModelT::guiding_params_t; using typename SlewModelT::slewing_params_t; using typename TrackModelT::tracking_params_t; MccGenericMount(HardwareT hardware, TelemetryT telemetry, PZoneContT pzone_cont, SlewModelT slew_model, TrackModelT track_model, GuidingModelT guiding_model, LoggerT logger = MccNullLogger{}) : HardwareT(std::move(hardware)), TelemetryT(std::move(telemetry)), PZoneContT(std::move(pzone_cont)), SlewModelT(std::move(slew_model)), TrackModelT(std::move(track_model)), GuidingModelT(std::move(guiding_model)), LoggerT(std::move(logger)) { } virtual ~MccGenericMount() = default; error_t stopMount() { logInfo("stop any movements ..."); this->stopGuidingTarget(); this->stopTracking(); this->stopSlewing(); auto hw_err = this->hardwareStop(); if (hw_err) { return mcc_deduce_error(hw_err, MccGenericMountErrorCode::ERROR_HW_STOP); } // poll hardware till stopped-state detected ... logInfo("mount was stopped"); return MccGenericMountErrorCode::ERROR_OK; } error_t initMount() { auto hw_err = this->hardwareInit(); if (hw_err) { return mcc_deduce_error(hw_err, MccGenericMountErrorCode::ERROR_HW_STOP); } return MccGenericMountErrorCode::ERROR_OK; } }; /* GENERIC FINITE-STATE-MOCHINE MOUNT REFERENCE IMPLEMENTATION */ template class MccGenericMountFSM : public fsm::MccFiniteStateMachine, public MccGenericMount { protected: typedef MccGenericMount base_gmount_t; public: typedef typename base_gmount_t::error_t error_t; /* EVENTS AND STATES DEFINITION */ /* base class for events */ struct MccGenericMountBaseEvent { virtual ~MccGenericMountBaseEvent() = default; MccGenericMountFSM& mount() const { return _mount; } protected: MccGenericMountFSM& _mount; MccGenericMountBaseEvent(MccGenericMountFSM& mount) : _mount(mount) {} }; // to IDLE state struct MccGenericMountEventIDLE : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-IDLE-EVENT"; // CTAD does not work for clang++ (at least till v. 20 and -std=c++23)! // so, one must explicitly define constructor here MccGenericMountEventIDLE(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; // to error state struct MccGenericMountEventError : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-ERROR-EVENT"; MccGenericMountEventError(MccGenericMountFSM& mount, const error_t& err) : MccGenericMountBaseEvent(mount), _error(err) { } error_t eventData() const { return _error; } protected: error_t _error; }; // to INIT state struct MccGenericMountEventInit : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-INIT-EVENT"; MccGenericMountEventInit(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; // to slewing state struct MccGenericMountEventSlew : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-SLEWING-EVENT"; MccGenericMountEventSlew(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; // to tracking state struct MccGenericMountEventTrack : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-TRACKING-EVENT"; MccGenericMountEventTrack(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; // to guiding state struct MccGenericMountEventGuiding : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-GUIDING-EVENT"; MccGenericMountEventGuiding(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; // to stoping state struct MccGenericMountEventStop : MccGenericMountBaseEvent { static constexpr std::string_view ID = "MCC-MOUNT-STOP-EVENT"; MccGenericMountEventStop(MccGenericMountFSM& mount) : MccGenericMountBaseEvent(mount) {} }; /* base class for states */ struct MccGenericMountBaseState { virtual ~MccGenericMountBaseState() = default; protected: MccGenericMountBaseState() = default; template EvT> void exitLog(this auto&& self, EvT& event) { using self_t = std::remove_cvref_t; event.mount().logDebug(std::format("Exit from '{}' state due to '{}' event ...", self_t::ID, EvT::ID)); } template EvT> void enterLog(this auto&& self, EvT& event) { using self_t = std::remove_cvref_t; event.mount().logDebug(std::format("Enter to '{}' state due to '{}' event ...", self_t::ID, EvT::ID)); } }; // forward declarations struct MccGenericMountStateInit; struct MccGenericMountStateIDLE; struct MccGenericMountStateError; struct MccGenericMountStateSlew; struct MccGenericMountStateTrack; struct MccGenericMountStateGuiding; struct MccGenericMountStateStopping; struct MccGenericMountStateUninit : MccGenericMountBaseState { // from uninitialized state only INIT-event is permitted! using transition_t = fsm::fsm_transition_table_t>; template EvT> void exit(EvT& event) { this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); } }; struct MccGenericMountStateInit : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair>; // fsm::fsm_transition_table_t, // std::pair, // std::pair, // std::pair, // std::pair, // std::pair, // std::pair>; template EvT> void exit(EvT& event) { this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); error_t err = event.mount()._initMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } else { event.mount().dispatchEvent(MccGenericMountEventIDLE{event.mount()}); } } }; struct MccGenericMountStateIDLE : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair, std::pair, std::pair>; template EvT> void exit(EvT& event) { this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); } }; struct MccGenericMountStateStopping : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair>; template EvT> void exit(EvT& event) { this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); error_t err = event.mount()._stopMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } else { event.mount().dispatchEvent(MccGenericMountEventIDLE{event.mount()}); } } }; struct MccGenericMountStateSlew : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair, std::pair>; template EvT> void exit(EvT& event) { error_t err = event.mount()._stopSlewingMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); error_t err = event.mount()._slewMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } else { auto slew_pars = event.mount().getSlewingParams(); if (slew_pars.slewAndStop) { event.mount().dispatchEvent(MccGenericMountEventIDLE{event.mount()}); } else { event.mount().dispatchEvent(MccGenericMountEventTrack{event.mount()}); } } } }; struct MccGenericMountStateTrack : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair>; template EvT> void exit(EvT& event) { error_t err = event.mount()._stopTrackingMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); error_t err = event.mount()._trackMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } } }; struct MccGenericMountStateGuiding : MccGenericMountBaseState { using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair>; template EvT> void exit(EvT& event) { error_t err = event.mount()._stopGuidingMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } this->exitLog(event); } template EvT> void enter(EvT& event) { this->enterLog(event); error_t err = event.mount()._startGuidingMount(); if (err) { event.mount().dispatchEvent(MccGenericMountEventError{event.mount(), err}); } } }; /* CONSTRUCTORS AND DESTRUCTOR */ MccGenericMountFSM(HardwareT hardware, TelemetryT telemetry, PZoneContT pzone_cont, SlewModelT slew_model, TrackModelT track_model, GuidingModelT guiding_model, LoggerT logger = MccNullLogger{}) : fsm::MccFiniteStateMachine(MccGenericMountStateUninit{}), base_gmount_t(std::move(hardware), std::move(telemetry), std::move(pzone_cont), std::move(slew_model), std::move(track_model), std::move(guiding_model), std::move(logger)) { } virtual ~MccGenericMountFSM() = default; // reimplementation of base-class methods to adapt it to FSM-behavior auto initMount() { this->dispatchEvent(MccGenericMountEventInit{*this}); } auto stopMount() { this->dispatchEvent(MccGenericMountEventStop{*this}); } auto slewToTarget() { this->dispatchEvent(MccGenericMountEventSlew{*this}); } auto stopSlewing() { this->dispatchEvent(MccGenericMountEventStop{*this}); } auto trackTarget() { this->dispatchEvent(MccGenericMountEventTrack{*this}); } auto stopTracking() { this->dispatchEvent(MccGenericMountEventIDLE{*this}); } auto startGuidingTarget() { this->dispatchEvent(MccGenericMountEventGuiding{*this}); } auto stopGuidingTarget() { this->dispatchEvent(MccGenericMountEventTrack{*this}); } protected: // wrappers auto _initMount() { return base_gmount_t::initMount(); } auto _stopMount() { return base_gmount_t::stopMount(); } auto _slewToTarget() { return base_gmount_t::slewToTarget(); } auto _trackTarget() { return base_gmount_t::trackTarget(); } auto _startGuidingTarget() { return base_gmount_t::startGuidingTarget(); } auto _stopGuidingTarget() { return base_gmount_t::stopGuidingTarget(); } }; } // namespace mcc