This commit is contained in:
Timur A. Fatkhullin 2025-10-28 01:11:34 +03:00
parent bdfc5dbc1c
commit 85dfa2e9a5
5 changed files with 337 additions and 200 deletions

View File

@ -524,222 +524,334 @@ protected:
return ec; return ec;
}; };
void updateAll()
public:
/* the most usefull config fields */
template <mcc::traits::mcc_time_duration_c DT>
DT hardwarePollingPeriod() const
{ {
hardwarePollingPeriod = getValue<decltype(hardwarePollingPeriod)>("hardwarePollingPeriod").value_or({}); return std::chrono::duration_cast<DT>(
getValue<std::chrono::milliseconds>("hardwarePollingPeriod").value_or(std::chrono::milliseconds{}));
};
// CCTE std::chrono::milliseconds hardwarePollingPeriod() const
{
return hardwarePollingPeriod<std::chrono::milliseconds>();
};
siteLatitude = getValue<mcc::MccAngle>("siteLatitude").value_or({}); template <mcc::mcc_angle_c T>
siteLongitude = getValue<mcc::MccAngle>("siteLongitude").value_or({}); T siteLatitude() const
siteElevation = getValue<double>("siteElevation").value_or({}); {
refractWavelength = getValue<double>("refractWavelength").value_or({}); return static_cast<double>(getValue<mcc::MccAngle>("siteLatitude").value_or(mcc::MccAngle{}));
};
leapSecondFilename = getValue<std::string>("leapSecondFilename").value_or({}); mcc::MccAngle siteLatitude() const
bulletinAFilename = getValue<std::string>("bulletinAFilename").value_or({}); {
return siteLatitude<mcc::MccAngle>();
};
// prohibited zones template <mcc::mcc_angle_c T>
T siteLongitude() const
{
return static_cast<double>(getValue<mcc::MccAngle>("siteLongitude").value_or(mcc::MccAngle{}));
};
pzMinAltitude = getValue<mcc::MccAngle>("pzMinAltitude").value_or({}); mcc::MccAngle siteLongitude() const
pzLimitSwitchHAMin = getValue<mcc::MccAngle>("pzLimitSwitchHAMin").value_or({}); {
pzLimitSwitchHAMax = getValue<mcc::MccAngle>("pzLimitSwitchHAMax").value_or({}); return siteLongitude<mcc::MccAngle>();
};
template <typename T>
T siteElevation() const
requires std::is_arithmetic_v<T>
{
return getValue<double>("siteElevation").value_or(0.0);
}
double siteElevation() const
{
return getValue<double>("siteElevation").value_or(0.0);
};
template <typename T>
T refractWavelength() const
requires std::is_arithmetic_v<T>
{
return getValue<double>("refractWavelength").value_or(0.0);
}
double refractWavelength() const
{
return getValue<double>("refractWavelength").value_or(0.0);
};
template <mcc::traits::mcc_view_or_output_char_range R>
R leapSecondFilename() const
{
R r;
if constexpr (std::ranges::view<R>) {
std::string const& val = getValue<std::string>("leapSecondFilename").value_or("");
r = R{val.begin(), val.end()};
} else {
std::string val = getValue<std::string>("leapSecondFilename").value_or("");
std::ranges::copy(val, std::back_inserter(r));
}
return r;
}
std::string_view leapSecondFilename() const
{
return leapSecondFilename<std::string_view>();
};
template <mcc::traits::mcc_view_or_output_char_range R>
R bulletinAFilename() const
{
R r;
if constexpr (std::ranges::view<R>) {
std::string const& val = getValue<std::string>("bulletinAFilename").value_or("");
r = R{val.begin(), val.end()};
} else {
std::string val = getValue<std::string>("bulletinAFilename").value_or("");
std::ranges::copy(val, std::back_inserter(r));
}
return r;
}
std::string_view bulletinAFilename() const
{
return bulletinAFilename<std::string_view>();
};
// hardware config template <mcc::mcc_angle_c T>
T pzMinAltitude() const
{
return static_cast<double>(getValue<mcc::MccAngle>("pzMinAltitude").value_or(mcc::MccAngle{}));
};
servoControllerConfig.hwConfig = {}; mcc::MccAngle pzMinAltitude() const
{
return pzMinAltitude<mcc::MccAngle>();
};
servoControllerConfig.MountDevPath = getValue<std::string>("MountDevPath").value_or({}); template <mcc::mcc_angle_c T>
servoControllerConfig.EncoderDevPath = getValue<std::string>("EncoderDevPath").value_or({}); T pzLimitSwitchHAMin() const
servoControllerConfig.EncoderXDevPath = getValue<std::string>("EncoderXDevPath").value_or({}); {
servoControllerConfig.EncoderYDevPath = getValue<std::string>("EncoderYDevPath").value_or({}); return static_cast<double>(getValue<mcc::MccAngle>("pzLimitSwitchHAMin").value_or(mcc::MccAngle{}));
};
servoControllerConfig.devConfig.MountDevPath = servoControllerConfig.MountDevPath.data(); mcc::MccAngle pzLimitSwitchHAMin() const
servoControllerConfig.devConfig.EncoderDevPath = servoControllerConfig.EncoderDevPath.data(); {
servoControllerConfig.devConfig.EncoderXDevPath = servoControllerConfig.EncoderXDevPath.data(); return pzLimitSwitchHAMin<mcc::MccAngle>();
servoControllerConfig.devConfig.EncoderYDevPath = servoControllerConfig.EncoderYDevPath.data(); };
servoControllerConfig.devConfig.RunModel = getValue<int>("RunModel").value_or({}); template <mcc::mcc_angle_c T>
servoControllerConfig.devConfig.MountDevSpeed = getValue<int>("MountDevSpeed").value_or({}); T pzLimitSwitchHAMax() const
servoControllerConfig.devConfig.EncoderDevSpeed = getValue<int>("EncoderDevSpeed").value_or({}); {
servoControllerConfig.devConfig.SepEncoder = getValue<int>("SepEncoder").value_or({}); return static_cast<double>(getValue<mcc::MccAngle>("pzLimitSwitchHAMax").value_or(mcc::MccAngle{}));
};
mcc::MccAngle pzLimitSwitchHAMax() const
{
return pzLimitSwitchHAMax<mcc::MccAngle>();
};
AsibFM700ServoController::hardware_config_t servoControllerConfig() const
{
AsibFM700ServoController::hardware_config_t hw_cfg;
hw_cfg.hwConfig = {};
hw_cfg.MountDevPath = getValue<std::string>("MountDevPath").value_or({});
hw_cfg.EncoderDevPath = getValue<std::string>("EncoderDevPath").value_or({});
hw_cfg.EncoderXDevPath = getValue<std::string>("EncoderXDevPath").value_or({});
hw_cfg.EncoderYDevPath = getValue<std::string>("EncoderYDevPath").value_or({});
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<int>("RunModel").value_or({});
hw_cfg.devConfig.MountDevSpeed = getValue<int>("MountDevSpeed").value_or({});
hw_cfg.devConfig.EncoderDevSpeed = getValue<int>("EncoderDevSpeed").value_or({});
hw_cfg.devConfig.SepEncoder = getValue<int>("SepEncoder").value_or({});
std::chrono::duration<double> secs; // seconds as floating-point std::chrono::duration<double> secs; // seconds as floating-point
secs = getValue<std::chrono::milliseconds>("MountReqInterval").value_or({}); secs = getValue<std::chrono::milliseconds>("MountReqInterval").value_or({});
servoControllerConfig.devConfig.MountReqInterval = secs.count(); hw_cfg.devConfig.MountReqInterval = secs.count();
secs = getValue<std::chrono::milliseconds>("EncoderReqInterval").value_or({}); secs = getValue<std::chrono::milliseconds>("EncoderReqInterval").value_or({});
servoControllerConfig.devConfig.EncoderReqInterval = secs.count(); hw_cfg.devConfig.EncoderReqInterval = secs.count();
secs = getValue<std::chrono::milliseconds>("EncoderSpeedInterval").value_or({}); secs = getValue<std::chrono::milliseconds>("EncoderSpeedInterval").value_or({});
servoControllerConfig.devConfig.EncoderSpeedInterval = secs.count(); hw_cfg.devConfig.EncoderSpeedInterval = secs.count();
std::vector<double> pid = getValue<std::vector<double>>("XPIDC").value_or({}); std::vector<double> pid = getValue<std::vector<double>>("XPIDC").value_or({});
if (pid.size() > 2) { if (pid.size() > 2) {
servoControllerConfig.devConfig.XPIDC.P = pid[0]; hw_cfg.devConfig.XPIDC.P = pid[0];
servoControllerConfig.devConfig.XPIDC.I = pid[1]; hw_cfg.devConfig.XPIDC.I = pid[1];
servoControllerConfig.devConfig.XPIDC.D = pid[2]; hw_cfg.devConfig.XPIDC.D = pid[2];
} }
pid = getValue<std::vector<double>>("XPIDV").value_or({}); pid = getValue<std::vector<double>>("XPIDV").value_or({});
if (pid.size() > 2) { if (pid.size() > 2) {
servoControllerConfig.devConfig.XPIDV.P = pid[0]; hw_cfg.devConfig.XPIDV.P = pid[0];
servoControllerConfig.devConfig.XPIDV.I = pid[1]; hw_cfg.devConfig.XPIDV.I = pid[1];
servoControllerConfig.devConfig.XPIDV.D = pid[2]; hw_cfg.devConfig.XPIDV.D = pid[2];
} }
pid = getValue<std::vector<double>>("YPIDC").value_or({}); pid = getValue<std::vector<double>>("YPIDC").value_or({});
if (pid.size() > 2) { if (pid.size() > 2) {
servoControllerConfig.devConfig.YPIDC.P = pid[0]; hw_cfg.devConfig.YPIDC.P = pid[0];
servoControllerConfig.devConfig.YPIDC.I = pid[1]; hw_cfg.devConfig.YPIDC.I = pid[1];
servoControllerConfig.devConfig.YPIDC.D = pid[2]; hw_cfg.devConfig.YPIDC.D = pid[2];
} }
pid = getValue<std::vector<double>>("YPIDV").value_or({}); pid = getValue<std::vector<double>>("YPIDV").value_or({});
if (pid.size() > 2) { if (pid.size() > 2) {
servoControllerConfig.devConfig.YPIDV.P = pid[0]; hw_cfg.devConfig.YPIDV.P = pid[0];
servoControllerConfig.devConfig.YPIDV.I = pid[1]; hw_cfg.devConfig.YPIDV.I = pid[1];
servoControllerConfig.devConfig.YPIDV.D = pid[2]; hw_cfg.devConfig.YPIDV.D = pid[2];
} }
return hw_cfg;
}
// slew and track parameters
mcc::MccSimpleMovingModelParams movingModelParams() const
{
static constexpr double arcsecs2rad = std::numbers::pi / 180.0 / 3600.0; // arcseconds to radians static constexpr double arcsecs2rad = std::numbers::pi / 180.0 / 3600.0; // arcseconds to radians
movingModelParams.telemetryTimeout = mcc::MccSimpleMovingModelParams pars;
getValue<decltype(movingModelParams.telemetryTimeout)>("telemetryTimeout").value_or({});
movingModelParams.minTimeToPZone = pars.telemetryTimeout =
getValue<decltype(movingModelParams.minTimeToPZone)>("minTimeToPZone").value_or({}); getValue<decltype(pars.telemetryTimeout)>("telemetryTimeout").value_or(pars.telemetryTimeout);
movingModelParams.updatingPZoneInterval = pars.minTimeToPZone = getValue<decltype(pars.minTimeToPZone)>("minTimeToPZone").value_or(pars.minTimeToPZone);
getValue<decltype(movingModelParams.updatingPZoneInterval)>("updatingPZoneInterval").value_or({});
movingModelParams.slewToleranceRadius = pars.updatingPZoneInterval = getValue<decltype(pars.updatingPZoneInterval)>("updatingPZoneInterval")
getValue<decltype(movingModelParams.slewToleranceRadius)>("slewToleranceRadius").value_or({}) * arcsecs2rad; .value_or(pars.updatingPZoneInterval);
movingModelParams.adjustCoordDiff = pars.slewToleranceRadius =
getValue<decltype(movingModelParams.adjustCoordDiff)>("adjustCoordDiff").value_or({}) * arcsecs2rad; getValue<decltype(pars.slewToleranceRadius)>("slewToleranceRadius").value_or(pars.slewToleranceRadius) *
movingModelParams.adjustCycleInterval =
getValue<decltype(movingModelParams.adjustCycleInterval)>("adjustCycleInterval").value_or({});
movingModelParams.slewTimeout = getValue<decltype(movingModelParams.slewTimeout)>("slewTimeout").value_or({});
movingModelParams.timeShiftToTargetPoint =
getValue<decltype(movingModelParams.timeShiftToTargetPoint)>("timeShiftToTargetPoint").value_or({});
movingModelParams.trackingCycleInterval =
getValue<decltype(movingModelParams.trackingCycleInterval)>("trackingCycleInterval").value_or({});
movingModelParams.trackingMaxCoordDiff =
getValue<decltype(movingModelParams.trackingMaxCoordDiff)>("trackingMaxCoordDiff").value_or({}) *
arcsecs2rad; arcsecs2rad;
// PCM data pars.adjustCoordDiff =
getValue<decltype(pars.adjustCoordDiff)>("adjustCoordDiff").value_or(pars.adjustCoordDiff) * arcsecs2rad;
pcmData.type = getValue<decltype(pcmData.type)>("pcmType").value_or({}); pars.adjustCycleInterval =
getValue<decltype(pars.adjustCycleInterval)>("adjustCycleInterval").value_or(pars.adjustCycleInterval);
pcmData.siteLatitude = getValue<mcc::MccAngle>("siteLatitude").value_or({}); pars.slewTimeout = getValue<decltype(pars.slewTimeout)>("slewTimeout").value_or(pars.slewTimeout);
pid = getValue<std::vector<double>>("pcmGeomCoeffs").value_or({}); pars.timeShiftToTargetPoint = getValue<decltype(pars.timeShiftToTargetPoint)>("timeShiftToTargetPoint")
if (pid.size() >= 9) { // must be 9 coefficients .value_or(pars.timeShiftToTargetPoint);
pcmData.geomCoefficients = {.zeroPointX = pid[0],
.zeroPointY = pid[1], pars.trackingCycleInterval = getValue<decltype(pars.trackingCycleInterval)>("trackingCycleInterval")
.collimationErr = pid[2], .value_or(pars.trackingCycleInterval);
.nonperpendErr = pid[3],
.misalignErr1 = pid[4], pars.trackingMaxCoordDiff =
.misalignErr2 = pid[5], getValue<decltype(pars.trackingMaxCoordDiff)>("trackingMaxCoordDiff").value_or(pars.trackingMaxCoordDiff) *
.tubeFlexure = pid[6], arcsecs2rad;
.forkFlexure = pid[7],
.DECaxisFlexure = pid[8]}; return pars;
}
Asibfm700PCM::pcm_data_t pcmData() const
{
Asibfm700PCM::pcm_data_t pcm_data;
std::vector<double> empty_vec;
pcm_data.type = getValue<decltype(pcm_data.type)>("pcmType").value_or(pcm_data.type);
pcm_data.siteLatitude = getValue<mcc::MccAngle>("siteLatitude").value_or(pcm_data.siteLatitude);
std::vector<double> vec = getValue<std::vector<double>>("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],
.forkFlexure = vec[7],
.DECaxisFlexure = vec[8]};
} }
std::vector<size_t> dd = getValue<decltype(dd)>("pcmBsplineDegree").value_or({}); std::vector<size_t> dd = getValue<decltype(dd)>("pcmBsplineDegree").value_or(dd);
if (dd.size() >= 2) { if (dd.size() >= 2) {
pcmData.bspline.bsplDegreeX = dd[0] > 0 ? dd[0] : 3; pcm_data.bspline.bsplDegreeX = dd[0] > 0 ? dd[0] : 3;
pcmData.bspline.bsplDegreeY = dd[1] > 0 ? dd[1] : 3; pcm_data.bspline.bsplDegreeY = dd[1] > 0 ? dd[1] : 3;
} }
pid = getValue<std::vector<double>>("pcmBsplineXknots").value_or({}); vec = getValue<std::vector<double>>("pcmBsplineXknots").value_or(empty_vec);
// pid must contains interior and border (single point for each border) knots so minimal length must be 2 // pid must contains interior and border (single point for each border) knots so minimal length must be 2
if (pid.size() >= 2) { if (vec.size() >= 2) {
// generate full knots array (with border knots) // generate full knots array (with border knots)
size_t Nknots = pid.size() + pcmData.bspline.bsplDegreeX * 2 - 2; size_t Nknots = vec.size() + pcm_data.bspline.bsplDegreeX * 2 - 2;
pcmData.bspline.knotsX.resize(Nknots); pcm_data.bspline.knotsX.resize(Nknots);
for (size_t i = 0; i <= pcmData.bspline.bsplDegreeX; ++i) { // border knots for (size_t i = 0; i <= pcm_data.bspline.bsplDegreeX; ++i) { // border knots
pcmData.bspline.knotsX[i] = pid[0]; pcm_data.bspline.knotsX[i] = vec[0];
pcmData.bspline.knotsX[Nknots - i - 1] = pid.back(); pcm_data.bspline.knotsX[Nknots - i - 1] = vec.back();
} }
for (size_t i = 0; i < (pid.size() - 2); ++i) { // interior knots for (size_t i = 0; i < (vec.size() - 2); ++i) { // interior knots
pcmData.bspline.knotsX[i + pcmData.bspline.bsplDegreeX] = pid[1 + i]; pcm_data.bspline.knotsX[i + pcm_data.bspline.bsplDegreeX] = vec[1 + i];
} }
} }
pid = getValue<std::vector<double>>("pcmBsplineYknots").value_or({}); vec = getValue<std::vector<double>>("pcmBsplineYknots").value_or(empty_vec);
// pid must contains interior and border (single point for each border) knots so minimal length must be 2 // pid must contains interior and border (single point for each border) knots so minimal length must be 2
if (pid.size() >= 2) { if (vec.size() >= 2) {
// generate full knots array (with border knots) // generate full knots array (with border knots)
size_t Nknots = pid.size() + pcmData.bspline.bsplDegreeY * 2 - 2; size_t Nknots = vec.size() + pcm_data.bspline.bsplDegreeY * 2 - 2;
pcmData.bspline.knotsY.resize(Nknots); pcm_data.bspline.knotsY.resize(Nknots);
for (size_t i = 0; i <= pcmData.bspline.bsplDegreeY; ++i) { // border knots for (size_t i = 0; i <= pcm_data.bspline.bsplDegreeY; ++i) { // border knots
pcmData.bspline.knotsY[i] = pid[0]; pcm_data.bspline.knotsY[i] = vec[0];
pcmData.bspline.knotsY[Nknots - i - 1] = pid.back(); pcm_data.bspline.knotsY[Nknots - i - 1] = vec.back();
} }
for (size_t i = 0; i < (pid.size() - 2); ++i) { // interior knots for (size_t i = 0; i < (vec.size() - 2); ++i) { // interior knots
pcmData.bspline.knotsY[i + pcmData.bspline.bsplDegreeY] = pid[1 + i]; pcm_data.bspline.knotsY[i + pcm_data.bspline.bsplDegreeY] = vec[1 + i];
} }
} }
// minimal allowed number of B-spline coefficients // minimal allowed number of B-spline coefficients
size_t Ncoeffs = pcmData.type == mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY size_t Ncoeffs = pcm_data.type == mcc::MccDefaultPCMType::PCM_TYPE_GEOMETRY
? 0 ? 0
: (pcmData.bspline.knotsX.size() - pcmData.bspline.bsplDegreeX - 1) * : (pcm_data.bspline.knotsX.size() - pcm_data.bspline.bsplDegreeX - 1) *
(pcmData.bspline.knotsY.size() - pcmData.bspline.bsplDegreeY - 1); (pcm_data.bspline.knotsY.size() - pcm_data.bspline.bsplDegreeY - 1);
pid = getValue<std::vector<double>>("pcmBsplineXcoeffs").value_or({}); vec = getValue<std::vector<double>>("pcmBsplineXcoeffs").value_or(empty_vec);
if (pid.size() >= Ncoeffs) { if (vec.size() >= Ncoeffs) {
pcmData.bspline.coeffsX.resize(Ncoeffs); pcm_data.bspline.coeffsX.resize(Ncoeffs);
for (size_t i = 0; i < Ncoeffs; ++i) { for (size_t i = 0; i < Ncoeffs; ++i) {
pcmData.bspline.coeffsX[i] = pid[i]; pcm_data.bspline.coeffsX[i] = vec[i];
} }
} }
pid = getValue<std::vector<double>>("pcmBsplineYcoeffs").value_or({}); vec = getValue<std::vector<double>>("pcmBsplineYcoeffs").value_or(empty_vec);
if (pid.size() >= Ncoeffs) { if (vec.size() >= Ncoeffs) {
pcmData.bspline.coeffsY.resize(Ncoeffs); pcm_data.bspline.coeffsY.resize(Ncoeffs);
for (size_t i = 0; i < Ncoeffs; ++i) { for (size_t i = 0; i < Ncoeffs; ++i) {
pcmData.bspline.coeffsY[i] = pid[i]; pcm_data.bspline.coeffsY[i] = vec[i];
} }
} }
return pcm_data;
} }
public:
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{};
Asibfm700MountConfig() : base_t(Asibfm700MountConfigDefaults) {} Asibfm700MountConfig() : base_t(Asibfm700MountConfigDefaults) {}
@ -763,9 +875,6 @@ public:
fst.close(); fst.close();
ec = base_t::fromCharRange(buffer, deserializer); ec = base_t::fromCharRange(buffer, deserializer);
if (!ec) {
updateAll();
}
} catch (std::ios_base::failure const& ex) { } catch (std::ios_base::failure const& ex) {
ec = ex.code(); ec = ex.code();
} catch (std::length_error const& ex) { } catch (std::length_error const& ex) {
@ -779,17 +888,6 @@ public:
return ec; return ec;
} }
template <typename T>
std::error_code setValue(std::string_view key, const T& value)
{
auto ec = base_t::setValue(key, value);
if (!ec) {
updateAll();
}
return ec;
}
}; };

