507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								#include "DXLabSuiteCommanderTransceiver.hpp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <QTcpSocket>
							 | 
						||
| 
								 | 
							
								#include <QRegularExpression>
							 | 
						||
| 
								 | 
							
								#include <QLocale>
							 | 
						||
| 
								 | 
							
								#include <QThread>
							 | 
						||
| 
								 | 
							
								#include <QDateTime>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "NetworkServerLookup.hpp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "moc_DXLabSuiteCommanderTransceiver.cpp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  char const * const commander_transceiver_name {"DX Lab Suite Commander"};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  QString map_mode (Transceiver::MODE mode)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    switch (mode)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								      case Transceiver::AM: return "AM";
							 | 
						||
| 
								 | 
							
								      case Transceiver::CW: return "CW";
							 | 
						||
| 
								 | 
							
								      case Transceiver::CW_R: return "CW-R";
							 | 
						||
| 
								 | 
							
								      case Transceiver::USB: return "USB";
							 | 
						||
| 
								 | 
							
								      case Transceiver::LSB: return "LSB";
							 | 
						||
| 
								 | 
							
								      case Transceiver::FSK: return "RTTY";
							 | 
						||
| 
								 | 
							
								      case Transceiver::FSK_R: return "RTTY-R";
							 | 
						||
| 
								 | 
							
								      case Transceiver::DIG_L: return "DATA-L";
							 | 
						||
| 
								 | 
							
								      case Transceiver::DIG_U: return "DATA-U";
							 | 
						||
| 
								 | 
							
								      case Transceiver::FM:
							 | 
						||
| 
								 | 
							
								      case Transceiver::DIG_FM:
							 | 
						||
| 
								 | 
							
								        return "FM";
							 | 
						||
| 
								 | 
							
								      default: break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    return "USB";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  (*registry)[commander_transceiver_name] = TransceiverFactory::Capabilities {id, TransceiverFactory::Capabilities::network, true};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped,
							 | 
						||
| 
								 | 
							
								                                                                QString const& address, bool use_for_ptt,
							 | 
						||
| 
								 | 
							
								                                                                int poll_interval, QObject * parent)
							 | 
						||
| 
								 | 
							
								  : PollingTransceiver {poll_interval, parent}
							 | 
						||
| 
								 | 
							
								  , wrapped_ {std::move (wrapped)}
							 | 
						||
| 
								 | 
							
								  , use_for_ptt_ {use_for_ptt}
							 | 
						||
| 
								 | 
							
								  , server_ {address}
							 | 
						||
| 
								 | 
							
								  , commander_ {nullptr}
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int DXLabSuiteCommanderTransceiver::do_start ()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", "starting");
							 | 
						||
| 
								 | 
							
								  if (wrapped_) wrapped_->start (0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  auto server_details = network_server_lookup (server_, 52002u, QHostAddress::LocalHost, QAbstractSocket::IPv4Protocol);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!commander_)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      commander_ = new QTcpSocket {this}; // QObject takes ownership
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  commander_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
							 | 
						||
| 
								 | 
							
								  if (!commander_->waitForConnected ())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to connect" << commander_->errorString ());
							 | 
						||
| 
								 | 
							
								      throw error {tr ("Failed to connect to DX Lab Suite Commander\n") + commander_->errorString ()};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // sleeps here are to ensure Commander has actually queried the rig
							 | 
						||
| 
								 | 
							
								  // rather than returning cached data which maybe stale or simply
							 | 
						||
| 
								 | 
							
								  // read backs of not yet committed values, the 2s delays are
							 | 
						||
| 
								 | 
							
								  // arbitrary but hopefully enough as the actual time required is rig
							 | 
						||
| 
								 | 
							
								  // and Commander setting dependent
							 | 
						||
| 
								 | 
							
								  int resolution {0};
							 | 
						||
| 
								 | 
							
								  QThread::msleep (2000);
							 | 
						||
| 
								 | 
							
								  auto reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
							 | 
						||
| 
								 | 
							
								  if (0 == reply.indexOf ("<CmdFreq:"))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
							 | 
						||
| 
								 | 
							
								      if (f && !(f % 10))
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          auto test_frequency = f - f % 100 + 55;
							 | 
						||
| 
								 | 
							
								          auto f_string = frequency_to_string (test_frequency);
							 | 
						||
| 
								 | 
							
								          auto params =  ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
							 | 
						||
| 
								 | 
							
								          simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								          QThread::msleep (2000);
							 | 
						||
| 
								 | 
							
								          reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
							 | 
						||
| 
								 | 
							
								          if (0 == reply.indexOf ("<CmdFreq:"))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              auto new_frequency = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
							 | 
						||
