264 lines
8.9 KiB
C++
264 lines
8.9 KiB
C++
#pragma once
|
|
|
|
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
|
|
|
|
|
|
|
/* AN GENERIC MOUNT CLASS IMPLEMENTATION BASED ON FINITE STATE MACHINE */
|
|
|
|
#include <chrono>
|
|
#include <functional>
|
|
#include <string_view>
|
|
#include "spdlog/sinks/null_sink.h"
|
|
|
|
#include "mcc_mount_concepts.h"
|
|
#include "mcc_mount_coord.h"
|
|
#include "mcc_spdlog.h"
|
|
#include "mcc_traits.h"
|
|
|
|
|
|
#include "mcc_finite_state_machine.h"
|
|
#include "mcc_mount_events_states.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> 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>
|
|
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'
|
|
// friend class MccMountStateSlew<MccMount<MOUNT_CONTROLS>>;
|
|
// friend class MccMountStateGuiding<MccMount<MOUNT_CONTROLS>>;
|
|
|
|
public:
|
|
typedef MOUNT_CONTROLS mount_controls_t;
|
|
typedef decltype(mount_controls_t::telemetry) mount_telemetry_t;
|
|
typedef typename mount_telemetry_t::mount_telemetry_data_t mount_telemetry_data_t;
|
|
|
|
typedef decltype(mount_controls_t::astrometryEngine) astrom_engine_t;
|
|
typedef decltype(mount_controls_t::PEC) pec_t;
|
|
typedef decltype(mount_controls_t::hardware) hardware_t;
|
|
typedef decltype(mount_controls_t::slewModel) slew_model_t;
|
|
typedef decltype(mount_controls_t::guidingModel) guiding_model_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 */
|
|
|
|
template <fsm::traits::fsm_state_c InitStateT, traits::mcc_input_char_range LogMarkT = std::string_view>
|
|
MccMount(mount_controls_t mount_controls,
|
|
InitStateT,
|
|
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("NULL"),
|
|
const LogMarkT& logger_mark = "[MOUNT]")
|
|
: fsm::MccFiniteStateMachine(InitStateT{}),
|
|
utils::MccSpdlogLogger(logger),
|
|
mount_controls_t(std::move(mount_controls))
|
|
{
|
|
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()));
|
|
}
|
|
|
|
MccMount(const MccMount&) = delete;
|
|
MccMount& operator=(const MccMount&) = delete;
|
|
|
|
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_telemetry_data_t mountTelemetryData() const
|
|
{
|
|
mount_telemetry_data_t mnt_data;
|
|
|
|
auto err = this->telemetry.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));
|
|
|
|
using d_t = typename MccPZoneWrapper<mount_telemetry_data_t>::pz_duration_t;
|
|
|
|
_pzFuncs.emplace_back(
|
|
{.coordPairKind = ZT::zoneCoordPairKind,
|
|
.name = [zone_ptr]() { return std::format("{}", zone_ptr->name()); },
|
|
.inZone = [zone_ptr](const mount_telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); },
|
|
.timeTo =
|
|
[zone_ptr](const mount_telemetry_data_t& tmry_data) {
|
|
auto d = zone_ptr->timeTo(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)) {
|
|
pzAddZone(std::move(zones)...);
|
|
}
|
|
|
|
return _pzFuncs.size();
|
|
}
|
|
|
|
// delete all zones from mount control system
|
|
void pzClearZone()
|
|
{
|
|
// stop mount here?!!
|
|
_pzFuncs.clear();
|
|
}
|
|
|
|
|
|
protected:
|
|
// 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{};
|
|
std::vector<MccPZoneWrapper<mount_telemetry_data_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
|