259 lines
9.2 KiB
C++
259 lines
9.2 KiB
C++
#pragma once
|
|
|
|
|
|
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
|
|
|
|
|
|
|
/* A GENERIC MOUNT CLASS IMPLEMENTATION */
|
|
|
|
|
|
#include <algorithm>
|
|
#include "mcc_mount_concepts.h"
|
|
|
|
namespace mcc
|
|
{
|
|
|
|
// adaptor class for prohibited zones
|
|
template <traits::mcc_mount_telemetry_data_c TelemetryDataT>
|
|
struct MccPZoneWrapper {
|
|
// a type to which the result of calling prohibited zone class methods 'timeTo' and 'timeFrom' will be converted
|
|
typedef std::chrono::duration<double> duration_t; // seconds as floating-point number
|
|
|
|
static constexpr duration_t infiniteDuration{std::numeric_limits<double>::infinity()};
|
|
static constexpr duration_t zeroDuration{0.0};
|
|
|
|
typedef std::function<bool(const TelemetryDataT&)> pz_inzone_func_t;
|
|
typedef std::function<duration_t(const TelemetryDataT&)> pz_timeto_func_t;
|
|
typedef std::function<duration_t(const TelemetryDataT&)> pz_timefrom_func_t;
|
|
|
|
MccCoordPairKind coordPairKind;
|
|
const std::function<std::string()> name;
|
|
pz_inzone_func_t inZone;
|
|
pz_timeto_func_t timeTo;
|
|
pz_timefrom_func_t timeFrom;
|
|
};
|
|
|
|
|
|
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T,
|
|
traits::mcc_mount_hardware_c HARDWARE_T,
|
|
traits::mcc_mount_pec_c PEC_T,
|
|
traits::mcc_mount_telemetry_c TELEMETRY_T,
|
|
traits::mcc_slew_model_c SLEWMODEL_T,
|
|
traits::mcc_guiding_model_c GUIDEMODEL_T,
|
|
traits::mcc_logger_c LOGGER_T>
|
|
class MccGenericMount : public LOGGER_T
|
|
{
|
|
typedef LOGGER_T logger_t;
|
|
|
|
using logger_t::logDebug;
|
|
using logger_t::logError;
|
|
using logger_t::logInfo;
|
|
using logger_t::logWarn;
|
|
|
|
typedef ASTROM_ENGINE_T astrom_engine_t;
|
|
typedef HARDWARE_T hardware_t;
|
|
typedef PEC_T pec_t;
|
|
typedef TELEMETRY_T telemetry_t;
|
|
typedef typename TELEMETRY_T::telemetry_data_t telemetry_data_t;
|
|
typedef SLEWMODEL_T slew_model_t;
|
|
typedef GUIDEMODEL_T guiding_model_t;
|
|
|
|
typedef typename MccPZoneWrapper<telemetry_data_t>::duration_t pz_duration_t;
|
|
|
|
static constexpr MccMountType mountType = pec_t::mountType;
|
|
|
|
virtual ~MccGenericMount() = default;
|
|
|
|
// get telemetry data
|
|
auto mountTelemetryData(telemetry_data_t& data) { return _telemetry.data(data); }
|
|
|
|
|
|
/* prohibited zone related public methods */
|
|
|
|
// add zones to mount control system
|
|
template <traits::mcc_prohibited_zone_c<telemetry_data_t> ZT,
|
|
traits::mcc_prohibited_zone_c<telemetry_data_t>... ZTs>
|
|
size_t pzAddZone(ZT zone, ZTs... zones)
|
|
{
|
|
auto zone_ptr = std::make_shared<ZT>(std::move(zone));
|
|
|
|
using d_t = typename MccPZoneWrapper<telemetry_data_t>::duration_t;
|
|
|
|
_pzFuncs.emplace_back(
|
|
{.coordPairKind = ZT::zoneCoordPairKind,
|
|
.name = [zone_ptr]() { return std::format("{}", zone_ptr->name()); },
|
|
.inZone = [zone_ptr](const telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); },
|
|
.timeTo =
|
|
[zone_ptr](const telemetry_data_t& tmry_data) {
|
|
auto d = zone_ptr->timeTo(tmry_data);
|
|
|
|
if constexpr (std::same_as<typename ZT::duration_t, d_t>) {
|
|
return d;
|
|
} else {
|
|
if (d == ZT::infiniteDuration) {
|
|
return MccPZoneWrapper<telemetry_data_t>::infiniteDuration;
|
|
} else if (d == ZT::zeroDuration) {
|
|
return MccPZoneWrapper<telemetry_data_t>::zeroDuration;
|
|
}
|
|
return std::chrono::duration_cast<d_t>(d);
|
|
}
|
|
},
|
|
.timeFrom =
|
|
[zone_ptr](const telemetry_data_t& tmry_data) {
|
|
auto d = zone_ptr->timeFrom(tmry_data);
|
|
|
|
if constexpr (std::same_as<typename ZT::duration_t, d_t>) {
|
|
return d;
|
|
} else {
|
|
if (d == ZT::infiniteDuration) {
|
|
return MccPZoneWrapper<telemetry_data_t>::infiniteDuration;
|
|
} else if (d == ZT::zeroDuration) {
|
|
return MccPZoneWrapper<telemetry_data_t>::zeroDuration;
|
|
}
|
|
return std::chrono::duration_cast<d_t>(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();
|
|
}
|
|
|
|
// prohibited zones timeTo from given time point
|
|
template <std::ranges::output_range<pz_duration_t> RT, traits::mcc_celestial_point_c CT, traits::mcc_systime_c TPT>
|
|
RT pzTimeTo(CT coord, const TPT& time_point)
|
|
requires std::convertible_to<TPT, typename astrom_engine_t::time_point_t>
|
|
{
|
|
RT res;
|
|
|
|
telemetry_data_t tdata;
|
|
typename astrom_engine_t::juldate_t jd;
|
|
|
|
_astromEngine.greg2jul(time_point, jd);
|
|
|
|
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
|
typename pec_t::pec_result_t pec_res;
|
|
auto pec_err = _pec.compute(coord.x, coord.y, pec_res);
|
|
if (!pec_err) {
|
|
if constexpr (mccIsEquatorialMount(mountType)) {
|
|
tdata.mntHA = coord.x + pec_res.dx;
|
|
tdata.mntDEC = coord.y + pec_res.dy;
|
|
_astromEngine.hadec2azalt(tdata.mntHA, tdata.mntDEC, tdata.mntAZ, tdata.mntALT);
|
|
} else if constexpr (mccIsAltAzMount(mountType)) {
|
|
tdata.mntAZ = coord.x + pec_res.dx;
|
|
tdata.mntALT = coord.y + pec_res.dy;
|
|
_astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC);
|
|
}
|
|
} else {
|
|
return res;
|
|
}
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC
|
|
typename astrom_engine_t::eo_t eo;
|
|
typename astrom_engine_t::sideral_time_t lst;
|
|
|
|
_astromEngine.apparentSiderTime(jd, lst, true);
|
|
_astromEngine.eqOrigins(jd, eo);
|
|
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC
|
|
tdata.mntHA = coord.x;
|
|
tdata.mntDEC = coord.y;
|
|
_astromEngine.hadec2azalt(tdata.mntHA, tdata.mntDEC, tdata.mntAZ, tdata.mntALT);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
|
tdata.mntAZ = coord.x;
|
|
tdata.mntALT = coord.y;
|
|
_astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD
|
|
tdata.mntAZ = coord.x;
|
|
tdata.mntALT = std::numbers::pi / 2.0 - coord.y;
|
|
_astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC);
|
|
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC
|
|
typename astrom_engine_t::coord_t az, alt;
|
|
typename astrom_engine_t::eo_t eo;
|
|
typename astrom_engine_t::juldate_t jd;
|
|
|
|
_astromEngine.greg2jul(time_point, jd);
|
|
_astromEngine.icrs2obs(coord.x, coord.y, jd, tdata.mntRA, tdata.mntDEC, tdata.mntHA, tdata.mntAZ,
|
|
tdata.mntALT, eo);
|
|
} else {
|
|
return res;
|
|
}
|
|
}
|
|
|
|
template <traits::mcc_celestial_point_c CT, traits::mcc_systime_c TPT>
|
|
auto pzTimeTo(CT point, const TPT& time_point)
|
|
{
|
|
return pzTimeTo<std::vector<pz_duration_t>>(std::move(point), time_point);
|
|
}
|
|
|
|
// prohibited zones timeTo from current mount position
|
|
template <std::ranges::output_range<pz_duration_t> RT, traits::mcc_celestial_point_c CT>
|
|
RT pzTimeTo(CT point)
|
|
{
|
|
RT result;
|
|
|
|
telemetry_data_t data;
|
|
auto err = _telemetry.data(data);
|
|
if (err) {
|
|
// log...
|
|
return result;
|
|
}
|
|
|
|
std::ranges::for_each(_pzFuncs,
|
|
[&result, &data](auto& funcs) { std::back_inserter(result) = funcs.timeTo(data); });
|
|
}
|
|
|
|
template <traits::mcc_celestial_point_c CT>
|
|
auto pzTimeTo(CT point)
|
|
{
|
|
return pzTimeTo<std::vector<pz_duration_t>>(std::move(point));
|
|
}
|
|
|
|
// prohibited zone timeFrom
|
|
|
|
protected:
|
|
ASTROM_ENGINE_T _astromEngine;
|
|
HARDWARE_T _hardware;
|
|
PEC_T _pec;
|
|
TELEMETRY_T _telemetry;
|
|
SLEWMODEL_T _slewModel;
|
|
GUIDEMODEL_T _gudingModel;
|
|
|
|
std::vector<MccPZoneWrapper<telemetry_data_t>> _pzFuncs{};
|
|
};
|
|
|
|
|
|
namespace traits
|
|
{
|
|
|
|
template <typename T>
|
|
concept mcc_generic_mount_c = requires(T t) {
|
|
// derived from MccGenericMount
|
|
[]<typename... Ts>(MccGenericMount<Ts...>*) {}(&t);
|
|
|
|
{ t.slewMount(std::declval<typename T::slew_model_t::slew_point_t>()) };
|
|
{ t.startGuiding(std::declval<typename T::guiding_model_t::guiding_point_t>()) };
|
|
|
|
{ t.stop() };
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
concept mcc_generic_fsm_mount_c = mcc_generic_mount_c<T> && std::derived_from<T, fsm::MccFiniteStateMachine>;
|
|
|
|
|
|
} // namespace traits
|
|
|
|
|
|
} // namespace mcc
|