View File

@ -12,12 +12,12 @@ Asibfm700Mount::Asibfm700Mount(Asibfm700MountConfig const& config,
std::shared_ptr<spdlog::logger> logger, std::shared_ptr<spdlog::logger> logger,
const auto& pattern_range) const auto& pattern_range)
: mcc::ccte::erfa::MccCCTE_ERFA({.meteo{.temperature = 10.0, .humidity = 0.5, .pressure = 1010.0}, : mcc::ccte::erfa::MccCCTE_ERFA({.meteo{.temperature = 10.0, .humidity = 0.5, .pressure = 1010.0},
.wavelength = config.refractWavelength, .wavelength = config.refractWavelength(),
.lat = config.siteLatitude, .lat = config.siteLatitude(),
.lon = config.siteLongitude, .lon = config.siteLongitude(),
.elev = config.siteElevation}), .elev = config.siteElevation()}),
Asibfm700PCM(config.pcmData), Asibfm700PCM(config.pcmData()),
base_gm_class_t(gm_class_t{AsibFM700ServoController{config.servoControllerConfig}, mcc::MccTelemetry{this}, base_gm_class_t(gm_class_t{AsibFM700ServoController{config.servoControllerConfig()}, mcc::MccTelemetry{this},
Asibfm700PZoneContainer{}, mcc::MccSimpleSlewingModel{this}, Asibfm700PZoneContainer{}, mcc::MccSimpleSlewingModel{this},
mcc::MccSimpleTrackingModel{this}, Asibfm700Logger{std::move(logger), pattern_range}}, mcc::MccSimpleTrackingModel{this}, Asibfm700Logger{std::move(logger), pattern_range}},
Asibfm700StartState{}), Asibfm700StartState{}),
@ -44,66 +44,66 @@ Asibfm700Mount::error_t Asibfm700Mount::initMount()
std::lock_guard lock{*_mountConfigMutex}; std::lock_guard lock{*_mountConfigMutex};
logInfo("Init AstroSib FM-700 mount with configuration:"); logInfo("Init AstroSib FM-700 mount with configuration:");
logInfo(" site latitude: {}", _mountConfig.siteLatitude.sexagesimal()); logInfo(" site latitude: {}", _mountConfig.siteLatitude().sexagesimal());
logInfo(" site longitude: {}", _mountConfig.siteLongitude.sexagesimal()); logInfo(" site longitude: {}", _mountConfig.siteLongitude().sexagesimal());
logInfo(" site elevation: {} meters", _mountConfig.siteElevation); logInfo(" site elevation: {} meters", _mountConfig.siteElevation());
logInfo(" refraction wavelength: {} mkm", _mountConfig.refractWavelength); logInfo(" refraction wavelength: {} mkm", _mountConfig.refractWavelength());
logInfo(" leap seconds filename: {}", _mountConfig.leapSecondFilename); logInfo(" leap seconds filename: {}", _mountConfig.leapSecondFilename());
logInfo(" IERS Bulletin A filename: {}", _mountConfig.bulletinAFilename); logInfo(" IERS Bulletin A filename: {}", _mountConfig.bulletinAFilename());
logInfo(""); logInfo("");
logDebug("Delete previously defined prohobited zones"); logDebug("Delete previously defined prohobited zones");
clearPZones(); clearPZones();
logInfo("Add prohibited zones ..."); logInfo("Add prohibited zones ...");
logInfo(" Add MccAltLimitPZ zone: min alt = {}, lat = {}", _mountConfig.pzMinAltitude.degrees(), logInfo(" Add MccAltLimitPZ zone: min alt = {}, lat = {}", _mountConfig.pzMinAltitude().degrees(),
_mountConfig.siteLatitude.degrees()); _mountConfig.siteLatitude().degrees());
addPZone(mcc::MccAltLimitPZ<mcc::MccAltLimitKind::MIN_ALT_LIMIT>{_mountConfig.pzMinAltitude, addPZone(mcc::MccAltLimitPZ<mcc::MccAltLimitKind::MIN_ALT_LIMIT>{_mountConfig.pzMinAltitude(),
_mountConfig.siteLatitude, this}); _mountConfig.siteLatitude(), this});
logInfo(" Add MccAxisLimitSwitchPZ zone: min value = {}, max value = {}", logInfo(" Add MccAxisLimitSwitchPZ zone: min value = {}, max value = {}",
_mountConfig.pzLimitSwitchHAMin.degrees(), _mountConfig.pzLimitSwitchHAMax.degrees()); _mountConfig.pzLimitSwitchHAMin().degrees(), _mountConfig.pzLimitSwitchHAMax().degrees());
size_t pz_num = addPZone(mcc::MccAxisLimitSwitchPZ<mcc::MccCoordKind::COORDS_KIND_HA>{ size_t pz_num = addPZone(mcc::MccAxisLimitSwitchPZ<mcc::MccCoordKind::COORDS_KIND_HA>{
_mountConfig.pzLimitSwitchHAMin, _mountConfig.pzLimitSwitchHAMax, this}); _mountConfig.pzLimitSwitchHAMin(), _mountConfig.pzLimitSwitchHAMax(), this});
logInfo("{} prohibited zones were added successfully", pz_num); logInfo("{} prohibited zones were added successfully", pz_num);
logInfo(""); logInfo("");
logInfo("Setup slewing and tracking parameters ..."); logInfo("Setup slewing and tracking parameters ...");
auto st_err = setSlewingParams(_mountConfig.movingModelParams); auto st_err = setSlewingParams(_mountConfig.movingModelParams());
if (st_err) { if (st_err) {
errorLogging(" An error occured while setting slewing parameters: ", st_err); errorLogging(" An error occured while setting slewing parameters: ", st_err);
} }
st_err = setTrackingParams(_mountConfig.movingModelParams); st_err = setTrackingParams(_mountConfig.movingModelParams());
if (st_err) { if (st_err) {
errorLogging(" An error occured while setting tracking parameters: ", st_err); errorLogging(" An error occured while setting tracking parameters: ", st_err);
} }
logInfo("Slewing and tracking parameters have been set successfully"); logInfo("Slewing and tracking parameters have been set successfully");
auto hw_cfg = _mountConfig.servoControllerConfig();
logInfo(""); logInfo("");
logInfo("Hardware initialization ..."); logInfo("Hardware initialization ...");
logInfo(" set hardware configuration:"); logInfo(" set hardware configuration:");
logInfo(" RunModel: {}", logInfo(" RunModel: {}", hw_cfg.devConfig.RunModel == 1 ? "MODEL-MODE" : "REAL-MODE");
_mountConfig.servoControllerConfig.devConfig.RunModel == 1 ? "MODEL-MODE" : "REAL-MODE"); logInfo(" mount dev path: {}", hw_cfg.MountDevPath);
logInfo(" mount dev path: {}", _mountConfig.servoControllerConfig.MountDevPath); logInfo(" encoder dev path: {}", hw_cfg.EncoderDevPath);
logInfo(" encoder dev path: {}", _mountConfig.servoControllerConfig.EncoderDevPath); logInfo(" encoder X-dev path: {}", hw_cfg.EncoderXDevPath);
logInfo(" encoder X-dev path: {}", _mountConfig.servoControllerConfig.EncoderXDevPath); logInfo(" encoder Y-dev path: {}", hw_cfg.EncoderYDevPath);
logInfo(" encoder Y-dev path: {}", _mountConfig.servoControllerConfig.EncoderYDevPath);
logInfo(" EncoderDevSpeed: {}", _mountConfig.servoControllerConfig.devConfig.EncoderDevSpeed); logInfo(" EncoderDevSpeed: {}", hw_cfg.devConfig.EncoderDevSpeed);
logInfo(" SepEncoder: {}", _mountConfig.servoControllerConfig.devConfig.SepEncoder); logInfo(" SepEncoder: {}", hw_cfg.devConfig.SepEncoder);
logInfo(" MountReqInterval: {}", _mountConfig.servoControllerConfig.devConfig.MountReqInterval); logInfo(" MountReqInterval: {}", hw_cfg.devConfig.MountReqInterval);
logInfo(" EncoderReqInterval: {}", _mountConfig.servoControllerConfig.devConfig.EncoderReqInterval); logInfo(" EncoderReqInterval: {}", hw_cfg.devConfig.EncoderReqInterval);
logInfo(" EncoderSpeedInterval: {}", _mountConfig.servoControllerConfig.devConfig.EncoderSpeedInterval); logInfo(" EncoderSpeedInterval: {}", hw_cfg.devConfig.EncoderSpeedInterval);
logInfo(" XPIDC: [P: {}, I: {}, D: {}]", _mountConfig.servoControllerConfig.devConfig.XPIDC.P, logInfo(" XPIDC: [P: {}, I: {}, D: {}]", hw_cfg.devConfig.XPIDC.P, hw_cfg.devConfig.XPIDC.I,
_mountConfig.servoControllerConfig.devConfig.XPIDC.I, _mountConfig.servoControllerConfig.devConfig.XPIDC.D); hw_cfg.devConfig.XPIDC.D);
logInfo(" XPIDV: [P: {}, I: {}, D: {}]", _mountConfig.servoControllerConfig.devConfig.XPIDV.P, logInfo(" XPIDV: [P: {}, I: {}, D: {}]", hw_cfg.devConfig.XPIDV.P, hw_cfg.devConfig.XPIDV.I,
_mountConfig.servoControllerConfig.devConfig.XPIDV.I, _mountConfig.servoControllerConfig.devConfig.XPIDV.D); hw_cfg.devConfig.XPIDV.D);
logInfo(" YPIDC: [P: {}, I: {}, D: {}]", _mountConfig.servoControllerConfig.devConfig.YPIDC.P, logInfo(" YPIDC: [P: {}, I: {}, D: {}]", hw_cfg.devConfig.YPIDC.P, hw_cfg.devConfig.YPIDC.I,
_mountConfig.servoControllerConfig.devConfig.YPIDC.I, _mountConfig.servoControllerConfig.devConfig.YPIDC.D); hw_cfg.devConfig.YPIDC.D);
logInfo(" YPIDV: [P: {}, I: {}, D: {}]", _mountConfig.servoControllerConfig.devConfig.YPIDV.P, logInfo(" YPIDV: [P: {}, I: {}, D: {}]", hw_cfg.devConfig.YPIDV.P, hw_cfg.devConfig.YPIDV.I,
_mountConfig.servoControllerConfig.devConfig.YPIDV.I, _mountConfig.servoControllerConfig.devConfig.YPIDV.D); hw_cfg.devConfig.YPIDV.D);
// auto hw_err = hardwareInit(); // auto hw_err = hardwareInit();
// if (hw_err) { // if (hw_err) {
@ -127,8 +127,9 @@ Asibfm700Mount::error_t Asibfm700Mount::updateMountConfig(const Asibfm700MountCo
_mountConfig = cfg; _mountConfig = cfg;
hardwareUpdateConfig(_mountConfig.servoControllerConfig.devConfig); auto hw_cfg = _mountConfig.servoControllerConfig();
hardwareUpdateConfig(_mountConfig.servoControllerConfig.hwConfig); hardwareUpdateConfig(hw_cfg.devConfig);
hardwareUpdateConfig(hw_cfg.hwConfig);
return AsibFM700ServoControllerErrorCode::ERROR_OK; return AsibFM700ServoControllerErrorCode::ERROR_OK;
} }

