#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 }; enum class MccGenericFsmMountErrorCode : int { ERROR_OK, ERROR_INVALID_OPERATION, ERROR_UNKNOWN_EVENT }; } // namespace mcc namespace std { template <> class is_error_code_enum : public true_type { }; 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, 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)), LoggerT(std::move(logger)) { } MccGenericMount(MccGenericMount&&) = default; MccGenericMount(const MccGenericMount&) = delete; MccGenericMount& operator=(MccGenericMount&&) = default; MccGenericMount& operator=(const MccGenericMount&) = delete; virtual ~MccGenericMount() = default; error_t stopMount() { logInfo("Stop any movements ..."); this->stopTracking(); this->stopSlewing(); auto hw_err = this->hardwareStop(); if (hw_err) { return mcc_deduce_error(hw_err, MccGenericMountErrorCode::ERROR_HW_STOP); } logInfo("Stop command was sent"); return MccGenericMountErrorCode::ERROR_OK; } error_t initMount() { logInfo("Start mount initialization ..."); auto hw_err = this->hardwareInit(); if (hw_err) { return mcc_deduce_error(hw_err, MccGenericMountErrorCode::ERROR_HW_STOP); } logInfo("Mount initialization was performed"); return MccGenericMountErrorCode::ERROR_OK; } }; /* GENERIC FINITE-STATE-MACHINE MOUNT REFERENCE IMPLEMENTATION */ template class MccGenericFsmMount : public MOUNT_T, protected fsm::MccFiniteStateMachine { public: typedef std::error_code error_t; using fsm::MccFiniteStateMachine::currentStateID; using typename MOUNT_T::slewing_params_t; using typename MOUNT_T::tracking_params_t; protected: /* default events implementation */ struct MccGenericFsmMountBaseEvent { virtual ~MccGenericFsmMountBaseEvent() = default; MccGenericFsmMount* mount() const { return _mount; } protected: MccGenericFsmMount* _mount; MccGenericFsmMountBaseEvent(MccGenericFsmMount* mount) : _mount(mount) {} }; struct MccGenericFsmMountInitEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-INIT-EVENT"}; MccGenericFsmMountInitEvent(MccGenericFsmMount* mount) : MccGenericFsmMountBaseEvent(mount) {} }; struct MccGenericFsmMountIdleEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-IDLE-EVENT"}; MccGenericFsmMountIdleEvent(MccGenericFsmMount* mount) : MccGenericFsmMountBaseEvent(mount) {} }; struct MccGenericFsmMountStopEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-STOP-EVENT"}; MccGenericFsmMountStopEvent(MccGenericFsmMount* mount) : MccGenericFsmMountBaseEvent(mount) {} }; struct MccGenericFsmMountErrorEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-ERROR-EVENT"}; MccGenericFsmMountErrorEvent(MccGenericFsmMount* mount, const MccGenericFsmMount::error_t& err) : MccGenericFsmMountBaseEvent(mount), _err(err) { } MccGenericFsmMount::error_t eventData() const noexcept { return _err; } protected: MccGenericFsmMount::error_t _err; }; struct MccGenericFsmMountSlewEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-SLEW-EVENT"}; MccGenericFsmMountSlewEvent(MccGenericFsmMount* mount) : MccGenericFsmMountBaseEvent(mount) {} }; struct MccGenericFsmMountTrackEvent : MccGenericFsmMountBaseEvent { static constexpr std::string_view ID{"GENERIC-MOUNT-TRACK-EVENT"}; MccGenericFsmMountTrackEvent(MccGenericFsmMount* mount) : MccGenericFsmMountBaseEvent(mount) {} }; /* default states implementation */ struct MccGenericFsmMountBaseState { virtual ~MccGenericFsmMountBaseState() = default; protected: MccGenericFsmMountBaseState() = default; template void exitLog(this auto&& self, EvT& event) { using self_t = std::remove_cvref_t; if constexpr (mcc_generic_log_mount_c && std::derived_from) { event.mount()->logDebug(std::format("Exit from '{}' state due to '{}' event ...", self_t::ID, EvT::ID)); } } template void enterLog(this auto&& self, EvT& event) { using self_t = std::remove_cvref_t; if constexpr (mcc_generic_log_mount_c && std::derived_from) { event.mount()->logDebug(std::format("Enter to '{}' state due to '{}' event ...", self_t::ID, EvT::ID)); } } }; struct MccGenericFsmMountErrorState; // default error-state class implementation (forward declaration) template struct MccGenericFsmMountInitState; template struct MccGenericFsmMountStopState; template struct MccGenericFsmMountSlewState; template struct MccGenericFsmMountTrackState; template struct MccGenericFsmMountStartState : MccGenericFsmMountBaseState // initial state after mount-class creation (uninitialized state) { static constexpr std::string_view ID{"GENERIC-MOUNT-START-STATE"}; // only initialization is allowed here using transition_t = fsm::fsm_transition_table_t< std::pair>>; }; template struct MccGenericFsmMountIdleState : MccGenericFsmMountBaseState // IDLE state: mount is stopped, wait for client commands { static constexpr std::string_view ID{"GENERIC-MOUNT-IDLDE-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair>, std::pair, std::pair>, std::pair>, std::pair>, std::pair>>; void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); } }; template struct MccGenericFsmMountInitState : MccGenericFsmMountBaseState { static constexpr std::string_view ID{"GENERIC-MOUNT-INIT-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair>, std::pair, std::pair>; void exit(MccGenericFsmMountInitEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn("It seems a re-entering to the initializing state was asked! Ignore the event!"); } } void enter(MccGenericFsmMountInitEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems a re-entering to the initializing state was asked! Ignore the event and wait for the " "mount " "to initialize!"); } } void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); auto* mount_ptr = event.mount(); // call base-class initMount method! auto err = static_cast(mount_ptr)->initMount(); if (err) { mount_ptr->dispatchEvent(MccGenericFsmMountErrorEvent{mount_ptr}); return; } // after initialization switch to IDLE state mount_ptr->dispatchEvent(MccGenericFsmMountIdleEvent{mount_ptr}); } }; template struct MccGenericFsmMountSlewState : MccGenericFsmMountBaseState { static constexpr std::string_view ID{"GENERIC-MOUNT-SLEW-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair>, std::pair, std::pair>, std::pair>; void exit(MccGenericFsmMountSlewEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems re-entering to slewing state was asked! Do not stop the current slewing process, just " "ignore this event!"); } } void enter(MccGenericFsmMountSlewEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems re-entering to slewing state was asked! Do not start a new slewing process, just ignore " "this event!"); } } void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); auto* mount_ptr = event.mount(); // call base-class stopMount method! auto err = static_cast(mount_ptr)->slewToTarget(); if (err) { mount_ptr->dispatchEvent(MccGenericFsmMountErrorEvent{mount_ptr}); return; } MccGenericFsmMount::slewing_params_t params; mount_ptr->getSlewingParams(¶ms); if (params.slewAndStop) { // after slewing switch to IDLE state mount_ptr->dispatchEvent(MccGenericFsmMountIdleEvent{mount_ptr}); } else { // after slewing switch to tracking state mount_ptr->dispatchEvent(MccGenericFsmMountTrackEvent{mount_ptr}); } } }; template struct MccGenericFsmMountTrackState : MccGenericFsmMountBaseState { static constexpr std::string_view ID{"GENERIC-MOUNT-TRACK-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair>, std::pair, std::pair>; void exit(MccGenericFsmMountTrackEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems re-entering to tracking state was asked! Do not stop the current tracking process, just " "ignore this event!"); } } void enter(MccGenericFsmMountTrackEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems re-entering to tracking state was asked! Do not start a new tracking process, just " "ignore this event!"); } } void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); auto* mount_ptr = event.mount(); // call base-class stopMount method! auto err = static_cast(mount_ptr)->trackTarget(); if (err) { mount_ptr->dispatchEvent(MccGenericFsmMountErrorEvent{mount_ptr}); return; } // after stop trackin switch to IDLE state mount_ptr->dispatchEvent(MccGenericFsmMountIdleEvent{mount_ptr}); } }; template struct MccGenericFsmMountStopState : MccGenericFsmMountBaseState { static constexpr std::string_view ID{"GENERIC-MOUNT-STOP-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair>, std::pair, std::pair>; void exit(MccGenericFsmMountStopEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn("It seems a re-entering to the stop state was asked! Ignore the event!"); } } void enter(MccGenericFsmMountStopEvent& event) { if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( "It seems a re-entering to the stop state was asked! Ignore the event and wait for the mount to " "stop!"); } } void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); auto* mount_ptr = event.mount(); // call base-class stopMount method! auto err = static_cast(mount_ptr)->stopMount(); if (err) { mount_ptr->dispatchEvent(MccGenericFsmMountErrorEvent{mount_ptr}); return; } // after stopping switch to IDLE state mount_ptr->dispatchEvent(MccGenericFsmMountIdleEvent{mount_ptr}); } }; struct MccGenericFsmMountErrorState : MccGenericFsmMountBaseState // default error-state class implementation // (just log error) { static constexpr std::string_view ID{"GENERIC-MOUNT-ERROR-STATE"}; using transition_t = fsm::fsm_transition_table_t< std::pair, std::pair>, std::pair>>; void exit(fsm::traits::fsm_event_c auto& event) { exitLog(event); if constexpr (mcc_generic_log_mount_c) { event.mount()->logWarn( std::format("The mount is in the error state!!! One must correct it before transit to any states! " "Event type is '{}'", decltype(event)::ID)); } } void enter(fsm::traits::fsm_event_c auto& event) { enterLog(event); if constexpr (mcc_generic_log_mount_c) { auto err = event.eventData(); event.mount()->logError( std::format("The mount is in the error state: code = {}, category = {}, message = '{}'", err.value(), err.category().name(), err.message())); } } }; public: template MccGenericFsmMount(MOUNT_T mount, fsm::traits::fsm_state_c auto start_state = MccGenericFsmMountStartState{}) : MOUNT_T(std::move(mount)), fsm::MccFiniteStateMachine(std::move(start_state)) { } // reimplementation of base-class methods to adapt it to FSM-behavior auto initMount() { try { this->dispatchEvent(MccGenericFsmMountInitEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } auto stopMount() { try { this->dispatchEvent(MccGenericFsmMountStopEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } auto slewToTarget() { try { this->dispatchEvent(MccGenericFsmMountSlewEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } auto stopSlewing() { try { this->dispatchEvent(MccGenericFsmMountStopEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } auto trackTarget() { try { this->dispatchEvent(MccGenericFsmMountTrackEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } auto stopTracking() { try { this->dispatchEvent(MccGenericFsmMountStopEvent{this}); } catch (std::system_error const& exc) { return exc.code(); } return MccGenericFsmMountErrorCode::ERROR_OK; } protected: // wrappers auto _initMount() { return MOUNT_T::initMount(); } auto _stopMount() { return MOUNT_T::stopMount(); } auto _slewToTarget() { return MOUNT_T::slewToTarget(); } auto _trackTarget() { return MOUNT_T::trackTarget(); } auto _startGuidingTarget() { return MOUNT_T::startGuidingTarget(); } auto _stopGuidingTarget() { return MOUNT_T::stopGuidingTarget(); } }; template class MccGenericMountFSM : public fsm::MccFiniteStateMachine, public MccGenericMount { protected: typedef MccGenericMount base_gmount_t; public: using typename base_gmount_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 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 { static constexpr std::string_view ID{"BASE-STATE"}; 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; // must be implemented in derived class struct MccGenericMountStateSlew; struct MccGenericMountStateTrack; // struct MccGenericMountStateGuiding; struct MccGenericMountStateStopping; struct MccGenericMountStateUninit : MccGenericMountBaseState { static constexpr std::string_view ID{"UNINITIALIZED-STATE"}; // 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 { static constexpr std::string_view ID{"INITIALIZING-STATE"}; using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair>; void exit(MccGenericMountEventInit& event) { event.mount().logWarn("It seems re-entering to initializing state was asked! Just ignore this event!"); } void enter(MccGenericMountEventInit& event) { event.mount().logWarn( "It seems re-entering to initializing state was asked! Ignore it and wait for mount to initialize!"); } 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 { static constexpr std::string_view ID{"IDLE-STATE"}; using transition_t = fsm::fsm_transition_table_t, 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); } }; struct MccGenericMountStateStopping : MccGenericMountBaseState { static constexpr std::string_view ID{"STOPPING-STATE"}; using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair>; void exit(MccGenericMountEventStop& event) { event.mount().logWarn("It seems re-entering to stopping state was asked! Just ignore it!"); } void enter(MccGenericMountEventStop& event) { event.mount().logWarn( "It seems re-entering to stopping state was asked! Ignore it and wait for mount to stop!"); } 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 { static constexpr std::string_view ID{"SLEWING-STATE"}; using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair, std::pair, std::pair>; void exit(MccGenericMountEventSlew& event) { event.mount().logWarn( "It seems re-entering to slewing state was asked! Do not stop the current slewing process, just ignore " "this event!"); } void enter(MccGenericMountEventSlew& event) { event.mount().logWarn( "It seems re-entering to slewing state was asked! Do not start a new slewing process, just ignore this " "event!"); } 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 { static constexpr std::string_view ID{"TRACKING-STATE"}; using transition_t = fsm::fsm_transition_table_t, std::pair, std::pair>; void exit(MccGenericMountEventTrack& event) { event.mount().logWarn( "It seems re-entering to tracking state was asked! Do not stop the current tracking process, just " "ignore this event!"); } void enter(MccGenericMountEventTrack& event) { event.mount().logWarn( "It seems re-entering to tracking state was asked! Do not start a new tracking process, just ignore " "this event!"); } template EvT> void exit(EvT& event) { // error_t err = event.mount()._stopTrackingMount(); error_t err = static_cast(&event.mount())->stopTracking(); 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}); } } }; using LoggerT::logDebug; using LoggerT::logError; using LoggerT::logInfo; using LoggerT::logWarn; using typename SlewModelT::slewing_params_t; using typename TrackModelT::tracking_params_t; /* CONSTRUCTORS AND DESTRUCTOR */ MccGenericMountFSM(HardwareT hardware, TelemetryT telemetry, PZoneContT pzone_cont, SlewModelT slew_model, TrackModelT track_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(logger)) { } virtual ~MccGenericMountFSM() = default; // reimplementation of base-class methods to adapt it to FSM-behavior auto initMount() { if (_currentStateID == MccGenericMountStateInit::ID) { logWarn("Already in initializing state! Ignore!"); return; } 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}); } 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