This commit is contained in:
Timur A. Fatkhullin 2025-08-24 01:30:14 +03:00
parent 06c8345fc9
commit dc87ce0fb9

View File

@ -7,6 +7,7 @@
#include <condition_variable> #include <condition_variable>
#include <future>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
@ -24,6 +25,7 @@ enum MccTelemetryErrorCode : int {
ERROR_COORD_TRANSFORM, ERROR_COORD_TRANSFORM,
ERROR_PCM_COMP, ERROR_PCM_COMP,
ERROR_HARDWARE_GETPOS, ERROR_HARDWARE_GETPOS,
ERROR_UPDATE_STOPPED,
ERROR_DATA_TIMEOUT ERROR_DATA_TIMEOUT
}; };
@ -69,6 +71,8 @@ struct MccTelemetryCategory : public std::error_category {
return "PCM computation error"; return "PCM computation error";
case MccTelemetryErrorCode::ERROR_HARDWARE_GETPOS: case MccTelemetryErrorCode::ERROR_HARDWARE_GETPOS:
return "cannot get hardware position"; return "cannot get hardware position";
case MccTelemetryErrorCode::ERROR_UPDATE_STOPPED:
return "telemetry update was stopped";
case MccTelemetryErrorCode::ERROR_DATA_TIMEOUT: case MccTelemetryErrorCode::ERROR_DATA_TIMEOUT:
return "a timeout occured while waiting for new data"; return "a timeout occured while waiting for new data";
default: default:
@ -114,7 +118,7 @@ public:
using hardware_t = std::remove_cvref_t<decltype(*hardware)>; using hardware_t = std::remove_cvref_t<decltype(*hardware)>;
_updateTargetFunc = [ccte, pcm, this](bool only_hw) -> error_t { _updateTargetFunc = [ccte, pcm, this](bool only_hw, std::stop_token stop_token) -> error_t {
if (!only_hw) { if (!only_hw) {
// //
// compute apparent coordinates // compute apparent coordinates
@ -135,6 +139,11 @@ public:
} }
} }
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
// compute hardware coordinates // compute hardware coordinates
// WARNING: It is assumed here that PCM corrections have small (arcseconds-arcminutes) values // WARNING: It is assumed here that PCM corrections have small (arcseconds-arcminutes) values
// since ususaly there is no reverse transformation for "hardware-to-apparent" relation! // since ususaly there is no reverse transformation for "hardware-to-apparent" relation!
@ -179,7 +188,7 @@ public:
return MccTelemetryErrorCode::ERROR_OK; return MccTelemetryErrorCode::ERROR_OK;
}; };
_updateFunc = [ccte, pcm, hardware, this]() { _updateFunc = [ccte, pcm, hardware, this](std::stop_token stop_token) {
// first, update mount quantities // first, update mount quantities
typename hardware_t::axes_pos_t hw_pos; typename hardware_t::axes_pos_t hw_pos;
auto hw_err = hardware->getPos(&hw_pos); auto hw_err = hardware->getPos(&hw_pos);
@ -187,6 +196,10 @@ public:
return mcc_deduce_error(hw_err, MccTelemetryErrorCode::ERROR_HARDWARE_GETPOS); return mcc_deduce_error(hw_err, MccTelemetryErrorCode::ERROR_HARDWARE_GETPOS);
} }
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
double eo; double eo;
_data.time_point = _data.time_point =
@ -194,8 +207,16 @@ public:
auto ccte_err = ccte->timepointToJulday(_data.time_point, &_data.JD); auto ccte_err = ccte->timepointToJulday(_data.time_point, &_data.JD);
if (!ccte_err) { if (!ccte_err) {
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
ccte_err = ccte->juldayToAppSideral(_data.JD, &_data.LST, true); ccte_err = ccte->juldayToAppSideral(_data.JD, &_data.LST, true);
if (!ccte_err) { if (!ccte_err) {
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
ccte_err = ccte->equationOrigins(_data.JD, &eo); ccte_err = ccte->equationOrigins(_data.JD, &eo);
} }
} }
@ -204,6 +225,10 @@ public:
return mcc_deduce_error(ccte_err, MccTelemetryErrorCode::ERROR_COORD_TRANSFORM); return mcc_deduce_error(ccte_err, MccTelemetryErrorCode::ERROR_COORD_TRANSFORM);
} }
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
_data.speedX = (double)hw_pos.speedX; _data.speedX = (double)hw_pos.speedX;
_data.speedY = (double)hw_pos.speedY; _data.speedY = (double)hw_pos.speedY;
@ -219,6 +244,10 @@ public:
_data.pcmX = pcm_res.dx; _data.pcmX = pcm_res.dx;
_data.pcmY = pcm_res.dy; _data.pcmY = pcm_res.dy;
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT, .time_point = _data.time_point}; MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT, .time_point = _data.time_point};
if constexpr (mccIsEquatorialMount(pcm_t::mountType)) { if constexpr (mccIsEquatorialMount(pcm_t::mountType)) {
@ -260,6 +289,10 @@ public:
} }
if (!ccte_err) { if (!ccte_err) {
if (stop_token.stop_requested()) {
return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED;
}
_data.pair_kind = MccCoordPairKind::COORDS_KIND_AZZD; _data.pair_kind = MccCoordPairKind::COORDS_KIND_AZZD;
_data.X = _data.AZ; _data.X = _data.AZ;
_data.Y = _data.ZD; _data.Y = _data.ZD;
@ -272,7 +305,7 @@ public:
// update target (assuming target ICRS coordinates are already set) // update target (assuming target ICRS coordinates are already set)
auto ret = _updateTargetFunc(false); auto ret = _updateTargetFunc(false, stop_token);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -314,7 +347,7 @@ public:
_data.target.DEC_ICRS = _data.target.Y; _data.target.DEC_ICRS = _data.target.Y;
// update apparent coordinates // update apparent coordinates
ret = _updateTargetFunc(false); ret = _updateTargetFunc(false, {});
} else { // apparent coordinates were computed above } else { // apparent coordinates were computed above
// compute ICRS coordinates // compute ICRS coordinates
MccCelestialPoint cpt{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS}; MccCelestialPoint cpt{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
@ -324,7 +357,7 @@ public:
_data.target.DEC_ICRS = cpt.Y; _data.target.DEC_ICRS = cpt.Y;
// compute only hardware coordinates // compute only hardware coordinates
ret = _updateTargetFunc(true); ret = _updateTargetFunc(true, {});
} }
} }
@ -335,49 +368,76 @@ public:
virtual ~MccTelemetry() = default; virtual ~MccTelemetry() = default;
template <traits::mcc_time_duration_c DT>
DT telemetryDataUpdateInterval() const
{
return std::chrono::duration_cast<DT>(_currentUpdateInterval);
}
std::chrono::milliseconds telemetryDataUpdateInterval() const
{
return telemetryDataUpdateInterval<std::chrono::milliseconds>();
}
error_t updateTelemetryData(traits::mcc_time_duration_c auto const& period) error_t updateTelemetryData(traits::mcc_time_duration_c auto const& period)
{ {
using d_t = typename std::remove_cvref_t<decltype(period)>::rep; // using d_t = typename std::remove_cvref_t<decltype(period)>::rep;
bool is_zero; // bool is_zero;
if (std::floating_point<d_t>) { // if (std::floating_point<d_t>) {
is_zero = utils::isEqual(period.count(), d_t::zero()); // is_zero = utils::isEqual(period.count(), d_t::zero());
} else { // } else {
is_zero = period.count() == d_t::zero(); // is_zero = period.count() == d_t::zero();
// }
// if (is_zero) { // just update once
// return _updateFunc();
// } else {
// // try to update once
// auto ret = _updateFunc();
// if (ret) {
// return ret;
// }
// _lastUpdateError = MccTelemetryErrorCode::ERROR_OK;
// _timerThread = [period, this](std::stop_token st) {
// while (!st.stop_requested()) {
// {
// std::lock_guard thread_lock{*_updateMutex};
// _lastUpdateError = _updateFunc();
// _updateCondVar->notify_all();
// if (_lastUpdateError) {
// return;
// }
// }
// std::this_thread::sleep_for(period);
// }
// };
// _timerThread.detach();
// return MccTelemetryErrorCode::ERROR_OK;
// }
std::lock_guard thread_lock{*_updateMutex};
std::stop_source stop_source;
std::future<error_t> update_ft = std::async(std::launch::async, _updateFunc, stop_source.get_token());
auto status = update_ft.wait_for(period);
if (status != std::future_status::ready) {
auto ok = stop_source.stop_requested();
return MccTelemetryErrorCode::ERROR_DATA_TIMEOUT;
} }
if (is_zero) { // just update once _updateCondVar->notify_all();
return _updateFunc();
} else {
// try to update once
auto ret = _updateFunc();
if (ret) {
return ret;
}
_lastUpdateError = MccTelemetryErrorCode::ERROR_OK; return update_ft.get();
_timerThread = [period, this](std::stop_token st) {
while (!st.stop_requested()) {
{
std::lock_guard thread_lock{*_updateMutex};
_lastUpdateError = _updateFunc();
_updateCondVar->notify_all();
if (_lastUpdateError) {
return;
}
}
std::this_thread::sleep_for(period);
}
};
_timerThread.detach();
return MccTelemetryErrorCode::ERROR_OK;
}
} }
// block the thread and wait for data to be ready (external synchronization) // block the thread and wait for data to be ready (external synchronization)
@ -412,13 +472,17 @@ public:
std::lock_guard thread_lock{*_updateMutex}; std::lock_guard thread_lock{*_updateMutex};
error_t ret = _updateFunc(); // error_t ret = _updateFunc();
if (!ret) { // if (!ret) {
mcc_copy_telemetry_data(_data, tdata); // mcc_copy_telemetry_data(_data, tdata);
} // }
return ret; // return ret;
mcc_copy_telemetry_data(_data, tdata);
return MccTelemetryErrorCode::ERROR_OK;
} }
@ -434,8 +498,10 @@ protected:
std::atomic_bool _updated; std::atomic_bool _updated;
MccTelemetryData _data; MccTelemetryData _data;
std ::function<error_t(bool)> _updateTargetFunc{}; std::chrono::nanoseconds _currentUpdateInterval{std::chrono::milliseconds(100)};
std::function<error_t()> _updateFunc{};
std ::function<error_t(bool, std::stop_token)> _updateTargetFunc{};
std::function<error_t(std::stop_token)> _updateFunc{};
std::function<error_t()> _setTargetFunc{}; std::function<error_t()> _setTargetFunc{};
std::unique_ptr<std::mutex> _updateMutex; std::unique_ptr<std::mutex> _updateMutex;