171 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			171 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | #ifndef TRANSCEIVER_BASE_HPP__ | ||
|  | #define TRANSCEIVER_BASE_HPP__ | ||
|  | 
 | ||
|  | #include <stdexcept> | ||
|  | 
 | ||
|  | #include <QString> | ||
|  | 
 | ||
|  | #include "Transceiver.hpp" | ||
|  | 
 | ||
|  | // | ||
|  | // Base Transceiver Implementation | ||
|  | // | ||
|  | //  Behaviour common to all Transceiver implementations. | ||
|  | // | ||
|  | // Collaborations | ||
|  | // | ||
|  | //  Implements the Transceiver abstract  interface as template methods | ||
|  | //  and provides  a new abstract interface  with similar functionality | ||
|  | //  (do_XXXXX operations). Provides and  calls abstract interface that | ||
|  | //  gets  called post  the above  operations (do_post_XXXXX)  to allow | ||
|  | //  caching implementation etc. | ||
|  | // | ||
|  | //  A  key factor  is  to  catch all  exceptions  thrown by  sub-class | ||
|  | //  implementations where  the template method  is a Qt slot  which is | ||
|  | //  therefore  likely  to  be  called   by  Qt  which  doesn't  handle | ||
|  | //  exceptions. Any exceptions are converted to Transceiver::failure() | ||
|  | //  signals. | ||
|  | // | ||
|  | //  Sub-classes update the stored state via a protected interface. | ||
|  | // | ||
|  | // Responsibilities: | ||
|  | // | ||
|  | //  Wrap incoming  Transceiver messages catching all  exceptions in Qt | ||
|  | //  slot driven  messages and converting  them to Qt signals.  This is | ||
|  | //  done because exceptions  make concrete Transceiver implementations | ||
|  | //  simpler  to   write,  but  exceptions  cannot   cross  signal/slot | ||
|  | //  boundaries  (especially across  threads).  This  also removes  any | ||
|  | //  requirement for the client code to handle exceptions. | ||
|  | // | ||
|  | //  Maintain the  state of the  concrete Transceiver instance  that is | ||
|  | //  passed back via  the Transceiver::update(TransceiverState) signal, | ||
|  | //  it   is  still   the   responsibility   of  concrete   Transceiver | ||
|  | //  implementations to emit  the state_change signal when  they have a | ||
|  | //  status update. | ||
|  | // | ||
|  | //  Maintain    a   go/no-go    status   for    concrete   Transceiver | ||
|  | //  implementations  ensuring only  a valid  sequence of  messages are | ||
|  | //  passed. A concrete Transceiver instance  must be started before it | ||
|  | //  can receive  messages, any exception thrown  takes the Transceiver | ||
|  | //  offline. | ||
|  | // | ||
|  | //  Implements methods  that concrete Transceiver  implementations use | ||
|  | //  to update the Transceiver state.  These do not signal state change | ||
|  | //  to  clients  as  this  is   the  responsibility  of  the  concrete | ||
|  | //  Transceiver implementation, thus allowing multiple state component | ||
|  | //  updates to be signalled together if required. | ||
|  | // | ||
|  | class TransceiverBase | ||
|  |   : public Transceiver | ||
|  | { | ||
|  |   Q_OBJECT; | ||
|  | 
 | ||
|  | protected: | ||
|  |   TransceiverBase (QObject * parent) | ||
|  |     : Transceiver {parent} | ||
|  |     , last_sequence_number_ {0} | ||
|  |   {} | ||
|  | 
 | ||
|  | public: | ||
|  |   // | ||
|  |   // Implement the Transceiver abstract interface. | ||
|  |   // | ||
|  |   void start (unsigned sequence_number) noexcept override final; | ||
|  |   void set (TransceiverState const&, | ||
|  |             unsigned sequence_number) noexcept override final; | ||
|  |   void stop () noexcept override final; | ||
|  | 
 | ||
|  |   // | ||
|  |   // Query operations | ||
|  |   // | ||
|  |   TransceiverState const& state () const {return actual_;} | ||
|  | 
 | ||
|  | protected: | ||
|  |   // | ||
|  |   // Error exception which is thrown to signal unexpected errors. | ||
|  |   // | ||
|  |   struct error | ||
|  |     : public std::runtime_error | ||
|  |   { | ||
|  |     explicit error (char const * const msg) : std::runtime_error (msg) {} | ||
|  |     explicit error (QString const& msg) : std::runtime_error (msg.toStdString ()) {} | ||
|  |   }; | ||
|  | 
 | ||
|  |   // Template methods that sub classes implement to do what they need to do. | ||
|  |   // | ||
|  |   // These methods may throw exceptions to signal errors. | ||
|  |   virtual int do_start () = 0;  // returns resolution, See Transceiver::resolution | ||
|  |   virtual void do_post_start () {} | ||
|  | 
 | ||
|  |   virtual void do_stop () = 0; | ||
|  |   virtual void do_post_stop () {} | ||
|  | 
 | ||
|  |   virtual void do_frequency (Frequency, MODE, bool no_ignore) = 0; | ||
|  |   virtual void do_post_frequency (Frequency, MODE) {} | ||
|  | 
 | ||
|  |   virtual void do_tx_frequency (Frequency, MODE, bool no_ignore) = 0; | ||
|  |   virtual void do_post_tx_frequency (Frequency, MODE) {} | ||
|  | 
 | ||
|  |   virtual void do_mode (MODE) = 0; | ||
|  |   virtual void do_post_mode (MODE) {} | ||
|  | 
 | ||
|  |   virtual void do_ptt (bool = true) = 0; | ||
|  |   virtual void do_post_ptt (bool = true) {} | ||
|  | 
 | ||
|  |   virtual void do_sync (bool force_signal = false, bool no_poll = false) = 0; | ||
|  | 
 | ||
|  |   virtual bool do_pre_update () {return true;} | ||
|  | 
 | ||
|  |   // sub classes report rig state changes with these methods | ||
|  |   void update_rx_frequency (Frequency); | ||
|  |   void update_other_frequency (Frequency = 0); | ||
|  |   void update_split (bool); | ||
|  |   void update_mode (MODE); | ||
|  |   void update_PTT (bool = true); | ||
|  | 
 | ||
|  |   // Calling this eventually triggers the Transceiver::update(State) signal. | ||
|  |   void update_complete (bool force_signal = false); | ||
|  | 
 | ||
|  |   // sub class may asynchronously take the rig offline by calling this | ||
|  |   void offline (QString const& reason); | ||
|  | 
 | ||
|  | private: | ||
|  |   void startup (); | ||
|  |   void shutdown (); | ||
|  |   bool maybe_low_resolution (Frequency low_res, Frequency high_res); | ||
|  | 
 | ||
|  |   // use this convenience class to notify in update methods | ||
|  |   class may_update | ||
|  |   { | ||
|  |   public: | ||
|  |     explicit may_update (TransceiverBase * self, bool force_signal = false) | ||
|  |       : self_ {self} | ||
|  |       , force_signal_ {force_signal} | ||
|  |     {} | ||
|  |     ~may_update () {self_->update_complete (force_signal_);} | ||
|  |   private: | ||
|  |     TransceiverBase * self_; | ||
|  |     bool force_signal_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   TransceiverState requested_; | ||
|  |   TransceiverState actual_; | ||
|  |   TransceiverState last_; | ||
|  |   unsigned last_sequence_number_;    // from set state operation | ||
|  | }; | ||
|  | 
 | ||
|  | // some trace macros | ||
|  | #if WSJT_TRACE_CAT | ||
|  | #define TRACE_CAT(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG | ||
|  | #else | ||
|  | #define TRACE_CAT(FAC, MSG) | ||
|  | #endif | ||
|  | 
 | ||
|  | #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS | ||
|  | #define TRACE_CAT_POLL(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG | ||
|  | #else | ||
|  | #define TRACE_CAT_POLL(FAC, MSG) | ||
|  | #endif | ||
|  | 
 | ||
|  | #endif |