mountcontrol/cxx/mcc_mount.h
2025-07-17 11:29:40 +03:00

204 lines
6.0 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
{
template <traits::mcc_mount_config_c MOUNT_CONFIG>
class MccMount : public fsm::MccFiniteStateMachine, public utils::MccSpdlogLogger
{
public:
typedef MOUNT_CONFIG mount_config_t;
typedef decltype(mount_config_t::telemetry) mount_telemetry_t;
typedef typename mount_telemetry_t::mount_telemetry_data_t mount_telemetry_data_t;
typedef decltype(mount_config_t::astrometryEngine) astrom_engine_t;
typedef decltype(mount_config_t::PEC) pec_t;
typedef decltype(mount_config_t::hardware) hardware_t;
typedef decltype(mount_config_t::slewModel) slew_model_t;
typedef decltype(mount_config_t::guidingModel) guiding_model_t;
typedef typename slew_model_t::slew_params_t slew_params_t;
/* constructors and destructor */
template <fsm::traits::fsm_state_c InitStateT, traits::mcc_input_char_range LogMarkT = std::string_view>
MccMount(mount_config_t mount_config,
InitStateT,
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("NULL"),
const LogMarkT& logger_mark = "[MOUNT]")
: fsm::MccFiniteStateMachine(InitStateT{}),
utils::MccSpdlogLogger(logger),
_mountConfig(std::move(mount_config)),
_mountTelemetry(_mountConfig.telemetry),
_slewModel(_mountConfig.slewModel),
_guidingModel(_mountConfig.guidingModel)
{
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_params_t params) {}
void startGuiding() {}
// mount_config_t mountConfig() const
// {
// return _mountConfig;
// }
// returns "mount_config_t&" or "mount_config_t const&"
decltype(auto) mountConfig(this auto&& self)
{
auto& config_ref = std::forward<decltype(self)>(self)._mountConfig;
return config_ref;
}
mount_telemetry_data_t mountTelemetryData() const
{
mount_telemetry_data_t mnt_data;
auto err = _mountTelemetry.data(mnt_data);
if (err) {
// log ....
}
return mnt_data;
}
/* prohibited zone related public methods */
// add zones to mount control system
template <traits::mcc_prohibited_zone_c<mount_telemetry_data_t> ZT,
traits::mcc_prohibited_zone_c<mount_telemetry_data_t>... ZTs>
size_t pzAddZone(ZT zone, ZTs... zones)
{
auto zone_ptr = std::make_shared<ZT>(std::move(zone));
_pzFuncs.emplace_back(
{.coordPairKind = ZT::zoneCoordPairKind,
.name = std::format("{}", zone_ptr->name()),
.inZoneFunc = [zone_ptr,
this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); },
.timeToFunc = [zone_ptr,
this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->timeTo(tmry_data); },
.timeFromFunc =
[zone_ptr, this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->timeFrom(tmry_data); }});
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:
mount_config_t _mountConfig;
mount_telemetry_t& _mountTelemetry;
slew_model_t& _slewModel;
guiding_model_t& _guidingModel;
// 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(const mount_telemetry_data_t&)> pz_inzone_func_t;
typedef std::function<pz_duration_t(const mount_telemetry_data_t&)> pz_timeto_func_t;
typedef std::function<pz_duration_t(const mount_telemetry_data_t&)> 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<pz_funcs_t> _pzFuncs{};
template <typename FuncT, traits::mcc_prohibited_zone_c<mount_telemetry_data_t>... ZTs>
auto forEachPZone(FuncT&& func, std::tuple<ZTs...>& zones)
{
std::array<traits::mcc_retval_t<FuncT>, sizeof...(ZTs)> result;
forEachPZoneHelper(std::forward<FuncT>(func), zones, result);
}
template <size_t I = 0, typename FuncT, traits::mcc_prohibited_zone_c<mount_telemetry_data_t>... ZTs>
auto forEachPZoneHelper(FuncT&& func, std::tuple<ZTs...>& zones, auto& result)
requires(I < sizeof...(ZTs))
{
std::get<I>(result) = std::forward<FuncT>(func)(std::get<I>(zones), mountTelemetryData());
forEachPZoneHelper<I + 1>(std::forward<FuncT>(func), zones, result);
}
}; // 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