2015-03-14 15:13:18 -04:00
|
|
|
#include "Radio.hpp"
|
|
|
|
|
|
|
|
#include <cmath>
|
2017-01-08 18:58:00 -05:00
|
|
|
#include <limits>
|
2015-03-14 15:13:18 -04:00
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QChar>
|
|
|
|
#include <QRegularExpression>
|
|
|
|
|
|
|
|
namespace Radio
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
double constexpr MHz_factor {1.e6};
|
|
|
|
int constexpr frequency_precsion {6};
|
|
|
|
|
2020-11-11 11:22:57 -05:00
|
|
|
// valid callsign alphabet
|
|
|
|
QRegularExpression callsign_alphabet_re {R"(^[A-Z0-9/]{3,11}$)"};
|
|
|
|
|
2015-03-14 15:13:18 -04:00
|
|
|
// very loose validation - callsign must contain a letter next to
|
|
|
|
// a number
|
|
|
|
QRegularExpression valid_callsign_regexp {R"(\d[[:alpha:]]|[[:alpha:]]\d)"};
|
2018-04-21 15:09:31 -04:00
|
|
|
|
2020-11-11 11:22:57 -05:00
|
|
|
// standard callsign
|
2020-12-22 09:57:48 -05:00
|
|
|
QRegularExpression strict_standard_callsign_re {R"(^([A-Z][0-9]?|[0-9A-Z][A-Z])[0-9][A-Z]{0,3}$)"};
|
2020-11-11 11:22:57 -05:00
|
|
|
|
2018-04-21 15:09:31 -04:00
|
|
|
// suffixes that are often used and should not be interpreted as a
|
|
|
|
// DXCC Entity prefix used as a suffix
|
|
|
|
QRegularExpression non_prefix_suffix {R"(\A([0-9AMPQR]|QRP|F[DF]|[AM]M|L[HT]|LGT)\z)"};
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-08 18:58:00 -05:00
|
|
|
Frequency frequency (QVariant const& v, int scale, bool * ok, QLocale const& locale)
|
2015-03-14 15:13:18 -04:00
|
|
|
{
|
2017-01-08 18:58:00 -05:00
|
|
|
double value {0.};
|
2015-09-10 17:03:42 -04:00
|
|
|
if (QVariant::String == v.type ())
|
|
|
|
{
|
2017-01-08 18:58:00 -05:00
|
|
|
value = locale.toDouble (v.value<QString> (), ok);
|
2015-09-10 17:03:42 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = v.toDouble ();
|
2017-01-08 18:58:00 -05:00
|
|
|
if (ok) *ok = true;
|
2015-09-10 17:03:42 -04:00
|
|
|
}
|
2017-01-08 18:58:00 -05:00
|
|
|
value *= std::pow (10., scale);
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
if (value < 0. || value > std::numeric_limits<Frequency>::max ())
|
|
|
|
{
|
|
|
|
value = 0.;
|
|
|
|
*ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::llround (value);
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
|
2017-01-08 18:58:00 -05:00
|
|
|
FrequencyDelta frequency_delta (QVariant const& v, int scale, bool * ok, QLocale const& locale)
|
2015-03-14 15:13:18 -04:00
|
|
|
{
|
2017-01-08 18:58:00 -05:00
|
|
|
double value {0.};
|
2015-09-10 17:03:42 -04:00
|
|
|
if (QVariant::String == v.type ())
|
|
|
|
{
|
2017-01-08 18:58:00 -05:00
|
|
|
value = locale.toDouble (v.value<QString> (), ok);
|
2015-09-10 17:03:42 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = v.toDouble ();
|
2017-01-08 18:58:00 -05:00
|
|
|
if (ok) *ok = true;
|
|
|
|
}
|
|
|
|
value *= std::pow (10., scale);
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
if (value < -std::numeric_limits<Frequency>::max ()
|
|
|
|
|| value > std::numeric_limits<Frequency>::max ())
|
|
|
|
{
|
|
|
|
value = 0.;
|
|
|
|
*ok = false;
|
|
|
|
}
|
2015-09-10 17:03:42 -04:00
|
|
|
}
|
2017-01-08 18:58:00 -05:00
|
|
|
return std::llround (value);
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-30 17:20:09 -04:00
|
|
|
QString frequency_MHz_string (Frequency f, int precision, QLocale const& locale)
|
2015-03-14 15:13:18 -04:00
|
|
|
{
|
2019-05-30 17:20:09 -04:00
|
|
|
return locale.toString (f / MHz_factor, 'f', precision);
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
|
2019-05-30 17:20:09 -04:00
|
|
|
QString frequency_MHz_string (FrequencyDelta d, int precision, QLocale const& locale)
|
2015-03-14 15:13:18 -04:00
|
|
|
{
|
2019-05-30 17:20:09 -04:00
|
|
|
return locale.toString (d / MHz_factor, 'f', precision);
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
QString pretty_frequency_MHz_string (Frequency f, QLocale const& locale)
|
|
|
|
{
|
|
|
|
auto f_string = locale.toString (f / MHz_factor, 'f', frequency_precsion);
|
|
|
|
return f_string.insert (f_string.size () - 3, QChar::Nbsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString pretty_frequency_MHz_string (double f, int scale, QLocale const& locale)
|
|
|
|
{
|
|
|
|
auto f_string = locale.toString (f / std::pow (10., scale - 6), 'f', frequency_precsion);
|
|
|
|
return f_string.insert (f_string.size () - 3, QChar::Nbsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString pretty_frequency_MHz_string (FrequencyDelta d, QLocale const& locale)
|
|
|
|
{
|
|
|
|
auto d_string = locale.toString (d / MHz_factor, 'f', frequency_precsion);
|
|
|
|
return d_string.insert (d_string.size () - 3, QChar::Nbsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_callsign (QString const& callsign)
|
|
|
|
{
|
|
|
|
return callsign.contains (valid_callsign_regexp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_compound_callsign (QString const& callsign)
|
|
|
|
{
|
|
|
|
return callsign.contains ('/');
|
|
|
|
}
|
|
|
|
|
2020-11-11 11:22:57 -05:00
|
|
|
bool is_77bit_nonstandard_callsign (QString const& callsign)
|
|
|
|
{
|
|
|
|
return callsign.contains (callsign_alphabet_re)
|
|
|
|
&& !callsign.contains (strict_standard_callsign_re);
|
|
|
|
}
|
|
|
|
|
2015-03-14 15:13:18 -04:00
|
|
|
// split on first '/' and return the larger portion or the whole if
|
|
|
|
// there is no '/'
|
|
|
|
QString base_callsign (QString callsign)
|
|
|
|
{
|
|
|
|
auto slash_pos = callsign.indexOf ('/');
|
|
|
|
if (slash_pos >= 0)
|
|
|
|
{
|
|
|
|
auto right_size = callsign.size () - slash_pos - 1;
|
|
|
|
if (right_size>= slash_pos)
|
|
|
|
{
|
|
|
|
callsign = callsign.mid (slash_pos + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
callsign = callsign.left (slash_pos);
|
|
|
|
}
|
|
|
|
}
|
2018-04-21 15:09:31 -04:00
|
|
|
return callsign.toUpper ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// analyze the callsign and determine the effective prefix, returns
|
|
|
|
// the full call if no valid prefix (or prefix as a suffix) is specified
|
|
|
|
QString effective_prefix (QString callsign)
|
|
|
|
{
|
2018-11-28 19:56:53 -05:00
|
|
|
auto prefix = callsign;
|
2018-04-21 15:09:31 -04:00
|
|
|
auto slash_pos = callsign.indexOf ('/');
|
|
|
|
if (slash_pos >= 0)
|
|
|
|
{
|
|
|
|
auto right_size = callsign.size () - slash_pos - 1;
|
2018-11-28 19:56:53 -05:00
|
|
|
if (right_size >= slash_pos) // native call is longer than
|
2018-04-21 15:09:31 -04:00
|
|
|
// prefix/suffix algorithm
|
|
|
|
{
|
|
|
|
prefix = callsign.left (slash_pos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prefix = callsign.mid (slash_pos + 1);
|
|
|
|
if (prefix.contains (non_prefix_suffix))
|
|
|
|
{
|
|
|
|
prefix = callsign.left (slash_pos); // ignore
|
|
|
|
// non-prefix
|
|
|
|
// suffixes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-28 19:56:53 -05:00
|
|
|
return prefix.toUpper ();
|
2015-03-14 15:13:18 -04:00
|
|
|
}
|
|
|
|
}
|