438 lines
18 KiB
C++
438 lines
18 KiB
C++
#pragma once
|
|
|
|
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
|
|
|
/* BASIC NETWORK PROTOCOL DEFINITIONS */
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
#include <string_view>
|
|
#include "mcc_angle.h"
|
|
#include "mcc_generics.h"
|
|
#include "mcc_utils.h"
|
|
|
|
namespace mcc::network
|
|
{
|
|
|
|
/*
|
|
* The network protocol is the ASCII-based, case-sensitive textual protocol.
|
|
* The "client-server" communication is performed through messages.
|
|
* The message is a minimal unit of this communication.
|
|
* The model of network communication is a simple "client-server" one, i.e.,
|
|
* client asks - server responds.
|
|
*
|
|
* network communication message format:
|
|
* <keyword>[[<key-param-delim>]<param1>[<param-param-delim>][<param2>]...]<stop-seq>
|
|
*
|
|
* where
|
|
* <keyword> - mandatory message keyword (one or more ASCII symbols)
|
|
* <key-param-delim>
|
|
*
|
|
* e.g.
|
|
* "TARGET 12:23:45.56 00:32:21.978\n"
|
|
*/
|
|
|
|
|
|
/* low-level network message format definitions */
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_STOP_SEQ = "\n";
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYPARAM_DELIM_SEQ = " ";
|
|
static constexpr std::string_view MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ = " ";
|
|
|
|
|
|
/* server special keywords */
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR = "ACK"; // ACK
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR = "ERROR"; // mount operational error
|
|
// pre-defined errors
|
|
static constexpr std::string_view MCC_COMMPROTO_SERVER_ERROR_INVKEY_STR = "INVKEY"; // invalid keyword
|
|
static constexpr std::string_view MCC_COMMPROTO_SERVER_ERROR_INVPAR_STR = "INVPAR"; // invalid parameter
|
|
|
|
|
|
/* server control keywords */
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_RESTART_SERVER_STR = "RESTART"; // restart server
|
|
|
|
|
|
/* BELOW IS ONE OF THE PROTOCOL OPTIONS CORRESPONDING MCC_GENERIC_MOUNT_C CONCEPT */
|
|
|
|
|
|
/* predefined parameters */
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_RADEC_ICRS = "RADEC_ICRS"; // ICRS RA and DEC
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_RADEC = "RADEC"; // apparent RA and DEC
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_HADEC = "HADEC"; // apparent HA and DEC
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_AZZD = "AZZD"; // azimuth and zenithal distance
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_AZALT = "AZALT"; // azimuth and altitude
|
|
static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_XY = "XY"; // hardware (encoder) coordinates
|
|
|
|
|
|
// static constexpr MccCoordPairKind mcc_str2pairkind(std::string_view spair)
|
|
// {
|
|
// return spair == MCC_COMMPROTO_COORD_KIND_RADEC_ICRS ? MccCoordPairKind::COORDS_KIND_RADEC_ICRS
|
|
// : spair == MCC_COMMPROTO_COORD_KIND_RADEC ? MccCoordPairKind::COORDS_KIND_RADEC_APP
|
|
// : spair == MCC_COMMPROTO_COORD_KIND_HADEC ? MccCoordPairKind::COORDS_KIND_HADEC_APP
|
|
// : spair == MCC_COMMPROTO_COORD_KIND_AZZD ? MccCoordPairKind::COORDS_KIND_AZZD
|
|
// : spair == MCC_COMMPROTO_COORD_KIND_AZALT ? MccCoordPairKind::COORDS_KIND_AZALT
|
|
// : spair == MCC_COMMPROTO_COORD_KIND_XY ? MccCoordPairKind::COORDS_KIND_XY
|
|
// : MccCoordPairKind::COORDS_KIND_GENERIC;
|
|
// }
|
|
|
|
template <mcc::traits::mcc_char_range R>
|
|
static constexpr MccCoordPairKind mcc_str2pairkind(R&& spair)
|
|
{
|
|
if constexpr (std::is_pointer_v<std::decay_t<R>>) {
|
|
return mcc_str2pairkind(std::string_view{spair});
|
|
}
|
|
|
|
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(spair));
|
|
|
|
return hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_RADEC_ICRS) ? MccCoordPairKind::COORDS_KIND_RADEC_ICRS
|
|
: hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_RADEC) ? MccCoordPairKind::COORDS_KIND_RADEC_APP
|
|
: hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_HADEC) ? MccCoordPairKind::COORDS_KIND_HADEC_APP
|
|
: hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_AZZD) ? MccCoordPairKind::COORDS_KIND_AZZD
|
|
: hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_AZALT) ? MccCoordPairKind::COORDS_KIND_AZALT
|
|
: hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_XY) ? MccCoordPairKind::COORDS_KIND_XY
|
|
: MccCoordPairKind::COORDS_KIND_GENERIC;
|
|
}
|
|
|
|
|
|
static constexpr std::string_view mcc_pairkind2str(MccCoordPairKind kind)
|
|
{
|
|
return kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS ? MCC_COMMPROTO_COORD_KIND_RADEC_ICRS
|
|
: kind == MccCoordPairKind::COORDS_KIND_RADEC_APP ? MCC_COMMPROTO_COORD_KIND_RADEC
|
|
: kind == MccCoordPairKind::COORDS_KIND_HADEC_APP ? MCC_COMMPROTO_COORD_KIND_HADEC
|
|
: kind == MccCoordPairKind::COORDS_KIND_AZZD ? MCC_COMMPROTO_COORD_KIND_AZZD
|
|
: kind == MccCoordPairKind::COORDS_KIND_AZALT ? MCC_COMMPROTO_COORD_KIND_AZALT
|
|
: kind == MccCoordPairKind::COORDS_KIND_XY ? MCC_COMMPROTO_COORD_KIND_XY
|
|
: "UNKNOWN";
|
|
}
|
|
|
|
|
|
/* keywords */
|
|
|
|
// NOTE: THE COORDINATES AND TIME-RELATED QUANTITIES CAN BE EXPRESSED IN THE TWO FORMAT:
|
|
// 1) fixed-point real number, e.g. 123.43987537359 or -0.09775
|
|
// 2) sexagesimal number, e.g. 10:43:43.12 or -123:54:12.435
|
|
//
|
|
// IN THE FIRST CASE ALL NUMBERS MUST BE INTERPRETATED AS DEGREES,
|
|
// IN THE SECOND CASE NUMBERS MUST BE INTERPRETATED ACCORDING TO ITS TYPE:
|
|
// ALL TIME-RELATED QUANTITIES AND RA/HA COORDINATES MUST BE EXPRESSED
|
|
// IN FORMAT 'HOURS:MINUTES:SECONDS', WHILE DEC/ALT/AZ/ZD COORDINATES MUST
|
|
// BE EXPRESSED AS '+/-DEGREES:ARCMINUTES:ARCSECONDS'
|
|
//
|
|
// USER-ENTERED (FROM NETWORK CLIENTS) COORDINATE PAIR MAY BE PROVIDED IN A MIXED FORM, I.E.,
|
|
// 12.34436658678 10:32:11.432 or
|
|
// 10:32:11.432 12.34436658678
|
|
//
|
|
// SERVER-RESPONDED COORDINATES ARE ALWAYS IN THE SAME FORMAT, SEXAGESIMAL OR FIXED-POINT
|
|
//
|
|
|
|
// format of output coordinates:
|
|
// "COORDFMT FMT-type\n"
|
|
// e.g.:
|
|
// "COORDFMT SGM\n"
|
|
// "COORDFMT\n"
|
|
//
|
|
// server must return "ACK" or "ERROR INVPAR" in the case of 'set'-operation and
|
|
// "ACK COORDFMT FMT-type" in the case of 'get'-operation
|
|
// e.g.:
|
|
// "COORDFMT FIX\n" -> "ACK\n"
|
|
// "COORDFMT SXT\n" -> "ERROR INVPAR\n" (invalid parameter of format type)
|
|
// "COORDFMT\n" -> "ACK COORDFMT FIX\n"
|
|
//
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_STR = "COORDFMT";
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_SEXGM_STR = "SGM"; // sexagesimal
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_FIXED_STR = "FIX"; // fixed point
|
|
|
|
|
|
// precision (number of decimal places) of returned coordinates:
|
|
// "COORDPREC seconds-prec arcseconds-prec\n"
|
|
// seconds-prec - precision of hour-based coordinates (RA and HA) or time-related quantities
|
|
// arcseconds-prec - precision of degree-based coordinates (DEC, AZ, ZD, ALT)
|
|
// precision must be given as non-negative integer number
|
|
// e.g.
|
|
// "COORDPREC 2 1\n" (output sexagesimal RA=12:34:56.67, DEC=32:54:21.9)
|
|
//
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDPREC_STR = "COORDPREC";
|
|
|
|
|
|
// set/get target coordinates
|
|
// "TARGET X-coord Y-coord XY-kind\n", if 'XY-kind' is omitted then one should assume RADEC_ICRS
|
|
// e.g.:
|
|
// "TARGET 12.7683487 10:23:09.75 AZZD\n"
|
|
// "TARGET HADEC\n"
|
|
// "TARGET\n"
|
|
//
|
|
// server must return "ACK" or "ERROR INVPAR" in the case of 'set'-operation and
|
|
// "ACK TARGET X-coord Y-coord XY-kind" in the case of 'get'-operation
|
|
// e.g.:
|
|
// "TARGET 12.7683487 10:23:09.75 AZZD\n" -> "ACK\n"
|
|
// "TARGET 12.7683487 10:23:09.75 AZZE\n" -> "ERROR INVPAR\n" (invalid parameter of coordinates pair kind)
|
|
//
|
|
// "TARGET HADEC\n" -> "ACK TARGET 20:21:56.32 -01:32:34.2 HADEC\n"
|
|
// "TARGET\n" -> "ACK TARGET 20:21:56.32 -01:32:34.2 RADEC_ICRS\n"
|
|
//
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TARGET_STR = "TARGET";
|
|
|
|
// get mount coordinates:
|
|
// "MOUNT coord-kind", if 'coord-kind' is omitted then coordinates are according to mount type,
|
|
// i.e., HADEC for equathorial-type mount and AZZD for alt-azimuthal one
|
|
// e.g.:
|
|
// "MOUNT RADEC\n" (get mount current apparent RA and DEC mount coordinates)
|
|
//
|
|
// server must return "ACK MOUNT X-coord Y-coord XY-kind" or "ERROR INVPAR"
|
|
// e.g.
|
|
// "MOUNT AZALT\n" -> "ACK MOUNT 1.2332325 54.23321312 AZALT\n"
|
|
// "MOUNT AZAL\n" -> "ERROR INVPAR\n" (invalid parameter of coordinates pair kind)
|
|
// "MOUNT\n" -> "ACK MOUNT 1.2332325 54.23321312 AZZD\n" for alt-azimuthal mount
|
|
// "MOUNT\n" -> "ACK MOUNT 1.2332325 54.23321312 HADEC\n" for equathorial mount
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_MOUNT_STR = "MOUNT";
|
|
|
|
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TELEMETRY_STR = "TELEMETRY";
|
|
|
|
// init mount
|
|
// "INIT\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_INIT_STR = "INIT";
|
|
|
|
// stop any movements
|
|
// "STOP\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_STOP_STR = "STOP";
|
|
|
|
// slew mount and track target:
|
|
// "SLEW\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SLEW_STR = "SLEW";
|
|
|
|
// slew mount and stop:
|
|
// "MOVE\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_MOVE_STR = "MOVE";
|
|
|
|
// track target
|
|
// "TRACK\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TRACK_STR = "TRACK";
|
|
|
|
// get mount status
|
|
// "STATUS\n"
|
|
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_STATUS_STR = "STATUS";
|
|
|
|
// valid keywords
|
|
static constexpr std::array MCC_COMMPROTO_VALID_KEYS = {
|
|
MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR, MCC_COMMPROTO_KEYWORD_COORDFMT_STR,
|
|
MCC_COMMPROTO_KEYWORD_COORDPREC_STR, MCC_COMMPROTO_KEYWORD_TARGET_STR, MCC_COMMPROTO_KEYWORD_MOUNT_STR,
|
|
MCC_COMMPROTO_KEYWORD_TELEMETRY_STR, MCC_COMMPROTO_KEYWORD_INIT_STR, MCC_COMMPROTO_KEYWORD_STOP_STR,
|
|
MCC_COMMPROTO_KEYWORD_SLEW_STR, MCC_COMMPROTO_KEYWORD_MOVE_STR, MCC_COMMPROTO_KEYWORD_TRACK_STR,
|
|
MCC_COMMPROTO_KEYWORD_STATUS_STR};
|
|
|
|
|
|
// hashes of valid keywords
|
|
static constexpr std::array MCC_COMMPROTO_VALID_KEYS_HASH = []<size_t... Is>(std::index_sequence<Is...>) {
|
|
return std::array{mcc::utils::FNV1aHash(MCC_COMMPROTO_VALID_KEYS[Is])...};
|
|
}(std::make_index_sequence<MCC_COMMPROTO_VALID_KEYS.size()>());
|
|
|
|
|
|
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 <traits::mcc_char_range T = std::string_view, std::ranges::output_range<T> RT = std::vector<T>>
|
|
struct mcc_netmsg_parse_result_t {
|
|
size_t keyword_hash;
|
|
T keyword;
|
|
RT params;
|
|
};
|
|
|
|
|
|
// network message parsing result class concept
|
|
template <typename T>
|
|
concept mcc_netmsg_parse_result_c = requires(T t) {
|
|
requires std::same_as<decltype(t.keyword_hash), size_t>; // hash of keyword
|
|
requires traits::mcc_char_range<decltype(t.keyword)>; // keyword char-range representation
|
|
// a range of parameters char-range representations
|
|
requires std::ranges::output_range<decltype(t.params), decltype(t.keyword)>;
|
|
};
|
|
|
|
// 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 <traits::mcc_input_char_range IR, mcc_netmsg_parse_result_c ResT>
|
|
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 <typename... PTs>
|
|
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]<typename T, typename... Ts>(this auto&& self, const T& par, const Ts&... pars) {
|
|
if constexpr (std::is_arithmetic_v<T>) {
|
|
std::ranges::copy(std::to_string(par), std::back_inserter(msg));
|
|
} else if constexpr (std::convertible_to<T, std::string>) {
|
|
std::ranges::copy(static_cast<std::string>(par), std::back_inserter(msg));
|
|
} else if constexpr (std::constructible_from<std::string, T>) {
|
|
std::ranges::copy(std::string(par), std::back_inserter(msg));
|
|
} else if constexpr (traits::mcc_char_range<T>) {
|
|
std::ranges::copy(std::string(par.begin(), par.end()), std::back_inserter(msg));
|
|
} else if constexpr (std::same_as<T, MccCoordPairKind>) {
|
|
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<decltype(self)>(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<decltype(parse_res.keyword)>
|
|
{
|
|
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<double> 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 = utils::parsAngleString(parse_res.params[from_idx], true);
|
|
break;
|
|
default:
|
|
ang1 = utils::parsAngleString(parse_res.params[from_idx]);
|
|
}
|
|
if (!ang1) {
|
|
return false;
|
|
}
|
|
|
|
ang2 = 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;
|
|
}
|
|
|
|
|
|
} // namespace mcc::network
|