mountcontrol/cxx/mcc_mount_concepts.h
Timur A. Fatkhullin d663f6b54a ...
2025-07-09 00:58:19 +03:00

250 lines
8.3 KiB
C++

#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
#include <concepts>
#include "mcc_traits.h"
/* SOME LIBRARY-WIDE DECLARATIONS */
namespace mcc
{
// mount construction type (only the most common ones)
enum class MccMountType : uint8_t { GERMAN_TYPE, FORK_TYPE, CROSSAXIS_TYPE, ALTAZ_TYPE };
template <MccMountType TYPE>
static constexpr std::string_view MccMountTypeStr = TYPE == MccMountType::GERMAN_TYPE ? "GERMAN"
: TYPE == MccMountType::FORK_TYPE ? "FORK"
: TYPE == MccMountType::CROSSAXIS_TYPE ? "CROSSAXIS"
: TYPE == MccMountType::ALTAZ_TYPE ? "ALTAZ"
: "UNKNOWN";
} // namespace mcc
namespace mcc::traits
{
/* ASTROMETRY-RELATED COMPUTATION ENGINE */
template <typename T>
concept mcc_astrom_engine_c = requires(T t, const T t_const) {
typename T::engine_err_t;
typename T::engine_state_t;
requires std::movable<typename T::engine_state_t>;
typename T::coord_t; // type for coordinates representation
typename T::time_point_t; // type to represent UTC time point
typename T::juldate_t; // type to represent Julian date
typename T::sideral_time_t; // type to represent sideral time
typename T::pa_t; // type to represent parallactic angle
typename T::refract_result_t;
{ t.setState(std::declval<typename T::engine_state_t>()) };
{ t_const.getState() } -> std::same_as<typename T::engine_state_t>;
{ t_const.errorString(std::declval<typename T::engine_err_t>()) } -> mcc_formattable;
/* coordinates conversional methods */
// ICRS RA and DEC to observed place: icrs2obs(ra, dec, jd, ra_app, dec_app, ha, az, alt)
{
t.icrs2obs(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
std::declval<typename T::juldate_t>(), std::declval<typename T::coord_t&>(),
std::declval<typename T::coord_t&>(), std::declval<typename T::coord_t&>(),
std::declval<typename T::coord_t&>(), std::declval<typename T::coord_t&>())
} -> std::same_as<typename T::engine_err_t>;
// compute hour angle and declination from azimuth and altitude: hadec2azalt(ha, dec, az, alt)
{
t.hadec2azalt(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
std::declval<typename T::coord_t&>(), std::declval<typename T::coord_t&>())
} -> std::same_as<typename T::engine_err_t>;
// compute azimuth and altitude from hour angle and declination: azalt2hadec(az, alt, ha, dec)
{
t.azalt2hadec(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
std::declval<typename T::coord_t&>(), std::declval<typename T::coord_t&>())
} -> std::same_as<typename T::engine_err_t>;
// compute parallactic angle: hadec2pa(ha, dec, pa)
{
t.hadec2pa(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
std::declval<typename T::pa_t&>())
} -> std::same_as<typename T::engine_err_t>;
/* time-related methods */
// Gregorian Calendar time point to Julian Date: greg2jul(time_point, jd)
{
t.greg2jul(std::declval<typename T::time_point_t>(), std::declval<typename T::juldate_t&>())
} -> std::same_as<typename T::engine_err_t>;
// apparent sideral time: apparentSiderTime(jd, gst, islocal)
// if islocal == false then the method must return the Greenwich apparent sideral time, otherwise - local one
{
t.apparentSiderTime(std::declval<typename T::juldate_t>(), std::declval<typename T::sideral_time_t&>(),
std::declval<bool>())
} -> std::same_as<typename T::engine_err_t>;
/* atmospheric refraction-related methods */
{ t.refraction(std::declval<typename T::refract_result_t&>()) } -> std::same_as<typename T::engine_err_t>;
};
/* MOUNT AXES AND MOTORS HARDWARE GENERIC ABSTRACTION */
// encoder basic concept (e.g. mount axis encoder or motor shaft one)
template <typename T>
concept mcc_hw_encoder_c = requires(T t, const T t_const) {
typename T::error_t;
typename T::time_point_t;
typename T::coord_t;
typename T::speed_t;
typename T::accel_t;
requires requires(typename T::state_t st) {
requires std::same_as<decltype(st.time), typename T::time_point_t>;
requires std::same_as<decltype(st.pos), typename T::coord_t>;
requires std::same_as<decltype(st.speed), typename T::speed_t>;
requires std::same_as<decltype(st.accel), typename T::accel_t>;
};
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
{ t_const.id() } -> mcc_formattable;
{ t.getState(std::declval<typename T::state_t&>()) } -> std::same_as<typename T::error_t>;
};
template <typename T>
concept mcc_hw_motor_c = requires(T t, const T t_const) {
typename T::error_t;
typename T::coord_t;
typename T::speed_t;
typename T::accel_t;
requires requires(typename T::pos_t st) {
requires std::same_as<decltype(st.pos), typename T::coord_t>;
requires std::same_as<decltype(st.speed), typename T::speed_t>; // means maximal allowed speed
requires std::same_as<decltype(st.accel), typename T::accel_t>; // means a maximal allowed acceleration (jerk)
};
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
{ t_const.id() } -> mcc_formattable;
{ t.toPos(std::declval<typename T::pos_t>()) } -> std::same_as<typename T::error_t>;
{ t.stop() } -> std::same_as<typename T::error_t>;
};
namespace details
{
template <typename T>
concept mcc_tuple_enc_ref_c = mcc_tuple_c<T> && requires(T t) {
[]<template <typename...> typename TT, mcc_hw_encoder_c... Ts>(TT<Ts & ...>) {}(t);
};
template <typename T>
concept mcc_tuple_enc_cref_c = mcc_tuple_c<T> && requires(T t) {
[]<template <typename...> typename TT, mcc_hw_encoder_c... Ts>(TT<const Ts & ...>) {}(t);
};
template <typename T>
concept mcc_tuple_motor_ref_c = mcc_tuple_c<T> && requires(T t) {
[]<template <typename...> typename TT, mcc_hw_motor_c... Ts>(TT<Ts & ...>) {}(t);
};
template <typename T>
concept mcc_hw_enc_lref_c = std::is_lvalue_reference_v<T> && mcc_hw_encoder_c<std::remove_reference_t<T>>;
template <typename T>
concept mcc_hw_motor_lref_c = std::is_lvalue_reference_v<T> && mcc_hw_motor_c<std::remove_reference_t<T>>;
} // namespace details
// a very generic mount hardware concept
template <typename T>
concept mcc_mount_hardware_c = requires(T t, const T t_const) {
{ t_const.id() } -> mcc_formattable;
// access to encoders
{ t_const.encoders() } -> details::mcc_tuple_enc_cref_c;
{ t.encoders() } -> details::mcc_tuple_enc_ref_c;
{ t.encoderPosX() } -> details::mcc_hw_enc_lref_c;
{ t.encoderPosY() } -> details::mcc_hw_enc_lref_c;
// access to motors
{ t.motors() } -> details::mcc_tuple_motor_ref_c;
{ t.motorX() } -> details::mcc_hw_motor_lref_c;
{ t.motorY() } -> details::mcc_hw_motor_lref_c;
};
/* POINTING-ERROR CORRECTION */
template <typename T>
concept mcc_mount_pec_c = requires(T t, const T t_const) {
typename T::coord_t;
typename T::pec_data_t;
typename T::pec_result_t;
{ t.setData(std::declval<typename T::pec_data_t>()) };
{ t_const.getData() } -> std::same_as<typename T::pec_data_t>;
{
t.compute(std::declval<const typename T::coord_t&>(), std::declval<const typename T::coord_t&>())
} -> std::same_as<typename T::pec_result_t>;
};
/* MOUNT STATE TELEMETRY */
template <typename T>
concept mcc_mount_telemetry_c = requires(T t, const T t_const) {
typename T::error_t;
typename T::mount_telemetry_data_t;
{ t_const.errorString(std::declval<typename T::error_t>()) } -> mcc_formattable;
{ t.update() } -> std::same_as<typename T::error_t>;
{ t_const.data() } -> std::same_as<typename T::mount_telemetry_data_t>;
};
/* MOUNT GENERIC CONFIGURATION */
template <typename T>
concept mcc_mount_config_c = requires(T t) {
{ t.astromEngine() } -> mcc_astrom_engine_c;
{ t.pec() } -> mcc_mount_pec_c;
{ t.hardware() } -> mcc_mount_hardware_c;
};
} // namespace mcc::traits