diff --git a/mcc_ccte_erfa.h b/mcc_ccte_erfa.h index 4d18fd0..30f71bd 100644 --- a/mcc_ccte_erfa.h +++ b/mcc_ccte_erfa.h @@ -280,15 +280,15 @@ public: } - // latitude and longitude - template - void geoPosition(std::pair* coords) const + // longitude and latitude + template + void geoPosition(std::pair* coords) const { std::lock_guard lock{*_stateMutex}; if (coords) { - coords->first = _currentState.lat; - coords->second = _currentState.lon; + coords->first = _currentState.lon; + coords->second = _currentState.lat; } } diff --git a/mcc_concepts.h b/mcc_concepts.h index 7156946..8c97eaa 100644 --- a/mcc_concepts.h +++ b/mcc_concepts.h @@ -473,11 +473,11 @@ struct mcc_skypoint_interface_t { return std::forward(self).refractInverseCorrection(dZ); } - // returns apparent sideral time (Greenwich) for the epoch of the celestial point + // returns apparent sideral time (Greenwich or local) for the epoch of the celestial point template SelfT> - auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st) + auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st, bool is_local) { - return std::forward(self).appSideralTime(st); + return std::forward(self).appSideralTime(st, is_local); } // returns equation of origins for the epoch of the celestial point @@ -571,7 +571,7 @@ concept mcc_pcm_c = std::derived_from -concept mcc_hardware_movement_state_c = requires { +concept mcc_hardware_movement_state_c = std::formattable && requires { []() { // // mount axes were stopped // [[maybe_unused]] static constexpr auto v0 = T::HW_MOVE_STOPPED; @@ -621,7 +621,6 @@ concept mcc_hardware_movement_state_c = requires { template concept mcc_hardware_state_c = requires(T state) { // encoder co-longitude and co-latiitude positions, as well as its measurement time point - // the given constrains on coordinate pair kind can be used to deduce mount type requires mcc_coord_pair_c && (decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_GENERIC || decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_XY); diff --git a/mcc_coordinate.h b/mcc_coordinate.h index 3378235..7fcd44d 100644 --- a/mcc_coordinate.h +++ b/mcc_coordinate.h @@ -475,7 +475,7 @@ public: std::pair pos; cctEngine.geoPosition(&pos); - return MccGeoLONLAT(pos.second, pos.first); + return MccGeoLONLAT(pos.first, pos.second); } @@ -581,10 +581,9 @@ public: } - error_t appSideralTime(mcc_angle_c auto* st) const + error_t appSideralTime(mcc_angle_c auto* st, bool is_local = false) const { - // return Greenwich apparent sideral time since epoch is UTC - return cctEngine.apparentSideralTime(_epoch, st, false); + return cctEngine.apparentSideralTime(_epoch, st, is_local); } @@ -735,6 +734,16 @@ protected: static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_UNKNOWN, "UNSUPPORTED SKY POINT TRANSFORMATION!"); + if constexpr (PT::pairKind == MccCoordPairKind::COORDS_KIND_LONLAT) { // returns geographic site coordinates + std::pair pos; + cctEngine.geoPosition(&pos); + + cpair.setX(pos.first); + cpair.setY(pos.second); + + return error_t{}; + } + if (_pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS && PT::pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS to ICRS - just copy and exit cpair = PT(typename PT::x_t(_x), typename PT::y_t(_y)); diff --git a/mcc_ser.h b/mcc_ser.h index 1f71a63..a381d4e 100644 --- a/mcc_ser.h +++ b/mcc_ser.h @@ -158,8 +158,10 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-FALLBACK-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { if constexpr (std::formattable) { } else if constexpr (std::convertible_to) { @@ -205,8 +207,10 @@ struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-SYSTIME-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { std::vformat_to(std::back_inserter(output), params.systime_format, std::make_format_args(value)); @@ -220,8 +224,10 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-ANGLE-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { double v = (double)value; // radians (see mcc_angle_c concept) std::string sgm; @@ -264,8 +270,10 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-COORD-EPOCH-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { double jd; @@ -304,11 +312,12 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-COORD-PAIR-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { - std::conditional_t, std::nullptr_t, mcc_serialization_params_t> pars = - std::is_null_pointer_v ? nullptr : params; + auto pars = params; pars.norm_sxgm = true; pars.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG; @@ -358,8 +367,10 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-SKYPOINT-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { auto serialize_cpair = [&](T& cp) { auto ccte_err = value.to(cp); @@ -423,52 +434,256 @@ template struct MccSerializer : MccSerializerBase { constexpr static std::string_view serializerName{"MCC-TELEMETRY-DATA-SERIALIZER"}; - template - error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr) + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) { // FORMAT: RA_OBS_MOUNT, DEC_OBS_MOUNT, RA_APP_MOUNT, DEC_APP_MOUNT, HA_APP_MOUNT, AZ_MOUNT, ZD_MOUNT, - // REFR_CORR_MOUNT, LAST, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, TIMEPOINT + // REFR_CORR_MOUNT, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, LAST, EO, TIMEPOINT, + // STATUS // NOTE: One must assume that the returned RA coordinates are in format of underlying celestial coordinate // transformation engine used in the mcc_skypoint_c class implementation. E.g. ERFA-library uses the // CIO-based representation of RA - std::conditional_t, std::nullptr_t, mcc_serialization_params_t> pars = - std::is_null_pointer_v ? nullptr : params; + auto pars_h = params; - pars.norm_sxgm = true; - pars.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG; + auto pars_d = params; - std::string ra_obs, ra_app, ha, last, ra_app_tg; - MccSkyRADEC_OBS r_obs; - MccSkyRADEC_APP r_app; + + pars_h.norm_sxgm = true; + pars_h.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG; + pars_d.norm_sxgm = true; + pars_d.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG; + + MccSkyRADEC_OBS rd_obs; + MccSkyRADEC_APP rd_app; + MccSkyHADEC_APP hd_app; + MccSkyAZZD azzd; // quantities in hour representation - MccSerializerBase::angleFormatFromCoordPairType(pars); + MccSerializerBase::angleFormatFromCoordPairType(pars_h); + + // quantities in degree representation + MccSerializerBase::angleFormatFromCoordPairType(pars_d); MccSerializer ang_sr; - // RA_OBS_MOUNT - auto ccte_err = value.mountPos.toAtSameEpoch(r_obs); + // RA_OBS_MOUNT, DEC_OBS_MOUNT + auto ccte_err = value.mountPos.toAtSameEpoch(rd_obs); if (ccte_err) { return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); } - auto err = ang_sr(ra_obs, r_obs, pars); + auto err = ang_sr(output, rd_obs.x(), pars_h); if (err) { return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); } - // RA_APP_MOUNT - ccte_err = value.mountPos.toAtSameEpoch(r_app); + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, rd_obs.y(), pars_h); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // RA_APP_MOUNT, DEC_APP_MOUNT + ccte_err = value.mountPos.toAtSameEpoch(rd_app); if (ccte_err) { return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); } - err = ang_sr(ra_app, r_app, pars); + err = ang_sr(output, rd_app.x(), pars_h); if (err) { return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, rd_app.y(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // HA_APP_MOUNT + ccte_err = value.mountPos.toAtSameEpoch(hd_app); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, hd_app.x(), pars_h); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // AZ_MOUNT, ZD_MOUNT + ccte_err = value.mountPos.toAtSameEpoch(azzd); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, azzd.x(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, azzd.y(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // refraction correction + + MccAngle ang; + ccte_err = value.mountPos.refractCorrection(&ang); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, ang, pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // encoder X and Y + + err = ang_sr(output, value.hwState.XY.x(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, value.hwState.XY.y(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // PCM X and Y + + err = ang_sr(output, value.pcmCorrection.pcmX(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, value.pcmCorrection.pcmY(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // RA_APP_TAG, DEC_APP_TAG + ccte_err = value.targetPos.toAtSameEpoch(rd_app); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, rd_app.x(), pars_h); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, rd_app.y(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // AZ_TAG, ZD_TAG + ccte_err = value.targetPos.toAtSameEpoch(azzd); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, azzd.x(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + err = ang_sr(output, azzd.y(), pars_d); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // LAST, local apparent sideral time + + ccte_err = value.mountPos.appSideralTime(&ang, true); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, ang, pars_h); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // EO, equation of origins + + ccte_err = value.mountPos.EO(&ang); + if (ccte_err) { + return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM); + } + + err = ang_sr(output, ang, pars_h); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + // coordinates epoch + + auto ep_err = MccSerializer{}(output, value.mountPos.epoch(), pars_d); + if (ep_err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + MccSerializerBase::addElemDelimiter(output, pars_h); + + + // status (it must be formattable, see mcc_concepts.h) + + auto st_err = + MccSerializer{}(output, value.hwState.movementState, pars_d); + if (st_err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + + return MccSerializerErrorCode::ERROR_OK; } }; diff --git a/mcc_serialization_common.h b/mcc_serialization_common.h index bed1243..334a254 100644 --- a/mcc_serialization_common.h +++ b/mcc_serialization_common.h @@ -163,7 +163,7 @@ static constexpr std::string_view MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER{","}; template -concept mcc_serialization_params_c = requires(T t) { +concept mcc_serialization_params_c = std::copyable && requires(T t) { requires traits::mcc_output_char_range; requires traits::mcc_output_char_range;