| 
								 | 
							
								              switch (static_cast<Radio::FrequencyDelta> (new_frequency - test_frequency))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                case -5: resolution = -1; break;  // 10Hz truncated
							 | 
						||
| 
								 | 
							
								                case 5: resolution = 1; break;    // 10Hz rounded
							 | 
						||
| 
								 | 
							
								                case -15: resolution = -2; break; // 20Hz truncated
							 | 
						||
| 
								 | 
							
								                case -55: resolution = -2; break; // 100Hz truncated
							 | 
						||
| 
								 | 
							
								                case 45: resolution = 2; break;   // 100Hz rounded
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              if (1 == resolution)      // may be 20Hz rounded
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  test_frequency = f - f % 100 + 51;
							 | 
						||
| 
								 | 
							
								                  f_string = frequency_to_string (test_frequency);
							 | 
						||
| 
								 | 
							
								                  params =  ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
							 | 
						||
| 
								 | 
							
								                  simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								                  QThread::msleep (2000);
							 | 
						||
| 
								 | 
							
								                  reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
							 | 
						||
| 
								 | 
							
								                  new_frequency = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
							 | 
						||
| 
								 | 
							
								                  if (9 == static_cast<Radio::FrequencyDelta> (new_frequency - test_frequency))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                      resolution = 2;   // 20Hz rounded
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              f_string = frequency_to_string (f);
							 | 
						||
| 
								 | 
							
								              params =  ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
							 | 
						||
| 
								 | 
							
								              simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency: ") + reply};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  poll ();
							 | 
						||
| 
								 | 
							
								  return resolution;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::do_stop ()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (commander_)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      commander_->close ();
							 | 
						||
| 
								 | 
							
								      delete commander_, commander_ = nullptr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (wrapped_) wrapped_->stop ();
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", "stopped");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", on << state ());
							 | 
						||
| 
								 | 
							
								  if (use_for_ptt_)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      simple_command (on  ? "<command:5>CmdTX<parameters:0>" : "<command:5>CmdRX<parameters:0>");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      bool tx {!on};
							 | 
						||
| 
								 | 
							
								      auto start = QDateTime::currentMSecsSinceEpoch ();
							 | 
						||
| 
								 | 
							
								      // we must now wait for Tx on the rig, we will wait a short while
							 | 
						||
| 
								 | 
							
								      // before bailing out
							 | 
						||
| 
								 | 
							
								      while (tx != on && QDateTime::currentMSecsSinceEpoch () - start < 1000)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          auto reply = command_with_reply ("<command:9>CmdSendTx<parameters:0>");
							 | 
						||
| 
								 | 
							
								          if (0 == reply.indexOf ("<CmdTX:"))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              auto state = reply.mid (reply.indexOf ('>') + 1);
							 | 
						||
| 
								 | 
							
								              if ("ON" == state)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  tx = true;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              else if ("OFF" == state)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  tx = false;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  TRACE_CAT ("DXLabSuiteCommanderTransceiver", "unexpected TX state" << state);
							 | 
						||
