#include "DXLabSuiteCommanderTransceiver.hpp" #include #include #include "NetworkServerLookup.hpp" namespace { char const * const commander_transceiver_name {"DX Lab Suite Commander"}; int socket_wait_time {5000}; 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 wrapped, QString const& address, bool use_for_ptt, int poll_interval) : PollingTransceiver {poll_interval} , wrapped_ {std::move (wrapped)} , use_for_ptt_ {use_for_ptt} , server_ {address} , commander_ {nullptr} { } DXLabSuiteCommanderTransceiver::~DXLabSuiteCommanderTransceiver () { } void DXLabSuiteCommanderTransceiver::do_start () { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::start"; #endif wrapped_->start (); 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 (socket_wait_time)) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::start failed to connect" << commander_->errorString (); #endif throw error {"Failed to connect to DX Lab Suite Commander\n" + commander_->errorString ().toLocal8Bit ()}; } poll (); } void DXLabSuiteCommanderTransceiver::do_stop () { if (commander_) { commander_->close (); delete commander_, commander_ = nullptr; } wrapped_->stop (); #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::stop"; #endif } void DXLabSuiteCommanderTransceiver::do_ptt (bool on) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::do_ptt:" << on << state (); #endif if (use_for_ptt_) { send_command (on ? "CmdTX" : "CmdRX"); } else { wrapped_->ptt (on); } update_PTT (on); } void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::do_frequency:" << f << state (); #endif // number is localised // avoid floating point translation errors by adding a small number (0.1Hz) send_command ("CmdSetFreq" + QString ("%L1").arg (f / 1e3 + 1e-4, 10, 'f', 3).toLocal8Bit ()); update_rx_frequency (f); } void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode */) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::do_tx_frequency:" << tx << state (); #endif if (tx) { send_command ("CmdSplit<1:2>on"); update_split (true); // number is localised // avoid floating point translation errors by adding a small number (0.1Hz) // set TX frequency after going split because going split // rationalises TX VFO mode and that can change the frequency on // Yaesu rigs if CW is involved send_command ("CmdSetTxFreq" + QString ("%L1").arg (tx / 1e3 + 1e-4, 10, 'f', 3).toLocal8Bit ()); } else { send_command ("CmdSplit<1:3>off"); } update_other_frequency (tx); } void DXLabSuiteCommanderTransceiver::do_mode (MODE mode, bool /* rationalise */) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::do_mode:" << mode << state (); #endif auto mapped = map_mode (mode); send_command ((QString ("CmdSetMode<1:%2>").arg (5 + mapped.size ()).arg (mapped.size ()) + mapped).toLocal8Bit ()); if (state ().split ()) { // this toggle ensures that the TX VFO mode is the same as the RX VFO send_command ("CmdSplit<1:3>off"); send_command ("CmdSplit<1:2>on"); } // setting TX frequency rationalises the mode on Icoms so get current and set poll (); } void DXLabSuiteCommanderTransceiver::poll () { #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS bool quiet {false}; #else bool quiet {true}; #endif send_command ("CmdSendFreq", quiet); auto reply = read_reply (quiet); if (0 == reply.indexOf ("') + 1).replace (",", "").replace (".", ""); update_rx_frequency (reply.toUInt ()); } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: get frequency unexpected response"; #endif throw error {"DX Lab Suite Commander didn't respond correctly polling frequency"}; } send_command ("CmdSendTXFreq", quiet); reply = read_reply (quiet); if (0 == reply.indexOf ("') + 1).replace (",", "").replace (".", ""); if ("000" != text) { update_other_frequency (text.toUInt ()); } } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: get tx frequency unexpected response"; #endif throw error {"DX Lab Suite Commander didn't respond correctly polling TX frequency"}; } send_command ("CmdSendSplit", quiet); reply = read_reply (quiet); if (0 == reply.indexOf ("') + 1); if ("ON" == split) { update_split (true); } else if ("OFF" == split) { update_split (false); } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected split state" << split; #endif throw error {"DX Lab Suite Commander sent an unrecognised split state: " + split}; } } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: get split mode unexpected response"; #endif throw error {"DX Lab Suite Commander didn't respond correctly polling split status"}; } send_command ("CmdSendMode", quiet); reply = read_reply (quiet); if (0 == reply.indexOf ("') + 1); MODE m {UNK}; 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) { m = DIG_L; } else if ("PKT-R" == mode || "DATA-U" == mode || "Data-U" == mode) { m = DIG_U; } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected mode name" << mode; #endif throw error {"DX Lab Suite Commander sent an unrecognised mode: " + mode}; } update_mode (m); } else { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected response"; #endif throw error {"DX Lab Suite Commander didn't respond correctly polling mode"}; } } void DXLabSuiteCommanderTransceiver::send_command (QByteArray const& cmd, bool no_debug) { Q_ASSERT (commander_); if (!no_debug) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver:send_command(" << cmd << ')'; #endif } if (QTcpSocket::ConnectedState != commander_->state ()) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::send_command failed:" << commander_->errorString (); #endif throw error {"DX Lab Suite Commander send command failed\n" + commander_->errorString ().toLocal8Bit ()}; } commander_->write (cmd); if (!commander_->waitForBytesWritten (socket_wait_time)) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::send_command failed:" << commander_->errorString (); #endif throw error {"DX Lab Suite Commander send command failed\n" + commander_->errorString ().toLocal8Bit ()}; } } QByteArray DXLabSuiteCommanderTransceiver::read_reply (bool no_debug) { Q_ASSERT (commander_); if (QTcpSocket::ConnectedState != commander_->state ()) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::read_reply failed:" << commander_->errorString (); #endif throw error {"DX Lab Suite Commander read reply failed\n" + commander_->errorString ().toLocal8Bit ()}; } if (!commander_->waitForReadyRead (socket_wait_time)) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver::read_reply failed:" << commander_->errorString (); #endif throw error {"DX Lab Suite Commander read reply failed\n" + commander_->errorString ().toLocal8Bit ()}; } auto result = commander_->readAll (); if (!no_debug) { #if WSJT_TRACE_CAT qDebug () << "DXLabSuiteCommanderTransceiver:read_reply() ->" << result; #endif } return result; }