#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* AN GENERIC MOUNT CLASS IMPLEMENTATION BASED ON FINITE STATE MACHINE */ #include #include #include #include "spdlog/sinks/null_sink.h" #include "mcc_mount_concepts.h" #include "mcc_mount_coord.h" #include "mcc_spdlog.h" #include "mcc_traits.h" #include "mcc_finite_state_machine.h" #include "mcc_mount_events_states.h" namespace mcc { // adaptor class for prohibited zones template struct MccPZoneWrapper { // a type to which the result of calling prohibited zone class methods 'timeTo' and 'timeFrom' will be converted typedef std::chrono::duration pz_duration_t; // seconds as floating-point number static constexpr pz_duration_t infiniteDuration{std::numeric_limits::infinity()}; static constexpr pz_duration_t zeroDuration{0.0}; typedef std::function pz_inzone_func_t; typedef std::function pz_timeto_func_t; typedef std::function pz_timefrom_func_t; MccCoordPairKind coordPairKind; const std::function name; pz_inzone_func_t inZone; pz_timeto_func_t timeTo; pz_timefrom_func_t timeFrom; }; template class MccMount : public fsm::MccFiniteStateMachine, public utils::MccSpdlogLogger, protected MOUNT_CONTROLS { // declare these classes as friends to allow them access protected members 'slewModel' and 'guidingModel' // friend class MccMountStateSlew>; // friend class MccMountStateGuiding>; public: typedef MOUNT_CONTROLS mount_controls_t; typedef decltype(mount_controls_t::telemetry) mount_telemetry_t; typedef typename mount_telemetry_t::mount_telemetry_data_t mount_telemetry_data_t; typedef decltype(mount_controls_t::astrometryEngine) astrom_engine_t; typedef decltype(mount_controls_t::PEC) pec_t; typedef decltype(mount_controls_t::hardware) hardware_t; typedef decltype(mount_controls_t::slewModel) slew_model_t; typedef decltype(mount_controls_t::guidingModel) guiding_model_t; // typedef typename slew_model_t::slew_params_t slew_params_t; /* base classes for event and state */ class MccMountEventBase { protected: MccMount& _mount; public: MccMountEventBase(MccMount& mount) : _mount(mount) {} virtual ~MccMountEventBase() = default; MccMount& mount() { return _mount; } }; // The implementation of FSM (see mcc_finite_state_machine.h) requires // state to be a default constructible class, so one needs to hold // a pointer to mount class to guarantee access to its private or protected // members and methods class MccMountStateBase { protected: // a pointer to mount class to allow access to private/protected // members/methods of MccMount class from descendent state-classes. // the memory address can be obtained from a call of // MccMountEventBase::mount method (see above) MccMount* _mount; public: MccMountStateBase() = default; MccMountStateBase(const MccMountStateBase&) = delete; MccMountStateBase& operator=(const MccMountStateBase&) = delete; // just as an example (ugly but I still cannot find a solution) // template EvT> // void enter(EvT& event) // { // _mount = &event.mount(); // _mount->forEachPZone(...); // } }; /* constructors and destructor */ template MccMount(mount_controls_t mount_controls, InitStateT, std::shared_ptr logger = spdlog::null_logger_mt("NULL"), const LogMarkT& logger_mark = "[MOUNT]") : fsm::MccFiniteStateMachine(InitStateT{}), utils::MccSpdlogLogger(logger), mount_controls_t(std::move(mount_controls)) { addMarkToPatternIdx(logger_mark); logDebug("Create MccMount class instance: thread = {}", getThreadId()); auto ids = this->stateIDs(); auto r = ids | std::views::join_with(','); logDebug("{}", std::string(r.begin(), r.end())); } MccMount(const MccMount&) = delete; MccMount& operator=(const MccMount&) = delete; virtual ~MccMount() { logDebug("Delete MccMount class instance: thread = {}", getThreadId()); } /* public methods */ void initMount() { this->logInfo("STATE: {}", this->currentStateID()); } void stopMount() {} void shutdownMount() {} // void slewMount(slew_params_t params) {} void startGuiding() {} mount_telemetry_data_t mountTelemetryData() const { mount_telemetry_data_t mnt_data; auto err = this->telemetry.data(); if (err) { // log .... } return mnt_data; } /* prohibited zone related public methods */ // add zones to mount control system template ZT, traits::mcc_prohibited_zone_c... ZTs> size_t pzAddZone(ZT zone, ZTs... zones) { auto zone_ptr = std::make_shared(std::move(zone)); using d_t = typename MccPZoneWrapper::pz_duration_t; _pzFuncs.emplace_back( {.coordPairKind = ZT::zoneCoordPairKind, .name = [zone_ptr]() { return std::format("{}", zone_ptr->name()); }, .inZone = [zone_ptr](const mount_telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); }, .timeTo = [zone_ptr](const mount_telemetry_data_t& tmry_data) { auto d = zone_ptr->timeTo(tmry_data); if (d == ZT::infiniteDuration) { return MccPZoneWrapper::infiniteDuration; } else if (d == ZT::zeroDuration) { return MccPZoneWrapper::zeroDuration; } return std::chrono::duration_cast(d); }, .timeFrom = [zone_ptr](const mount_telemetry_data_t& tmry_data) { auto d = zone_ptr->timeFrom(tmry_data); if (d == ZT::infiniteDuration) { return MccPZoneWrapper::infiniteDuration; } else if (d == ZT::zeroDuration) { return MccPZoneWrapper::zeroDuration; } return std::chrono::duration_cast(d); }}); if constexpr (sizeof...(ZTs)) { pzAddZone(std::move(zones)...); } return _pzFuncs.size(); } // delete all zones from mount control system void pzClearZone() { // stop mount here?!! _pzFuncs.clear(); } protected: // a type to which the result of calling prohibited zone class methods 'timeTo' and 'timeFrom' will be converted typedef std::chrono::duration pz_duration_t; // seconds as floating-point number typedef std::function pz_inzone_func_t; typedef std::function pz_timeto_func_t; typedef std::function pz_timefrom_func_t; struct pz_funcs_t { MccCoordPairKind coordPairKind; std::string name; pz_inzone_func_t inZoneFunc; pz_timeto_func_t timeToFunc; pz_timefrom_func_t timeFromFunc; }; // std::vector _pzFuncs{}; std::vector> _pzFuncs{}; template ... ZTs> auto forEachPZone(FuncT&& func, std::tuple& zones) { std::array, sizeof...(ZTs)> result; forEachPZoneHelper(std::forward(func), zones, result); } template ... ZTs> auto forEachPZoneHelper(FuncT&& func, std::tuple& zones, auto& result) requires(I < sizeof...(ZTs)) { std::get(result) = std::forward(func)(std::get(zones), mountTelemetryData()); forEachPZoneHelper(std::forward(func), zones, result); } }; // end of MccMount class // namespace traits // { // // given mount class must be a descendant of MccMount // template // concept mcc_mount_c = requires(T t) { [](MccMount*) {}(&t); }; // } // namespace traits } // namespace mcc