| 
								 | 
							
								                  throw error {tr ("DX Lab Suite Commander sent an unrecognised TX state: ") + state};
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              TRACE_CAT ("DXLabSuiteCommanderTransceiver", "get TX unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								              throw error {tr ("DX Lab Suite Commander didn't respond correctly polling TX status: ") + reply};
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          if (tx != on) QThread::msleep (10); // don't thrash Commander
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      update_PTT (tx);
							 | 
						||
| 
								 | 
							
								      if (tx != on)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          TRACE_CAT ("DXLabSuiteCommanderTransceiver", "rig failed to respond to PTT: " << on);
							 | 
						||
| 
								 | 
							
								          throw error {tr ("DX Lab Suite Commander rig did not respond to PTT: ") + (on ? "ON" : "OFF")};
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      Q_ASSERT (wrapped_);
							 | 
						||
| 
								 | 
							
								      TransceiverState new_state {wrapped_->state ()};
							 | 
						||
| 
								 | 
							
								      new_state.ptt (on);
							 | 
						||
| 
								 | 
							
								      wrapped_->set (new_state, 0);
							 | 
						||
| 
								 | 
							
								      update_PTT (on);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", f << state ());
							 | 
						||
| 
								 | 
							
								  auto f_string = frequency_to_string (f);
							 | 
						||
| 
								 | 
							
								  if (UNK != m && m != get_mode ())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto m_string = map_mode (m);
							 | 
						||
| 
								 | 
							
								      auto params =  ("<xcvrfreq:%1>" + f_string + "<xcvrmode:%2>" + m_string + "<preservesplitanddual:1>Y").arg (f_string.size ()).arg (m_string.size ());
							 | 
						||
| 
								 | 
							
								      simple_command (("<command:14>CmdSetFreqMode<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								      update_mode (m);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto params =  ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
							 | 
						||
| 
								 | 
							
								      simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  update_rx_frequency (f);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool /*no_ignore*/)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", tx << state ());
							 | 
						||
| 
								 | 
							
								  if (tx)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto f_string = frequency_to_string (tx);
							 | 
						||
| 
								 | 
							
								      auto params = ("<xcvrfreq:%1>" + f_string + "<SuppressDual:1>Y").arg (f_string.size ());
							 | 
						||
| 
								 | 
							
								      if (UNK == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          params += "<SuppressModeChange:1>Y";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      simple_command (("<command:11>CmdQSXSplit<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      simple_command ("<command:8>CmdSplit<parameters:8><1:3>off");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  update_split (tx);
							 | 
						||
| 
								 | 
							
								  update_other_frequency (tx);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  TRACE_CAT ("DXLabSuiteCommanderTransceiver", m << state ());
							 | 
						||
| 
								 | 
							
								  auto m_string = map_mode (m);
							 | 
						||
| 
								 | 
							
								  auto params =  ("<1:%1>" + m_string).arg (m_string.size ());
							 | 
						||
| 
								 | 
							
								  simple_command (("<command:10>CmdSetMode<parameters:%1>" + params).arg (params.size ()));
							 | 
						||
| 
								 | 
							
								  update_mode (m);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::poll ()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
							 | 
						||
| 
								 | 
							
								  bool quiet {false};
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								  bool quiet {true};
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  auto reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>", quiet);
							 | 
						||
| 
								 | 
							
								  if (0 == reply.indexOf ("<CmdFreq:"))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
							 | 
						||
| 
								 | 
							
								      if (f)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          if (!state ().ptt ()) // Commander is not reliable on frequency
							 | 
						||
| 
								 | 
							
								                                // polls while transmitting
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              update_rx_frequency (f);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander didn't respond correctly polling frequency: ") + reply};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (state ().split ())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      reply = command_with_reply ("<command:12>CmdGetTXFreq<parameters:0>", quiet);
							 | 
						||
| 
								 | 
							
								      if (0 == reply.indexOf ("<CmdTXFreq:"))
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
							 | 
						||
| 
								 | 
							
								          if (f)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              if (!state ().ptt ()) // Commander is not reliable on frequency
							 | 
						||
| 
								 | 
							
								                                // polls while transmitting
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                  update_other_frequency (f);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get tx frequency unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								          throw error {tr ("DX Lab Suite Commander didn't respond correctly polling TX frequency: ") + reply};
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  reply = command_with_reply ("<command:12>CmdSendSplit<parameters:0>", quiet);
							 | 
						||
| 
								 | 
							
								  if (0 == reply.indexOf ("<CmdSplit:"))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto split = reply.mid (reply.indexOf ('>') + 1);
							 | 
						||
| 
								 | 
							
								      if ("ON" == split)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          update_split (true);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("OFF" == split)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          update_split (false);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected split state" << split);
							 | 
						||
| 
								 | 
							
								          throw error {tr ("DX Lab Suite Commander sent an unrecognised split state: ") + split};
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get split mode unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander didn't respond correctly polling split status: ") + reply};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get_mode (quiet);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								auto DXLabSuiteCommanderTransceiver::get_mode (bool no_debug) -> MODE
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  MODE m {UNK};
							 | 
						||
| 
								 | 
							
								  auto reply = command_with_reply ("<command:11>CmdSendMode<parameters:0>", no_debug);
							 | 
						||
| 
								 | 
							
								  if (0 == reply.indexOf ("<CmdMode:"))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto mode = reply.mid (reply.indexOf ('>') + 1);
							 | 
						||
| 
								 | 
							
								      if ("AM" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = AM;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("CW" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = CW;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("CW-R" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = CW_R;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("FM" == mode || "WBFM" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = FM;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("LSB" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = LSB;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("USB" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = USB;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("RTTY" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = FSK;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("RTTY-R" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = FSK_R;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("PKT" == mode || "DATA-L" == mode || "Data-L" == mode || "DIGL" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = DIG_L;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else if ("PKT-R" == mode || "DATA-U" == mode || "Data-U" == mode || "DIGU" == mode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          m = DIG_U;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected mode name" << mode);
							 | 
						||
| 
								 | 
							
								          throw error {tr ("DX Lab Suite Commander sent an unrecognised mode: \"") + mode + '"'};
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      update_mode (m);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected response" << reply);
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander didn't respond correctly polling mode: ") + reply};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return m;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd, bool no_debug)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  Q_ASSERT (commander_);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!no_debug)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!write_to_port (cmd))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed:" << commander_->errorString ());
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander send command failed\n") + commander_->errorString ()};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd, bool no_debug)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  Q_ASSERT (commander_);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!write_to_port (cmd))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to send command:" << commander_->errorString ());
							 | 
						||
| 
								 | 
							
								      throw error {
							 | 
						||
| 
								 | 
							
								        tr ("DX Lab Suite Commander failed to send command \"%1\": %2\n")
							 | 
						||
| 
								 | 
							
								          .arg (cmd)
							 | 
						||
| 
								 | 
							
								          .arg (commander_->errorString ())
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // waitForReadReady appears to be unreliable on Windows timing out
							 | 
						||
| 
								 | 
							
								  // when data is waiting so retry a few times
							 | 
						||
| 
								 | 
							
								  unsigned retries {5};
							 | 
						||
| 
								 | 
							
								  bool replied {false};
							 | 
						||
| 
								 | 
							
								  while (!replied && --retries)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      replied = commander_->waitForReadyRead ();
							 | 
						||
| 
								 | 
							
								      if (!replied && commander_->error () != commander_->SocketTimeoutError)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "failed to read reply:" << commander_->errorString ());
							 | 
						||
| 
								 | 
							
								          throw error {
							 | 
						||
| 
								 | 
							
								            tr ("DX Lab Suite Commander send command \"%1\" read reply failed: %2\n")
							 | 
						||
| 
								 | 
							
								              .arg (cmd)
							 | 
						||
| 
								 | 
							
								              .arg (commander_->errorString ())
							 | 
						||
| 
								 | 
							
								              };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!replied)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "retries exhausted");
							 | 
						||
| 
								 | 
							
								      throw error {
							 | 
						||
| 
								 | 
							
								        tr ("DX Lab Suite Commander retries exhausted sending command \"%1\"")
							 | 
						||
| 
								 | 
							
								          .arg (cmd)
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  auto result = commander_->readAll ();
							 | 
						||
| 
								 | 
							
								  // qDebug () << "result: " << result;
							 | 
						||
| 
								 | 
							
								  // for (int i = 0; i < result.size (); ++i)
							 | 
						||
| 
								 | 
							
								  //   {
							 | 
						||
| 
								 | 
							
								  //     qDebug () << i << ":" << hex << int (result[i]);
							 | 
						||
| 
								 | 
							
								  //   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!no_debug)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "->" << result);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return result;                // converting raw UTF-8 bytes to QString
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool DXLabSuiteCommanderTransceiver::write_to_port (QString const& s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  auto data = s.toLocal8Bit ();
							 | 
						||
| 
								 | 
							
								  auto to_send = data.constData ();
							 | 
						||
| 
								 | 
							
								  auto length = data.size ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  qint64 total_bytes_sent {0};
							 | 
						||
| 
								 | 
							
								  while (total_bytes_sent < length)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      auto bytes_sent = commander_->write (to_send + total_bytes_sent, length - total_bytes_sent);
							 | 
						||
| 
								 | 
							
								      if (bytes_sent < 0 || !commander_->waitForBytesWritten ())
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      total_bytes_sent += bytes_sent;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return true;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								QString DXLabSuiteCommanderTransceiver::frequency_to_string (Frequency f) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  // number is localized and in kHz, avoid floating point translation
							 | 
						||
| 
								 | 
							
								  // errors by adding a small number (0.1Hz)
							 | 
						||
| 
								 | 
							
								  return QString {"%L1"}.arg (f / 1e3 + 1e-4, 10, 'f', 3);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								auto DXLabSuiteCommanderTransceiver::string_to_frequency (QString s) const -> Frequency
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  // temporary hack because Commander is returning invalid UTF-8 bytes
							 | 
						||
| 
								 | 
							
								  s.replace (QChar {QChar::ReplacementCharacter}, locale_.groupSeparator ());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // remove DP - relies on n.nnn kHz format so we can do ulonglong
							 | 
						||
| 
								 | 
							
								  // conversion to Hz
							 | 
						||
| 
								 | 
							
								  bool ok;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // auto f = locale_.toDouble (s, &ok); // use when CmdSendFreq and
							 | 
						||
| 
								 | 
							
								                                      // CmdSendTxFreq reinstated
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  auto f = QLocale::c ().toDouble (s, &ok); // temporary fix
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!ok)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      throw error {tr ("DX Lab Suite Commander sent an unrecognized frequency")};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  return (f + 1e-4) * 1e3;
							 | 
						||
| 
								 | 
							
								}
							 |