View File

@ -61,7 +61,7 @@ int main()
auto ec = acfg.load("/tmp/cfg.cfg"); auto ec = acfg.load("/tmp/cfg.cfg");
std::cout << "EC (load) = " << ec.message() << "\n"; std::cout << "EC (load) = " << ec.message() << "\n";
std::cout << "refr w: " << acfg.refractWavelength << "\n"; std::cout << "refr w: " << acfg.refractWavelength() << "\n";
// acfg.update("refractWavelength", 0.3); // acfg.update("refractWavelength", 0.3);
acfg.setValue("refractWavelength", 0.3); acfg.setValue("refractWavelength", 0.3);
@ -69,7 +69,7 @@ int main()
auto e = acfg.getValue<double>("refractWavelength"); auto e = acfg.getValue<double>("refractWavelength");
// auto e = acfg.value<double>("refractWavelength"); // auto e = acfg.value<double>("refractWavelength");
std::cout << "refr w: " << e.value_or(0.0) << "\n"; std::cout << "refr w: " << e.value_or(0.0) << "\n";
std::cout << "refr w: " << acfg.refractWavelength << "\n"; std::cout << "refr w: " << acfg.refractWavelength() << "\n";
mcc::utils::KeyValueHolder kvh(desc); mcc::utils::KeyValueHolder kvh(desc);

