#ifndef TRANSCEIVER_HPP__ #define TRANSCEIVER_HPP__ #include #include "qt_helpers.hpp" #include "Radio.hpp" class QString; // // Abstract Transceiver Interface // // This is the minimal generic interface to a rig as required by // wsjtx. // // Responsibilities // // Provides Qt slots to set the frequency, mode and PTT of some // transceiver. They are Qt slots so that they may be invoked across // a thread boundary. // // Provides a synchronisation Qt slot which should be implemented in // sub-classes in such a way that normal operation of the rig is not // disturbed. This is intended to be use to poll rig state // periodically and changing VFO to read the other VFO frequency or // mode for example should not be done since the operator may be // tuning the VFO at the time and would be surprised by an unprompted // VFO change. // // Provides a control interface using Qt slots to start and stop the // rig control and PTT connections. // // These are Qt slots rather than the constructor and destructor // because it is expected that the concrete Transceiver // implementations will run in a separate thread from where they are // constructed. // // Qt signals are defined to notify clients of asynchronous rig state // changes and failures. These can and are expected to cross thread // boundaries. // // A signal finished() is defined that concrete Transceiver // implementations must emit when they are ripe for destruction. This // is intended to be used by clients that move the Transceiver // instance to a thread and need to use QObject::deleteLater() to // safely dispose of the Transceiver instance. Implementations should // expect Qt slot calls after emitting finished, it is up to the // implementation whether these slot invocations are ignored. // class Transceiver : public QObject { Q_OBJECT; Q_ENUMS (MODE); public: using Frequency = Radio::Frequency; protected: Transceiver () { } public: virtual ~Transceiver () { } enum MODE {UNK, CW, CW_R, USB, LSB, FSK, FSK_R, DIG_U, DIG_L, AM, FM, DIG_FM}; // // Aggregation of all of the rig and PTT state accessible via this // interface. class TransceiverState { public: TransceiverState () : online_ {false} , frequency_ {0, 0} , mode_ {UNK} , split_ {unknown} , ptt_ {false} { } bool online () const {return online_;} Frequency frequency () const {return frequency_[0];} Frequency tx_frequency () const {return frequency_[1];} bool split () const {return on == split_;} MODE mode () const {return mode_;} bool ptt () const {return ptt_;} void online (bool state) {online_ = state;} void frequency (Frequency f) {frequency_[0] = f;} void tx_frequency (Frequency f) {frequency_[1] = f;} void split (bool state) {split_ = state ? on : off;} void mode (MODE m) {mode_ = m;} void ptt (bool state) {ptt_ = state;} private: bool online_; Frequency frequency_[2]; // [0] -> Rx; [1] -> Other MODE mode_; enum {unknown, off, on} split_; bool ptt_; // Don't forget to update the debug print and != operator if you // add more members here friend QDebug operator << (QDebug, TransceiverState const&); friend bool operator != (TransceiverState const&, TransceiverState const&); }; // // The following slots and signals are expected to all run in the // same thread which is not necessarily the main GUI thread. It is // up to the client of the Transceiver class to organise the // allocation to a thread and the lifetime of the object instances. // // Connect and disconnect. Q_SLOT virtual void start () noexcept = 0; Q_SLOT virtual void stop () noexcept = 0; // Ready to be destroyed. Q_SIGNAL void finished () const; // Set frequency in Hertz. Q_SLOT virtual void frequency (Frequency) noexcept = 0; // Setting a non-zero TX frequency means split operation, the value // zero means simplex operation. // // Rationalise_mode means ensure TX uses same mode as RX. Q_SLOT virtual void tx_frequency (Frequency tx = 0, bool rationalise_mode = true) noexcept = 0; // Set mode. // Rationalise means ensure TX uses same mode as RX. Q_SLOT virtual void mode (MODE, bool rationalise = true) noexcept = 0; // Set/unset PTT. Q_SLOT virtual void ptt (bool = true) noexcept = 0; // Attempt to re-synchronise or query state. // Force_signal guarantees a update or failure signal. Q_SLOT virtual void sync (bool force_signal = false) noexcept = 0; // asynchronous status updates Q_SIGNAL void update (Transceiver::TransceiverState) const; Q_SIGNAL void failure (QString reason) const; }; Q_DECLARE_METATYPE (Transceiver::TransceiverState); Q_DECLARE_METATYPE (Transceiver::MODE); #if !defined (QT_NO_DEBUG_STREAM) ENUM_QDEBUG_OPS_DECL (Transceiver, MODE); QDebug operator << (QDebug, Transceiver::TransceiverState const&); #endif ENUM_QDATASTREAM_OPS_DECL (Transceiver, MODE); ENUM_CONVERSION_OPS_DECL (Transceiver, MODE); bool operator != (Transceiver::TransceiverState const&, Transceiver::TransceiverState const&); bool operator == (Transceiver::TransceiverState const&, Transceiver::TransceiverState const&); #endif