171 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			171 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | #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
 |