JS8Call-Improved master
Loading...
Searching...
No Matches
TransceiverBase.h
1#ifndef TRANSCEIVER_BASE_HPP__
2#define TRANSCEIVER_BASE_HPP__
3
4#include "Transceiver.h"
5
6#include <QLoggingCategory>
7#include <QString>
8
9#include <stdexcept>
10
11//
12// Base Transceiver Implementation
13//
14// Behaviour common to all Transceiver implementations.
15//
16// Collaborations
17//
18// Implements the Transceiver abstract interface as template methods
19// and provides a new abstract interface with similar functionality
20// (do_XXXXX operations). Provides and calls abstract interface that
21// gets called post the above operations (do_post_XXXXX) to allow
22// caching implementation etc.
23//
24// A key factor is to catch all exceptions thrown by sub-class
25// implementations where the template method is a Qt slot which is
26// therefore likely to be called by Qt which doesn't handle
27// exceptions. Any exceptions are converted to Transceiver::failure()
28// signals.
29//
30// Sub-classes update the stored state via a protected interface.
31//
32// Responsibilities:
33//
34// Wrap incoming Transceiver messages catching all exceptions in Qt
35// slot driven messages and converting them to Qt signals. This is
36// done because exceptions make concrete Transceiver implementations
37// simpler to write, but exceptions cannot cross signal/slot
38// boundaries (especially across threads). This also removes any
39// requirement for the client code to handle exceptions.
40//
41// Maintain the state of the concrete Transceiver instance that is
42// passed back via the Transceiver::update(TransceiverState) signal,
43// it is still the responsibility of concrete Transceiver
44// implementations to emit the state_change signal when they have a
45// status update.
46//
47// Maintain a go/no-go status for concrete Transceiver
48// implementations ensuring only a valid sequence of messages are
49// passed. A concrete Transceiver instance must be started before it
50// can receive messages, any exception thrown takes the Transceiver
51// offline.
52//
53// Implements methods that concrete Transceiver implementations use
54// to update the Transceiver state. These do not signal state change
55// to clients as this is the responsibility of the concrete
56// Transceiver implementation, thus allowing multiple state component
57// updates to be signalled together if required.
58//
59class TransceiverBase : public Transceiver {
60 Q_OBJECT;
61
62 protected:
63 TransceiverBase(QObject *parent)
64 : Transceiver{parent}, last_sequence_number_{0} {}
65
66 public:
67 //
68 // Implement the Transceiver abstract interface.
69 //
70 void start(unsigned sequence_number) noexcept override final;
71 void set(TransceiverState const &,
72 unsigned sequence_number) noexcept override final;
73 void stop() noexcept override final;
74
75 //
76 // Query operations
77 //
78 TransceiverState const &state() const { return actual_; }
79
80 protected:
81 //
82 // Error exception which is thrown to signal unexpected errors.
83 //
84 struct error : public std::runtime_error {
85 explicit error(char const *const msg) : std::runtime_error(msg) {}
86 explicit error(QString const &msg)
87 : std::runtime_error(msg.toStdString()) {}
88 };
89
90 // Template methods that sub classes implement to do what they need to do.
91 //
92 // These methods may throw exceptions to signal errors.
93 virtual int
94 do_start() = 0; // returns resolution, See Transceiver::resolution
95 virtual void do_post_start() {}
96
97 virtual void do_stop() = 0;
98 virtual void do_post_stop() {}
99
100 virtual void do_frequency(Frequency, MODE, bool no_ignore) = 0;
101 virtual void do_post_frequency(Frequency, MODE) {}
102
105 inline virtual void hamlib_bug_bandaid(TransceiverState const &) {};
106 virtual void do_tx_frequency(Frequency, MODE, bool no_ignore) = 0;
107 virtual void do_post_tx_frequency(Frequency, MODE) {}
108
109 virtual void do_mode(MODE) = 0;
110 virtual void do_post_mode(MODE) {}
111
112 virtual void do_ptt(bool = true) = 0;
113 virtual void do_post_ptt(bool = true) {}
114
115 virtual void do_sync(bool force_signal = false, bool no_poll = false) = 0;
116
117 virtual bool do_pre_update() { return true; }
118
119 // sub classes report rig state changes with these methods
120 void update_rx_frequency(Frequency);
121 void update_other_frequency(Frequency = 0);
122 void update_split(bool);
123 void update_mode(MODE);
124 void update_PTT(bool = true);
125
126 // Calling this eventually triggers the Transceiver::update(State) signal.
127 void update_complete(bool force_signal = false);
128
129 // sub class may asynchronously take the rig offline by calling this
130 void offline(QString const &reason);
131
132 private:
133 void startup();
134 void shutdown();
135 bool maybe_low_resolution(Frequency low_res, Frequency high_res);
136
137 // use this convenience class to notify in update methods
138 class may_update {
139 public:
140 explicit may_update(TransceiverBase *self, bool force_signal = false)
141 : self_{self}, force_signal_{force_signal} {}
142 ~may_update() { self_->update_complete(force_signal_); }
143
144 private:
145 TransceiverBase *self_;
146 bool force_signal_;
147 };
148
149 TransceiverState requested_;
150 TransceiverState actual_;
151 TransceiverState last_;
152 unsigned last_sequence_number_; // from set state operation
153};
154
155// some trace macros
156Q_DECLARE_LOGGING_CATEGORY(transceiverbase_js8)
157#define TRACE_CAT(FAC, MSG) \
158 qCDebug(transceiverbase_js8) \
159 << QString{"%1::%2:"}.arg((FAC)).arg(__func__) << MSG
160#define TRACE_CAT_POLL(FAC, MSG) \
161 qCDebug(transceiverbase_js8) \
162 << QString{"%1::%2:"}.arg((FAC)).arg(__func__) << MSG
163
164#endif
virtual void hamlib_bug_bandaid(TransceiverState const &)
Definition TransceiverBase.h:105
Definition Transceiver.h:83