Use the low confidence decode quality marker to elide spots and pass info via UDP

The UDP  decode and reply message  have been augmented with  a boolean
flag denoting a  low confidence decode when set.  Existing clients can
safely use the  reply message without passing the flag  as the default
value will  still action  messages that have  high confidence.  If low
confidence decodes  are to be passed  back via the reply  message then
the low  confidence flag must be  included and correctly set  to match
the original decode.

See NetworkMessage.hpp for message fields and meanings.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7957 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2017-07-26 21:18:59 +00:00
parent 8fe7d5c5de
commit ee2badb86f
14 changed files with 72 additions and 40 deletions

View File

@ -151,11 +151,13 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
quint32 delta_frequency;
QByteArray mode;
QByteArray message;
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
bool low_confidence {false};
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message >> low_confidence;
if (check_status (in) != Fail)
{
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence);
}
}
break;
@ -366,13 +368,14 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
}
void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message_text)
, QString const& mode, QString const& message_text, bool low_confidence)
{
if (m_->server_port_ && !m_->server_string_.isEmpty ())
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_, m_->schema_};
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
<< message_text.toUtf8 () << low_confidence;
m_->send_message (out, message);
}
}

View File

@ -53,7 +53,7 @@ public:
, QString const& dx_grid, bool watchdog_timeout, QString const& sub_mode
, bool fast_mode);
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
Q_SLOT void WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power);
Q_SLOT void clear_decodes ();
@ -70,7 +70,7 @@ public:
// this signal is emitted if the server sends us a reply, the only
// reply supported is reply to a prior CQ or QRZ message
Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message_text);
, QString const& message_text, bool low_confidence);
// this signal is emitted if the server has requested a replay of
// all decodes

View File

@ -241,11 +241,14 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
quint32 delta_frequency;
QByteArray mode;
QByteArray message;
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
bool low_confidence;
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode
>> message >> low_confidence;
if (check_status (in) != Fail)
{
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence);
}
}
break;
@ -396,14 +399,15 @@ void MessageServer::start (port_type port, QHostAddress const& multicast_group_a
}
}
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text)
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text, bool low_confidence)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_};
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
out << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
<< message_text.toUtf8 () << low_confidence;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}

View File

@ -46,7 +46,7 @@ public:
// note that the client is not obliged to take any action and only
// takes any action if the decode is present and is a CQ or QRZ message
Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
// ask the client with identification 'id' to replay all decodes
Q_SLOT void replay (QString const& id);
@ -69,7 +69,8 @@ public:
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode);
Q_SIGNAL void client_closed (QString const& id);
Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message);
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence);
Q_SIGNAL void WSPR_decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power);
Q_SIGNAL void qso_logged (QString const& id, QDateTime timeOff, QString const& dx_call, QString const& dx_grid

View File

@ -156,13 +156,19 @@
* Delta frequency (Hz) quint32
* Mode utf8
* Message utf8
* Low confidence bool
*
* The decode message is sent when a new decode is completed, in
* this case the 'New' field is true. It is also used in response
* to a "Replay" message where each old decode in the "Band
* activity" window, that has not been erased, is sent in order
* as a one of these messages with the 'New' field set to
* false. See the "Replay" message below for details of usage.
* as a one of these messages with the 'New' field set to false.
* See the "Replay" message below for details of usage. Low
* confidence decodes are flagged in protocols where the decoder
* has knows that a decode has a higher than normal probability
* of being false, they should not be reported on publicly
* accessible services without some attached warning or further
* validation.
*
*
* Clear Out 3 quint32
@ -184,6 +190,7 @@
* Delta frequency (Hz) quint32
* Mode utf8
* Message utf8
* Low confidence bool
*
* In order for a server to provide a useful cooperative service
* to WSJT-X it is possible for it to initiate a QSO by sending

View File

@ -244,7 +244,7 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
, QString const& /*message*/)
, QString const& /*message*/, bool /*low_confidence*/)
{
if (client_id == id_)
{

View File

@ -33,7 +33,7 @@ public:
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode);
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message);
, QString const& message, bool low_confidence);
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift
, QString const& callsign, QString const& grid, qint32 power);

View File

