This commit is contained in:
Timur A. Fatkhullin 2025-08-06 02:06:20 +03:00
parent 138e4bf84d
commit 6315d5e18e
15 changed files with 630 additions and 152 deletions

View File

@ -123,9 +123,12 @@ set(CNTR_PROTO_LIB comm_proto)
add_library(${CNTR_PROTO_LIB} STATIC ${CNTR_PROTO_LIB_SRC}) add_library(${CNTR_PROTO_LIB} STATIC ${CNTR_PROTO_LIB_SRC})
set(MCC_LIBRARY_SRC mcc_mount_concepts.h mcc_fsm_mount.h mcc_mount_coord.h mcc_mount_events_states.h mcc_finite_state_machine.h include_directories(${FITPACK_INCLUDE_DIR})
set(MCC_LIBRARY_SRC mcc_mount_concepts.h mcc_fsm_mount.h mcc_generic_mount.h mcc_mount_coord.h mcc_mount_events_states.h mcc_finite_state_machine.h
mcc_mount_pec.h mcc_mount_pz.h mcc_traits.h mcc_mount_telemetry_astrom.h mcc_mount_telemetry.h mcc_mount_config.h mcc_mount_astro_erfa.h mcc_mount_pec.h mcc_mount_pz.h mcc_traits.h mcc_mount_telemetry_astrom.h mcc_mount_telemetry.h mcc_mount_config.h mcc_mount_astro_erfa.h
mcc_astrom_iers.h mcc_astrom_iers_default.h mcc_slew_model.h mcc_guiding_model.h mcc_utils.h mcc_spdlog.h) mcc_astrom_iers.h mcc_astrom_iers_default.h mcc_slew_model.h mcc_guiding_model.h mcc_slew_guiding_model_common.h mcc_utils.h mcc_spdlog.h)
set(MCC_LIBRARY mcc) set(MCC_LIBRARY mcc)
add_library(${MCC_LIBRARY} INTERFACE ${MCC_LIBRARY_SRC}) add_library(${MCC_LIBRARY} INTERFACE ${MCC_LIBRARY_SRC})
target_compile_features(${MCC_LIBRARY} INTERFACE cxx_std_23) target_compile_features(${MCC_LIBRARY} INTERFACE cxx_std_23)

View File

@ -29,6 +29,9 @@ typedef mcc::MccMountTelemetry<AsibFM700AstromEngine,
AsibFM700TelemetryData> AsibFM700TelemetryData>
AsibFM700Telemetry; AsibFM700Telemetry;
static_assert(std::movable<AsibFM700Telemetry>);
static_assert(std::movable<AsibFM700AstromEngine>);
static_assert(std::movable<mcc::MccAltLimitPZ<>>);
// typedef mcc::MccSimpleSlewModel<> AsibFM700SlewModel; // typedef mcc::MccSimpleSlewModel<> AsibFM700SlewModel;
// typedef mcc::MccSimpleGuidingModel<> AsibFM700GuidingModel; // typedef mcc::MccSimpleGuidingModel<> AsibFM700GuidingModel;
@ -63,7 +66,7 @@ static_assert(mcc::traits::mcc_mount_controls_c<AsibFM700MountControls<mcc::util
// global mount configuration // global mount configuration
struct AsibFM700Config { struct AsibFM700Config {
std::chrono::milliseconds hardwareAskingPeriod{100}; // main cycle period std::chrono::milliseconds hardwarePollingPeriod{100}; // main cycle period
// mount hardware config // mount hardware config
AsibFM700Hardware::hardware_config_t hardwareConfig; AsibFM700Hardware::hardware_config_t hardwareConfig;
@ -72,6 +75,10 @@ struct AsibFM700Config {
class AsibFM700Mount : public mcc::MccMount<AsibFM700MountControls<mcc::utils::MccSpdlogLogger>> class AsibFM700Mount : public mcc::MccMount<AsibFM700MountControls<mcc::utils::MccSpdlogLogger>>
{ {
class InitState : public AsibFM700Mount::MccMountEventBase
{
};
public: public:
}; };

View File

@ -100,19 +100,26 @@ AsibFM700Hardware::error_t AsibFM700Hardware::setPos(AsibFM700Hardware::axes_pos
double tp = std::chrono::duration<double>(pos.time_point.time_since_epoch()).count(); double tp = std::chrono::duration<double>(pos.time_point.time_since_epoch()).count();
coordval_pair_t hw_posval{.X{.val = pos.x, .t = tp}, .Y{.val = pos.y, .t = tp}}; coordval_pair_t hw_posval{.X{.val = pos.x, .t = tp}, .Y{.val = pos.y, .t = tp}};
//
// WARNING: The LibSidservo API was chagned! hw_pos is endpoint where mount must
// go "after" slewing
//
switch (pos.moving_type) { switch (pos.moving_type) {
case hw_moving_type_t::HW_MOVE_SLEWING: // slew mount case hw_moving_type_t::HW_MOVE_SLEWING: // slew mount
if (pos.moveAndStop) { if (pos.moveAndStop) {
err = static_cast<AsibFM700HardwareErrorCode>(Mount.moveTo(&hw_pos)); // err = static_cast<AsibFM700HardwareErrorCode>(Mount.moveTo(&hw_pos));
err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval, &hw_pos));
} else { } else {
err = static_cast<AsibFM700HardwareErrorCode>(Mount.slewTo(&hw_pos, pos.flags)); // err = static_cast<AsibFM700HardwareErrorCode>(Mount.slewTo(&hw_pos, pos.flags));
err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval, &hw_pos));
} }
break; break;
case hw_moving_type_t::HW_MOVE_ADJUSTING: // corrections at the end of slewing case hw_moving_type_t::HW_MOVE_ADJUSTING: // corrections at the end of slewing
err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval)); err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval, &hw_pos));
break; break;
case hw_moving_type_t::HW_MOVE_GUIDING: // interpretate as guiding correction case hw_moving_type_t::HW_MOVE_GUIDING: // interpretate as guiding correction
err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval)); err = static_cast<AsibFM700HardwareErrorCode>(Mount.correctTo(&hw_posval, &hw_pos));
break; break;
default: default:
break; break;

