mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-03 13:30:52 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "Radio.hpp"
 | 
						|
 | 
						|
#include <cmath>
 | 
						|
#include <limits>
 | 
						|
 | 
						|
#include <QString>
 | 
						|
#include <QChar>
 | 
						|
#include <QRegularExpression>
 | 
						|
 | 
						|
namespace Radio
 | 
						|
{
 | 
						|
  namespace
 | 
						|
  {
 | 
						|
    double constexpr MHz_factor {1.e6};
 | 
						|
    int constexpr frequency_precsion {6};
 | 
						|
 | 
						|
    // valid callsign alphabet
 | 
						|
    QRegularExpression callsign_alphabet_re {R"(^[A-Z0-9/]{3,11}$)"};
 | 
						|
 | 
						|
    // very loose validation - callsign must contain a letter next to
 | 
						|
    // a number
 | 
						|
    QRegularExpression valid_callsign_regexp {R"(\d[[:alpha:]]|[[:alpha:]]\d)"};
 | 
						|
 | 
						|
    // standard callsign
 | 
						|
    QRegularExpression strict_standard_callsign_re {R"(^([A-Z][0-9]?|[0-9A-Z][A-Z])[0-9][A-Z]{0,3}$)"};
 | 
						|
 | 
						|
    // 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)"};
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  Frequency frequency (QVariant const& v, int scale, bool * ok, QLocale const& locale)
 | 
						|
  {
 | 
						|
    double value {0.};
 | 
						|
    if (QVariant::String == v.type ())
 | 
						|
      {
 | 
						|
        value = locale.toDouble (v.value<QString> (), ok);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        value = v.toDouble ();
 | 
						|
        if (ok) *ok = true;
 | 
						|
      }
 | 
						|
    if (ok && !*ok)
 | 
						|
      {
 | 
						|
        return value;
 | 
						|
      }
 | 
						|
    return frequency (value, scale, ok);
 | 
						|
  }
 | 
						|
 | 
						|
  Frequency frequency (double value, int scale, bool * ok)
 | 
						|
  {
 | 
						|
    value *= std::pow (10., scale);
 | 
						|
    if (ok)
 | 
						|
      {
 | 
						|
        if (value < 0. || value > static_cast<double>(std::numeric_limits<Frequency>::max ()))
 | 
						|
          {
 | 
						|
            value = 0.;
 | 
						|
            *ok = false;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            *ok = true;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return std::llround (value);
 | 
						|
  }
 | 
						|
 | 
						|
  FrequencyDelta frequency_delta (QVariant const& v, int scale, bool * ok, QLocale const& locale)
 | 
						|
  {
 | 
						|
    double value {0.};
 | 
						|
    if (QVariant::String == v.type ())
 | 
						|
      {
 | 
						|
        value = locale.toDouble (v.value<QString> (), ok);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        value = v.toDouble ();
 | 
						|
        if (ok) *ok = true;
 | 
						|
      }
 | 
						|
    if (ok && !*ok)
 | 
						|
      {
 | 
						|
        return value;
 | 
						|
      }
 | 
						|
    return frequency_delta (value, scale, ok);
 | 
						|
  }
 | 
						|
 | 
						|
  FrequencyDelta frequency_delta (double value, int scale, bool * ok)
 | 
						|
  {
 | 
						|
    value *= std::pow (10., scale);
 | 
						|
    if (ok)
 | 
						|
      {
 | 
						|
        if (value < static_cast<double>(std::numeric_limits<Frequency>::min ())
 | 
						|
            || value > static_cast<double>(std::numeric_limits<Frequency>::max ()))
 | 
						|
          {
 | 
						|
            value = 0.;
 | 
						|
            *ok = false;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            *ok = true;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return std::llround (value);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  QString frequency_MHz_string (Frequency f, int precision, QLocale const& locale)
 | 
						|
  {
 | 
						|
    return locale.toString (f / MHz_factor, 'f', precision);
 | 
						|
  }
 | 
						|
 | 
						|
  QString frequency_MHz_string (FrequencyDelta d, int precision, QLocale const& locale)
 | 
						|
  {
 | 
						|
    return locale.toString (d / MHz_factor, 'f', precision);
 | 
						|
  }
 | 
						|
 | 
						|
  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 ('/');
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_77bit_nonstandard_callsign (QString const& callsign)
 | 
						|
  {
 | 
						|
    return callsign.contains (callsign_alphabet_re)
 | 
						|
      && !callsign.contains (strict_standard_callsign_re);
 | 
						|
  }
 | 
						|
 | 
						|
  // 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);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    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)
 | 
						|
  {
 | 
						|
    auto prefix = callsign;
 | 
						|
    auto slash_pos = callsign.indexOf ('/');
 | 
						|
    if (slash_pos >= 0)
 | 
						|
      {
 | 
						|
        auto right_size = callsign.size () - slash_pos - 1;
 | 
						|
        if (right_size >= slash_pos) // native call is longer than
 | 
						|
                                     // 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
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return prefix.toUpper ();
 | 
						|
  }
 | 
						|
}
 |