View File

@ -173,6 +173,15 @@ using mcc_func_argN_t = std::conditional_t<N >= mcc_func_traits<T>::arity,
void>; void>;
// std::array
template <typename T>
concept mcc_array_c = requires(T t) {
[]<typename VT, size_t N>(std::array<VT, N>) {
}(t);
};
// non-const lvalue reference, constructible from CtorArgTs (an output argument of function) // non-const lvalue reference, constructible from CtorArgTs (an output argument of function)
template <typename T, typename... CtorArgTs> template <typename T, typename... CtorArgTs>
concept mcc_output_arg_c = !std::is_const_v<std::remove_reference_t<T>> && std::is_lvalue_reference_v<T> && concept mcc_output_arg_c = !std::is_const_v<std::remove_reference_t<T>> && std::is_lvalue_reference_v<T> &&

View File

@ -158,7 +158,7 @@ static std::optional<double> parsAngleString(R&& r, bool hms = false)
return std::nullopt; return std::nullopt;
} }
static std::optional<double> parsAngleString(const char* s, bool hms = false) [[maybe_unused]] static std::optional<double> parsAngleString(const char* s, bool hms = false)
{ {
return parsAngleString(std::span{s, std::strlen(s)}, hms); return parsAngleString(std::span{s, std::strlen(s)}, hms);
} }
@ -455,7 +455,21 @@ public:
value = v.value(); value = v.value();
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) { } else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
VT r; VT r;
std::ranges::copy(bytes, std::back_inserter(r)); if constexpr (traits::mcc_array_c<VT>) {
size_t N =
std::ranges::size(r) <= std::ranges::size(bytes) ? std::ranges::size(r) : std::ranges::size(bytes);
for (size_t i = 0; i < N; ++i) {
r[i] = bytes[i];
}
if (std::ranges::size(r) > N) {
for (size_t i = N; i < std::ranges::size(r); ++i) {
r[i] = '\0';
}
}
} else {
std::ranges::copy(bytes, std::back_inserter(r));
}
value = r; value = r;
} else if constexpr (std::ranges::range<VT>) { } else if constexpr (std::ranges::range<VT>) {
using el_t = std::ranges::range_value_t<VT>; using el_t = std::ranges::range_value_t<VT>;
@ -466,13 +480,21 @@ public:
VT r; VT r;
el_t elem; el_t elem;
size_t i = 0;
auto els = std::views::split(bytes, _rangeDelim); auto els = std::views::split(bytes, _rangeDelim);
for (auto const& el : els) { for (auto const& el : els) {
ret = (*this)(std::string_view(el), elem); ret = (*this)(std::string_view(el), elem);
if (!ret) { if (!ret) {
std::back_inserter(r) = elem; if constexpr (traits::mcc_array_c<VT>) {
if (i < std::ranges::size(r)) {
r[i] = elem;
}
++i;
} else {
std::back_inserter(r) = elem;
}
} else { } else {
return std::make_error_code(std::errc::invalid_argument); return std::make_error_code(std::errc::invalid_argument);
} }
@ -582,7 +604,7 @@ public:
} }
template <typename T> template <typename T>
std::expected<T, std::error_code> getValue(std::string_view key) std::expected<T, std::error_code> getValue(std::string_view key) const
{ {
T v; T v;
auto err = forKey(key, [&v]<typename VT>(const VT& val) { auto err = forKey(key, [&v]<typename VT>(const VT& val) {
@ -686,20 +708,27 @@ protected:
std::array<size_t, std::tuple_size_v<DESCR_T>> _hashes; std::array<size_t, std::tuple_size_v<DESCR_T>> _hashes;
std::error_code forKey(std::string_view key, auto&& func) //
// NOTE: deduced this is needed here to use "forKey" method in getter and setter (const and non-const contexts)!!!
//
std::error_code forKey(this auto&& self, std::string_view key, auto&& func)
{ {
return forHash<0>(FNV1aHash(key), std::forward<decltype(func)>(func)); return std::forward<decltype(self)>(self).template forHash<0>(FNV1aHash(key),
std::forward<decltype(func)>(func));
} }
template <size_t I = 0> template <size_t I = 0>
std::error_code forHash(size_t hash, auto&& func) std::error_code forHash(this auto&& self, size_t hash, auto&& func)
{ {
if constexpr (I < std::tuple_size_v<DESCR_T>) { if constexpr (I < std::tuple_size_v<DESCR_T>) {
if (hash == _hashes[I]) { if (hash == std::forward<decltype(self)>(self)._hashes[I]) {
return std::forward<decltype(func)>(func)(std::get<I>(_keyValue).value); return std::forward<decltype(func)>(func)(
std::get<I>(std::forward<decltype(self)>(self)._keyValue).value);
} else { } else {
return forHash<I + 1>(hash, std::forward<decltype(func)>(func)); return std::forward<decltype(self)>(self).template forHash<I + 1>(hash,
std::forward<decltype(func)>(func));
} }
} }