diff --git a/CMakeLists.txt b/CMakeLists.txt index a41c27d..f91d8c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,20 +121,17 @@ set(ASIBFM700_LIB_SRC asibfm700_common.h asibfm700_servocontroller.h asibfm700_servocontroller.cpp -) - -set(ASIBFM700_LIB asibfm700mount) -add_library( - ${ASIBFM700_LIB} - STATIC - ${ASIBFM700_LIB_SRC} asibfm700_mount.h asibfm700_mount.cpp asibfm700_configfile.h asibfm700_netserver.cpp asibfm700_netserver.h + asibfm700_config.h ) +set(ASIBFM700_LIB asibfm700mount) +add_library(${ASIBFM700_LIB} STATIC ${ASIBFM700_LIB_SRC}) + # add_dependencies(${ASIBFM700_LIB} mcc) target_include_directories(${ASIBFM700_LIB} PUBLIC ${CMAKE_BINARY_DIR}) # LibSidServo headers diff --git a/asibfm700_config.h b/asibfm700_config.h new file mode 100644 index 0000000..36f11d5 --- /dev/null +++ b/asibfm700_config.h @@ -0,0 +1,234 @@ +#pragma once + + +#include +#include +#include + +namespace asibfm700 +{ + +template +struct config_record_t : mcc::impl::mcc_simple_kv_record_t { + std::vector head_comment; + std::string_view inline_comment; +}; + + +template +static config_record_t make_config_record( + std::string_view key, + T value, + std::vector hcomm = {}, + 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}; +} + + +static auto Asibfm700MountConfigurationDefaults = std::make_tuple( + + /* geographic coordinates of the observation site */ + + make_config_record("siteLatitude", mcc::impl::MccAngle(43.646711_degs), {"site latitude in degrees"}), + make_config_record("siteLongitude", mcc::impl::MccAngle(41.440732_degs), {"site longitude in degrees"}), + make_config_record("siteElevation", 2070.0, {"site elevation in meters"}), + + /* celestial coordinate transformation */ + + make_config_record("refractWavelength", 0.55, {"wavelength at which refraction is calculated (in mkm)"}), + make_config_record("leapSecondFilename", std::string(), {"an empty filename means default precompiled string"}), + make_config_record("bulletinAFilename", std::string(), {"an empty filename means default precompiled string"}), + + /* pointing correction model */ + + // PCM type + make_config_record( + "pcmType", + mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY, + {"PCM type:", "a case-sensetive string:", " 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 + make_config_record("pcmGeomCoeffs", + std::vector{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {"PCM geometrical coefficients"}), + + // make_config_record("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! + make_config_record("pcmBsplineXknots", + std::vector{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 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! + make_config_record( + "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) + make_config_record("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) + make_config_record("pcmBsplineYcoeffs", + std::vector{}, + {"PCM B-spline coeffs for along Y-axis (declination angle)"})); + +class Asibfm700MountConfiguration : public mcc::impl::MccKeyValueHolder +{ + using base_t = mcc::impl::MccKeyValueHolder; + +public: + Asibfm700MountConfiguration() : base_t(Asibfm700MountConfigurationDefaults) + { + // fill comments + + auto get_comm = [this]() { + auto& rec = std::get(Asibfm700MountConfigurationDefaults); + for (auto const& comm : rec.head_comment) { + if (comm.size()) { + _headComment[_hashes[I]].emplace_back(std::string{comm.begin(), comm.end()}); + } else { + _headComment[_hashes[I]].emplace_back(std::nullopt); + } + } + _inlineComment[_hashes[I]] = rec.inline_comment; + }; + + [&, this](std::index_sequence) { + (get_comm.template operator()(), ...); + }(std::make_index_sequence{}); + } + + ~Asibfm700MountConfiguration() = 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::fromCharRange(buffer); + if (!ec) { + // remove possible spaces in filenames + + std::string val = getValue("leapSecondFilename").value_or(""); + auto fname = mcc::utils::trimSpaces(val); + setValue("leapSecondFilename", fname); + + + val = getValue("bulletinAFilename").value_or(""); + fname = mcc::utils::trimSpaces(val); + setValue("bulletinAFilename", fname); + + val = getValue("MountDevPath").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("MountDevPath", fname); + + val = getValue("EncoderDevPath").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("EncoderDevPath", fname); + + val = getValue("EncoderXDevPath").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("EncoderXDevPath", fname); + + val = getValue("EncoderYDevPath").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("EncoderYDevPath", fname); + + val = getValue("slewingPathFilename").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("slewingPathFilename", fname); + + val = getValue("trackingPathFilename").value_or(std::string{}); + fname = mcc::utils::trimSpaces(val); + setValue("trackingPathFilename", fname); + } + } 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); + } + + _lastConfigPath = path; + } + + return ec; + } + + std::error_code reloadCurrentConfig() + { + return load(_lastConfigPath); + } + + + std::error_code save(const std::filesystem::path& path) + { + std::error_code ec; + std::string buff; + + ec = toCharRange(buff); + if (ec) { + return ec; + } + + std::ofstream fst(path, std::ios_base::trunc); + if (!fst.is_open()) { + ec = std::make_error_code(std::errc::io_error); + } else { + try { + fst << buff; + } catch (std::ios_base::failure const& ex) { + ec = ex.code(); + } catch (...) { + ec = std::make_error_code(std::errc::operation_canceled); + } + } + + return ec; + } + + std::error_code save() + { + return save(_lastConfigPath); + } + + std::filesystem::path configFilename() const + { + return _lastConfigPath; + } + +private: + std::filesystem::path _lastConfigPath{}; +}; + +} // namespace asibfm700 \ No newline at end of file