@ -17,13 +17,19 @@ namespace
QT_TRANSLATE_NOOP ("DecodesModel", "DF"),
QT_TRANSLATE_NOOP ("DecodesModel", "Md"),
QT_TRANSLATE_NOOP ("DecodesModel", "Message"),
QT_TRANSLATE_NOOP ("DecodesModel", "Confidence"),
};
QString confidence_string (bool low_confidence)
{
return low_confidence ? QT_TRANSLATE_NOOP ("DecodesModel", "low") : QT_TRANSLATE_NOOP ("DecodesModel", "high");
}
QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool is_fast)
, bool low_confidence, bool is_fast)
{
auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")};
time_item->setData (time);
@ -44,8 +50,11 @@ namespace
auto md = new QStandardItem {mode};
md->setTextAlignment (Qt::AlignHCenter);
auto confidence = new QStandardItem {confidence_string (low_confidence)};
confidence->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, new QStandardItem {message}};
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, new QStandardItem {message}, confidence};
Q_FOREACH (auto& item, row)
{
item->setEditable (false);
@ -57,7 +66,7 @@ namespace
}
DecodesModel::DecodesModel (QObject * parent)
: QStandardItemModel {0, 7, parent}
: QStandardItemModel {0, sizeof (headings) / sizeof (headings[0]), parent}
{
int column {0};
for (auto const& heading : headings)
@ -68,7 +77,7 @@ DecodesModel::DecodesModel (QObject * parent)
void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool is_fast)
, bool low_confidence, bool is_fast)
{
if (!is_new)
{
@ -83,7 +92,8 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
&& item (row, 3)->data ().toFloat () == delta_time
&& item (row, 4)->data ().toUInt () == delta_frequency
&& data (index (row, 5)).toString () == mode
&& data (index (row, 6)).toString () == message)
&& data (index (row, 6)).toString () == message
&& data (index (row, 7)).toString () == confidence_string (low_confidence))
{
return;
}
@ -96,12 +106,12 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
if (target_row >= 0)
{
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, delta_frequency, mode
, message, is_fast));
, message, low_confidence, is_fast));
return;
}
}
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, is_fast));
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, low_confidence, is_fast));
}
void DecodesModel::clear_decodes (QString const& client_id)
@ -124,7 +134,8 @@ void DecodesModel::do_reply (QModelIndex const& source)
, item (row, 3)->data ().toFloat ()
, item (row, 4)->data ().toInt ()
, data (index (row, 5)).toString ()
, data (index (row, 6)).toString ());
, data (index (row, 6)).toString ()
, confidence_string (true) == data (index (row, 7)).toString ());
}
#include "moc_DecodesModel.cpp"

View File

@ -32,12 +32,13 @@ public:
explicit DecodesModel (QObject * parent = nullptr);
Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message, bool is_fast);
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool is_fast);
Q_SLOT void clear_decodes (QString const& client_id);
Q_SLOT void do_reply (QModelIndex const& source);
Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
};
#endif

View File

@ -91,9 +91,9 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time
, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode
, QString const& message) {
, QString const& message, bool low_confidence) {
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message
, dock_widgets_[id]->fast_mode ());});
, low_confidence, dock_widgets_[id]->fast_mode ());});
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
connect (server_, &MessageServer::clear_decodes, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes);

View File

@ -69,13 +69,13 @@ public:
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime time, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message)
, QString const& message, bool low_confidence)
{
if (client_id == id_)
{
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency
<< "mode:" << mode;
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high");
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl;
}
}

View File

@ -56,6 +56,11 @@ bool DecodedText::isTX()
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
}
bool DecodedText::isLowConfidence ()
{
return QChar {'?'} == _string.mid (padding_ + column_qsoText + 21, 1);
}
int DecodedText::frequencyOffset()
{
return _string.mid(column_freq + padding_,4).toInt();

View File

@ -57,6 +57,7 @@ public:
bool isJT65();
bool isJT9();
bool isTX();
bool isLowConfidence ();
int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency
int snr();
float dt();

View File

@ -1440,7 +1440,7 @@ void MainWindow::fastSink(qint64 frames)
bool stdMsg = decodedtext.report(m_baseCall,
Radio::base_callsign(ui->dxCallEntry->text()),m_rptRcvd);
decodedtext=message.mid(0,4) + message.mid(6,-1);
if(m_config.spot_to_psk_reporter() and stdMsg and !m_diskData) pskPost(decodedtext);
if (stdMsg) pskPost (decodedtext);
}
float fracTR=float(k)/(12000.0*m_TRperiod);
@ -2593,9 +2593,7 @@ void::MainWindow::fast_decode_done()
Radio::base_callsign(ui->dxCallEntry->text()), m_rptRcvd);
// extract details and send to PSKreporter
if(m_config.spot_to_psk_reporter() and stdMsg and !m_diskData) {
pskPost(decodedtext);
}
if (stdMsg) pskPost(decodedtext);
}
}
m_startAnother=m_loopall;
@ -2774,9 +2772,7 @@ void MainWindow::readFromStdout() //readFromStdout
// extract details and send to PSKreporter
int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged;
bool okToPost=(nsec>(4*m_TRperiod)/5);
if(m_config.spot_to_psk_reporter () and stdMsg and !m_diskData and okToPost) {
pskPost(decodedtext);
}
if (stdMsg && okToPost) pskPost(decodedtext);
if((m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") and m_msgAvgWidget!=NULL) {
if(m_msgAvgWidget->isVisible()) {
@ -2832,6 +2828,8 @@ void MainWindow::auto_sequence (QString const& message, unsigned tolerance)
void MainWindow::pskPost (DecodedText decodedtext)
{
if (m_diskData || !m_config.spot_to_psk_reporter() || decodedtext.isLowConfidence ()) return;
QString msgmode=m_mode;
if(m_mode=="JT9+JT65") {
msgmode="JT9";
@ -6157,14 +6155,15 @@ void MainWindow::postDecode (bool is_new, QString const& message)
{
auto const& decode = message.trimmed ();
auto const& parts = decode.left (22).split (' ', QString::SkipEmptyParts);
if (parts.size () >= 5)
if (!m_diskData && parts.size () >= 5)
{
auto has_seconds = parts[0].size () > 4;
m_messageClient->decode (is_new
, QTime::fromString (parts[0], has_seconds ? "hhmmss" : "hhmm")
, parts[1].toInt ()
, parts[2].toFloat (), parts[3].toUInt (), parts[4][0]
, decode.mid (has_seconds ? 24 : 22));
, decode.mid (has_seconds ? 24 : 22, 21)
, QChar {'?'} == decode.mid (has_seconds ? 24 + 21 : 22 + 21, 1));
}
}