View File

@ -79,7 +79,7 @@ public:
coord_t xrate, yrate; coord_t xrate, yrate;
hw_moving_type_t moving_type{hw_moving_type_t::HW_MOVE_TRACKING}; hw_moving_type_t moving_type{hw_moving_type_t::HW_MOVE_TRACKING};
slewflags_t flags; // slewflags_t flags;
bool moveAndStop{false}; bool moveAndStop{false};
}; };

View File

@ -23,12 +23,33 @@
namespace mcc 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> pz_duration_t; // seconds as floating-point number
static constexpr pz_duration_t infiniteDuration{std::numeric_limits<double>::infinity()};
static constexpr pz_duration_t zeroDuration{0.0};
typedef std::function<bool(const TelemetryDataT&)> pz_inzone_func_t;
typedef std::function<pz_duration_t(const TelemetryDataT&)> pz_timeto_func_t;
typedef std::function<pz_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_mount_controls_c MOUNT_CONTROLS> template <traits::mcc_mount_controls_c MOUNT_CONTROLS>
class MccMount : public fsm::MccFiniteStateMachine, public utils::MccSpdlogLogger, protected MOUNT_CONTROLS class MccMount : public fsm::MccFiniteStateMachine, public utils::MccSpdlogLogger, protected MOUNT_CONTROLS
{ {
// declare these classes as friends to allow them access protected members 'slewModel' and 'guidingModel' // declare these classes as friends to allow them access protected members 'slewModel' and 'guidingModel'
friend class MccMountStateSlew<MccMount<MOUNT_CONTROLS>>; // friend class MccMountStateSlew<MccMount<MOUNT_CONTROLS>>;
friend class MccMountStateGuiding<MccMount<MOUNT_CONTROLS>>; // friend class MccMountStateGuiding<MccMount<MOUNT_CONTROLS>>;
public: public:
typedef MOUNT_CONTROLS mount_controls_t; typedef MOUNT_CONTROLS mount_controls_t;
@ -43,6 +64,47 @@ public:
// typedef typename slew_model_t::slew_params_t slew_params_t; // typedef typename slew_model_t::slew_params_t slew_params_t;
/* base classes for event and state */
class MccMountEventBase
{
protected:
MccMount& _mount;
public:
MccMountEventBase(MccMount& mount) : _mount(mount) {}
virtual ~MccMountEventBase() = default;
MccMount& mount() { return _mount; }
};
// The implementation of FSM (see mcc_finite_state_machine.h) requires
// state to be a default constructible class, so one needs to hold
// a pointer to mount class to guarantee access to its private or protected
// members and methods
class MccMountStateBase
{
protected:
// a pointer to mount class to allow access to private/protected
// members/methods of MccMount class from descendent state-classes.
// the memory address can be obtained from a call of
// MccMountEventBase::mount method (see above)
MccMount* _mount;
public:
MccMountStateBase() = default;
MccMountStateBase(const MccMountStateBase&) = delete;
MccMountStateBase& operator=(const MccMountStateBase&) = delete;
// just as an example (ugly but I still cannot find a solution)
// template <std::derived_from<MccMountEventBase> EvT>
// void enter(EvT& event)
// {
// _mount = &event.mount();
// _mount->forEachPZone(...);
// }
};
/* constructors and destructor */ /* constructors and destructor */
@ -64,6 +126,8 @@ public:
logDebug("{}", std::string(r.begin(), r.end())); logDebug("{}", std::string(r.begin(), r.end()));
} }
MccMount(const MccMount&) = delete;
MccMount& operator=(const MccMount&) = delete;
virtual ~MccMount() { logDebug("Delete MccMount class instance: thread = {}", getThreadId()); } virtual ~MccMount() { logDebug("Delete MccMount class instance: thread = {}", getThreadId()); }
@ -103,15 +167,34 @@ public:
{ {
auto zone_ptr = std::make_shared<ZT>(std::move(zone)); auto zone_ptr = std::make_shared<ZT>(std::move(zone));
using d_t = typename MccPZoneWrapper<mount_telemetry_data_t>::pz_duration_t;
_pzFuncs.emplace_back( _pzFuncs.emplace_back(
{.coordPairKind = ZT::zoneCoordPairKind, {.coordPairKind = ZT::zoneCoordPairKind,
.name = std::format("{}", zone_ptr->name()), .name = [zone_ptr]() { return std::format("{}", zone_ptr->name()); },
.inZoneFunc = [zone_ptr, .inZone = [zone_ptr](const mount_telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); },
this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); }, .timeTo =
.timeToFunc = [zone_ptr, [zone_ptr](const mount_telemetry_data_t& tmry_data) {
this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->timeTo(tmry_data); }, auto d = zone_ptr->timeTo(tmry_data);
.timeFromFunc =
[zone_ptr, this](const mount_telemetry_data_t& tmry_data) { return zone_ptr->timeFrom(tmry_data); }}); if (d == ZT::infiniteDuration) {
return MccPZoneWrapper<mount_telemetry_data_t>::infiniteDuration;
} else if (d == ZT::zeroDuration) {
return MccPZoneWrapper<mount_telemetry_data_t>::zeroDuration;
}
return std::chrono::duration_cast<d_t>(d);
},
.timeFrom =
[zone_ptr](const mount_telemetry_data_t& tmry_data) {
auto d = zone_ptr->timeFrom(tmry_data);
if (d == ZT::infiniteDuration) {
return MccPZoneWrapper<mount_telemetry_data_t>::infiniteDuration;
} else if (d == ZT::zeroDuration) {
return MccPZoneWrapper<mount_telemetry_data_t>::zeroDuration;
}
return std::chrono::duration_cast<d_t>(d);
}});
if constexpr (sizeof...(ZTs)) { if constexpr (sizeof...(ZTs)) {
@ -144,8 +227,8 @@ protected:
pz_timefrom_func_t timeFromFunc; pz_timefrom_func_t timeFromFunc;
}; };
std::vector<pz_funcs_t> _pzFuncs{}; // std::vector<pz_funcs_t> _pzFuncs{};
std::vector<MccPZoneWrapper<mount_telemetry_data_t>> _pzFuncs{};
template <typename FuncT, traits::mcc_prohibited_zone_c<mount_telemetry_data_t>... ZTs> template <typename FuncT, traits::mcc_prohibited_zone_c<mount_telemetry_data_t>... ZTs>
auto forEachPZone(FuncT&& func, std::tuple<ZTs...>& zones) auto forEachPZone(FuncT&& func, std::tuple<ZTs...>& zones)

