mountcontrol/cxx/mcc_mount.h
2025-07-12 13:43:53 +03:00

232 lines
7.2 KiB
C++

#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
/* AN GENERIC MOUNT CLASS IMPLEMENTATION */
// #include <atomic>
#include <chrono>
// #include <concepts>
// #include <cstdint>
#include <functional>
#include <string_view>
#include "spdlog/sinks/null_sink.h"
#include "mcc_finite_state_machine.h"
#include "mcc_mount_coord.h"
#include "mcc_spdlog.h"
#include "mcc_traits.h"
// #include "mount_astrom.h"
// #include "mcc_mount_pz.h"
#include "mcc_mount_concepts.h"
namespace mcc
{
// mount configuration
template <MccMountType MOUNT_TYPE>
struct MccMountConfig {
static constexpr MccMountType mountType = MOUNT_TYPE;
virtual ~MccMountConfig() = default;
};
namespace traits
{
// given mount configuration class must be a descendant of MccMountConfig
template <typename T>
concept mcc_mountconfig_c = requires(T t) { []<MccMountType MOUNT_TYPE>(MccMountConfig<MOUNT_TYPE>*) {}(&t); };
} // namespace traits
template <traits::mcc_mountconfig_c MOUNT_CONFIG, traits::mcc_mount_telemetry_c MOUNT_TELEMETRY>
class MccMount : public fsm::MccFiniteStateMachine, public utils::MccSpdlogLogger
{
public:
static constexpr auto mountType = MOUNT_CONFIG::mountType;
typedef MOUNT_CONFIG mount_config_t;
typedef MOUNT_TELEMETRY mount_telemetry_t;
typedef typename mount_telemetry_t::mount_telemetry_data_t mount_telemetry_data_t;
struct slew_param_t {
MccCoordPairKind kind; // input coordinates type
MccAngle x; // co-longitude (e.g. RA or Az)
MccAngle y; // co-latitude (e.g. DEC or ZD)
bool stop; // stop after slewing
};
/* constructors and destructor */
template <fsm::traits::fsm_state_c InitStateT, traits::mcc_input_char_range LogMarkT = std::string_view>
MccMount(InitStateT,
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("NULL"),
const LogMarkT& logger_mark = "[MOUNT]")
: fsm::MccFiniteStateMachine(InitStateT{}), utils::MccSpdlogLogger(logger)
{
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()));
}
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_param_t params) {}
void startGuiding() {}
mount_config_t mountConfig() const
{
return _mountConfig;
}
mount_telemetry_data_t mountTelemetry() const
{
return _mountTelemetry.data();
}
/* prohibited zone related public methods */
// add zones to mount control system
template <traits::mcc_prohibited_zone_c ZT, traits::mcc_prohibited_zone_c... ZTs>
size_t pzAddZone(ZT zone, ZTs... zones)
{
static constexpr auto pi2 = std::numbers::pi / 2.0;
auto zone_ptr = std::make_shared<ZT>(std::move(zone));
// typename ZT::coord_t x, y;
if constexpr (ZT::preferedCoordKind == MccCoordPairKind::COORDS_KIND_AZALT) { // azimuth and altitude
_pzFuncs.emplace_back({.coordPairKind = ZT::preferedCoordKind,
.inZoneFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->inZone(tmry_data.mntAZ, tmry_data.mntALT, tmry_data.utc);
},
.timeToFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->timeTo(tmry_data.mntAZ, tmry_data.mntALT, tmry_data.utc);
},
.timeFromFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->timeFrom(tmry_data.mntAZ, tmry_data.mntALT, tmry_data.utc);
}});
} else if constexpr (ZT::preferedCoordKind ==
MccCoordPairKind::COORDS_KIND_AZZD) { // azimuth and zenithal distance
_pzFuncs.emplace_back(
{.coordPairKind = ZT::preferedCoordKind,
.inZoneFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->inZone(tmry_data.mntAZ, pi2 - tmry_data.mntALT, tmry_data.utc);
},
.timeToFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->timeTo(tmry_data.mntAZ, pi2 - tmry_data.mntALT, tmry_data.utc);
},
.timeFromFunc =
[zone_ptr, this]() {
auto tmry_data = _mountTelemetry.data();
return zone_ptr->timeFrom(tmry_data.mntAZ, pi2 - tmry_data.mntALT, tmry_data.utc);
}});
} else if constexpr (ZT::preferedCoordKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
} else if constexpr (ZT::preferedCoordKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
} else if constexpr (ZT::preferedCoordKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
} else if constexpr (ZT::preferedCoordKind == MccCoordPairKind::COORDS_KIND_XY) {
} else {
static_assert(false, "UNKNOWN COORDINATE SYSTEM!!!");
}
if constexpr (sizeof...(ZTs)) {
pzAddZone(std::move(zones)...);
}
return _pzFuncs.size();
}
// delete all zones from mount control system
void pzClearZone()
{
_pzFuncs.clear();
}
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
auto pzInZone(const XT& x, const YT& y, traits::mcc_time_duration_c auto const& utc)
{
}
protected:
mount_config_t _mountConfig;
mount_telemetry_t _mountTelemetry;
// a type to which the result of calling prohibited zone class methods 'timeTo' and 'timeFrom' will be converted
typedef std::chrono::duration<double> pz_duration_t; // seconds as floating-point number
typedef std::function<bool()> pz_inzone_func_t;
typedef std::function<pz_duration_t()> pz_timeto_func_t;
typedef std::function<pz_duration_t()> pz_timefrom_func_t;
struct pz_funcs_t {
MccCoordPairKind coordPairKind;
pz_inzone_func_t inZoneFunc;
pz_timeto_func_t timeToFunc;
pz_timefrom_func_t timeFromFunc;
};
std::vector<pz_funcs_t> _pzFuncs{};
}; // end of MccMount class
namespace traits
{
// given mount class must be a descendant of MccMount
template <typename T>
concept mcc_mount_c = requires(T t) { []<typename... Ts>(MccMount<Ts...>*) {}(&t); };
} // namespace traits
} // namespace mcc