174 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			174 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | #ifndef TRANSCEIVER_HPP__
 | ||
|  | #define TRANSCEIVER_HPP__
 | ||
|  | 
 | ||
|  | #include <QObject>
 | ||
|  | 
 | ||
|  | #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 a  Qt slot  to set  the frequency, mode  and PTT  of some
 | ||
|  | //  transceiver. This is a Qt slot so  that it 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 (QObject * parent) : QObject {parent} {} | ||
|  | 
 | ||
|  | public: | ||
|  |   virtual ~Transceiver () {} | ||
|  | 
 | ||
|  |   enum MODE {UNK, CW, CW_R, USB, LSB, FSK, FSK_R, DIG_U, DIG_L, AM, FM, DIG_FM}; | ||
|  |   Q_ENUM (MODE) | ||
|  | 
 | ||
|  |   //
 | ||
|  |   // Aggregation of all of the rig and PTT state accessible via this
 | ||
|  |   // interface.
 | ||
|  |   //
 | ||
|  |   class TransceiverState | ||
|  |   { | ||
|  |   public: | ||
|  |     TransceiverState () | ||
|  |       : online_ {false} | ||
|  |       , rx_frequency_ {0} | ||
|  |       , tx_frequency_ {0} | ||
|  |       , mode_ {UNK} | ||
|  |       , split_ {Split::unknown} | ||
|  |       , ptt_ {false} | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     bool online () const {return online_;} | ||
|  |     Frequency frequency () const {return rx_frequency_;} | ||
|  |     Frequency tx_frequency () const {return tx_frequency_;} | ||
|  |     bool split () const {return Split::on == split_;} | ||
|  |     MODE mode () const {return mode_;} | ||
|  |     bool ptt () const {return ptt_;} | ||
|  | 
 | ||
|  |     void online (bool state) {online_ = state;} | ||
|  |     void frequency (Frequency f) {rx_frequency_ = f;} | ||
|  |     void tx_frequency (Frequency f) {tx_frequency_ = f;} | ||
|  |     void split (bool state) {split_ = state ? Split::on : Split::off;} | ||
|  |     void mode (MODE m) {mode_ = m;} | ||
|  |     void ptt (bool state) {ptt_ = state;} | ||
|  | 
 | ||
|  |   private: | ||
|  |     bool online_; | ||
|  |     Frequency rx_frequency_; | ||
|  |     Frequency tx_frequency_;    // 0 means use Rx
 | ||
|  |     MODE mode_; | ||
|  |     enum class Split {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.
 | ||
|  |   //
 | ||
|  | 
 | ||
|  |   // Apply  state changes  to the  rig. The  sequence_number parameter
 | ||
|  |   // will  be included  in  any status  updates  generated after  this
 | ||
|  |   // transaction  is processed.  The sequence  number may  be used  to
 | ||
|  |   // ignore any status  updates until the results  of this transaction
 | ||
|  |   // have been processed thus avoiding any unwanted "ping-pong" due to
 | ||
|  |   // signals crossing in transit.
 | ||
|  |   Q_SLOT virtual void set (Transceiver::TransceiverState const&, | ||
|  |                            unsigned sequence_number) noexcept = 0; | ||
|  | 
 | ||
|  |   // Connect and disconnect.
 | ||
|  |   Q_SLOT virtual void start (unsigned sequence_number) noexcept = 0; | ||
|  |   Q_SLOT virtual void stop () noexcept = 0; | ||
|  | 
 | ||
|  |   //
 | ||
|  |   // asynchronous status updates
 | ||
|  |   //
 | ||
|  | 
 | ||
|  |   // 0 - 1Hz
 | ||
|  |   // 1 - 10Hz rounded
 | ||
|  |   // -1 - 10Hz truncated
 | ||
|  |   // 2 - 100Hz rounded
 | ||
|  |   // -2 - 100Hz truncated
 | ||
|  |   Q_SIGNAL void resolution (int); | ||
|  | 
 | ||
|  |   // rig state changed
 | ||
|  |   Q_SIGNAL void update (Transceiver::TransceiverState const&, | ||
|  |                         unsigned sequence_number) const; | ||
|  | 
 | ||
|  |   // something went wrong - not recoverable, start new instance
 | ||
|  |   Q_SIGNAL void failure (QString const& reason) const; | ||
|  | 
 | ||
|  |   // Ready to be destroyed.
 | ||
|  |   Q_SIGNAL void finished () const; | ||
|  | }; | ||
|  | 
 | ||
|  | Q_DECLARE_METATYPE (Transceiver::TransceiverState); | ||
|  | #if QT_VERSION < 0x050500
 | ||
|  | Q_DECLARE_METATYPE (Transceiver::MODE); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #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
 |