mirror of
https://github.com/jtdx-project/jtdx
synced 2026-08-13 17:35:38 -04:00
300 lines
9.9 KiB
C++
300 lines
9.9 KiB
C++
#include "PollingTransceiver.hpp"
|
|
|
|
#include <exception>
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include <QTimer>
|
|
#include <QDateTime>
|
|
#include <QThread>
|
|
#include <QDir>
|
|
#include <QStandardPaths>
|
|
#include "moc_PollingTransceiver.cpp"
|
|
|
|
namespace
|
|
{
|
|
unsigned const polls_to_stabilize {2};
|
|
}
|
|
|
|
PollingTransceiver::PollingTransceiver (int poll_interval, QObject * parent)
|
|
: TransceiverBase {parent}
|
|
, interval_ {(poll_interval & 0x7fff) * 1000}
|
|
, poll_timer_ {nullptr}
|
|
, ft4_mode_ {false}
|
|
, fast_mode_ {interval_ == 500}
|
|
, retries_ {0}
|
|
, debug_file_ {QDir(QStandardPaths::writableLocation (QStandardPaths::DataLocation)).absoluteFilePath ("jtdx_debug.txt").toStdString()}
|
|
, m_jtdxtime {nullptr}
|
|
{
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf (pFile,"Polling Tranceiver created interval %d\n",poll_interval & 0x7fff);
|
|
fclose (pFile);
|
|
#endif
|
|
}
|
|
|
|
void PollingTransceiver::start_timer ()
|
|
{
|
|
if (interval_)
|
|
{
|
|
if (!poll_timer_)
|
|
{
|
|
poll_timer_ = new QTimer {this}; // pass ownership to
|
|
// QObject which handles
|
|
// destruction for us
|
|
|
|
connect (poll_timer_, &QTimer::timeout, this,
|
|
&PollingTransceiver::handle_timeout);
|
|
}
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
if (m_jtdxtime == nullptr)
|
|
fprintf(pFile," Poll timer start interval=%d\n",interval_);
|
|
else
|
|
fprintf(pFile,"%s Poll timer start interval=%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),interval_);
|
|
#endif
|
|
poll_timer_->start (interval_);
|
|
#if JTDX_DEBUG_TO_FILE
|
|
if (m_jtdxtime == nullptr)
|
|
fprintf(pFile," Poll timer started\n");
|
|
else
|
|
fprintf(pFile,"%s Poll timer started\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str());
|
|
fclose (pFile);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
stop_timer ();
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::stop_timer ()
|
|
{
|
|
if (poll_timer_)
|
|
{
|
|
poll_timer_->stop ();
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::do_post_start (JTDXDateTime * jtdxtime)
|
|
{
|
|
m_jtdxtime = jtdxtime;
|
|
auto ms = m_jtdxtime->currentMSecsSinceEpoch2() % 1000;
|
|
int sec = m_jtdxtime->currentDateTimeUtc2().toString("ss").toInt() % 15;
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
if (m_jtdxtime == nullptr)
|
|
fprintf (pFile," Poll start ms %lld %d\n",ms,sec);
|
|
else
|
|
fprintf (pFile,"%s Poll start ms %lld %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),ms,sec);
|
|
fclose (pFile);
|
|
#endif
|
|
if (fast_mode_)
|
|
if (ms <= 500)
|
|
QThread::msleep (500-ms);
|
|
else
|
|
QThread::msleep (1000-ms);
|
|
else if (ft4_mode_ && (sec == 5 || sec == 6 || sec == 7 || sec == 8 || sec == 9 || sec == 10 || sec == 11))
|
|
QThread::msleep (1000-ms);
|
|
else
|
|
if (ms <= 500)
|
|
QThread::msleep (500-ms);
|
|
else
|
|
QThread::msleep (1500-ms);
|
|
|
|
start_timer ();
|
|
if (!next_state_.online ())
|
|
{
|
|
// remember that we are expecting to go online
|
|
next_state_.online (true);
|
|
retries_ = polls_to_stabilize;
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::do_post_stop ()
|
|
{
|
|
// not much point waiting for rig to go offline since we are ceasing
|
|
// polls
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
if (m_jtdxtime == nullptr)
|
|
fprintf (pFile," Poll stop\n");
|
|
else
|
|
fprintf (pFile,"%s Poll stop\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str());
|
|
fclose (pFile);
|
|
#endif
|
|
stop_timer ();
|
|
}
|
|
|
|
void PollingTransceiver::do_post_frequency (Frequency f, MODE m)
|
|
{
|
|
// take care not to set the expected next mode to unknown since some
|
|
// callers use mode == unknown to signify that they do not know the
|
|
// mode and don't care
|
|
if (next_state_.frequency () != f || (m != UNK && next_state_.mode () != m))
|
|
{
|
|
// update expected state with new frequency and set poll count
|
|
next_state_.frequency (f);
|
|
if (m != UNK)
|
|
{
|
|
next_state_.mode (m);
|
|
}
|
|
retries_ = polls_to_stabilize;
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::do_post_tx_frequency (Frequency f, MODE)
|
|
{
|
|
if (next_state_.tx_frequency () != f)
|
|
{
|
|
// update expected state with new TX frequency and set poll
|
|
// count
|
|
next_state_.tx_frequency (f);
|
|
next_state_.split (f); // setting non-zero TX frequency means split
|
|
retries_ = polls_to_stabilize;
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::do_post_mode (MODE m)
|
|
{
|
|
// we don't ever expect mode to goto to unknown
|
|
if (m != UNK && next_state_.mode () != m)
|
|
{
|
|
// update expected state with new mode and set poll count
|
|
next_state_.mode (m);
|
|
retries_ = polls_to_stabilize;
|
|
}
|
|
}
|
|
|
|
void PollingTransceiver::do_post_ft4_mode (bool p)
|
|
{
|
|
// printf("PollingTransceiver do_post_ft4_mode = %d\n",p);
|
|
// update polling style
|
|
next_state_.ft4_mode (p);
|
|
ft4_mode_ = p && (interval_ == 1000 || fast_mode_);
|
|
if (interval_ == 1000 && !fast_mode_ && m_jtdxtime != nullptr) do_post_start (m_jtdxtime);
|
|
}
|
|
|
|
void PollingTransceiver::do_post_ptt (bool p)
|
|
{
|
|
if (next_state_.ptt () != p)
|
|
{
|
|
// update expected state with new PTT and set poll count
|
|
next_state_.ptt (p);
|
|
retries_ = polls_to_stabilize;
|
|
retries_ = 1; // fast feedback on PTT
|
|
}
|
|
}
|
|
|
|
bool PollingTransceiver::do_pre_update ()
|
|
{
|
|
// if we are holding off a change then withhold the signal
|
|
if (retries_ && state () != next_state_)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PollingTransceiver::handle_timeout ()
|
|
{
|
|
QString message;
|
|
bool force_signal {false};
|
|
|
|
// we must catch all exceptions here since we are called by Qt and
|
|
// inform our parent of the failure via the offline() message
|
|
if (m_jtdxtime == nullptr) {
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf(pFile," Poll start retries=%d fast_mode=%d ft4_mode=%d\n",retries_,fast_mode_,ft4_mode_);
|
|
fclose (pFile);
|
|
#endif
|
|
offline ("Polling destroyed");
|
|
} else {
|
|
try
|
|
{
|
|
int sec = m_jtdxtime->currentDateTimeUtc2().toString("ss").toInt() % 15;
|
|
auto ms = m_jtdxtime->currentMSecsSinceEpoch2() % 1000;
|
|
#if JTDX_DEBUG_TO_FILE
|
|
FILE * pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf(pFile,"%s %d Poll start retries=%d fast_mode=%d ft4_mode=%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),sec,retries_,fast_mode_,ft4_mode_);
|
|
fclose (pFile);
|
|
#endif
|
|
if (!ft4_mode_ && !fast_mode_) {
|
|
if (ms < 125) {poll_timer_->stop (); QThread::msleep (500); poll_timer_->start (interval_);}
|
|
else if (ms < 250) {poll_timer_->stop (); QThread::msleep (500 - ms); poll_timer_->start (interval_);}
|
|
else if (ms > 875) {poll_timer_->stop (); QThread::msleep (500); poll_timer_->start (interval_);}
|
|
else if (ms > 750) {poll_timer_->stop (); QThread::msleep (1500 - ms); poll_timer_->start (interval_);}
|
|
} else if (!fast_mode_) {
|
|
if ((sec == 6 || sec == 7 || sec == 8 || sec == 9 || sec == 10 || sec == 11 || sec == 12) && ms > 250 && ms < 750) {
|
|
if (ms > 375 && ms < 625) {poll_timer_->stop (); QThread::msleep (500); poll_timer_->start (interval_);}
|
|
else {poll_timer_->stop (); QThread::msleep (1000 - ms); poll_timer_->start (interval_);}
|
|
} else if (sec == 13 || sec == 14 || sec == 0 || sec == 1 || sec == 2 || sec == 3 || sec == 14) {
|
|
if (ms < 125) {poll_timer_->stop (); QThread::msleep (500); poll_timer_->start (interval_);}
|
|
else if (ms < 250) {poll_timer_->stop (); QThread::msleep (500 - ms); poll_timer_->start (interval_);}
|
|
else if (ms > 875) {poll_timer_->stop (); QThread::msleep (500); poll_timer_->start (interval_);}
|
|
else if (ms > 750) {poll_timer_->stop (); QThread::msleep (1500 - ms); poll_timer_->start (interval_);}
|
|
}
|
|
}
|
|
do_poll (); // tell sub-classes to update our state
|
|
#if JTDX_DEBUG_TO_FILE
|
|
pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf(pFile,"%s %d Poll end ",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),sec);
|
|
fclose (pFile);
|
|
#endif
|
|
// Signal new state if it what we expected or, hasn't become
|
|
// what we expected after polls_to_stabilize polls. Unsolicited
|
|
// changes will be signalled immediately unless they intervene
|
|
// in a expected sequence where they will be delayed.
|
|
if (retries_)
|
|
{
|
|
--retries_;
|
|
if (state () == next_state_ || !retries_)
|
|
{
|
|
// the expected state has arrived or there are no more
|
|
// retries
|
|
force_signal = true;
|
|
}
|
|
}
|
|
else if (state () != last_signalled_state_)
|
|
{
|
|
// here is the normal passive polling path where state has
|
|
// changed asynchronously
|
|
force_signal = true;
|
|
}
|
|
|
|
if (force_signal)
|
|
{
|
|
// reset everything, record and signal the current state
|
|
retries_ = 0;
|
|
next_state_ = state ();
|
|
last_signalled_state_ = state ();
|
|
#if JTDX_DEBUG_TO_FILE
|
|
pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf(pFile,"%s signal\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str());
|
|
fclose (pFile);
|
|
#endif
|
|
update_complete (true);
|
|
}
|
|
else {
|
|
#if JTDX_DEBUG_TO_FILE
|
|
pFile = fopen (debug_file_.c_str(),"a");
|
|
fprintf(pFile,"%s no signal\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str());
|
|
fclose (pFile);
|
|
#endif
|
|
}
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
message = e.what ();
|
|
}
|
|
catch (...)
|
|
{
|
|
message = tr ("Unexpected rig error");
|
|
}
|
|
if (!message.isEmpty ())
|
|
{
|
|
offline (message);
|
|
}
|
|
}
|
|
}
|