From f2be52d17c3b745912c40580657f9bff4403f60a Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 30 Oct 2025 16:11:23 +0300 Subject: [PATCH] ... add dump of config for Asibfm700MountConfig class --- asibfm700/asibfm700_configfile.h | 379 +++++++++++++------------------ asibfm700/tests/cfg_test.cpp | 11 +- 2 files changed, 155 insertions(+), 235 deletions(-) diff --git a/asibfm700/asibfm700_configfile.h b/asibfm700/asibfm700_configfile.h index cd71f56..d323c11 100644 --- a/asibfm700/asibfm700_configfile.h +++ b/asibfm700/asibfm700_configfile.h @@ -30,6 +30,7 @@ template struct simple_config_record_t { std::string_view key; T value; + std::vector comment; }; @@ -38,60 +39,77 @@ struct simple_config_record_t { // configuration description and its defaults static auto Asibfm700MountConfigDefaults = std::make_tuple( // main cycle period in millisecs - simple_config_record_t{"hardwarePollingPeriod", std::chrono::milliseconds{100}}, + simple_config_record_t{"hardwarePollingPeriod", std::chrono::milliseconds{100}, {"main cycle period in millisecs"}}, /* geographic coordinates of the observation site */ // site latitude in degrees - simple_config_record_t{"siteLatitude", mcc::MccAngle(43.646711_degs)}, + simple_config_record_t{"siteLatitude", mcc::MccAngle(43.646711_degs), {"site latitude in degrees"}}, // site longitude in degrees - simple_config_record_t{"siteLongitude", mcc::MccAngle(41.440732_degs)}, + simple_config_record_t{"siteLongitude", mcc::MccAngle(41.440732_degs), {"site longitude in degrees"}}, // site elevation in meters - simple_config_record_t{"siteElevation", 2070.0}, + simple_config_record_t{"siteElevation", 2070.0, {"site elevation in meters"}}, /* celestial coordinate transformation */ - // wavelength at which refraction is calculated (in mkm) - simple_config_record_t{"refractWavelength", 0.55}, + // wavelength at which refraction is calculated (in mkm) + simple_config_record_t{"refractWavelength", 0.55, {"wavelength at which refraction is calculated (in mkm)"}}, // an empty filename means default precompiled string - simple_config_record_t{"leapSecondFilename", std::string()}, + simple_config_record_t{"leapSecondFilename", std::string(), {"an empty filename means default precompiled string"}}, // an empty filename means default precompiled string - simple_config_record_t{"bulletinAFilename", std::string()}, + simple_config_record_t{"bulletinAFilename", std::string(), {"an empty filename means default precompiled string"}}, /* pointing correction model */ // PCM default type - simple_config_record_t{"pcmType", mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY}, + simple_config_record_t{"pcmType", + mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY, + {"PCM type:", "GEOMETRY - 'classic' geometry-based correction coefficients", + "GEOMETRY-BSPLINE - previous one and additional 2D B-spline corrections", + "BSPLINE - pure 2D B-spline corrections"}}, // PCM geometrical coefficients - simple_config_record_t{"pcmGeomCoeffs", std::vector{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, + simple_config_record_t{"pcmGeomCoeffs", + std::vector{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {"PCM geometrical coefficients"}}, // PCM B-spline degrees - simple_config_record_t{"pcmBsplineDegree", std::vector{3, 3}}, + simple_config_record_t{"pcmBsplineDegree", std::vector{3, 3}, {"PCM B-spline degrees"}}, // PCM B-spline knots along X-axis (HA-angle or azimuth). By default from 0 to 2*PI radians // NOTE: The first and last values are interpretated as border knots!!! // Thus the array length must be equal to or greater than 2! simple_config_record_t{"pcmBsplineXknots", std::vector{0.0, 0.6981317, 1.3962634, 2.0943951, 2.7925268, 3.4906585, 4.1887902, - 4.88692191, 5.58505361, 6.28318531}}, + 4.88692191, 5.58505361, 6.28318531}, + {"PCM B-spline knots along X-axis (HA-angle or azimuth). By default from 0 to 2*PI radians", + "NOTE: The first and last values are interpretated as border knots!!!", + " Thus the array length must be equal to or greater than 2!"}}, // PCM B-spline knots along Y-axis (declination or zenithal distance). By default from -PI/6 to PI/2 radians // NOTE: The first and last values are interpretated as border knots!!! // Thus the array length must be equal to or greater than 2! - simple_config_record_t{"pcmBsplineYknots", - std::vector{-0.52359878, -0.29088821, -0.05817764, 0.17453293, 0.40724349, - 0.63995406, 0.87266463, 1.10537519, 1.33808576, 1.57079633}}, + simple_config_record_t{ + "pcmBsplineYknots", + std::vector{-0.52359878, -0.29088821, -0.05817764, 0.17453293, 0.40724349, 0.63995406, 0.87266463, + 1.10537519, 1.33808576, 1.57079633}, + {"PCM B-spline knots along Y-axis (declination or zenithal distance). By default from -PI/6 to PI/2 radians", + "NOTE: The first and last values are interpretated as border knots!!!", + " Thus the array length must be equal to or greater than 2!"}}, // PCM B-spline coeffs for along X-axis (HA-angle or azimuth) - simple_config_record_t{"pcmBsplineXcoeffs", std::vector{}}, + simple_config_record_t{"pcmBsplineXcoeffs", + std::vector{}, + {"PCM B-spline coeffs for along X-axis (HA-angle)"}}, // PCM B-spline coeffs for along Y-axis (declination or zenithal distance) - simple_config_record_t{"pcmBsplineYcoeffs", std::vector{}}, + simple_config_record_t{"pcmBsplineYcoeffs", + std::vector{}, + {"PCM B-spline coeffs for along Y-axis (declination angle)"}}, /* slewing and tracking parameters */ @@ -100,286 +118,144 @@ static auto Asibfm700MountConfigDefaults = std::make_tuple( // simple_config_record_t{"sideralRate", 15.0410686}, // timeout for telemetry updating in milliseconds - simple_config_record_t{"telemetryTimeout", std::chrono::milliseconds(3000)}, + simple_config_record_t{"telemetryTimeout", + std::chrono::milliseconds(3000), + {"timeout for telemetry updating in milliseconds"}}, // minimal allowed time in seconds to prohibited zone - simple_config_record_t{"minTimeToPZone", std::chrono::seconds(10)}, + simple_config_record_t{"minTimeToPZone", + std::chrono::seconds(10), + {"minimal allowed time in seconds to prohibited zone"}}, // a time interval to update prohibited zones related quantities (millisecs) - simple_config_record_t{"updatingPZoneInterval", std::chrono::milliseconds(5000)}, + simple_config_record_t{"updatingPZoneInterval", + std::chrono::milliseconds(5000), + {"a time interval to update prohibited zones related quantities (millisecs)"}}, // coordinates difference in arcsecs to stop slewing - simple_config_record_t{"slewToleranceRadius", 5.0}, + simple_config_record_t{"slewToleranceRadius", 5.0, {"coordinates difference in arcsecs to stop slewing"}}, // target-mount coordinate difference in arcsecs to start adjusting of slewing - simple_config_record_t{"adjustCoordDiff", 50.0}, + simple_config_record_t{"adjustCoordDiff", + 50.0, + {"target-mount coordinate difference in arcsecs to start adjusting of slewing"}}, // minimum time in millisecs between two successive adjustments - simple_config_record_t{"adjustCycleInterval", std::chrono::milliseconds(300)}, + simple_config_record_t{"adjustCycleInterval", + std::chrono::milliseconds(300), + {"minimum time in millisecs between two successive adjustments"}}, // slew process timeout in seconds - simple_config_record_t{"slewTimeout", std::chrono::seconds(3600)}, + simple_config_record_t{"slewTimeout", std::chrono::seconds(3600), {"slew process timeout in seconds"}}, // a time shift into future to compute target position in future (UT1-scale time duration, millisecs) - simple_config_record_t{"timeShiftToTargetPoint", std::chrono::milliseconds(10000)}, + simple_config_record_t{ + "timeShiftToTargetPoint", + std::chrono::milliseconds(10000), + {"a time shift into future to compute target position in future (UT1-scale time duration, millisecs)"}}, // minimum time in millisecs between two successive tracking corrections - simple_config_record_t{"trackingCycleInterval", std::chrono::milliseconds(300)}, + simple_config_record_t{"trackingCycleInterval", + std::chrono::milliseconds(300), + {"minimum time in millisecs between two successive tracking corrections"}}, // maximal valid target-to-mount distance for tracking process (arcsecs) // if current distance is greater than assume current mount coordinate as target point - simple_config_record_t{"trackingMaxCoordDiff", 20.0}, + simple_config_record_t{"trackingMaxCoordDiff", + 20.0, + {"maximal valid target-to-mount distance for tracking process (arcsecs)", + "if current distance is greater than assume current mount coordinate as target point"}}, /* prohibited zones */ // minimal altitude - simple_config_record_t{"pzMinAltitude", mcc::MccAngle(10.0_degs)}, + simple_config_record_t{"pzMinAltitude", mcc::MccAngle(10.0_degs), {"minimal altitude"}}, // HA-axis limit switch minimal value - simple_config_record_t{"pzLimitSwitchHAMin", mcc::MccAngle(-170.0_degs)}, + simple_config_record_t{"pzLimitSwitchHAMin", mcc::MccAngle(-170.0_degs), {"HA-axis limit switch minimal value"}}, // HA-axis limit switch maximal value - simple_config_record_t{"pzLimitSwitchHAMax", mcc::MccAngle(170.0_degs)}, + simple_config_record_t{"pzLimitSwitchHAMax", mcc::MccAngle(170.0_degs), {"HA-axis limit switch maximal value"}}, // DEC-axis limit switch minimal value - simple_config_record_t{"pzLimitSwitchDecMin", mcc::MccAngle(-90.0_degs)}, + simple_config_record_t{"pzLimitSwitchDecMin", mcc::MccAngle(-90.0_degs), {"DEC-axis limit switch minimal value"}}, // DEC-axis limit switch maximal value - simple_config_record_t{"pzLimitSwitchDecMax", mcc::MccAngle(90.0_degs)}, + simple_config_record_t{"pzLimitSwitchDecMax", mcc::MccAngle(90.0_degs), {"DEC-axis limit switch maximal value"}}, /* hardware-related */ // hardware mode: 1 - model mode, otherwise real mode - simple_config_record_t{"RunModel", 0}, + simple_config_record_t{"RunModel", 0, {"hardware mode: 1 - model mode, otherwise real mode"}}, // mount serial device paths - simple_config_record_t{"MountDevPath", std::string("/dev/ttyUSB0")}, + simple_config_record_t{"MountDevPath", std::string("/dev/ttyUSB0"), {"mount serial device paths"}}, // mount serial device speed - simple_config_record_t{"MountDevSpeed", 19200}, + simple_config_record_t{"MountDevSpeed", 19200, {"mount serial device speed"}}, // motor encoders serial device path - simple_config_record_t{"EncoderDevPath", std::string("")}, + simple_config_record_t{"EncoderDevPath", std::string(""), {"motor encoders serial device path"}}, // X-axis encoder serial device path - simple_config_record_t{"EncoderXDevPath", std::string("/dev/encoderX0")}, + simple_config_record_t{"EncoderXDevPath", std::string("/dev/encoderX0"), {"X-axis encoder serial device path"}}, // Y-axis encoder serial device path - simple_config_record_t{"EncoderYDevPath", std::string("/dev/encoderY0")}, + simple_config_record_t{"EncoderYDevPath", std::string("/dev/encoderY0"), {"Y-axis encoder serial device path"}}, // encoders serial device speed - simple_config_record_t{"EncoderDevSpeed", 153000}, + simple_config_record_t{"EncoderDevSpeed", 153000, {"encoders serial device speed"}}, // ==1 if encoder works as separate serial device, ==2 if there's new version with two devices - simple_config_record_t{"SepEncoder", 2}, + simple_config_record_t{ + "SepEncoder", + 2, + {"==1 if encoder works as separate serial device, ==2 if there's new version with two devices"}}, // mount polling interval in millisecs - simple_config_record_t{"MountReqInterval", std::chrono::milliseconds(100)}, + simple_config_record_t{"MountReqInterval", std::chrono::milliseconds(100), {"mount polling interval in millisecs"}}, // encoders polling interval in millisecs - simple_config_record_t{"EncoderReqInterval", std::chrono::milliseconds(50)}, + simple_config_record_t{"EncoderReqInterval", + std::chrono::milliseconds(50), + {"encoders polling interval in millisecs"}}, // mount axes rate calculation interval in millisecs - simple_config_record_t{"EncoderSpeedInterval", std::chrono::milliseconds(100)}, + simple_config_record_t{"EncoderSpeedInterval", + std::chrono::milliseconds(100), + {"mount axes rate calculation interval in millisecs"}}, // X-axis coordinate PID P,I,D-params - simple_config_record_t{"XPIDC", std::vector{0.8, 0.1, 0.3}}, + simple_config_record_t{"XPIDC", std::vector{0.8, 0.1, 0.3}, {"X-axis coordinate PID P,I,D-params"}}, // X-axis rate PID P,I,D-params - simple_config_record_t{"XPIDV", std::vector{1.0, 0.01, 0.2}}, + simple_config_record_t{"XPIDV", std::vector{1.0, 0.01, 0.2}, {"X-axis rate PID P,I,D-params"}}, // Y-axis coordinate PID P, I, D-params - simple_config_record_t{"YPIDC", std::vector{0.8, 0.1, 0.3}}, + simple_config_record_t{"YPIDC", std::vector{0.8, 0.1, 0.3}, {"Y-axis coordinate PID P, I, D-params"}}, // Y-axis rate PID P,I,D-params - simple_config_record_t{"YPIDV", std::vector{0.5, 0.2, 0.5}}, + simple_config_record_t{"YPIDV", std::vector{0.5, 0.2, 0.5}, {"Y-axis rate PID P,I,D-params"}}, // maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller) - simple_config_record_t{"hwMaxRateHA", mcc::MccAngle(8.0_degs)}, + simple_config_record_t{ + "hwMaxRateHA", + mcc::MccAngle(8.0_degs), + {"maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller)"}}, // maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller) - simple_config_record_t{"hwMaxRateDEC", mcc::MccAngle(10.0_degs)} - + simple_config_record_t{ + "hwMaxRateDEC", + mcc::MccAngle(10.0_degs), + {"maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller)"}} ); -static constexpr std::string_view Asibfm700MountDefaultConfigString = - R"--( -# -# ASTROSIB FM-700 MOUNT DEFAULT CONFIGURATION -# -# (created 2025-10-01T03:00:00.0) -# - -# main cycle period in millisecs -hardwarePollingPeriod = 100 - -# geographic coordinates of the observation site - -# site latitude in degrees -siteLatitude = 43.646711 - -# site longitude in degrees -siteLongitude = 41.440732 - -# site elevation in meters -siteElevation = 2070.0 - -# celestial coordinate transformation - -# wavelength at which refraction is calculated (in mkm) -refractWavelength = 0.5 - -# an empty filename means default precompiled string -leapSecondFilename = - -# an empty filename means default precompiled string -bulletinAFilename = - -# pointing correction model - -# PCM default type: -# GEOMETRY - "classic" geometry-based correction coefficients -# GEOMETRY-BSPLINE - previous one and additional 2D B-spline corrections -# BSPLINE - pure 2D B-spline corrections -pcmType = GEOMETRY - -# PCM geometrical coefficients -pcmGeomCoeffs = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - -# PCM B-spline degrees -pcmBsplineDegree = 3, 3 - -# PCM B-spline knots along X-axis (HA-angle). By default from 0 to 2*PI radians -pcmBsplineXknots = 0.0, 0.6981317, 1.3962634, 2.0943951, 2.7925268, 3.4906585, 4.1887902, 4.88692191, 5.58505361, 6.28318531 - -# PCM B-spline knots along Y-axis (declination-angle). By default from -PI/6 to PI/2 radians -pcmBsplineYknots = -0.52359878, -0.29088821, -0.05817764, 0.17453293, 0.40724349, 0.63995406, 0.87266463, 1.10537519, 1.33808576, 1.57079633 - -# PCM B-spline coeffs for along X-axis (HA-angle) -pcmBsplineXcoeffs = - -# PCM B-spline coeffs for along Y-axis (declination-angle) -pcmBsplineYcoeffs = - - -# slewing and tracking parameters - -# arcseconds per second -#sideralRate = 15.0410686 - -# timeout for telemetry updating in milliseconds -telemetryTimeout = 3000 - -# minimal allowed time in seconds to prohibited zone -minTimeToPZone = 10 - -# a time interval to update prohibited zones related quantities (millisecs) -updatingPZoneInterval = 5000 - -# coordinates difference in arcsecs to stop slewing -slewToleranceRadius = 5.0 - -# target-mount coordinate difference in arcsecs to start adjusting of slewing -adjustCoordDiff = 50.0 - -# minimum time in millisecs between two successive adjustments -adjustCycleInterval = 300 - -# slew process timeout in seconds -slewTimeout = 3600 - -# a time shift into future to compute target position in future (UT1-scale time duration, millisecs) -timeShiftToTargetPoint = 10000 - -# minimum time in millisecs between two successive tracking corrections -trackingCycleInterval = 300 - -# maximal valid target-to-mount distance for tracking process (arcsecs) -# if current distance is greater than assume current mount coordinate as target point -trackingMaxCoordDiff = 20.0 - -# prohibited zones - -# minimal altitude in degrees -pzMinAltitude = 10.0 - -# HA-axis limit switch minimal value in degrees -pzLimitSwitchHAMin = -170.0 - -# HA-axis limit switch maximal value in degrees -pzLimitSwitchHAMax = 170.0 - -# DEC-axis limit switch minimal value in degrees -pzLimitSwitchDecMin = -90.0 - -# DEC-axis limit switch maximal value in degrees -pzLimitSwitchDecMax = 90.0 - - -# hardware-related - -# hardware mode: 1 - model mode, otherwise real mode -RunModel = 0 - -# mount serial device paths -MountDevPath = /dev/ttyUSB0 - -# mount serial device speed -MountDevSpeed = 19200 - -# motor encoders serial device path -EncoderDevPath = - -# X-axis encoder serial device path -EncoderXDevPath = /dev/encoderX0 - -# Y-axis encoder serial device path -EncoderYDevPath = /dev/encoderY0 - -# encoders serial device speed -EncoderDevSpeed = 153000 - -# ==1 if encoder works as separate serial device, ==2 if there's new version with two devices -SepEncoder = 2 - -# mount polling interval in millisecs -MountReqInterval = 100 - -# encoders polling interval in millisecs -EncoderReqInterval = 50 - -# mount axes rate calculation interval in millisecs -EncoderSpeedInterval = 100 - -# X-axis coordinate PID P,I,D-params -XPIDC = 0.8, 0.1, 0.3 - -# X-axis rate PID P,I,D-params -XPIDV = 1.0, 0.01, 0.2 - -# Y-axis coordinate PID P,I,D-params -YPIDC = 0.8, 0.1, 0.3 - -# Y-axis rate PID P,I,D-params -YPIDV = 0.5, 0.2, 0.5 - - -# maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller) -hwMaxRateHA = 8.0 - -# maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller) -hwMaxRateDEC = 10.0 - -)--"; - - - class Asibfm700MountConfig : public mcc::utils::KeyValueHolder { using base_t = mcc::utils::KeyValueHolder; @@ -792,19 +668,70 @@ public: return ec; } - // dump default values to file - static bool dumpDefaults(const std::filesystem::path& path) + bool dumpDefaultsToFile(const std::filesystem::path& path) { std::ofstream fst(path); if (!fst.is_open()) { return false; } - fst << asibfm700::Asibfm700MountDefaultConfigString; + fst << "#\n"; + fst << "# ASTROSIB FM-700 MOUNT CONFIGURATION\n" << "#\n"; + fst << "# (created at " << std::format("{:%FT%T UTC}", std::chrono::system_clock::now()) << ")\n"; + fst << "#\n"; + + auto wrec = [&fst, this]() { + fst << "\n"; + for (size_t i = 0; i < std::get(_keyValue).comment.size(); ++i) { + fst << "# " << std::get(_keyValue).comment[i] << "\n"; + } + fst << std::get(_keyValue).key << " = "; + auto v = std::get(_keyValue).value; + using v_t = std::remove_cvref_t; + + if constexpr (std::is_arithmetic_v || mcc::traits::mcc_char_range) { + fst << std::format("{}", v); + } else if constexpr (mcc::traits::mcc_time_duration_c) { + fst << std::format("{}", v.count()); + } else if constexpr (mcc::mcc_angle_c) { + fst << std::format("{}", mcc::MccAngle(static_cast(v)).degrees()); + } else if constexpr (std::same_as) { + if (v == mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY) { + fst << mcc::MccDefaultPCMTypeString; + } else if (v == mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) { + fst << mcc::MccDefaultPCMTypeString; + } else if (v == mcc::MccDefaultPCMType::PCM_TYPE_BSPLINE) { + fst << mcc::MccDefaultPCMTypeString; + } + } else if constexpr (std::ranges::range && std::formattable, char>) { + size_t sz = std::ranges::size(v); + if (!sz) { + return; + } + --sz; + + auto it = v.begin(); + for (size_t j = 0; j < sz; ++j, ++it) { + fst << std::format("{}", *it) << base_t::VALUE_ARRAY_DELIM; + } + fst << std::format("{}", *it); + } else if constexpr (std::formattable) { + fst << std::format("{}", v); + } else { + static_assert(false, "INVALID TYPE!"); + } + + fst << "\n"; + }; + + [&wrec, this](std::index_sequence) { + (wrec.operator()(), ...); + }(std::make_index_sequence>()); + fst.close(); return true; - } + }; }; diff --git a/asibfm700/tests/cfg_test.cpp b/asibfm700/tests/cfg_test.cpp index c0de86c..a35fd49 100644 --- a/asibfm700/tests/cfg_test.cpp +++ b/asibfm700/tests/cfg_test.cpp @@ -23,28 +23,21 @@ int main() std::error_code err; - // std::ofstream fst("/tmp/cfg.cfg"); - // fst << asibfm700::Asibfm700MountConfigString; - // fst.close(); - - bool ok = asibfm700::Asibfm700MountConfig::dumpDefaults("/tmp/cfg.cfg"); + asibfm700::Asibfm700MountConfig acfg; + bool ok = acfg.dumpDefaultsToFile("/tmp/cfg.cfg"); if (!ok) { std::cerr << "Cannot dump default configuration!\n"; exit(10); } - asibfm700::Asibfm700MountConfig acfg; - auto ec = acfg.load("/tmp/cfg.cfg"); std::cout << "EC (load) = " << ec.message() << "\n"; std::cout << "refr w: " << acfg.refractWavelength() << "\n"; - // acfg.update("refractWavelength", 0.3); acfg.setValue("refractWavelength", 0.3); auto e = acfg.getValue("refractWavelength"); - // auto e = acfg.value("refractWavelength"); std::cout << "refr w: " << e.value_or(0.0) << "\n"; std::cout << "refr w: " << acfg.refractWavelength() << "\n";