diff --git a/asibfm700_config.h b/asibfm700_config.h index 22886b9..b23140a 100644 --- a/asibfm700_config.h +++ b/asibfm700_config.h @@ -7,6 +7,9 @@ #include #include "mcc/mcc_pzone.h" +#include "asibfm700_common.h" +#include "asibfm700_servocontroller.h" + namespace asibfm700 { @@ -29,7 +32,7 @@ static config_record_t make_config_record( std::string_view icomm = {}, mcc::impl::mcc_serialization_params_t const& spars = mcc::impl::mcc_serialization_params_t{}) { - return config_record_t{key, value, value, spars, hcomm, icomm}; + return config_record_t{{key, value, value, spars}, hcomm, icomm}; } @@ -463,6 +466,296 @@ public: return _lastConfigPath; } + + /* some most often used quantities */ + + template + T siteLatitude() const + { + return static_cast(getValue("siteLatitude").value_or(mcc::impl::MccAngle{})); + }; + + mcc::impl::MccAngle siteLatitude() const + { + return siteLatitude(); + }; + + template + T siteLongitude() const + { + return static_cast(getValue("siteLongitude").value_or(mcc::impl::MccAngle{})); + }; + + mcc::impl::MccAngle siteLongitude() const + { + return siteLongitude(); + }; + + template + T siteElevation() const + requires std::is_arithmetic_v + { + return getValue("siteElevation").value_or(0.0); + } + + double siteElevation() const + { + return getValue("siteElevation").value_or(0.0); + }; + + template + T refractWavelength() const + requires std::is_arithmetic_v + { + return getValue("refractWavelength").value_or(0.0); + } + + double refractWavelength() const + { + return getValue("refractWavelength").value_or(0.0); + }; + + template + R leapSecondFilename() const + { + R r; + + std::string val = getValue("leapSecondFilename").value_or(""); + std::ranges::copy(val, std::back_inserter(r)); + + return r; + } + + std::string leapSecondFilename() const + { + return leapSecondFilename(); + }; + + template + R bulletinAFilename() const + { + R r; + std::string val = getValue("bulletinAFilename").value_or(""); + std::ranges::copy(val, std::back_inserter(r)); + + return r; + } + + std::string bulletinAFilename() const + { + return bulletinAFilename(); + }; + + AsibFM700ServoController::hardware_config_t servoControllerConfig() const + { + AsibFM700ServoController::hardware_config_t hw_cfg; + + hw_cfg.hwConfig = {}; + + hw_cfg.MountDevPath = getValue("MountDevPath").value_or(std::string{}); + hw_cfg.EncoderDevPath = getValue("EncoderDevPath").value_or(std::string{}); + hw_cfg.EncoderXDevPath = getValue("EncoderXDevPath").value_or(std::string{}); + hw_cfg.EncoderYDevPath = getValue("EncoderYDevPath").value_or(std::string{}); + + hw_cfg.devConfig.MountDevPath = hw_cfg.MountDevPath.data(); + hw_cfg.devConfig.EncoderDevPath = hw_cfg.EncoderDevPath.data(); + hw_cfg.devConfig.EncoderXDevPath = hw_cfg.EncoderXDevPath.data(); + hw_cfg.devConfig.EncoderYDevPath = hw_cfg.EncoderYDevPath.data(); + + hw_cfg.devConfig.RunModel = getValue("RunModel").value_or(int{}); + hw_cfg.devConfig.MountDevSpeed = getValue("MountDevSpeed").value_or(int{}); + hw_cfg.devConfig.EncoderDevSpeed = getValue("EncoderDevSpeed").value_or(int{}); + hw_cfg.devConfig.SepEncoder = getValue("SepEncoder").value_or(int{}); + + std::chrono::duration secs; // seconds as floating-point + + secs = getValue("MountReqInterval").value_or(std::chrono::milliseconds{}); + hw_cfg.devConfig.MountReqInterval = secs.count(); + + secs = getValue("EncoderReqInterval").value_or(std::chrono::milliseconds{}); + hw_cfg.devConfig.EncoderReqInterval = secs.count(); + + secs = getValue("EncoderSpeedInterval").value_or(std::chrono::milliseconds{}); + hw_cfg.devConfig.EncoderSpeedInterval = secs.count(); + + secs = getValue("PIDMaxDt").value_or(std::chrono::milliseconds{1000}); + hw_cfg.devConfig.PIDMaxDt = secs.count(); + + secs = getValue("PIDRefreshDt").value_or(std::chrono::milliseconds{100}); + hw_cfg.devConfig.PIDRefreshDt = secs.count(); + + secs = getValue("PIDCycleDt").value_or(std::chrono::milliseconds{5000}); + hw_cfg.devConfig.PIDCycleDt = secs.count(); + + + std::vector pid = getValue>("XPIDV").value_or(std::vector{}); + if (pid.size() > 2) { + hw_cfg.devConfig.XPIDV.P = pid[0]; + hw_cfg.devConfig.XPIDV.I = pid[1]; + hw_cfg.devConfig.XPIDV.D = pid[2]; + } + + pid = getValue>("YPIDV").value_or(std::vector{}); + if (pid.size() > 2) { + hw_cfg.devConfig.YPIDV.P = pid[0]; + hw_cfg.devConfig.YPIDV.I = pid[1]; + hw_cfg.devConfig.YPIDV.D = pid[2]; + } + + double ang = getValue("MaxPointingErr").value_or(mcc::impl::MccAngle(8.0_degs)); + hw_cfg.devConfig.MaxPointingErr = ang; + + ang = getValue("MaxFinePointingErr").value_or(mcc::impl::MccAngle(1.5_degs)); + hw_cfg.devConfig.MaxFinePointingErr = ang; + + ang = getValue("MaxGuidingErr").value_or(mcc::impl::MccAngle(0.5_arcsecs)); + hw_cfg.devConfig.MaxGuidingErr = ang; + + ang = getValue("XEncZero").value_or(0); + hw_cfg.devConfig.XEncZero = ang; + + + ang = getValue("YEncZero").value_or(0); + hw_cfg.devConfig.YEncZero = ang; + + + + return hw_cfg; + } + + + Asibfm700PCM::pcm_data_t pcmData() const + { + Asibfm700PCM::pcm_data_t pcm_data; + + std::vector empty_vec; + + pcm_data.type = getValue("pcmType").value_or(pcm_data.type); + + pcm_data.siteLatitude = getValue("siteLatitude").value_or(pcm_data.siteLatitude); + + std::vector vec = getValue>("pcmGeomCoeffs").value_or(empty_vec); + if (vec.size() >= 9) { // must be 9 coefficients + pcm_data.geomCoefficients = {.zeroPointX = vec[0], + .zeroPointY = vec[1], + .collimationErr = vec[2], + .nonperpendErr = vec[3], + .misalignErr1 = vec[4], + .misalignErr2 = vec[5], + .tubeFlexure = vec[6], + .DECaxisFlexure = vec[7], + .forkFlexure = vec[8]}; + } + +#ifdef USE_BSPLINE_PCM + // std::vector dd = getValue("pcmBsplineDegree").value_or(dd); + // if (dd.size() >= 2) { + // pcm_data.bspline.bsplDegreeX = dd[0] > 0 ? dd[0] : 3; + // pcm_data.bspline.bsplDegreeY = dd[1] > 0 ? dd[1] : 3; + // } + + vec = getValue>("pcmBsplineXknots").value_or(empty_vec); + // pid must contains interior and border (single point for each border) knots so minimal length must be 2 + if (vec.size() >= 2) { + // generate full knots array (with border knots) + size_t Nknots = vec.size() + pcm_data.bspline.bsplDegreeX * 2 - 2; + pcm_data.bspline.knotsX.resize(Nknots); + + for (size_t i = 0; i <= pcm_data.bspline.bsplDegreeX; ++i) { // border knots + pcm_data.bspline.knotsX[i] = vec[0]; + pcm_data.bspline.knotsX[Nknots - i - 1] = vec.back(); + } + for (size_t i = 0; i < (vec.size() - 2); ++i) { // interior knots + pcm_data.bspline.knotsX[i + pcm_data.bspline.bsplDegreeX] = vec[1 + i]; + } + } + + vec = getValue>("pcmBsplineYknots").value_or(empty_vec); + // pid must contains interior and border (single point for each border) knots so minimal length must be 2 + if (vec.size() >= 2) { + // generate full knots array (with border knots) + size_t Nknots = vec.size() + pcm_data.bspline.bsplDegreeY * 2 - 2; + pcm_data.bspline.knotsY.resize(Nknots); + + for (size_t i = 0; i <= pcm_data.bspline.bsplDegreeY; ++i) { // border knots + pcm_data.bspline.knotsY[i] = vec[0]; + pcm_data.bspline.knotsY[Nknots - i - 1] = vec.back(); + } + for (size_t i = 0; i < (vec.size() - 2); ++i) { // interior knots + pcm_data.bspline.knotsY[i + pcm_data.bspline.bsplDegreeY] = vec[1 + i]; + } + } + + // minimal allowed number of B-spline coefficients + size_t Ncoeffs = pcm_data.type == mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY + ? 0 + : (pcm_data.bspline.knotsX.size() - pcm_data.bspline.bsplDegreeX - 1) * + (pcm_data.bspline.knotsY.size() - pcm_data.bspline.bsplDegreeY - 1); + + vec = getValue>("pcmBsplineXcoeffs").value_or(empty_vec); + + if (vec.size() >= Ncoeffs) { + pcm_data.bspline.coeffsX.clear(); + std::ranges::copy_n(vec.begin(), Ncoeffs, std::back_inserter(pcm_data.bspline.coeffsX)); + // pcm_data.bspline.coeffsX.resize(Ncoeffs); + // for (size_t i = 0; i < Ncoeffs; ++i) { + // pcm_data.bspline.coeffsX[i] = vec[i]; + // } + } + + vec = getValue>("pcmBsplineYcoeffs").value_or(empty_vec); + + if (vec.size() >= Ncoeffs) { + pcm_data.bspline.coeffsY.clear(); + std::ranges::copy_n(vec.begin(), Ncoeffs, std::back_inserter(pcm_data.bspline.coeffsY)); + // pcm_data.bspline.coeffsY.resize(Ncoeffs); + // for (size_t i = 0; i < Ncoeffs; ++i) { + // pcm_data.bspline.coeffsY[i] = vec[i]; + // } + } + + vec = getValue>("pcmInverseBsplineXcoeffs").value_or(empty_vec); + + if (vec.size() >= Ncoeffs) { + pcm_data.bspline.inverseCoeffsX.clear(); + std::ranges::copy_n(vec.begin(), Ncoeffs, std::back_inserter(pcm_data.bspline.inverseCoeffsX)); + } + + vec = getValue>("pcmInverseBsplineYcoeffs").value_or(empty_vec); + + if (vec.size() >= Ncoeffs) { + pcm_data.bspline.inverseCoeffsY.clear(); + std::ranges::copy_n(vec.begin(), Ncoeffs, std::back_inserter(pcm_data.bspline.inverseCoeffsY)); + } +#endif + return pcm_data; + } + + + mcc::impl::MccAltLimitPZ minAltPZone() + { + return getValue>("altLimPZ") + .value_or(mcc::impl::MccAltLimitPZ{10.0, SAORAS_LATITUDE}); + } + + + mcc::impl::MccAxisLimitSwitchPZ axisLimitSwitchHA() + { + return getValue>( + "axisLimitSwitchHA") + .value_or(mcc::impl::MccAxisLimitSwitchPZ{ + -170.0_degs, 170.0_degs, nullptr}); + } + + mcc::impl::MccAxisLimitSwitchPZ axisLimitSwitchDEC() + { + return getValue>( + "axisLimitSwitchDEC") + .value_or(mcc::impl::MccAxisLimitSwitchPZ{ + -90.0_degs, 90.0_degs, nullptr}); + } + + private: std::filesystem::path _lastConfigPath{};