258
cxx/mcc_generic_mount.h Normal file
View File

@ -0,0 +1,258 @@
#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

View File

@ -164,6 +164,27 @@ public:
init(telemetry, hardware, prohibited_zone); init(telemetry, hardware, prohibited_zone);
} }
MccSimpleGuidingModel(MccSimpleGuidingModel&& other)
: _guidingFunc(std::move(other._guidingFunc)),
_doCorrection(other._doCorrection.load()),
_stopRequested(other._stopRequested.load())
{
}
MccSimpleGuidingModel& operator=(MccSimpleGuidingModel&& other)
{
if (this == &other) {
return *this;
}
_guidingFunc = std::move(other._guidingFunc);
_doCorrection = other._doCorrection.load();
_stopRequested = other._stopRequested.load();
return *this;
}
virtual ~MccSimpleGuidingModel() virtual ~MccSimpleGuidingModel()
{ {
logDebug(std::format("Delete 'MccSimpleGuidingModel' class instance ({})", (void*)this)); logDebug(std::format("Delete 'MccSimpleGuidingModel' class instance ({})", (void*)this));
@ -333,4 +354,6 @@ protected:
} }
}; };
// static_assert(std::movable<MccSimpleGuidingModel<>>);
} // namespace mcc } // namespace mcc

View File

