From 78e4bb182cf2e3d517a6798a5d7ee5016cc50b32 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Tue, 28 Oct 2025 18:01:22 +0300 Subject: [PATCH] ... --- asibfm700/asibfm700_common.h | 3 +- asibfm700/asibfm700_mount.cpp | 43 +++++ asibfm700/asibfm700_mount.h | 14 +- asibfm700/asibfm700_netserver.cpp | 2 +- asibfm700/asibfm700_netserver.h | 82 ++++++++- mcc/mcc_ccte_iers.h | 14 +- mcc/mcc_defaults.h | 23 ++- mcc/mcc_netserver.h | 25 ++- mcc/mcc_netserver_proto.h | 267 +++++++++++------------------- mcc/tests/netmsg_test.cpp | 4 +- 10 files changed, 277 insertions(+), 200 deletions(-) diff --git a/asibfm700/asibfm700_common.h b/asibfm700/asibfm700_common.h index efd3283..75502e9 100644 --- a/asibfm700/asibfm700_common.h +++ b/asibfm700/asibfm700_common.h @@ -12,13 +12,14 @@ #include #include "asibfm700_servocontroller.h" +#include "mcc_ccte_erfa.h" namespace asibfm700 { static constexpr mcc::MccMountType asibfm700MountType = mcc::MccMountType::FORK_TYPE; - +typedef mcc::ccte::erfa::MccCCTE_ERFA Asibfm700CCTE; typedef mcc::MccDefaultPCM Asibfm700PCM; typedef mcc::MccPZoneContainer Asibfm700PZoneContainer; typedef mcc::utils::MccSpdlogLogger Asibfm700Logger; diff --git a/asibfm700/asibfm700_mount.cpp b/asibfm700/asibfm700_mount.cpp index 8772f66..05c6d9f 100644 --- a/asibfm700/asibfm700_mount.cpp +++ b/asibfm700/asibfm700_mount.cpp @@ -115,8 +115,51 @@ Asibfm700Mount::error_t Asibfm700Mount::initMount() if (hw_err) { errorLogging("", hw_err); return hw_err; + } else { + logInfo("Hardware initialization was performed sucessfully!"); } + logInfo("ERFA engine initialization ..."); + + // set ERFA state + Asibfm700CCTE::engine_state_t ccte_state{.meteo{}, + .wavelength = _mountConfig.refractWavelength(), + .lat = _mountConfig.siteLatitude(), + .lon = _mountConfig.siteLongitude(), + .elev = _mountConfig.siteElevation()}; + + + if (!_mountConfig.leapSecondFilename().empty()) { // load leap seconds file + logInfo("Loading leap second file: {} ...", _mountConfig.leapSecondFilename()); + bool ok = ccte_state._leapSeconds.load(_mountConfig.leapSecondFilename()); + if (ok) { + logInfo("Leap second file was loaded successfully (expire date: {})", ccte_state._leapSeconds.expireDate()); + } else { + logError("Leap second file loading failed! Using hardcoded defauls (expire date: {})", + ccte_state._leapSeconds.expireDate()); + } + } else { + logError("Using hardcoded leap seconds defauls (expire date: {})", ccte_state._leapSeconds.expireDate()); + } + + if (!_mountConfig.bulletinAFilename().empty()) { // load IERS Bulletin A file + logInfo("Loading IERS Bulletin A file: {} ...", _mountConfig.bulletinAFilename()); + bool ok = ccte_state._bulletinA.load(_mountConfig.bulletinAFilename()); + if (ok) { + logInfo("IERS Bulletin A file was loaded successfully (date range: {} - {})", + ccte_state._bulletinA.dateRange().begin, ccte_state._bulletinA.dateRange().end); + } else { + logError("IERS Bulletin A file loading failed! Using hardcoded defauls (date range: {} - {})", + ccte_state._bulletinA.dateRange().begin, ccte_state._bulletinA.dateRange().end); + } + } else { + logError("Using hardcoded IERS Bulletin A defauls (date range: {} - {})", + ccte_state._bulletinA.dateRange().begin, ccte_state._bulletinA.dateRange().end); + } + + setStateERFA(std::move(ccte_state)); + + return mcc::MccGenericMountErrorCode::ERROR_OK; } diff --git a/asibfm700/asibfm700_mount.h b/asibfm700/asibfm700_mount.h index 9b8bdb7..551fa22 100644 --- a/asibfm700/asibfm700_mount.h +++ b/asibfm700/asibfm700_mount.h @@ -1,9 +1,7 @@ #pragma once -#include #include -#include #include #include #include @@ -19,8 +17,8 @@ namespace asibfm700 -class Asibfm700Mount : public mcc::ccte::erfa::MccCCTE_ERFA, - public mcc::MccDefaultPCM, +class Asibfm700Mount : public Asibfm700CCTE, + public Asibfm700PCM, public mcc::MccGenericFsmMount -Asibfm700MountNetserver::Asibfm700MountNetserver(asio::io_context& ctx, +Asibfm700MountNetServer::Asibfm700MountNetServer(asio::io_context& ctx, std::shared_ptr logger, const R& pattern_range) : _base_t(ctx, [this](std::string_view msg) { return handleMessage(msg); }, std::move(logger), pattern_range) diff --git a/asibfm700/asibfm700_netserver.h b/asibfm700/asibfm700_netserver.h index 7f5deef..2ee085c 100644 --- a/asibfm700/asibfm700_netserver.h +++ b/asibfm700/asibfm700_netserver.h @@ -8,17 +8,93 @@ namespace asibfm700 { -class Asibfm700MountNetserver : public mcc::network::MccGenericNetworkServer +namespace details +{ + +template +static constexpr auto merge_arrays(const std::array& arr1, const std::array& arr2) +{ + constexpr auto N = N1 + N2; + std::array res; + + for (size_t i = 0; i < N1; ++i) { + res[i] = arr1[i]; + } + + for (size_t i = N1; i < N; ++i) { + res[i] = arr2[i - N1]; + } + + return res; +} + +} // namespace details + +constexpr static std::string_view ASIBFM700_COMMPROTO_KEYWORD_METEO_STR{"METEO"}; + +struct Asibfm700NetMessageValidKeywords { + static constexpr std::array NETMSG_VALID_KEYWORDS = + details::merge_arrays(mcc::network::MccNetMessageValidKeywords::NETMSG_VALID_KEYWORDS, + std::array{ASIBFM700_COMMPROTO_KEYWORD_METEO_STR}); + + // hashes of valid keywords + static constexpr std::array NETMSG_VALID_KEYWORD_HASHES = [](std::index_sequence) { + return std::array{mcc::utils::FNV1aHash(NETMSG_VALID_KEYWORDS[Is])...}; + }(std::make_index_sequence()); + + constexpr static const size_t* isKeywordValid(std::string_view key) + { + const auto hash = mcc::utils::FNV1aHash(key); + + for (auto const& h : NETMSG_VALID_KEYWORD_HASHES) { + if (h == hash) { + return &h; + } + } + + return nullptr; + } +}; + +template +class Asibfm700MountNetMessage : public mcc::network::MccNetMessage +{ +protected: + using base_t = mcc::network::MccNetMessage; + + +public: + using base_t::base_t; + + template + std::expected paramValue(size_t idx) + { + return paramValue(idx, _defaultDeserilizer); + } + + + + template + std::error_code construct(KT&& key, PTs&&... params) + requires mcc::traits::mcc_output_char_range + { + return construct(_defaultSerializer, std::forward(key), std::forward(params)...); + } +}; + + + +class Asibfm700MountNetServer : public mcc::network::MccGenericNetworkServer { using _base_t = mcc::network::MccGenericNetworkServer; public: template - Asibfm700MountNetserver(asio::io_context& ctx, + Asibfm700MountNetServer(asio::io_context& ctx, std::shared_ptr logger, const R& pattern_range = Asibfm700Logger::LOGGER_DEFAULT_FORMAT); - ~Asibfm700MountNetserver(); + ~Asibfm700MountNetServer(); private: std::vector handleMessage(std::string_view msg); diff --git a/mcc/mcc_ccte_iers.h b/mcc/mcc_ccte_iers.h index aa3a781..799a243 100644 --- a/mcc/mcc_ccte_iers.h +++ b/mcc/mcc_ccte_iers.h @@ -134,7 +134,12 @@ public: bool load(traits::mcc_input_char_range auto const& filename, char comment_sym = '#') { - std::ifstream fst(filename); + std::ifstream fst; + if constexpr (std::same_as, std::string>) { + fst.open(filename); + } else { + fst.open(std::string{filename.begin(), filename.end()}); + } bool ok = fst.is_open(); if (!ok) { @@ -436,7 +441,12 @@ public: bool load(traits::mcc_input_char_range auto const& filename, char comment_sym = '*') { - std::ifstream fst(filename); + std::ifstream fst; + if constexpr (std::same_as, std::string>) { + fst.open(filename); + } else { + fst.open(std::string{filename.begin(), filename.end()}); + } bool ok = fst.is_open(); if (!ok) { diff --git a/mcc/mcc_defaults.h b/mcc/mcc_defaults.h index 669e886..5e19557 100644 --- a/mcc/mcc_defaults.h +++ b/mcc/mcc_defaults.h @@ -515,6 +515,15 @@ static constexpr std::string_view MccCoordinateDefaultDelimiter{","}; class MccCoordinateDeserializer { public: + MccCoordinateDeserializer() = default; + + template + MccCoordinateDeserializer(R&& delim) : MccCoordinateDeserializer() + { + setDelimiter(std::forward(delim)); + } + + virtual ~MccCoordinateDeserializer() = default; template @@ -612,9 +621,9 @@ public: }; - MccCoordinateSerializer() = default; + constexpr MccCoordinateSerializer() = default; - MccCoordinateSerializer(SerializedCoordFormat fmt, SexagesimalCoordPrec prec) + constexpr MccCoordinateSerializer(SerializedCoordFormat fmt, SexagesimalCoordPrec prec) { setFormat(fmt); setPrecision(std::move(prec)); @@ -701,6 +710,8 @@ protected: class MccCelestialPointSerializer : public MccCoordinateSerializer { public: + using MccCoordinateSerializer::MccCoordinateSerializer; + template void operator()(const T& value, OR& bytes) { @@ -737,6 +748,8 @@ public: class MccCelestialPointDeserializer : public MccCoordinateDeserializer { public: + using MccCoordinateDeserializer::MccCoordinateDeserializer; + template std::error_code operator()(IR&& bytes, T& value) { @@ -808,6 +821,8 @@ public: class MccEqtHrzCoordsSerializer : public MccCoordinateSerializer { public: + using MccCoordinateSerializer::MccCoordinateSerializer; + template void operator()(const T& value, OR& bytes) { @@ -855,6 +870,8 @@ public: class MccEqtHrzCoordsDeserializer : public MccCoordinateDeserializer { public: + using MccCoordinateDeserializer::MccCoordinateDeserializer; + template std::error_code operator()(IR&& bytes, T& value) { @@ -1019,6 +1036,8 @@ public: class MccTelemetryDataDeserializer : public MccCoordinateDeserializer { public: + using MccCoordinateDeserializer::MccCoordinateDeserializer; + template std::error_code operator()(IR&& bytes, T& value) { diff --git a/mcc/mcc_netserver.h b/mcc/mcc_netserver.h index 870a2d0..0b0f775 100644 --- a/mcc/mcc_netserver.h +++ b/mcc/mcc_netserver.h @@ -159,8 +159,9 @@ public: static constexpr std::chrono::duration DEFAULT_RCV_TIMEOUT = std::chrono::hours(12); static constexpr std::chrono::duration DEFAULT_SND_TIMEOUT = std::chrono::milliseconds(2000); + typedef std::vector handle_message_func_result_t; // handle received message user function - typedef std::function(std::string_view)> handle_message_func_t; + typedef std::function handle_message_func_t; MccGenericNetworkServer(asio::io_context& ctx, const handle_message_func_t& func) @@ -892,6 +893,8 @@ class MccGenericMountNetworkServer : public MccGenericNetworkServer using base_t = MccGenericNetworkServer; public: + using typename base_t::handle_message_func_result_t; + template MccGenericMountNetworkServer(asio::io_context& ctx, MountT& mount, LoggerCtorArgsTs&&... log_args) : base_t(ctx, {}, std::forward(log_args)...) @@ -901,7 +904,7 @@ public: mount_error_t m_err; MccNetMessage input_msg; - MccNetMessage> output_msg; + MccNetMessage output_msg; std::error_code err{}; @@ -941,7 +944,7 @@ public: err = mcc_deduce_error_code(m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_TRACK); } } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_COORDFMT_STR)) { - auto v = input_msg.paramValue(0); + auto v = input_msg.paramValue(0); if (v) { _coordFormat = v.value(); output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); @@ -949,7 +952,7 @@ public: err = v.error(); } } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_COORDPREC_STR)) { - auto v = input_msg.paramValue(0); + auto v = input_msg.paramValue(0); if (v) { _coordPrec = v.value(); output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); @@ -990,7 +993,7 @@ public: err = coordsFromTelemetryData(mount, true, cp); if (!err) { output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_TARGET_STR, - cp); + _coordFormat, _coordPrec, cp); } } @@ -1015,7 +1018,7 @@ public: err = coordsFromTelemetryData(mount, false, cp); if (!err) { output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_MOUNT_STR, - cp); + _coordFormat, _coordPrec, cp); } } } else { @@ -1030,15 +1033,19 @@ public: // } } - return output_msg; + return output_msg.byteRepr(); }; } virtual ~MccGenericMountNetworkServer() {} protected: - MccNetMessageCoordFormat _coordFormat{MccNetMessageCoordFormat::CFMT_SGM}; // ouput coordinates format - MccNetMessageCoordPrec _coordPrec{2, 1}; + // MccNetMessageCoordFormat _coordFormat{MccNetMessageCoordFormat::CFMT_SGM}; // ouput coordinates format + // MccNetMessageCoordPrec _coordPrec{2, 1}; + + MccCoordinateSerializer::SerializedCoordFormat _coordFormat{ + MccCoordinateSerializer::SerializedCoordFormat::CFMT_SGM}; + MccCoordinateSerializer::SexagesimalCoordPrec _coordPrec{2, 1}; template std::error_code parseMessage(std::string_view msg_bytes, MSG_T& msg) diff --git a/mcc/mcc_netserver_proto.h b/mcc/mcc_netserver_proto.h index a6c4203..2827ed9 100644 --- a/mcc/mcc_netserver_proto.h +++ b/mcc/mcc_netserver_proto.h @@ -516,90 +516,22 @@ protected: protected: using base_t = mcc::utils::MccSimpleDeserializer; + inline static mcc::MccCelestialPointDeserializer _cpDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; + inline static mcc::MccEqtHrzCoordsDeserializer _eqhrDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; + inline static mcc::MccTelemetryDataDeserializer _telemetryDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; + public: DefaultDeserializer() : base_t(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ) {} template std::error_code operator()(IR&& bytes, VT& value) { - if constexpr (mcc_celestial_point_c) { - std::vector vs; - auto ec = base_t::operator()(std::forward(bytes), vs); - if (ec) { - return ec; - } - - if (vs.size() < 2) { // at least a pair of coordinates must be given - return std::make_error_code(std::errc::invalid_argument); - } - - MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS}; - - if (vs.size() > 2) { // pair of coordinates and the pair kind - pt.pair_kind = MccCoordStrToPairKind(vs[2]); - if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_GENERIC) { - return std::make_error_code(std::errc::invalid_argument); - } - } - - if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { - // J2000.0: 11:58:55.816 1 January 2000 UTC - auto tp = std::chrono::sys_days(std::chrono::year_month_day( - std::chrono::January / std::chrono::day(1) / std::chrono::year(2000))) + - std::chrono::hours(11) + std::chrono::minutes(58) + std::chrono::milliseconds(55816); - mcc_tp2tp(tp, pt.time_point); - } else { - if (vs.size() > 3) { // coordinates epoch is given - // std::chrono::sys_time tp; - - // std::istringstream iss(std::string{utils::trimSpaces(vs[3])}); - - // std::chrono::from_stream(iss, "%FT%T", tp); - // if (iss.fail()) { - // return std::make_error_code(std::errc::invalid_argument); - // } - - // mcc_tp2tp(tp, pt.time_point); - - MccCelestialCoordEpoch cep; - // bool ok = cep.fromCharRange(utils::trimSpaces(vs[3])); - bool ok = cep.fromCharRange(vs[3]); - if (!ok) { - return std::make_error_code(std::errc::invalid_argument); - } - mcc_tp2tp(cep.UTC(), pt.time_point); - } else { // no time point - use NOW - mcc_tp2tp(std::chrono::system_clock::now(), pt.time_point); - } - } - - std::optional ang1, ang2; - - switch (pt.pair_kind) { - // if sexagesimal then hours:minutes:seconds form - case mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS: - case mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP: - case mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP: - ang1 = mcc::utils::parsAngleString(vs[0], true); - break; - default: - // if sexagesimal then degrees:arcminutes:arcseconds form - ang1 = mcc::utils::parsAngleString(vs[0]); - } - if (!ang1) { - return std::make_error_code(std::errc::invalid_argument); - } - - ang2 = mcc::utils::parsAngleString(vs[1]); - if (!ang2) { - return std::make_error_code(std::errc::invalid_argument); - } - - - pt.X = MccAngle(ang1.value(), mcc::MccDegreeTag{}); - pt.Y = MccAngle(ang2.value(), mcc::MccDegreeTag{}); - - mcc_copy_celestial_point(pt, &value); + if constexpr (mcc_telemetry_data_c) { + return _telemetryDeserializer(std::forward(bytes), value); + } else if constexpr (mcc_eqt_hrz_coord_c) { + return _eqhrDeserializer(std::forward(bytes), value); + } else if constexpr (mcc_celestial_point_c) { + return _cpDeserializer(std::forward(bytes), value); } else if constexpr (std::same_as) { value = MccCoordStrToPairKind(bytes); if (value == MccCoordPairKind::COORDS_KIND_UNKNOWN) { @@ -651,20 +583,12 @@ protected: class DefaultSerializer { - MccNetMessageCoordFormat _currentCoordFormat = MccNetMessageCoordFormat::CFMT_SGM; - MccNetMessageCoordPrec _currentCoordPrec{2, 1}; + friend class MccNetMessage; + + MccCoordinateSerializer::SerializedCoordFormat _coordFmt{}; + MccCoordinateSerializer::SexagesimalCoordPrec _coordPrec{}; public: - void setCoordFormat(MccNetMessageCoordFormat fmt) - { - _currentCoordFormat = fmt; - } - - void setCoordPrec(MccNetMessageCoordPrec prec) - { - _currentCoordPrec = prec; - } - template void operator()(const T& value, OR& bytes) { @@ -680,83 +604,30 @@ protected: // std::ranges::copy(mcc_pairkind2str(value), std::back_inserter(bytes)); } else if constexpr (traits::mcc_time_duration_c) { (*this)(value.count(), bytes); + } else if constexpr (mcc_telemetry_data_c) { + static MccTelemetryDataSerializer sr; + + sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); + sr.setFormat(_coordFmt); + sr.setPrecision(_coordPrec); + + sr(value, bytes); } else if constexpr (mcc_eqt_hrz_coord_c) { - // output format: RA, DEC, HA, AZ, ZD, ALT, X, Y, pair-kind, time-point - // in the case of sexagesimal output X,Y coordinates will be interpretated - // according to value.pair_kind field - if (_currentCoordFormat == MccNetMessageCoordFormat::CFMT_DEGREES) { - std::format_to(std::back_inserter(bytes), "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", - MccAngle(value.RA).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.DEC).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.HA).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.AZ).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.ZD).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.ALT).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.X).degrees(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.Y).degrees()); - } else { - std::format_to(std::back_inserter(bytes), "{}{}{}{}{}{}{}{}{}{}{}{}", - MccAngle(value.RA).sexagesimal(true, _currentCoordPrec.hour_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.DEC).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.HA).sexagesimal(true, _currentCoordPrec.hour_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.AZ).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.ZD).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - MccAngle(value.ALT).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); + static MccEqtHrzCoordsSerializer sr; - // interpretate X,Y angles according to .pair_kind field - switch (value.pair_kind) { - case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: - case MccCoordPairKind::COORDS_KIND_RADEC_APP: - case MccCoordPairKind::COORDS_KIND_HADEC_APP: - std::format_to(std::back_inserter(bytes), "{}{}{}{}", - MccAngle(value.X).sexagesimal(true, _currentCoordPrec.hour_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - break; - default: - std::format_to(std::back_inserter(bytes), "{}{}", - MccAngle(value.X).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - } - std::format_to(std::back_inserter(bytes), "{}", - MccAngle(value.Y).sexagesimal(false, _currentCoordPrec.deg_prec)); - } - - std::format_to(std::back_inserter(bytes), "{0:}{1:}{2:}{3:%F}T{3:%T}", - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccCoordPairKindToStr(value.pair_kind), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, value.time_point); + sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); + sr.setFormat(_coordFmt); + sr.setPrecision(_coordPrec); + sr(value, bytes); } else if constexpr (mcc_celestial_point_c) { - if (_currentCoordFormat == MccNetMessageCoordFormat::CFMT_DEGREES) { - std::format_to(std::back_inserter(bytes), "{}{}{}", MccAngle(value.X).degrees(), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccAngle(value.Y).degrees()); - } else { - switch (value.pair_kind) { - case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: - case MccCoordPairKind::COORDS_KIND_RADEC_APP: - case MccCoordPairKind::COORDS_KIND_HADEC_APP: - std::format_to(std::back_inserter(bytes), "{}{}", - MccAngle(value.X).sexagesimal(true, _currentCoordPrec.hour_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - break; - default: - std::format_to(std::back_inserter(bytes), "{}{}", - MccAngle(value.X).sexagesimal(false, _currentCoordPrec.deg_prec), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - } + MccCelestialPointSerializer sr; - std::format_to(std::back_inserter(bytes), "{}", - MccAngle(value.Y).sexagesimal(false, _currentCoordPrec.deg_prec)); - } + sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); + sr.setFormat(_coordFmt); + sr.setPrecision(_coordPrec); - std::format_to(std::back_inserter(bytes), "{0:}{1:}{2:}{3:%F}T{3:%T}", - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccCoordPairKindToStr(value.pair_kind), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, value.time_point); + sr(value, bytes); } else if constexpr (std::ranges::range) { auto sz = std::ranges::size(value); if (sz == 0) { @@ -796,7 +667,7 @@ public: MccNetMessage(KT&& key, PTs&&... params) requires traits::mcc_output_char_range { - construct(std::forward(key), std::forward(params)...); + construct(_defaultSerializer, std::forward(key), std::forward(params)...); } template @@ -964,9 +835,22 @@ public: template std::error_code construct(KT&& key, PTs&&... params) requires traits::mcc_output_char_range + { + return construct(_defaultSerializer, std::forward(key), std::forward(params)...); + } + + // + // serializing function SerFuncT - a callable with the signature: + // template + // void ser_func(const T& val, R&& buffer) + // + template + std::error_code construct(SerFuncT&& ser_func, KT&& key, PTs&&... params) + requires(traits::mcc_output_char_range && + !traits::mcc_input_char_range>) { if constexpr (std::is_pointer_v>) { - return construct(std::string_view(key), std::forward(params)...); + return construct(std::forward(ser_func), std::string_view(key), std::forward(params)...); } @@ -993,7 +877,7 @@ public: if constexpr (sizeof...(PTs)) { std::ranges::copy(MCC_COMMPROTO_KEYPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); - convertFunc(par_idx, std::forward(params)...); + convertFunc(std::forward(ser_func), par_idx, std::forward(params)...); for (size_t i = 0; i < par_idx.size(); i += 2) { _params.emplace_back(_msgBuffer.begin() + par_idx[i], _msgBuffer.begin() + par_idx[i + 1]); @@ -1005,7 +889,6 @@ public: return {}; } - template constexpr MccNetMessageError fromCharRange(const R& r) { @@ -1072,30 +955,68 @@ protected: template void convertFunc(std::vector& idx, const T& par, const Ts&... pars) { - if constexpr (std::same_as) { - _defaultSerializer.setCoordFormat(par); + if constexpr (std::same_as) { + _defaultSerializer._coordFmt = par; if constexpr (sizeof...(Ts)) { convertFunc(idx, pars...); } - } else if constexpr (std::same_as) { - _defaultSerializer.setCoordPrec(par); + } else if constexpr (std::same_as) { + _defaultSerializer._coordPrec = par; if constexpr (sizeof...(Ts)) { convertFunc(idx, pars...); } + } else { + convertFunc(_defaultSerializer, idx, par, pars...); + // idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); + + // _defaultSerializer(par, _msgBuffer); + + // idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); + + // if constexpr (sizeof...(Ts)) { + // std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); + + // convertFunc(idx, pars...); + // } + } + }; + + template + void convertFunc(SerFuncT&& ser_func, std::vector& idx, const T& par, const Ts&... pars) + requires(!std::same_as, std::vector>) + { + if constexpr (std::derived_from, DefaultSerializer>) { + if constexpr (std::same_as) { + _defaultSerializer._coordFmt = par; + } else if constexpr (std::same_as) { + _defaultSerializer._coordPrec = par; + } else { + idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); + + std::forward(ser_func)(par, _msgBuffer); + + idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); + + if constexpr (sizeof...(Ts)) { + std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); + } + } } else { idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - _defaultSerializer(par, _msgBuffer); + std::forward(ser_func)(par, _msgBuffer); idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); if constexpr (sizeof...(Ts)) { std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); - - convertFunc(idx, pars...); } } - }; + + if constexpr (sizeof...(Ts)) { + convertFunc(std::forward(ser_func), idx, pars...); + } + } }; static_assert(MccNetMessage{"ACK"}.withKey("ACK")); diff --git a/mcc/tests/netmsg_test.cpp b/mcc/tests/netmsg_test.cpp index 87e6b0f..2d7e51d 100644 --- a/mcc/tests/netmsg_test.cpp +++ b/mcc/tests/netmsg_test.cpp @@ -60,7 +60,9 @@ int main() .Y = mcc::MccAngle(67.9827148715, mcc::mcc_degrees)}; // msg2.construct("ACK", "MOUNT", msg2_t::CFMT_DEGREES, msg2_t::MccNetMessageCoordPrec{2, 3}, cpt); - msg2.construct("ACK", "MOUNT", mcc::network::MccNetMessageCoordPrec{2, 3}, cpt); + // msg2.construct("ACK", "MOUNT", mcc::network::MccNetMessageCoordPrec{2, 3}, cpt); + msg2.construct("ACK", "MOUNT", mcc::MccCoordinateSerializer::SerializedCoordFormat::CFMT_SGM, + mcc::MccCoordinateSerializer::SexagesimalCoordPrec{3, 2}, cpt); std::cout << "MSG2: " << msg2.byteRepr() << "\n"; auto cpt1 = msg2.paramValue(1); if (cpt1) {