1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#ifndef TXLOOP_H
#define TXLOOP_H
#include <QDateTime>
#include <QTimer>
#include "TwoPhaseSignal.h"
#include "varicode.h"
/**
* Class to organize transmit loops, i.e., regular schedule of repeated
*transmissions. Intended use cases are either repeated CQ or HB transmissions.
*
* One object of this class organizes one such transmit loop.
*
* This class knows no other time than what DriftingDateTime tells it.
**/
class TxLoop : public TwoPhaseSignal {
Q_OBJECT
private:
// Name, only used for logging:
const QString m_name;
// When do we need to start transmitting the next time?
QDateTime m_next_activity;
// How much tx_delay, in milliseconds, we need to be early.
qint64 m_tx_delay_ms;
// A timer that is supposed to wake us up when it is time.
// This will be m_tx_delay_ms earlier than m_next_activity.
QTimer m_next_activity_timer;
// The currently active JS8 m_submode.
Varicode::SubmodeType m_submode;
// Whether this loop is active (or else does nothing).
bool m_active;
// The loop's period: After how many milliseconds to repeat sending.
qint64 m_loop_period_ms;
public:
// Provide a "name" argument that can be used for logging.
TxLoop(const QString &name);
~TxLoop();
// The TX delay cannot be set to any value larger than this:
static constexpr qint64 MAX_TX_DELAY_MS = 1000;
inline bool isActive() const { return m_active; }
/**
* Return the timestamp when the payload signal is supposed to start.
* This timestamp will always point to a full second.
* The actual triggering happens tx_delay earlier.
*
* The value this returns is undetermined (arbitrary) when called while
* isActive() returns false.
*/
inline const QDateTime &nextActivity() const { return m_next_activity; }
/**
* Return the present period of the loop, in milliseconds, if isActive()
* returns true.
*
* Not sure this is useful, but: If isActive() returns false,
* this will hand out the previous period used, or,
* if this loop object has never been active, some reasonable initial value.
*/
inline qint64 period_ms() const { return m_loop_period_ms; }
signals:
/** Tells whoever wants to know that now is the time to push the PTT for TX
* delay: */
void triggerTxNow() const;
/**
* Tells whoever wants to know that our future plans have changed. Only an
* active loop will emit this.
*
* This signal is emitted in conjunction with triggerTxNow and also each
* time our onTxLoopPeriodChangeStart receives a signal.
*
* The QDateTime sent is the same that will be returned by nextActivity().
*
* In addition, it gets fired when some other incoming onXXX signal caused
* our next activity to change.
*/
void nextActivityChanged(const QDateTime &) const;
/** Tells whoever wants to know that we have become inactive. */
void canceled() const;
public slots:
/** Asks us to emit initial signals, either nextActivityChanged or, more
* likely, canceled. */
void onPlumbingCompleted() const;
/** Tells us that the DriftingDateTime has a new drift value. We'll adjust
* accordingly. Idempotent. */
void onDriftChange(qint64 new_drift);
/** Tells us that the next transmission organized by this loop will be in
* this new submode. Idempotent. */
void onModeChange(Varicode::SubmodeType new_submode);
/**
* Tells us that the desired TX delay
* (switch TX on a bit before the full second that starts the mode period)
* has changed. Idempotent.
*/
void onTxDelayChange(qint64 tx_delay_ms);
/**
* This starts or restarts the loop.
* You need to provide the desired period.
*
* After this signal has come in, isActive() will return true
* and triggerTxNow will fire every loop_period_ms milliseconds.
* This continues until the onLoopCancel signal is received.
*
* Calling this on a loop that is active will cause the schedule
* to be reset; i.e., this restarts the loop.
*/
void onTxLoopPeriodChangeStart(qint64 loop_period_ms);
/**
* Cancel the loop. After this signal has come in, isActive() will return
* false and triggerTxNow will not fire any longer. Loop activity will
* restart when a onTxLoopPeriodChangeStart signal is again received.
*
* This is idempotent, it does no harm to call this on an idle loop.
*/
void onLoopCancel();
private slots:
void onTimer();
};
#endif
|