@ -151,15 +151,9 @@ public:
double mjd{51544.5}; // J2000.0 double mjd{51544.5}; // J2000.0
}; };
// typedef MccAngle coord_t;
// typedef MccAngle sideral_time_t; /* use of the same type for representation of celestial and geodetic coordinates, celestial angles (e.g. P.A.),
// typedef MccAngle pa_t; * and sideral time */
// typedef MccAngle eo_t;
/* use of the same type fro representation of celestial and geodetic coordinates, celestial angles (e.g. P.A.),
* sideral time */
typedef AngleT coord_t; typedef AngleT coord_t;
typedef AngleT sideral_time_t; typedef AngleT sideral_time_t;
@ -173,40 +167,51 @@ public:
MccMountAstromEngineERFA() = default; MccMountAstromEngineERFA() = default;
MccMountAstromEngineERFA(engine_state_t state) : _currentState(std::move(state)) {} MccMountAstromEngineERFA(engine_state_t state) : _currentState(std::move(state)), _stateMutex(new std::mutex) {}
MccMountAstromEngineERFA(MccMountAstromEngineERFA&&) = default;
MccMountAstromEngineERFA& operator=(MccMountAstromEngineERFA&&) = default;
MccMountAstromEngineERFA(const MccMountAstromEngineERFA&) = delete; MccMountAstromEngineERFA(const MccMountAstromEngineERFA&) = delete;
MccMountAstromEngineERFA& operator=(const MccMountAstromEngineERFA&) = delete; MccMountAstromEngineERFA& operator=(const MccMountAstromEngineERFA&) = delete;
MccMountAstromEngineERFA(MccMountAstromEngineERFA&& other)
: _currentState(std::move(other._currentState)), _stateMutex(std::move(other._stateMutex)) {};
MccMountAstromEngineERFA& operator=(MccMountAstromEngineERFA&& other)
{
if (this != &other) {
_currentState = std::move(other._currentState);
_stateMutex = std::move(other._stateMutex);
}
return *this;
}
virtual ~MccMountAstromEngineERFA() = default; virtual ~MccMountAstromEngineERFA() = default;
void setState(engine_state_t state) void setState(engine_state_t state)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
_currentState = std::move(state); _currentState = std::move(state);
} }
engine_state_t getState() const engine_state_t getState() const
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
return _currentState; return _currentState;
} }
void updateMeteo(meteo_t meteo) void updateMeteo(meteo_t meteo)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
_currentState.meteo = std::move(meteo); _currentState.meteo = std::move(meteo);
} }
error_t updateLeapSeconds(std::derived_from<std::basic_istream<char>> auto& stream, char comment_sym = '#') error_t updateLeapSeconds(std::derived_from<std::basic_istream<char>> auto& stream, char comment_sym = '#')
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
if (!_currentState._leapSeconds.load(stream, comment_sym)) { if (!_currentState._leapSeconds.load(stream, comment_sym)) {
return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS;
@ -218,7 +223,7 @@ public:
error_t updateLeapSeconds(traits::mcc_input_char_range auto const& filename, char comment_sym = '#') error_t updateLeapSeconds(traits::mcc_input_char_range auto const& filename, char comment_sym = '#')
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
if (!_currentState._leapSeconds.load(filename, comment_sym)) { if (!_currentState._leapSeconds.load(filename, comment_sym)) {
return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_LEAPSECONDS;
@ -230,7 +235,7 @@ public:
error_t updateBulletinA(std::derived_from<std::basic_istream<char>> auto& stream, char comment_sym = '*') error_t updateBulletinA(std::derived_from<std::basic_istream<char>> auto& stream, char comment_sym = '*')
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
if (!_currentState._bulletinA.load(stream, comment_sym)) { if (!_currentState._bulletinA.load(stream, comment_sym)) {
return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA;
@ -242,7 +247,7 @@ public:
error_t updateBulletinA(traits::mcc_input_char_range auto const& filename, char comment_sym = '*') error_t updateBulletinA(traits::mcc_input_char_range auto const& filename, char comment_sym = '*')
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
if (!_currentState._bulletinA.load(filename, comment_sym)) { if (!_currentState._bulletinA.load(filename, comment_sym)) {
return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA; return MccMountAstromEngineERFAErrorCode::ERROR_UPDATE_BULLETINA;
@ -299,7 +304,7 @@ public:
error_t terrestrialTime(juldate_t juldate, juldate_t& tt) error_t terrestrialTime(juldate_t juldate, juldate_t& tt)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
using real_days_t = std::chrono::duration<double, std::ratio<86400>>; using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
@ -320,7 +325,7 @@ public:
error_t apparentSiderTime(juldate_t juldate, sideral_time_t& gst, bool islocal = false) error_t apparentSiderTime(juldate_t juldate, sideral_time_t& gst, bool islocal = false)
{ {
// std::lock_guard lock{_stateMutex}; // std::lock_guard lock{*_stateMutex};
using real_days_t = std::chrono::duration<double, std::ratio<86400>>; using real_days_t = std::chrono::duration<double, std::ratio<86400>>;
@ -328,7 +333,7 @@ public:
// double tt = juldate.mjd; // double tt = juldate.mjd;
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd); auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
@ -384,7 +389,7 @@ public:
error_t refraction(refract_result_t& refr) error_t refraction(refract_result_t& refr)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity, eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity,
_currentState.wavelength, &refr.refa, &refr.refb); _currentState.wavelength, &refr.refa, &refr.refb);
@ -417,7 +422,7 @@ public:
coord_t& alt, coord_t& alt,
eo_t& eo) eo_t& eo)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd); auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
@ -459,7 +464,7 @@ public:
error_t obs2icrs(MccCoordPairKind coord_kind, coord_t x, coord_t y, juldate_t juldate, coord_t ra, coord_t dec) error_t obs2icrs(MccCoordPairKind coord_kind, coord_t x, coord_t y, juldate_t juldate, coord_t ra, coord_t dec)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd); auto dut1 = _currentState._bulletinA.DUT1(juldate.mjd);
@ -516,7 +521,7 @@ public:
error_t hadec2azalt(coord_t ha, coord_t dec, coord_t& az, coord_t& alt) error_t hadec2azalt(coord_t ha, coord_t dec, coord_t& az, coord_t& alt)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
double r_az, r_alt; double r_az, r_alt;
eraHd2ae(ha, dec, _currentState.lat, &r_az, &r_alt); eraHd2ae(ha, dec, _currentState.lat, &r_az, &r_alt);
@ -529,7 +534,7 @@ public:
error_t azalt2hadec(coord_t az, coord_t alt, coord_t& ha, coord_t& dec) error_t azalt2hadec(coord_t az, coord_t alt, coord_t& ha, coord_t& dec)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
double r_ha, r_dec; double r_ha, r_dec;
@ -544,7 +549,7 @@ public:
error_t hadec2pa(coord_t ha, coord_t dec, pa_t& pa) error_t hadec2pa(coord_t ha, coord_t dec, pa_t& pa)
{ {
std::lock_guard lock{_stateMutex}; std::lock_guard lock{*_stateMutex};
pa = eraHd2pa(ha, dec, _currentState.lat); pa = eraHd2pa(ha, dec, _currentState.lat);
@ -566,7 +571,7 @@ public:
protected: protected:
engine_state_t _currentState{}; engine_state_t _currentState{};
mutable std::mutex _stateMutex; std::unique_ptr<std::mutex> _stateMutex;
}; };
} // namespace mcc::astrom::erfa } // namespace mcc::astrom::erfa

View File

@ -297,7 +297,7 @@ concept mcc_mount_pec_c = requires(T t) {
// a class that contains at least celestial (equatorial and horizontal) and harware coordinates // a class that contains at least celestial (equatorial and horizontal) and harware coordinates
template <typename T> template <typename T>
concept mcc_mount_telemetry_data_c = requires(T telemetry) { concept mcc_mount_telemetry_data_c = std::movable<T> && requires(T telemetry) {
typename T::coord_t; typename T::coord_t;
typename T::time_point_t; typename T::time_point_t;
@ -423,8 +423,8 @@ concept mcc_guiding_model_c = requires(T t) {
template <typename T, typename TelemetryDataT> template <typename T, typename TelemetryDataT>
concept mcc_prohibited_zone_c = concept mcc_prohibited_zone_c =
mcc_mount_telemetry_data_c<TelemetryDataT> && std::movable<T> && requires(T t, const T t_const) { mcc_mount_telemetry_data_c<TelemetryDataT> && std::movable<T> && requires(T t, const T t_const) {
typename T::coord_t; // typename T::coord_t;
typename T::time_point_t; // typename T::time_point_t;
requires mcc_time_duration_c<typename T::duration_t>; requires mcc_time_duration_c<typename T::duration_t>;
// static constexpr member to represent inifite duration // static constexpr member to represent inifite duration
@ -436,6 +436,15 @@ concept mcc_prohibited_zone_c =
}; };
}; };
// static constexpr member to represent zero duration
requires requires {
requires std::same_as<decltype(T::zeroDuration), typename T::duration_t>;
[]() {
constexpr auto val = T::zeroDuration;
return val;
};
};
// the type 'T' must define a static constexpr member of type MccCoordPairKind // the type 'T' must define a static constexpr member of type MccCoordPairKind
// to declarate type of coordinate pair used to describe the zone. // to declarate type of coordinate pair used to describe the zone.
@ -491,6 +500,11 @@ concept mcc_prohibited_zone_c =
{ t.timeFrom(std::declval<const TelemetryDataT&>()) } -> std::same_as<typename T::duration_t>; { t.timeFrom(std::declval<const TelemetryDataT&>()) } -> std::same_as<typename T::duration_t>;
}; };
// an input range of prohibited zones
template <typename T, typename TelemetryDataT>
concept mcc_irange_of_pzones_c = mcc_mount_telemetry_data_c<TelemetryDataT> && std::ranges::input_range<T> &&
mcc_prohibited_zone_c<std::ranges::range_value_t<T>, TelemetryDataT>;
/* MOUNT GENERIC CONTROLS */ /* MOUNT GENERIC CONTROLS */
@ -511,7 +525,9 @@ concept mcc_mount_controls_c = requires(T t) {
// []<mcc_prohibited_zone_c<typename decltype(t.telemetry)::mount_telemetry_data_t>... Ts>(std::tuple<Ts...>) { // []<mcc_prohibited_zone_c<typename decltype(t.telemetry)::mount_telemetry_data_t>... Ts>(std::tuple<Ts...>) {
// }(t.prohibitedZones); // }(t.prohibitedZones);
requires mcc_tuple_c<decltype(t.prohibitedZones)>; // requires mcc_tuple_c<decltype(t.prohibitedZones)>;
requires mcc_irange_of_pzones_c<decltype(t.prohibitedZones),
typename decltype(t.telemetry)::mount_telemetry_data_t>;
}; };
@ -530,18 +546,24 @@ concept mcc_mount_c = requires(T t) {
requires mcc_astrom_engine_c<typename T::astrom_engine_t>; requires mcc_astrom_engine_c<typename T::astrom_engine_t>;
requires mcc_mount_pec_c<typename T::pec_t>; requires mcc_mount_pec_c<typename T::pec_t>;
requires mcc_mount_hardware_c<typename T::hardware_t>; requires mcc_mount_hardware_c<typename T::hardware_t>;
// requires mcc_slew_model_c<typename T::slew_model_t, typename T::mount_telemetry_t>;
requires mcc_slew_model_c<typename T::slew_model_t>; requires mcc_slew_model_c<typename T::slew_model_t>;
// requires mcc_guiding_model_c<typename T::guiding_model_t, typename T::mount_telemetry_t>;
requires mcc_guiding_model_c<typename T::guiding_model_t>; requires mcc_guiding_model_c<typename T::guiding_model_t>;
// requires std::same_as<typename T::slew_params_t, typename T::slew_model_t::slew_params_t>; // public methods
{
t.mountTelemetryData(std::declval<typename T::mount_telemetry_data_t&>())
} -> std::same_as<typename T::mount_telemetry_t::error_t>;
// public method {
{ t.mountTelemetryData() } -> std::same_as<typename T::mount_telemetry_data_t>; t.slewMount(std::declval<typename T::slew_model_t::slew_point_t>())
} -> std::same_as<typename T::slew_model_t::error_t>;
{
t.guidingTarget(std::declval<typename T::guiding_model_t::guiding_point_t>())
} -> std::same_as<typename T::guiding_model_t::error_t>;
}; };
// generic with logging methods // generic with public logging methods
template <typename T> template <typename T>
concept mcc_log_mount_c = mcc_mount_c<T> && mcc_logger_c<T>; concept mcc_log_mount_c = mcc_mount_c<T> && mcc_logger_c<T>;

