#pragma once /**************************************************************************************** * * * MOUNT CONTROL COMPONENTS LIBRARY * * * * * * IMPLEMENTATION OF A GENERIC MOUNT CLASS * * (A SOME OF POSSIBLE GENERIC IMPLEMENTATIONS) * * * ****************************************************************************************/ #include #include "mcc_error.h" namespace mcc::impl { enum class MccGenericMountErrorCode : int { ERROR_OK, ERROR_HW_INIT, ERROR_HW_STOP, ERROR_HW_GETSTATE, ERROR_SET_TARGET, ERROR_MOUNT_SLEW, ERROR_MOUNT_TRACK, ERROR_GET_TELEMETRY, ERROR_UNSUPPORTED_TARGET_COORDPAIR, ERROR_PZONE_COMP, ERROR_TARGET_IN_ZONE }; enum class MccGenericFsmMountErrorCode : int { ERROR_OK, ERROR_INVALID_OPERATION, ERROR_UNKNOWN_EVENT }; } // namespace mcc::impl namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace mcc::impl { // error category struct MccGenericMountCategory : public std::error_category { MccGenericMountCategory() : std::error_category() {} const char* name() const noexcept { return "MCC-GENERIC-MOUNT"; } std::string message(int ec) const { MccGenericMountErrorCode err = static_cast(ec); switch (err) { case MccGenericMountErrorCode::ERROR_OK: return "OK"; case MccGenericMountErrorCode::ERROR_HW_INIT: return "an error occured while initializing mount"; case MccGenericMountErrorCode::ERROR_HW_STOP: return "an error occured while stopping mount"; case MccGenericMountErrorCode::ERROR_HW_GETSTATE: return "cannot get state of hardware"; case MccGenericMountErrorCode::ERROR_SET_TARGET: return "cannot set target coordinates"; case MccGenericMountErrorCode::ERROR_MOUNT_SLEW: return "slewing error"; case MccGenericMountErrorCode::ERROR_MOUNT_TRACK: return "tracking error"; case MccGenericMountErrorCode::ERROR_GET_TELEMETRY: return "cannot get telemetry data"; case MccGenericMountErrorCode::ERROR_UNSUPPORTED_TARGET_COORDPAIR: return "unsupported coordinate pair of target"; case MccGenericMountErrorCode::ERROR_PZONE_COMP: return "an error occured while computing prohibited zone"; case MccGenericMountErrorCode::ERROR_TARGET_IN_ZONE: return "target coordinates are in prohibitted zone"; default: return "UNKNOWN"; } } static const MccGenericMountCategory& get() { static const MccGenericMountCategory constInst; return constInst; } }; inline std::error_code make_error_code(MccGenericMountErrorCode ec) { return std::error_code(static_cast(ec), MccGenericMountCategory::get()); } template class MccGenericMount : protected HARDWARE_T, public TELEMETRY_T, public PZONE_CONT_T, public MOVE_CNTRL_T, public LOGGER_T { public: using LOGGER_T::logDebug; using LOGGER_T::logError; using LOGGER_T::logInfo; using LOGGER_T::logTrace; using LOGGER_T::logWarn; typedef MccError error_t; using typename TELEMETRY_T::telemetry_data_t; enum class mount_status_t : int { MOUNT_STATUS_ERROR, MOUNT_STATUS_IDLE, MOUNT_STATUS_UNINITIALIZED, MOUNT_STATUS_INITIALIZATION, MOUNT_STATUS_STOPPED, MOUNT_STATUS_STOPPING, MOUNT_STATUS_SLEWING, MOUNT_STATUS_ADJUSTING, MOUNT_STATUS_GUIDING, MOUNT_STATUS_TRACKING }; template MccGenericMount(std::tuple hw_ctor_args, std::tuple telemetry_ctor_args, std::tuple pzone_cont_ctor_ars, std::tuple move_cntrl_ctor_ars, std::tuple logger_ctor_args) : HARDWARE_T(std::make_from_tuple(std::move(hw_ctor_args))), TELEMETRY_T(std::make_from_tuple(std::move(telemetry_ctor_args))), PZONE_CONT_T(std::make_from_tuple(pzone_cont_ctor_ars)), MOVE_CNTRL_T(std::make_from_tuple(move_cntrl_ctor_ars)), LOGGER_T(std::make_from_tuple(logger_ctor_args)) { logDebug(std::format("Create MccGenericMount class instance (thread: {})", std::this_thread::get_id())); } MccGenericMount(const MccGenericMount&) = delete; MccGenericMount(MccGenericMount&&) = default; MccGenericMount& operator=(const MccGenericMount&) = delete; MccGenericMount& operator=(MccGenericMount&&) = default; virtual ~MccGenericMount() { logDebug(std::format("Delete MccGenericMount class instance (thread: {})", std::this_thread::get_id())); auto err = MOVE_CNTRL_T::stopMount(); if (err) { logError(formatError(err)); } } error_t initMount() { logInfo(std::format("Start MccGenericMount class initialization (thread: {}) ...", std::this_thread::get_id())); *_lastMountError = MccGenericMountErrorCode::ERROR_OK; *_mountStatus = mount_status_t::MOUNT_STATUS_INITIALIZATION; auto hw_err = this->hardwareInit(); if (hw_err) { *_mountStatus = mount_status_t::MOUNT_STATUS_ERROR; *_lastMountError = mcc_deduce_err(hw_err, MccGenericMountErrorCode::ERROR_HW_INIT); } else { logInfo("Generic mount initialization was performed"); *_mountStatus = mount_status_t::IDLE; } return *_lastMountError; } mount_status_t mountStatus() const { return _mountStatus->load(); } error_t mountLastError() const { return _lastMountError->load(); } protected: std::unique_ptr> _mountStatus{ new std::atomic{mount_status_t::MOUNT_STATUS_UNINITIALIZED}}; std::unique_ptr> _lastMountError{new std::atomic{MccGenericMountErrorCode::ERROR_OK}}; std::string formatError(error_t const& err, std::string_view prefix = "") const { return std::format("{}{} (category: {}, code: {})", prefix, err.message(), err.value(), err.category().name()); } }; } // namespace mcc::impl