318 lines
9.1 KiB
C++
318 lines
9.1 KiB
C++
#pragma once
|
|
|
|
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <concepts>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string_view>
|
|
#include "spdlog/sinks/null_sink.h"
|
|
|
|
#include "mcc_spdlog.h"
|
|
#include "mcc_traits.h"
|
|
#include "mount_astrom.h"
|
|
|
|
// low-level functions
|
|
// namespace lowlevel
|
|
// {
|
|
// #include "../LibSidServo/sidservo.h"
|
|
// } // namespace lowlevel
|
|
|
|
|
|
|
|
namespace mcc
|
|
{
|
|
|
|
namespace traits
|
|
{
|
|
|
|
|
|
// mount state type concept
|
|
template <typename T>
|
|
concept mcc_mount_state_c = requires(T t, const T t_const) {
|
|
{ t_const.ident() } -> std::same_as<std::string_view>;
|
|
|
|
// requires mcc_is_callable<typename T::error_callback_t>;
|
|
// requires mcc_is_callable<typename T::enter_callback_t>;
|
|
// requires mcc_is_callable<typename T::exit_callback_t>;
|
|
|
|
{ t.enter() } -> std::same_as<void>;
|
|
{ t.exit() } -> std::same_as<void>;
|
|
};
|
|
|
|
} // namespace traits
|
|
|
|
|
|
/* SOME BASIC DATA STRUCTURES DEFINITIONS */
|
|
|
|
// meteo parameters (e.g. to compute refraction)
|
|
struct MccMountMeteo {
|
|
typedef double temp_t;
|
|
typedef double humid_t;
|
|
typedef double press_t;
|
|
|
|
temp_t temperature; // Temperature in C
|
|
humid_t humidity; // humidity in %
|
|
press_t pressure; // atmospheric presure in hPa=mB
|
|
};
|
|
|
|
// mount current position and related quantities
|
|
struct MccMountPosition {
|
|
typedef double mnt_coord_t;
|
|
typedef double mnt_speed_t;
|
|
typedef double time_point_t;
|
|
|
|
// time-related
|
|
std::chrono::system_clock::time_point utc;
|
|
time_point_t mjd; // modified Julian date
|
|
time_point_t ut1;
|
|
time_point_t tt;
|
|
time_point_t siderTime; // sideral time (in radians)
|
|
|
|
// apparent target (user-input) current coordinates (in radians)
|
|
mnt_coord_t tagRA, tagDEC;
|
|
mnt_coord_t tagHA;
|
|
mnt_coord_t tagAZ, tagZD;
|
|
mnt_coord_t tagPA; // paralactic angle
|
|
|
|
// encoder-measured current mount coordinates (in radians)
|
|
mnt_coord_t mntRA, mntDEC;
|
|
mnt_coord_t mntHA;
|
|
mnt_coord_t mntAZ, mntZD;
|
|
mnt_coord_t mntPA;
|
|
|
|
// encoder-measured current mount moving speed (in radians/s)
|
|
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ZD for horizontal-type one
|
|
mnt_speed_t mntSpeedX, mntSpeedY;
|
|
|
|
// current refraction coefficient (for tagZD)
|
|
mnt_coord_t currRefr;
|
|
|
|
// PCS (pointing correction system) corrections
|
|
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ZD for horizontal-type one
|
|
mnt_coord_t pcsX, pcsY;
|
|
};
|
|
|
|
|
|
// mount site geographical location
|
|
struct MccMountSiteInfo {
|
|
typedef double mnt_site_coord_t;
|
|
typedef double mnt_site_elev_t;
|
|
|
|
mnt_site_coord_t latitude{0.0}; // in radians
|
|
mnt_site_coord_t longitude{0.0}; // in radians (positive to the East)
|
|
mnt_site_elev_t elevation{0.0}; // in meters
|
|
|
|
std::string_view name{"ALL-ZERO"}; // just a human-readable name
|
|
};
|
|
|
|
|
|
|
|
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";
|
|
|
|
|
|
/* MOUNT CONFIGURATION BASE CLASS */
|
|
|
|
struct MccMountConfig {
|
|
std::string leap_seconds_filename{}; // empty to use hardcoded default value!
|
|
std::string earth_orient_filename{}; // empty to use hardcoded default value!
|
|
|
|
MccMountSiteInfo siteInfo{.latitude = 0.0, .longitude = 0.0, .elevation = 0.0, .name{"ALL-ZERO"}};
|
|
};
|
|
|
|
|
|
/* MOUNT BASE TEMPLATED CLASS WITH BASIC FUNCTIONALITY */
|
|
|
|
// implements a Finite State Machine Pattern
|
|
template <MccMountType MOUNT_TYPE, std::derived_from<MccMountConfig> CONFIG_TYPE = MccMountConfig>
|
|
class MccMount : public utils::MccSpdlogLogger
|
|
{
|
|
public:
|
|
static constexpr MccMountType mountType = MOUNT_TYPE;
|
|
static constexpr std::string_view mountTypeStr = MccMountTypeStr<MOUNT_TYPE>;
|
|
|
|
typedef CONFIG_TYPE mount_config_t;
|
|
|
|
enum IersDatabaseType { IERS_DB_LEAPSECS, IERS_DB_EARTH_ORIENT };
|
|
|
|
|
|
/* Constructors and destructor */
|
|
|
|
MccMount(traits::mcc_input_char_range auto const& logger_mark = "[MOUNT]",
|
|
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("NULL"))
|
|
: utils::MccSpdlogLogger(logger), _exitCurrentState([]() {})
|
|
{
|
|
std::istringstream strst;
|
|
|
|
addMarkToPatternIdx(logger_mark);
|
|
|
|
logDebug("Create MccMount class instance: thread = {}", getThreadId());
|
|
|
|
|
|
logInfo("Load leap seconds and Earth orientation databases ...");
|
|
|
|
updateIERSDatabase(IERS_DB_LEAPSECS);
|
|
updateIERSDatabase(IERS_DB_EARTH_ORIENT);
|
|
}
|
|
|
|
virtual ~MccMount()
|
|
{
|
|
logDebug("Delete MccMount class instance: thread = {}", getThreadId());
|
|
}
|
|
|
|
|
|
/* Public methods */
|
|
|
|
template <traits::mcc_mount_state_c StateT>
|
|
void setMountState(StateT& state)
|
|
{
|
|
_exitCurrentState(); // exit from current state
|
|
_exitCurrentState = [&state]() { state.exit(); };
|
|
|
|
state.enter();
|
|
}
|
|
|
|
|
|
MccMountPosition getMountData() const noexcept
|
|
{
|
|
return _currentMountOrient.load();
|
|
}
|
|
|
|
|
|
// geo location setters/getters
|
|
|
|
void setGeoLocation(const MccMountSiteInfo& geoloc)
|
|
{
|
|
_geoLocation.store(geoloc);
|
|
}
|
|
|
|
void setSiteLatitude(auto const& lat)
|
|
{
|
|
auto v = utils::parsAngleString(lat);
|
|
if (v.has_value()) {
|
|
auto st = _geoLocation.load();
|
|
st.latitude = v.value() * utils::deg2radCoeff; // to radians
|
|
logInfo("Set current site latitude to {} radians", st.latitude);
|
|
_geoLocation.store(st);
|
|
} else {
|
|
logError("Invalid user latitude value! Do not change the current value!");
|
|
}
|
|
}
|
|
|
|
void setSiteLongitude(auto const& lon)
|
|
{
|
|
auto v = utils::parsAngleString(lon);
|
|
if (v.has_value()) {
|
|
auto st = _geoLocation.load();
|
|
st.longitude = v.value() * utils::deg2radCoeff; // to radians
|
|
logInfo("Set current site longitude to {} radians", st.longitude);
|
|
_geoLocation.store(st);
|
|
} else {
|
|
logError("Invalid user longitude value! Do not change the current value!");
|
|
}
|
|
}
|
|
|
|
void setSiteElevation(MccMountSiteInfo::mnt_site_elev_t elev)
|
|
{
|
|
auto st = _geoLocation.load();
|
|
st.elevation = elev;
|
|
logInfo("Set current site elevation to {} meters", st.elevation);
|
|
_geoLocation.store(st);
|
|
}
|
|
|
|
|
|
MccMountSiteInfo getGeoLocation() const
|
|
{
|
|
return _geoLocation.load();
|
|
}
|
|
|
|
|
|
// current meteo setters/getters
|
|
|
|
void setMeteo(const MccMountMeteo& meteo)
|
|
{
|
|
_currentMeteo.store(meteo);
|
|
}
|
|
|
|
MccMountMeteo getMeteo() const
|
|
{
|
|
return _currentMeteo.load();
|
|
}
|
|
|
|
|
|
// prohibited zone related methods
|
|
|
|
bool pzCheck(traits::mcc_real_or_char_range auto const& xcoord, traits::mcc_real_or_char_range auto const& ycoord)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
auto pzPredict(traits::mcc_systime_c auto const& time_point,
|
|
traits::mcc_real_or_char_range auto const& xcoord,
|
|
traits::mcc_real_or_char_range auto const& ycoord)
|
|
{
|
|
using d_t = std::remove_cvref_t<decltype(time_point)>::duration;
|
|
|
|
return d_t::max();
|
|
}
|
|
|
|
|
|
// IERS databases updater
|
|
|
|
bool updateIERSDatabase(IersDatabaseType type)
|
|
{
|
|
auto time_db_loader = [this](const std::string& filename, std::string_view type, auto& db) {
|
|
if (filename.empty()) {
|
|
logWarn("An empty {} filename! Skip and keep default values!", type);
|
|
return false;
|
|
}
|
|
|
|
bool ok = db.load(filename);
|
|
if (!ok) {
|
|
logError("CANNOT parse {} file '{}' or it is not accessible!", type, filename);
|
|
logWarn("Keep {} database in default state!", type);
|
|
} else {
|
|
logInfo("{} database was successfully loaded from '{}' file", type, filename);
|
|
}
|
|
|
|
return ok;
|
|
};
|
|
|
|
switch (type) {
|
|
case IERS_DB_LEAPSECS:
|
|
return time_db_loader(_mountCurrentConfig.leap_seconds_filename, "leap seconds", _leapSecondsDB);
|
|
case IERS_DB_EARTH_ORIENT:
|
|
return time_db_loader(_mountCurrentConfig.earth_orient_filename, "Earth orientation", _earthOrientDB);
|
|
default:
|
|
logError("Invalid type for IERS database!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
mount_config_t _mountCurrentConfig;
|
|
|
|
// std::shared_ptr<spdlog::logger> _mountLogger;
|
|
std::function<void()> _exitCurrentState;
|
|
|
|
// time scales related databases
|
|
astrom::MccLeapSeconds _leapSecondsDB;
|
|
astrom::MccIersBulletinA _earthOrientDB;
|
|
|
|
std::atomic<MccMountPosition> _currentMountOrient;
|
|
|
|
std::atomic<MccMountSiteInfo> _geoLocation;
|
|
std::atomic<MccMountMeteo> _currentMeteo;
|
|
};
|
|
|
|
} // namespace mcc
|