View File

@ -23,10 +23,7 @@ enum class MccMountDefaultPECErrorCode : int { ERROR_OK, ERROR_INVALID_INPUTS_BI
struct MccMountDefaultPECCategory : public std::error_category { struct MccMountDefaultPECCategory : public std::error_category {
MccMountDefaultPECCategory() : std::error_category() {} MccMountDefaultPECCategory() : std::error_category() {}
const char* name() const noexcept const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; }
{
return "ADC_GENERIC_DEVICE";
}
std::string message(int ec) const std::string message(int ec) const
{ {
@ -140,14 +137,41 @@ public:
: _pecData(std::move(pdata)), : _pecData(std::move(pdata)),
_phi(_pecData.siteLatitude), _phi(_pecData.siteLatitude),
_geomCoeffs(_pecData.geomCoefficients), _geomCoeffs(_pecData.geomCoefficients),
_bsplCoeffs(_pecData.bsplineCoefficients) _bsplCoeffs(_pecData.bsplineCoefficients),
_pecDataMutex(new std::mutex)
{ {
} }
MccMountDefaultPEC(const MccMountDefaultPEC&) = delete;
MccMountDefaultPEC& operator=(const MccMountDefaultPEC&) = delete;
MccMountDefaultPEC(MccMountDefaultPEC&& other)
: _pecData(std::move(other._pecData)),
_phi(_pecData.siteLatitude),
_geomCoeffs(_pecData.geomCoefficients),
_bsplCoeffs(_pecData.bsplineCoefficients),
_pecDataMutex(std::move(other._pecDataMutex))
{
}
MccMountDefaultPEC& operator=(MccMountDefaultPEC&& other)
{
if (this == &other) {
return *this;
}
_pecData = std::move(other._pecData);
_phi = _pecData.siteLatitude;
_geomCoeffs = _pecData.geomCoefficients;
_bsplCoeffs = _pecData.bsplineCoefficients;
_pecDataMutex = std::move(other._pecDataMutex);
return *this;
}
void setData(pec_data_t pdata) void setData(pec_data_t pdata)
{ {
std::lock_guard lock(_pecDataMutex); std::lock_guard lock(*_pecDataMutex);
_pecData = std::move(pdata); _pecData = std::move(pdata);
_phi = _pecData.siteLatitude; _phi = _pecData.siteLatitude;
@ -158,21 +182,21 @@ public:
pec_data_t getData() const pec_data_t getData() const
{ {
std::lock_guard lock(_pecDataMutex); std::lock_guard lock(*_pecDataMutex);
return _pecData; return _pecData;
} }
void setType(MccMountDefaultPECType type) void setType(MccMountDefaultPECType type)
{ {
std::lock_guard lock(_pecDataMutex); std::lock_guard lock(*_pecDataMutex);
_pecData.type = type; _pecData.type = type;
} }
MccMountDefaultPECType getType() const MccMountDefaultPECType getType() const
{ {
std::lock_guard lock(_pecDataMutex); std::lock_guard lock(*_pecDataMutex);
return _pecData.type; return _pecData.type;
} }
@ -183,7 +207,7 @@ public:
// so, input x and y are assumed to be mount axis encoder coordinates // so, input x and y are assumed to be mount axis encoder coordinates
error_t compute(const coord_t& x, const coord_t& y, pec_result_t& res) error_t compute(const coord_t& x, const coord_t& y, pec_result_t& res)
{ {
std::lock_guard lock(_pecDataMutex); std::lock_guard lock(*_pecDataMutex);
if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial
if (_pecData.type == MccMountDefaultPECType::PEC_TYPE_GEOMETRY) { if (_pecData.type == MccMountDefaultPECType::PEC_TYPE_GEOMETRY) {
@ -249,70 +273,6 @@ public:
return MccMountDefaultPECErrorCode::ERROR_OK; return MccMountDefaultPECErrorCode::ERROR_OK;
} }
// from celestial to encoder (use of iterative scheme)
error_t reverseCompute(const coord_t& x, const coord_t& y, pec_result_t& res, coord_t eps, size_t max_iter = 5)
{
coord_t e2 = eps * eps;
coord_t xi = x, yi = y;
coord_t xe, ye;
size_t iter = 1;
// the first iteration
auto err = compute(x, y, res);
if (!err) {
// 'encoder' cocordinates
xe = x - res.dx;
ye = y - res.dy;
err = compute(xe, ye, res); // to celestial
if (err) {
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
}
xi = xe + res.dx; // celestial
yi = ye + res.dy;
auto rx = (x - xi);
auto ry = (y - yi);
auto d = rx * rx + ry * ry;
bool ok = d <= e2;
if (ok) {
return MccMountDefaultPECErrorCode::ERROR_OK;
}
while (iter < max_iter) {
err = compute(xi, yi, res); // to encoder
if (err) {
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
}
xe = x - res.dx;
ye = y - res.dy;
err = compute(xe, ye, res); // to celestial
if (err) {
return MccMountDefaultPECErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
}
xi = xe + res.dx; // celestial
yi = ye + res.dy;
ok = ((x - xi) * (x - xi) + (y - yi) * (y - yi)) <= e2;
if (ok) {
return MccMountDefaultPECErrorCode::ERROR_OK;
}
++iter;
}
err = MccMountDefaultPECErrorCode::ERROR_EXCEED_MAX_ITERS;
}
return err;
}
private: private:
pec_data_t _pecData; pec_data_t _pecData;
@ -320,7 +280,7 @@ private:
pec_geom_coeffs_t& _geomCoeffs; pec_geom_coeffs_t& _geomCoeffs;
pec_bspline_coeffs_t& _bsplCoeffs; pec_bspline_coeffs_t& _bsplCoeffs;
mutable std::mutex _pecDataMutex; std::unique_ptr<std::mutex> _pecDataMutex;
}; };
@ -328,6 +288,7 @@ typedef MccMountDefaultPEC<MccMountType::ALTAZ_TYPE> MccMountDefaultAltAzPec;
typedef MccMountDefaultPEC<MccMountType::FORK_TYPE> MccMountDefaultForkPec; typedef MccMountDefaultPEC<MccMountType::FORK_TYPE> MccMountDefaultForkPec;
static_assert(traits::mcc_mount_pec_c<MccMountDefaultForkPec>, ""); static_assert(traits::mcc_mount_pec_c<MccMountDefaultForkPec>, "");
static_assert(std::movable<MccMountDefaultForkPec>);
} // namespace mcc } // namespace mcc

View File

@ -45,8 +45,6 @@ public:
static constexpr duration_t infiniteDuration{std::numeric_limits<double>::infinity()}; static constexpr duration_t infiniteDuration{std::numeric_limits<double>::infinity()};
static constexpr duration_t zeroDuration{0.0}; static constexpr duration_t zeroDuration{0.0};
//
// TODO: add context (e.g. TT-TAI, UT1-UTC, geo location and so on)!!!
MccAltLimitPZ(const MccAngle& alt_limit, const MccAngle& lat) MccAltLimitPZ(const MccAngle& alt_limit, const MccAngle& lat)
// : MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE" // : MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE"
// : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE" // : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"

View File

@ -148,6 +148,32 @@ public:
{ {
} }
MccMountTelemetry(MccMountTelemetry&& other)
: base_t(std::move(other)),
_data(std::move(other._data)),
_hardware(other._hardware),
_updateMutex(std::move(other._updateMutex)),
_updateCondVar(std::move(other._updateCondVar))
{
}
MccMountTelemetry& operator=(MccMountTelemetry&& other)
{
if (this == &other) {
return *this;
}
base_t::operator=(std::move(other));
_data = std::move(other._data);
_hardware = other._hardware;
_updateMutex = std::move(other._updateMutex);
_updateCondVar = std::move(other._updateCondVar);
return *this;
}
virtual ~MccMountTelemetry() = default; virtual ~MccMountTelemetry() = default;
@ -155,7 +181,7 @@ public:
template <traits::mcc_celestial_point_c PointT> template <traits::mcc_celestial_point_c PointT>
error_t setTarget(PointT tag_point) error_t setTarget(PointT tag_point)
{ {
std::lock_guard lock{_updateMutex}; std::lock_guard lock{*_updateMutex};
auto err = this->toICRS(tag_point, _data.utc, _data.tagRA_ICRS, _data.tagDEC_ICRS); auto err = this->toICRS(tag_point, _data.utc, _data.tagRA_ICRS, _data.tagDEC_ICRS);
if (!err) { if (!err) {
@ -168,7 +194,7 @@ public:
// target - mount coordinate difference // target - mount coordinate difference
auto targetToMountDiff() auto targetToMountDiff()
{ {
std::lock_guard lk(_updateMutex); std::lock_guard lk(*_updateMutex);
coord_diff_t result; coord_diff_t result;
@ -232,13 +258,16 @@ public:
// correction for PEC // compute corrections for PEC and celestial apparent coordinates
if constexpr (base_t::equatorialMount) { if constexpr (base_t::equatorialMount) {
res_err = this->toApparent(point_t{.coordPairKind = MccCoordPairKind::COORDS_KIND_XY, res_err = this->toApparent(point_t{.coordPairKind = MccCoordPairKind::COORDS_KIND_XY,
.x = current_data.mntPosX, .x = current_data.mntPosX,
.y = current_data.mntPosY}, .y = current_data.mntPosY},
current_data.utc, current_data.mntHA, current_data.mntDEC); current_data.utc, current_data.mntHA, current_data.mntDEC);
if (!res_err) { if (!res_err) {
current_data.pecX = current_data.mntHA - current_data.mntPosX;
current_data.pecY = current_data.mntDEC - current_data.mntPosY;
ast_err = this->_astromEngine.hadec2azalt(current_data.mntHA, current_data.mntDEC, current_data.mntAZ, ast_err = this->_astromEngine.hadec2azalt(current_data.mntHA, current_data.mntDEC, current_data.mntAZ,
current_data.mntALT); current_data.mntALT);
} }
@ -248,6 +277,9 @@ public:
.y = current_data.mntPosY}, .y = current_data.mntPosY},
current_data.utc, current_data.mntAZ, current_data.mntALT); current_data.utc, current_data.mntAZ, current_data.mntALT);
if (!res_err) { if (!res_err) {
current_data.pecX = current_data.mntAZ - current_data.mntPosX;
current_data.pecY = current_data.mntALT - current_data.mntPosY;
ast_err = this->_astromEngine.azalt2hadec(current_data.mntAZ, current_data.mntALT, current_data.mntHA, ast_err = this->_astromEngine.azalt2hadec(current_data.mntAZ, current_data.mntALT, current_data.mntHA,
current_data.mntDEC); current_data.mntDEC);
} }
@ -284,12 +316,12 @@ public:
return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP; return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP;
} }
std::lock_guard lock{_updateMutex}; std::lock_guard lock{*_updateMutex};
_data = std::move(current_data); _data = std::move(current_data);
// notify all threads for new telemetry data // notify all threads for new telemetry data
_updateCondVar.notify_all(); _updateCondVar->notify_all();
return MccMountTelemetryErrorCode::ERROR_OK; return MccMountTelemetryErrorCode::ERROR_OK;
} }
@ -297,7 +329,7 @@ public:
error_t data(mount_telemetry_data_t& data) error_t data(mount_telemetry_data_t& data)
{ {
std::lock_guard lock{_updateMutex}; std::lock_guard lock{*_updateMutex};
data = _data; data = _data;
@ -310,9 +342,9 @@ public:
{ {
auto timeout_tp = std::chrono::steady_clock::now() + timeout; auto timeout_tp = std::chrono::steady_clock::now() + timeout;
std::unique_lock lk(_updateMutex); std::unique_lock lk(*_updateMutex);
auto res = _updateCondVar.wait_until( auto res = _updateCondVar->wait_until(
lk, timeout_tp, [last_time_point = _data.time_point, this]() { return last_time_point < _data.timepoint; }); lk, timeout_tp, [last_time_point = _data.time_point, this]() { return last_time_point < _data.timepoint; });
if (res == std::cv_status::timeout) { if (res == std::cv_status::timeout) {
return MccMountTelemetryErrorCode::ERROR_DATA_TIMEOUT; return MccMountTelemetryErrorCode::ERROR_DATA_TIMEOUT;
@ -327,8 +359,8 @@ protected:
mount_telemetry_data_t _data{}; mount_telemetry_data_t _data{};
hardware_t& _hardware; hardware_t& _hardware;
std::mutex _updateMutex; std::unique_ptr<std::mutex> _updateMutex;
std::condition_variable _updateCondVar; std::unique_ptr<std::condition_variable> _updateCondVar;
}; };

View File

@ -109,6 +109,41 @@ public:
{ {
} }
MccMountTelemetryAstromTransform(MccMountTelemetryAstromTransform&& other)
: _pec(other._pec), _astromEngine(other._astromEngine)
{
}
MccMountTelemetryAstromTransform& operator=(MccMountTelemetryAstromTransform&& other)
{
if (this == &other) {
return;
}
_pec = other._pec;
_astromEngine = other._astromEngine;
return *this;
}
MccMountTelemetryAstromTransform(const MccMountTelemetryAstromTransform& other)
: _pec(other._pec), _astromEngine(other._astromEngine)
{
}
MccMountTelemetryAstromTransform& operator=(const MccMountTelemetryAstromTransform& other)
{
if (this == &other) {
return;
}
_pec = other._pec;
_astromEngine = other._astromEngine;
return *this;
}
virtual ~MccMountTelemetryAstromTransform() = default; virtual ~MccMountTelemetryAstromTransform() = default;
template <traits::mcc_celestial_point_c CT> template <traits::mcc_celestial_point_c CT>
@ -189,9 +224,12 @@ public:
} }
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
if constexpr (equatorialMount) { if constexpr (equatorialMount) {
ast_err = azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC ast_err = _astromEngine.azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC
if (!ast_err) { // compute CIO RA (as XX_app) if (!ast_err) { // compute CIO RA (as XX_app)
ast_err = toApparent(X_app, Y_app, X_app, Y_app, XX_app); coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
coord.x = X_app;
coord.y = Y_app;
ast_err = toApparent(std::move(coord), std::move(time_point), X_app, Y_app, XX_app);
} }
} else if (altAzMount) { } else if (altAzMount) {
X_app = coord.x; X_app = coord.x;
@ -465,4 +503,5 @@ protected:
pec_t& _pec; pec_t& _pec;
}; };
} // namespace mcc } // namespace mcc

View File

@ -95,5 +95,29 @@ auto mccCheckInZonePZTuple(const TelemetryDataT& telemetry_data,
}(std::make_index_sequence<sizeof...(ZTs)>{}); }(std::make_index_sequence<sizeof...(ZTs)>{});
} }
template <traits::mcc_mount_telemetry_data_c TelemetryDataT,
traits::mcc_irange_of_pzones_c<TelemetryDataT> RT,
std::ranges::output_range<bool> ResT>
auto mccCheckInZonePZRange(const TelemetryDataT& telemetry_data, const RT& pzones, ResT& result)
{
auto Npz = std::ranges::distance(pzones);
if (!Npz) {
return;
}
auto res_sz = std::ranges::distance(result);
size_t i = 1;
auto res_iter = result.begin();
for (auto& el : pzones) {
if (i > res_sz) {
std::back_inserter(result) = el.inZone(telemetry_data);
} else {
std::ranges::advance(res_iter, 1);
*res_iter = el.inZone(telemetry_data);
}
++i;
}
}
} // namespace mcc } // namespace mcc

View File

@ -150,10 +150,25 @@ public:
init(telemetry, hardware, prohibited_zone); init(telemetry, hardware, prohibited_zone);
} }
MccSimpleSlewModel(MccSimpleSlewModel&&) = default; MccSimpleSlewModel(MccSimpleSlewModel&& other)
MccSimpleSlewModel& operator=(MccSimpleSlewModel&&) = default; : _stopRequested(other._stopRequested.load()), _slewFunc(std::move(other._slewFunc))
MccSimpleSlewModel(const MccSimpleSlewModel&) = default; {
MccSimpleSlewModel& operator=(const MccSimpleSlewModel&) = default; }
MccSimpleSlewModel& operator=(MccSimpleSlewModel&& other)
{
if (this == &other) {
return *this;
}
_stopRequested = other._stopRequested.load();
_slewFunc = std::move(_slewFunc);
return *this;
};
MccSimpleSlewModel(const MccSimpleSlewModel&) = delete;
MccSimpleSlewModel& operator=(const MccSimpleSlewModel&) = delete;
virtual ~MccSimpleSlewModel() virtual ~MccSimpleSlewModel()
{ {
@ -422,5 +437,6 @@ protected:
} }
}; };
static_assert(std::movable<MccSimpleSlewModel<>>);
} // namespace mcc } // namespace mcc