From 6a72ead8557e4f8d8bfd90ff092ecbbe42d1f2d2 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Wed, 29 Oct 2025 16:15:58 +0300 Subject: [PATCH] cleanups of commented code --- asibfm700/asibfm700_common.h | 88 ----- asibfm700/asibfm700_configfile.h | 583 +----------------------------- asibfm700/asibfm700_netserver.cpp | 9 +- asibfm700/tests/cfg_test.cpp | 32 +- mcc/mcc_netserver.h | 137 +------ mcc/mcc_netserver_proto.h | 198 ---------- mcc/tests/ccte_test.cpp | 59 --- 7 files changed, 12 insertions(+), 1094 deletions(-) diff --git a/asibfm700/asibfm700_common.h b/asibfm700/asibfm700_common.h index 75502e9..84fb71e 100644 --- a/asibfm700/asibfm700_common.h +++ b/asibfm700/asibfm700_common.h @@ -11,7 +11,6 @@ #include #include -#include "asibfm700_servocontroller.h" #include "mcc_ccte_erfa.h" namespace asibfm700 @@ -25,91 +24,4 @@ typedef mcc::MccPZoneContainer Asibfm700PZoneContainer; typedef mcc::utils::MccSpdlogLogger Asibfm700Logger; -/* MOUNT CONFIGURATION CLASS */ - -struct Asibfm700MountConfig1 { - std::chrono::milliseconds hardwarePollingPeriod{100}; // main cycle period - - // CCTE-related configuration - mcc::MccAngle siteLatitude{43.646711_degs}; // in radians - mcc::MccAngle siteLongitude{41.440732_degs}; // in radians - double siteElevation{2070.0}; // in meters - double refractWavelength{0.55}; // in mkm - - std::string leapSecondFilename{""}; // an empty filename means default precompiled string - std::string bulletinAFilename{""}; // an empty filename means default precompiled string - - - // PCM-related configuration (no B-spline term, all coefficients are zero) - Asibfm700PCM::pcm_data_t pcmData{.type = mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY, - .siteLatitude = siteLatitude, - .geomCoefficients = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; - - // servo controller configuration - AsibFM700ServoController::hardware_config_t servoControllerConfig{}; - - // slew and track parameters - mcc::MccSimpleMovingModelParams movingModelParams{}; - - // prohibited zones parameters - mcc::MccAngle pzMinAltitude{10.0_degs}; // in radians - mcc::MccAngle pzLimitSwitchHAMin{}; // in radians - mcc::MccAngle pzLimitSwitchHAMax{}; // in radians -}; - - -/* MOUNT CONFIGURATION FILE DEFAULTS */ - -struct Asibfm700MountConfigFileDefailts { - std::string hardwarePollingPeriod{"100"}; // main cycle period in millisecs - - std::string siteLatitude{"43.646711"}; // site latitude in degrees or sexagesimal format - std::string siteLongitude{"41.440732"}; // site longitude in degrees or sexagesimal format - std::string siteElevation{"2070.0"}; // site elevation in meters - - std::string refractWavelength{"0.55"}; // wavelength at which refraction is calculated (in mkm) - - std::string leapSecondFilename{""}; // an empty filename means default precompiled string - std::string bulletinAFilename{""}; // an empty filename means default precompiled string - - // pointing correction model - - std::string pcmType{"GEOMETRY"}; - std::vector pcmGeomCoeffs{"0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "0.0"}; - std::vector pcmBsplineDegree{"3", "3"}; - // [0, 360] - std::vector pcmBsplineXknots{"0.0", "0.6981317", "1.3962634", "2.0943951", "2.7925268", - "3.4906585", "4.1887902", "4.88692191", "5.58505361", "6.28318531"}; - // [-30, 90] - std::vector pcmBsplineYknots{"-0.52359878", "-0.29088821", "-0.05817764", "0.17453293", "0.40724349", - "0.63995406", "0.87266463", "1.10537519", "1.33808576", "1.57079633"}; - - std::vector pcmBsplineXcoeffs{}; - std::vector pcmBsplineYcoeffs{}; - - // slewing and tracking parameters - - std::string sideralRate{"15.0410686"}; // arcseconds per second - std::string telemetryTimeout{"3"}; // timeout for telemetry updating in seconds - std::string minTimeToPZone{"10"}; // minimal time in seconds to prohibited zone - // a time interval to update prohibited zones related quantities - std::string updatingPZoneInterval{"5000"}; // in millisecs - std::string slewToleranceRadius{"5.0"}; // coordinates difference in arcsecs to stop slewing - std::string adjustCoordDiff{"50.0"}; // target-mount coordinate difference in arcsecs to start adjusting of slewing - std::string adjustCycleInterval{"300"}; // minimum time in millisecs between two successive adjustments - std::string slewTimeout{"3600"}; // slew process timeout - // a time shift into future to compute target position in future (UT1-scale time duration) - std::string timeShiftToTargetPoint{"10000"}; // in millisecs - std::string trackingCycleInterval{"300"}; // minimum time in millisecs between two successive tracking corrections - - // prohibited zones - std::string pzMinAltitude{"10.0"}; // minimal altitude in degrees - std::string pzLimitSwitchHAMin{""}; // HA-axis limit switch minimal value - std::string pzLimitSwitchHAMax{""}; // HA-axis limit switch maximal value - - // hardware - std::string hwMaxRateHA{""}; // maximal moving rate along HA-axis (Y-axis of Sidereal servo microcontroller) - std::string hwMaxRateDEC{""}; // maximal moving rate along DEC-axis (X-axis of Sidereal servo microcontroller) -}; - } // namespace asibfm700 diff --git a/asibfm700/asibfm700_configfile.h b/asibfm700/asibfm700_configfile.h index a9cc402..3385011 100644 --- a/asibfm700/asibfm700_configfile.h +++ b/asibfm700/asibfm700_configfile.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -24,282 +23,15 @@ namespace asibfm700 // to follow std::variant requirements (not references, not array, not void) template -concept variant_valid_type_c = requires { !std::is_array_v && !std::is_void_v && !std::is_reference_v; }; - -// configuration record -template -concept config_record_c = requires(T t) { - requires std::same_as; // keyword - requires variant_valid_type_c; // value -}; +concept config_record_valid_type_c = requires { !std::is_array_v && !std::is_void_v && !std::is_reference_v; }; // simple minimal-requirement configuration record class -template +template struct simple_config_record_t { std::string_view key; T value; }; -// description of config (a std::tuple of "config_record_c"s) -template -concept config_desc_c = requires(T t) { [](std::tuple) {}(t); }; - - -template -class ConfigHolder -{ -protected: - /* helper definitions */ - - // deduce unique value types of the given config records - template - struct deduce_val_types; - - template - struct deduce_val_types> { - using value_type_t = std::tuple; - }; - - template - struct deduce_val_types> { - using value_type_t = - std::conditional_t<(std::same_as || ...), - typename deduce_val_types>::value_type_t, - decltype(std::tuple_cat( - std::declval>(), - std::declval>::value_type_t>()))>; - }; - - template - using deduce_val_types_t = typename deduce_val_types::value_type_t; - - // deduce std::variant type from std::tuple element types - template - struct variant_from_tuple; - - template - struct variant_from_tuple> { - using variant_t = std::variant; - }; - - template - using variant_from_tuple_t = typename variant_from_tuple::variant_t; - - -public: - static constexpr char COMMENT_SYMBOL = '#'; - static constexpr char KEY_VALUE_DELIM = '='; - static constexpr char VALUE_ARRAY_DELIM = ','; - - - // very simple de-serializer (only numbers and strings) - inline static auto defaultDeserializeFunc = [](this auto&& self, std::string_view str, auto& value) { - using value_t = std::decay_t; - - if constexpr (std::is_arithmetic_v) { - auto v = mcc::utils::numFromStr(str); - if (!v.has_value()) { - return false; - } - - value = v.value(); - } else if constexpr (mcc::traits::mcc_output_char_range) { - value_t r; - std::ranges::copy(str, std::back_inserter(r)); - value = r; - } else if constexpr (std::ranges::range) { - using el_t = std::ranges::range_value_t; - - if constexpr (std::is_reference_v || std::is_const_v) { // no reference or constants allowed - return false; - } - - value_t r; - el_t elem; - - auto els = std::views::split(str, VALUE_ARRAY_DELIM); - - for (auto const& el : els) { - // if (std::forward(self)(std::string_view(el), elem)) { - if (std::forward(self)(mcc::utils::trimSpaces(el), elem)) { - std::back_inserter(r) = elem; - } else { - return false; - } - } - - value = r; - } else if constexpr (mcc::traits::mcc_time_duration_c) { - typename value_t::rep vd; - - bool ok = self(str, vd); - if (ok) { - value = value_t{vd}; - } - } else { - return false; - } - - return true; - }; - - - ConfigHolder(DESCR_T desc) - { - [desc = std::move(desc), this](std::index_sequence) { - ((_configDB[std::get(desc).key] = std::get(desc).value), ...); - }(std::make_index_sequence>()); - } - - virtual ~ConfigHolder() = default; - - // deser_func - de-serialization function, i.e., a conversional function - // from string-representation to some value - // - // DeserFuncT is a type of callable with signature: - // bool deser_func(std::string_view str, value_type& val) - // where - // str - input (serialized) string-representation of configuration - // item value - // 'value_type' - must take into account all possible value types - // in the input configuration description (see constructor) - // - // most suitable implementation is a generic lambda function, i.e.: - // auto deser_func(std::string_view str, auto& cnv_val)->bool { - // ... - // }; - template - std::error_code parse(const R& buffer, DeserFuncT&& deser_func) - requires std::same_as>, char> - { - if constexpr (std::is_array_v>) { // char*, const char* - return parse(std::string_view{std::forward(buffer)}, std::forward(deser_func)); - } - - auto curr_buffer = std::string_view(buffer.begin(), buffer.end()); - std::string_view key, value; - bool buffer_end = false; - - do { - auto it = std::ranges::find(curr_buffer, '\n'); - if (it == curr_buffer.end()) { - buffer_end = true; - } - - auto sv = - mcc::utils::trimSpaces(std::string_view(curr_buffer.begin(), it), mcc::utils::TrimType::TRIM_LEFT); - - curr_buffer = {it + 1, curr_buffer.end()}; - - if (sv.size() && (sv[0] != COMMENT_SYMBOL)) { - it = std::ranges::find(sv, KEY_VALUE_DELIM); - if (it != sv.begin()) { // ignore an empty key - key = mcc::utils::trimSpaces(std::string_view(sv.begin(), it), mcc::utils::TrimType::TRIM_RIGHT); - auto rec_it = _configDB.find(key); - if (rec_it != _configDB.end()) { // ignore key if it is not in description - value = - mcc::utils::trimSpaces(std::string_view(it + 1, sv.end()), mcc::utils::TrimType::TRIM_BOTH); - - bool ok = forIndex(rec_it->second, value, std::forward(deser_func), - rec_it->second.index()); - - if (!ok) { - return std::make_error_code(std::errc::invalid_argument); - } - } - } - } - - } while (!buffer_end); - - - return {}; - } - - template - std::error_code parse(const R& buffer) - { - return parse(buffer, defaultDeserializeFunc); - } - - template - std::expected value(std::string_view key) - { - auto it = _configDB.find(key); - if (it == _configDB.end()) { - return std::unexpected(std::make_error_code(std::errc::argument_out_of_domain)); - } - - std::expected res; - - std::visit( - [&res](auto&& val) { - using v_t = std::decay_t; - - if constexpr (std::convertible_to) { - res = static_cast(std::forward(val)); - // } else if constexpr (std::constructible_from) { - // res = T{std::forward(val)}; - } else { - res = std::unexpected(std::make_error_code(std::errc::invalid_argument)); - } - }, - it->second); - - return res; - } - - template - bool update(std::string_view key, const T& value) - { - auto it = _configDB.find(key); - if (it == _configDB.end()) { - return false; - } - - bool ok; - std::visit( - [&value, &ok](auto& val) { - using v_t = std::decay_t; - - if constexpr (std::convertible_to) { - val = static_cast(value); - ok = true; - } else { - ok = false; - } - }, - it->second); - - return ok; - } - -protected: - std::unordered_map>> _configDB; - - template - bool forIndex(std::variant& var, std::string_view s, FuncT&& func, size_t idx) - { - if constexpr (I < sizeof...(Ts)) { - if (I == idx) { - using v_t = std::tuple_element_t>; - v_t val; - bool ok = std::forward(func)(s, val); - if (ok) { - var = val; - } - - return ok; - } else { - return forIndex(var, s, std::forward(func), idx); - } - } - - return false; - } -}; - - /* ASTOROSIB FM700 MOUNT CONFIGURATION CLASS */ @@ -891,317 +623,6 @@ public: }; -class Asibfm700MountConfig2 : protected ConfigHolder -{ - using base_t = ConfigHolder; - -public: - using base_t::update; - using base_t::value; - - Asibfm700MountConfig2() : base_t(Asibfm700MountConfigDefaults) - { - updateAll(); - } - - ~Asibfm700MountConfig2() = default; - - std::error_code load(const std::filesystem::path& path) - { - std::string buffer; - - std::error_code ec; - auto sz = std::filesystem::file_size(path, ec); - - if (!ec && sz) { - std::ifstream fst(path); - - try { - buffer.resize(sz); - - fst.read(buffer.data(), sz); - - fst.close(); - - ec = base_t::parse(buffer, deserializer); - if (!ec) { - updateAll(); - } - } catch (std::ios_base::failure const& ex) { - ec = ex.code(); - } catch (std::length_error const& ex) { - ec = std::make_error_code(std::errc::no_buffer_space); - } catch (std::bad_alloc const& ex) { - ec = std::make_error_code(std::errc::not_enough_memory); - } catch (...) { - ec = std::make_error_code(std::errc::operation_canceled); - } - } - - return ec; - } - - template - bool update(std::string_view key, const T& value) - { - bool ok = base_t::update(key, value); - if (ok) { - updateAll(); - } - - return ok; - } - - std::chrono::milliseconds hardwarePollingPeriod{}; - - mcc::MccAngle siteLatitude{}; - mcc::MccAngle siteLongitude{}; - double siteElevation{}; - double refractWavelength{}; - - std::string leapSecondFilename{}; - std::string bulletinAFilename{}; - - mcc::MccAngle pzMinAltitude{}; - mcc::MccAngle pzLimitSwitchHAMin{}; - mcc::MccAngle pzLimitSwitchHAMax{}; - - - AsibFM700ServoController::hardware_config_t servoControllerConfig{}; - mcc::MccSimpleMovingModelParams movingModelParams{}; - Asibfm700PCM::pcm_data_t pcmData{}; - -protected: - void updateAll() - { - hardwarePollingPeriod = std::get(this->_configDB["hardwarePollingPeriod"]); - - // CCTE - - siteLatitude = std::get(this->_configDB["siteLatitude"]); - siteLongitude = std::get(this->_configDB["siteLongitude"]); - siteElevation = std::get(this->_configDB["siteElevation"]); - refractWavelength = std::get(this->_configDB["refractWavelength"]); - - leapSecondFilename = std::get(this->_configDB["leapSecondFilename"]); - bulletinAFilename = std::get(this->_configDB["bulletinAFilename"]); - - // prohibited zones - - pzMinAltitude = std::get(this->_configDB["pzMinAltitude"]); - pzLimitSwitchHAMin = std::get(this->_configDB["pzLimitSwitchHAMin"]); - pzLimitSwitchHAMax = std::get(this->_configDB["pzLimitSwitchHAMax"]); - - - // hardware config - - servoControllerConfig.hwConfig = {}; - - servoControllerConfig.MountDevPath = std::get(this->_configDB["MountDevPath"]); - servoControllerConfig.EncoderDevPath = std::get(this->_configDB["EncoderDevPath"]); - servoControllerConfig.EncoderXDevPath = std::get(this->_configDB["EncoderXDevPath"]); - servoControllerConfig.EncoderYDevPath = std::get(this->_configDB["EncoderYDevPath"]); - - servoControllerConfig.devConfig.MountDevPath = servoControllerConfig.MountDevPath.data(); - servoControllerConfig.devConfig.EncoderDevPath = servoControllerConfig.EncoderDevPath.data(); - servoControllerConfig.devConfig.EncoderXDevPath = servoControllerConfig.EncoderXDevPath.data(); - servoControllerConfig.devConfig.EncoderYDevPath = servoControllerConfig.EncoderYDevPath.data(); - - servoControllerConfig.devConfig.RunModel = std::get(this->_configDB["RunModel"]); - servoControllerConfig.devConfig.MountDevSpeed = std::get(this->_configDB["MountDevSpeed"]); - servoControllerConfig.devConfig.EncoderDevSpeed = std::get(this->_configDB["EncoderDevSpeed"]); - servoControllerConfig.devConfig.SepEncoder = std::get(this->_configDB["SepEncoder"]); - - std::chrono::duration secs; // seconds as floating-point - - secs = std::get(this->_configDB["MountReqInterval"]); - servoControllerConfig.devConfig.MountReqInterval = secs.count(); - - secs = std::get(this->_configDB["EncoderReqInterval"]); - servoControllerConfig.devConfig.EncoderReqInterval = secs.count(); - - secs = std::get(this->_configDB["EncoderSpeedInterval"]); - servoControllerConfig.devConfig.EncoderSpeedInterval = secs.count(); - - std::vector pid = std::get>(this->_configDB["XPIDC"]); - if (pid.size() > 2) { - servoControllerConfig.devConfig.XPIDC.P = pid[0]; - servoControllerConfig.devConfig.XPIDC.I = pid[1]; - servoControllerConfig.devConfig.XPIDC.D = pid[2]; - } - - pid = std::get>(this->_configDB["XPIDV"]); - if (pid.size() > 2) { - servoControllerConfig.devConfig.XPIDV.P = pid[0]; - servoControllerConfig.devConfig.XPIDV.I = pid[1]; - servoControllerConfig.devConfig.XPIDV.D = pid[2]; - } - - pid = std::get>(this->_configDB["YPIDC"]); - if (pid.size() > 2) { - servoControllerConfig.devConfig.YPIDC.P = pid[0]; - servoControllerConfig.devConfig.YPIDC.I = pid[1]; - servoControllerConfig.devConfig.YPIDC.D = pid[2]; - } - - pid = std::get>(this->_configDB["YPIDV"]); - if (pid.size() > 2) { - servoControllerConfig.devConfig.YPIDV.P = pid[0]; - servoControllerConfig.devConfig.YPIDV.I = pid[1]; - servoControllerConfig.devConfig.YPIDV.D = pid[2]; - } - - - // slew and track parameters - - movingModelParams.telemetryTimeout = - std::get(this->_configDB["telemetryTimeout"]); - - movingModelParams.minTimeToPZone = - std::get(this->_configDB["minTimeToPZone"]); - - movingModelParams.updatingPZoneInterval = - std::get(this->_configDB["updatingPZoneInterval"]); - - movingModelParams.slewToleranceRadius = - std::get(this->_configDB["slewToleranceRadius"]); - - movingModelParams.adjustCoordDiff = - std::get(this->_configDB["adjustCoordDiff"]); - - movingModelParams.adjustCycleInterval = - std::get(this->_configDB["adjustCycleInterval"]); - - movingModelParams.slewTimeout = - std::get(this->_configDB["slewTimeout"]); - - movingModelParams.timeShiftToTargetPoint = - std::get(this->_configDB["timeShiftToTargetPoint"]); - - movingModelParams.trackingCycleInterval = - std::get(this->_configDB["trackingCycleInterval"]); - - - // PCM data - - pcmData.type = std::get(this->_configDB["pcmType"]); - - pcmData.siteLatitude = std::get(this->_configDB["siteLatitude"]); - - pid = std::get>(this->_configDB["pcmGeomCoeffs"]); - if (pid.size() >= 9) { // must be 9 coefficients - pcmData.geomCoefficients = {.zeroPointX = pid[0], - .zeroPointY = pid[1], - .collimationErr = pid[2], - .nonperpendErr = pid[3], - .misalignErr1 = pid[4], - .misalignErr2 = pid[5], - .tubeFlexure = pid[6], - .forkFlexure = pid[7], - .DECaxisFlexure = pid[8]}; - } - - std::vector dd = std::get(this->_configDB["pcmBsplineDegree"]); - if (dd.size() >= 2) { - pcmData.bspline.bsplDegreeX = dd[0] > 0 ? dd[0] : 3; - pcmData.bspline.bsplDegreeY = dd[1] > 0 ? dd[1] : 3; - } - - pid = std::get>(this->_configDB["pcmBsplineXknots"]); - // pid must contains interior and border (single point for each border) knots so minimal length must be 2 - if (pid.size() >= 2) { - // generate full knots array (with border knots) - size_t Nknots = pid.size() + pcmData.bspline.bsplDegreeX * 2 - 2; - pcmData.bspline.knotsX.resize(Nknots); - - for (size_t i = 0; i <= pcmData.bspline.bsplDegreeX; ++i) { // border knots - pcmData.bspline.knotsX[i] = pid[0]; - pcmData.bspline.knotsX[Nknots - i - 1] = pid.back(); - } - for (size_t i = 0; i < (pid.size() - 2); ++i) { // interior knots - pcmData.bspline.knotsX[i + pcmData.bspline.bsplDegreeX] = pid[1 + i]; - } - } - - pid = std::get>(this->_configDB["pcmBsplineYknots"]); - // pid must contains interior and border (single point for each border) knots so minimal length must be 2 - if (pid.size() >= 2) { - // generate full knots array (with border knots) - size_t Nknots = pid.size() + pcmData.bspline.bsplDegreeY * 2 - 2; - pcmData.bspline.knotsY.resize(Nknots); - - for (size_t i = 0; i <= pcmData.bspline.bsplDegreeY; ++i) { // border knots - pcmData.bspline.knotsY[i] = pid[0]; - pcmData.bspline.knotsY[Nknots - i - 1] = pid.back(); - } - for (size_t i = 0; i < (pid.size() - 2); ++i) { // interior knots - pcmData.bspline.knotsY[i + pcmData.bspline.bsplDegreeY] = pid[1 + i]; - } - } - - // minimal allowed number of B-spline coefficients - size_t Ncoeffs = pcmData.type == mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY - ? 0 - : (pcmData.bspline.knotsX.size() - pcmData.bspline.bsplDegreeX - 1) * - (pcmData.bspline.knotsY.size() - pcmData.bspline.bsplDegreeY - 1); - - pid = std::get>(this->_configDB["pcmBsplineXcoeffs"]); - - if (pid.size() >= Ncoeffs) { - pcmData.bspline.coeffsX.resize(Ncoeffs); - for (size_t i = 0; i < Ncoeffs; ++i) { - pcmData.bspline.coeffsX[i] = pid[i]; - } - } - - pid = std::get>(this->_configDB["pcmBsplineYcoeffs"]); - - if (pid.size() >= Ncoeffs) { - pcmData.bspline.coeffsY.resize(Ncoeffs); - for (size_t i = 0; i < Ncoeffs; ++i) { - pcmData.bspline.coeffsY[i] = pid[i]; - } - } - } - - inline static auto deserializer = [](std::string_view str, auto& value) { - using value_t = std::decay_t; - - bool ok = true; - - if constexpr (std::is_arithmetic_v || mcc::traits::mcc_output_char_range || - std::ranges::range || mcc::traits::mcc_time_duration_c) { - return base_t::defaultDeserializeFunc(str, value); - } else if constexpr (std::same_as) { // assume here all angles are in degrees - double vd; - ok = base_t::defaultDeserializeFunc(str, vd); - if (ok) { - value = mcc::MccAngle(vd, mcc::MccDegreeTag{}); - } - } else if constexpr (std::same_as) { - std::string vstr; - ok = base_t::defaultDeserializeFunc(str, vstr); - auto s = mcc::utils::trimSpaces(vstr); - - if (ok) { - if (s == mcc::MccDefaultPCMTypeString) { - value = mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY; - } else if (s == mcc::MccDefaultPCMTypeString) { - value = mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY; - } else if (s == mcc::MccDefaultPCMTypeString) { - value = mcc::MccDefaultPCMType::PCM_TYPE_BSPLINE; - } else { - return false; - } - } - } else { - return false; - } - - return ok; - }; -}; - static constexpr std::string_view Asibfm700MountConfigString = R"--( diff --git a/asibfm700/asibfm700_netserver.cpp b/asibfm700/asibfm700_netserver.cpp index d10a9b2..39f3abd 100644 --- a/asibfm700/asibfm700_netserver.cpp +++ b/asibfm700/asibfm700_netserver.cpp @@ -14,13 +14,13 @@ Asibfm700MountNetServer::Asibfm700MountNetServer(asio::io_context& ctx, // to avoid possible compiler optimization (one needs to catch 'mount' strictly by reference) auto* mount_ptr = &mount; - base_t::_handleMessageFunc = [base_hndl_func = std::move(base_t::_handleMessageFunc), mount_ptr, - this](std::string_view command) { + base_t::_handleMessageFunc = [mount_ptr, this](std::string_view command) { using mount_error_t = typename Asibfm700Mount::error_t; std::error_code err{}; Asibfm700NetMessage input_msg; - Asibfm700NetMessage output_msg; + using output_msg_t = Asibfm700NetMessage; + output_msg_t output_msg; auto ec = parseMessage(command, input_msg); @@ -41,7 +41,8 @@ Asibfm700MountNetServer::Asibfm700MountNetServer(asio::io_context& ctx, ASIBFM700_COMMPROTO_KEYWORD_METEO_STR, mount_ptr->getStateERFA().meteo); } } else { - output_msg = base_t::handleMessage(input_msg, mount_ptr); + // basic network message processing + output_msg = base_t::handleMessage(input_msg, mount_ptr); } } diff --git a/asibfm700/tests/cfg_test.cpp b/asibfm700/tests/cfg_test.cpp index 01c3d3c..de7430d 100644 --- a/asibfm700/tests/cfg_test.cpp +++ b/asibfm700/tests/cfg_test.cpp @@ -21,35 +21,7 @@ int main() auto desc = std::make_tuple(rec_t{"A", 1}, rec_t{"B", 2.2}, rec_t{"C", std::string("EEE")}, rec_t{"D", 3.3}, rec_t{"E", std::vector{1, 2, 3}}); - asibfm700::ConfigHolder ch(desc); - - // auto err = ch.parse(cfg_str, [](auto s, auto &v) { - // if constexpr (std::is_arithmetic_v>) { - // v = 77; - // } else { - // v = std::string{s.begin(), s.end()}; - // } - - // return true; - // }); - - auto err = ch.parse(cfg_str); - - auto v = ch.value("A"); - - std::cout << v.value() << "\n"; - - // auto v2 = ch.value("D"); - auto v2 = ch.value("C"); - std::cout << v2.value_or("") << "\n"; - - auto v3 = ch.value>("E"); - std::cout << "["; - for (auto& el : v3.value_or({0, 0, 0})) { - std::cout << el << " "; - } - std::cout << "]\n"; - + std::error_code err; std::ofstream fst("/tmp/cfg.cfg"); fst << asibfm700::Asibfm700MountConfigString; @@ -85,7 +57,7 @@ int main() if (ec) { std::cout << "EC = " << ec.message() << "\n"; } else { - v3 = kvh.getValue>("E"); + auto v3 = kvh.getValue>("E"); std::cout << "["; for (auto& el : v3.value_or({0, 0, 0})) { std::cout << el << " "; diff --git a/mcc/mcc_netserver.h b/mcc/mcc_netserver.h index 695bc9a..4454f78 100644 --- a/mcc/mcc_netserver.h +++ b/mcc/mcc_netserver.h @@ -907,148 +907,17 @@ public: mount_error_t m_err; MccNetMessage input_msg; - MccNetMessage output_msg; + using output_msg_t = MccNetMessage; + output_msg_t output_msg; auto ec = parseMessage(command, input_msg); if (ec) { output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR, ec); } else { - output_msg = handleMessage(input_msg, mount_ptr); + output_msg = handleMessage(input_msg, mount_ptr); } return output_msg.byteRepr(); - - // std::error_code err{}; - - // if (auto ec = parseMessage(command, input_msg)) { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR, ec); - // } else { - // if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR)) { // strange! - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR)) { // ??!!! - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_RESTART_SERVER_STR)) { - // this->restart(); - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_INIT_STR)) { - // m_err = mount_ptr->initMount(); - // if (m_err) { - // err = mcc_deduce_error_code(m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_INIT); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_STOP_STR)) { - // m_err = mount_ptr->stopMount(); - // if (m_err) { - // err = mcc_deduce_error_code(m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_STOP); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_SLEW_STR)) { - // m_err = mount_ptr->slewToTarget(false); - // if (m_err) { - // err = mcc_deduce_error_code(m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_SLEW); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_MOVE_STR)) { - // m_err = mount_ptr->slewToTarget(true); - // if (m_err) { - // err = mcc_deduce_error_code(m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_MOVE); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_TRACK_STR)) { - // m_err = mount_ptr->trackTarget(); - // if (m_err) { - // 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); - // if (v) { - // _coordFormat = v.value(); - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } else { - // err = v.error(); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_COORDPREC_STR)) { - // auto v = input_msg.paramValue(0); - // if (v) { - // _coordPrec = v.value(); - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } else { - // err = v.error(); - // } - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_TARGET_STR)) { - // // by default return ICRS coordinates - // MccCelestialPoint cp{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS}; - - // auto sz = input_msg.paramSize(); - // if (sz) { // set or get operation - // auto vc = input_msg.paramValue(0); // is it set operation? - // if (vc) { // coordinates are given - set - // operation - // auto m_err = mount_ptr->setPointingTarget(vc.value()); - // if (m_err) { - // if (m_err) { - // err = mcc_deduce_error_code( - // m_err, MccGenericMountNetworkServerErrorCode::ERROR_MOUNT_SET_TARGET); - // } - // } else { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // } - // } else { - // auto vp = input_msg.paramValue(0); - // if (vp) { // coordinate pair kind is given - // cp.pair_kind = vp.value(); - // err = coordsFromTelemetryData(*mount_ptr, true, cp); - // if (!err) { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, - // MCC_COMMPROTO_KEYWORD_TARGET_STR, cp); - // } - // } else { // invalid command!!! - // err = vp.error(); - // } - // } - // } else { // get operation - // err = coordsFromTelemetryData(*mount_ptr, true, cp); - // if (!err) { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, - // MCC_COMMPROTO_KEYWORD_TARGET_STR, - // _coordFormat, _coordPrec, cp); - // } - // } - - // } else if (input_msg.withKey(MCC_COMMPROTO_KEYWORD_MOUNT_STR)) { - // // by default return ICRS coordinates - // MccCelestialPoint cp{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS}; - - // if (input_msg.paramSize()) { // ccordinate pair kind is given - // auto vp = input_msg.paramValue(0); - // if (vp) { // coordinate pair kind is given - // cp.pair_kind = vp.value(); - // err = coordsFromTelemetryData(*mount_ptr, false, cp); - // if (!err) { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, - // MCC_COMMPROTO_KEYWORD_MOUNT_STR, cp); - // } - // } else { // invalid command!!! - // err = vp.error(); - // } - - // } else { - // err = coordsFromTelemetryData(*mount_ptr, false, cp); - // if (!err) { - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, - // MCC_COMMPROTO_KEYWORD_MOUNT_STR, - // _coordFormat, _coordPrec, cp); - // } - // } - // } else { - // err = std::make_error_code(std::errc::invalid_argument); - // } - - // if (err) { // send error description - // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR, err); - // } - // // else { // send ACK with copy of the input message - // // output_msg.construct(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, command); - // // } - // } - - // return output_msg.byteRepr(); }; } diff --git a/mcc/mcc_netserver_proto.h b/mcc/mcc_netserver_proto.h index ef68b40..9abbc4b 100644 --- a/mcc/mcc_netserver_proto.h +++ b/mcc/mcc_netserver_proto.h @@ -237,204 +237,6 @@ static constexpr std::array MCC_COMMPROTO_VALID_KEYS_HASH = [](std }(std::make_index_sequence()); -static constexpr size_t MCC_COMMPROTO_KEYWORD_SERVER_ACK_HASH = - mcc::utils::FNV1aHash(MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR); - -static constexpr size_t MCC_COMMPROTO_KEYWORD_SERVER_ERROR_HASH = - mcc::utils::FNV1aHash(MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR); - -static constexpr size_t MCC_COMMPROTO_KEYWORD_TARGET_HASH = mcc::utils::FNV1aHash(MCC_COMMPROTO_KEYWORD_TARGET_STR); - -static constexpr size_t MCC_COMMPROTO_KEYWORD_MOUNT_HASH = mcc::utils::FNV1aHash(MCC_COMMPROTO_KEYWORD_MOUNT_STR); - - -template RT = std::vector> -struct mcc_netmsg_parse_result_t { - size_t keyword_hash; - T keyword; - RT params; -}; - - -// network message parsing result class concept -template -concept mcc_netmsg_parse_result_c = requires(T t) { - requires std::same_as; // hash of keyword - requires traits::mcc_char_range; // keyword char-range representation - // a range of parameters char-range representations - requires std::ranges::output_range; -}; - -// the function returns hash of message keyword -// if 'from_server' is true then given network message is considered as a server response, i.e., -// valid keywords are "ACK" or "ERROR" -// -// the funtions returns false in the case of invalid message format and true otherwise -// -template -bool mcc_parse_netmsg(const IR& netmsg, ResT& parse_res, bool from_server = false) -{ - if (std::ranges::size(netmsg) == 0) { - return false; - }; - - auto found = std::ranges::search(netmsg, MCC_COMMPROTO_KEYPARAM_DELIM_SEQ); - if (std::distance(netmsg.begin(), found.begin()) == 0) { - return false; - } - - const size_t hash = mcc::utils::FNV1aHash(netmsg.begin(), found.begin()); - auto it = std::ranges::find(MCC_COMMPROTO_VALID_KEYS_HASH, hash); - if (it == MCC_COMMPROTO_VALID_KEYS_HASH.end()) { - return false; - } - - if (from_server) { // only ACK or ERROR - auto ok = hash == MCC_COMMPROTO_VALID_KEYS_HASH[0] || hash == MCC_COMMPROTO_VALID_KEYS_HASH[1]; - if (!ok) { - return false; - } - } - - parse_res.keyword_hash = hash; - parse_res.keyword = {netmsg.begin(), found.begin()}; - - auto pars = netmsg | std::views::drop(std::distance(netmsg.begin(), found.end())) | - std::views::split(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ); - - decltype(parse_res.params) res; - - for (auto const& el : pars) { // parameters - std::back_inserter(res) = {el.begin(), el.end()}; - } - - parse_res.params = std::move(res); - - return true; -} - - -// construct network message -// the function returns false if input keyword is not valid one (see MCC_COMMPROTO_VALID_KEYS)! -template -bool mcc_netmsg_construct(traits::mcc_output_char_range auto& msg, - traits::mcc_input_char_range auto const& keyword, - PTs... params) -{ - const size_t hash = mcc::utils::FNV1aHash(keyword); - if (!std::ranges::contains(MCC_COMMPROTO_VALID_KEYS_HASH, hash)) { - return false; - } - - msg = {keyword.begin(), keyword.end()}; - - if constexpr (sizeof...(PTs)) { - std::ranges::copy(MCC_COMMPROTO_KEYPARAM_DELIM_SEQ, std::back_inserter(msg)); - - [&msg](this auto&& self, const T& par, const Ts&... pars) { - if constexpr (std::is_arithmetic_v) { - std::ranges::copy(std::to_string(par), std::back_inserter(msg)); - } else if constexpr (std::convertible_to) { - std::ranges::copy(static_cast(par), std::back_inserter(msg)); - } else if constexpr (std::constructible_from) { - std::ranges::copy(std::string(par), std::back_inserter(msg)); - } else if constexpr (traits::mcc_char_range) { - std::ranges::copy(std::string(par.begin(), par.end()), std::back_inserter(msg)); - } else if constexpr (std::same_as) { - std::ranges::copy(mcc_pairkind2str(par), std::back_inserter(msg)); - } else { - static_assert(false, "UNSUPPORTED TYPE!!!"); - } - - if constexpr (sizeof...(Ts)) { - std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(msg)); - - std::forward(self)(pars...); - } - }(params...); - } - - return true; -} - - -// the function convert given network message parsing result class to -// celestial point coordinates according to parsed message parameters. -// -// It is assumed that the coordinates and their type are contained in the consecutive elements of the input array -// starting from the element 'from_idx' (zero-based): -// -// parse_res.params[..., X-COORD, Y-COORD, XY-KIND, ...] -// -// th last parameter 'XY-KIND' can be omitted and, in this case, 'default_kind' is assumed -// -// NOTE: IT IS ASSUMED THAT THE COORDINATES ARE REPRESENTED AS DEGREES EXPRESSED BY THE NUMBER WITH A FLOATING POINT -// OR IN SEXAGESIMAL FORM. IN THE CASE OF SEXAGESIMAL FORM THE TYPE (DEGREES OR HOURS) OF THE COORDINATE -// REPRESENTATION IS DETERMINED BY 'XY-KIND', E.G.: -// parse_res.params[..., "12:34:52.123", "23:43:56.12", "HADEC", ...] -// 'HADEC' STRING FOR 'XY-KIND' DETERMINES THE FIRST COORDINATE (HOUR ANGLE) -// AS AN ANGLE IN HOUR FORM WHILE THE SECOND ONE (DECLINATION) IN DEGREES -// -// -// The function returns false if it can not convert coordinate string to number or the 'XY-KIND' string is invalid -// -bool mcc_netmsg_get_cpoint(mcc_netmsg_parse_result_c auto const& parse_res, - size_t from_idx, - mcc_celestial_point_c auto& cpoint, - MccCoordPairKind default_kind) - requires std::ranges::contiguous_range -{ - if (std::ranges::size(parse_res.params) < (from_idx + 2)) { - return false; - } - - MccCoordPairKind kind = default_kind; - - if (std::ranges::size(parse_res.params) > (from_idx + 2)) { - kind = mcc_str2pairkind(parse_res.params[from_idx + 2]); - if (kind == MccCoordPairKind::COORDS_KIND_GENERIC) { - return false; - } - } - - std::optional ang1, ang2; - - switch (kind) { - 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(parse_res.params[from_idx], true); - break; - default: - ang1 = mcc::utils::parsAngleString(parse_res.params[from_idx]); - } - if (!ang1) { - return false; - } - - ang2 = mcc::utils::parsAngleString(parse_res.params[from_idx + 1]); - if (!ang2) { - return false; - } - - if (kind != mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { - mcc_tp2tp(std::chrono::system_clock::now(), cpoint.time_point); - } else { - // 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, cpoint.time_point); - } - - cpoint.pair_kind = kind; - - cpoint.X = MccAngle(ang1.value(), mcc::MccDegreeTag{}); // to radians - cpoint.Y = MccAngle(ang2.value(), mcc::MccDegreeTag{}); // to radians - - return true; -} - template concept mcc_netmsg_valid_keys_c = requires(T t) { diff --git a/mcc/tests/ccte_test.cpp b/mcc/tests/ccte_test.cpp index 522fb30..8a5f04d 100644 --- a/mcc/tests/ccte_test.cpp +++ b/mcc/tests/ccte_test.cpp @@ -2,7 +2,6 @@ #include #include "../mcc_ccte_erfa.h" -#include "../mcc_netserver_proto.h" #include "../mcc_pzone.h" #include "../mcc_pzone_container.h" @@ -157,63 +156,5 @@ int main() std::cout << a1.sexagesimal() << "\n" << a2.sexagesimal() << "\n"; - std::cout << "\n\n"; - - std::string sm{"ACK TARGET 12:23:45.13 -09.23423525 RADEC"}; - // std::vector sv; - std::vector sv; - mcc::network::mcc_netmsg_parse_result_t<> p_res; - - auto mr = mcc::network::mcc_parse_netmsg(sm, p_res); - - std::cout << "MSG: <" << sm << ">\n"; - std::cout << "\t" << p_res.keyword_hash << "\n"; - std::cout << "\t[" << p_res.keyword << "]\n"; - for (auto const& pr : p_res.params) { - std::cout << "\t[" << pr << "]\n"; - } - - std::cout << "GET CPOINT RET: " - << mcc::network::mcc_netmsg_get_cpoint(p_res, 1, cp, mcc::MccCoordPairKind::COORDS_KIND_AZZD) << "\n"; - std::cout << "CPOINT.X = " << cp.X << ", CPOINT.Y = " << cp.Y << " (" - << mcc::network::mcc_pairkind2str(cp.pair_kind) << ")\n"; - - - sm = "ERROR "; - - mr = mcc::network::mcc_parse_netmsg(sm, p_res); - - std::cout << "MSG: <" << sm << ">\n"; - sm[0] = 'e'; - std::cout << "\t" << p_res.keyword_hash << "\n"; - std::cout << "\t[" << p_res.keyword << "]\n"; - for (auto const& pr : p_res.params) { - std::cout << "\t[" << pr << "]\n"; - } - - - mr = mcc::network::mcc_netmsg_construct(sm, mcc::network::MCC_COMMPROTO_KEYWORD_TARGET_STR, 12.3456789, - "34:21:56.132", mcc::MccCoordPairKind::COORDS_KIND_AZZD); - - std::cout << "\nNETMSG: [" << sm << "] (" << mr << ")\n"; - - 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::duration(55.816); - + std::chrono::hours(11) + std::chrono::minutes(58) + std::chrono::milliseconds(55816); - - std::cout << tp << "\n"; - // std::cout << std::chrono::system_clock::now() << "\n"; - - - constexpr std::string_view stv{"RADEC"}; - constexpr char ccv[] = "RADEC"; - - // const auto pk = mcc::network::mcc_str2pairkind(stv); - // const auto pk = mcc::network::mcc_str2pairkind(std::string_view{"RADEC"}); - // const auto pk = mcc::network::mcc_str2pairkind("RADEC"); - const auto pk = mcc::network::mcc_str2pairkind(ccv); - static_assert(pk == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP); - return 0; }