SVN r8748

This commit is contained in:
Jordan Sherer
2018-06-14 21:27:34 -04:00
parent 419c039d08
commit 4f1fe4fc94
581 changed files with 69338 additions and 39836 deletions
@@ -1,100 +0,0 @@
<HTML><HEAD>
<TITLE> Support Programs </TITLE>
</HEAD><BODY>
<H1> Support Programs </H1>
The following programs provide support for testing and performance
assessment.
<P><A NAME="rand-src"><HR><B>rand-src</B>: Generate random message bits.
<BLOCKQUOTE><PRE>
rand-src <I>source-file seed n-bits</I>
</PRE></BLOCKQUOTE>
<P>Creates a file of random messages bits called
<TT><I>source-file</I></TT>, which is suitable for testing the
correctness and performance of other programs. The bits in the file
are independent, and are equally likely to be 0 or 1. They are
generated pseudo-randomly based on <TT><I>seed</I></TT>. The actual
random number seed used will be <TT><I>seed</I></TT> times 10 plus 2,
so that the stream of pseudo-random numbers will not be the same as
any that might have been used by another program.
<P>The <TT><I>n-bits</I></TT> argument specifies the number of bits to
produce. It can be a single number, or it can consist of a block size
and a number of blocks, written with <TT>x</TT> separating these
numbers, with no spaces. Each block is written as a single line, with
the bits in the block represented by the characters '0' and '1', with
no intervening spaces. If the bit count is given by a single number,
the block size is assumed to be one.
<P><B>Example:</B> The following command produces a file containing
3 blocks, each consisting of 15 random bits, produced using the pseudo-random
number stream identified by the <TT><I>seed</I></TT> of 17:
<UL><PRE>
<LI>rand-src rsrc 17 15x3
</PRE></UL>
The contents of the file <TT>rsrc</TT> after this command might be something
like the following:
<BLOCKQUOTE><PRE>
111011000110000
010010110010111
100000000000111
</BLOCKQUOTE></PRE>
<P><A NAME="verify"><HR><B>verify</B>: Verify that decoded blocks are
codewords, and that they match the source.
<BLOCKQUOTE><PRE>
verify [ -t ] <I>pchk-file decoded-file</I> [ <I>gen-file</I> [ <I>source-file</I> ] ]
</PRE></BLOCKQUOTE>
<P>Checks whether or not the blocks in <TT><I>decoded-file</I></TT>
are codewords, according to the parity check matrix in
<TT><I>pchk-file</I></TT>. If <TT><I>gen-file</I></TT> is specified,
the message bits of the blocks are also checked against the
corresponding blocks of <TT><I>source-file</I></TT>, or against zero
if <TT><I>source-file</I></TT> is not given. (Normally, one would
leave out <TT><I>source-file</I></TT> only if the <A
HREF="channel.html#transmit"><TT>transmit</TT></A> command was used
with an argument specifying that zeros are to be transmitted, rather
than a file of encoded data.)
<P>A summary of the results is displayed on standard error, giving the
total numbers of blocks, the number with parity check errors, and, if
<TT><I>gen-file</I></TT> was specified, the number of blocks with
source errors and the number with errors of both kinds. If
<TT><I>gen-file</I></TT> was specified, a second
summary line displays the bit error rate from
comparing the decoded message bits with the true message bits (zeros
if no <TT><I>source file</I></TT> was given).
<P>If the <B>-t</B> option is given, block-by-block results are
printed on standard output in two or three columns, giving the block
number (from zero), the number of parity check errors for that block,
and the number of errors in source bits. The last column is omitted
if <TT><I>gen-file</I></TT> is not specified. The columns are
preceded by a line of headers, so the file is suitable for reading
into the S-Plus or R statistics packages, with a command such as
<BLOCKQUOTE><PRE>
data <- read.table(<I>file</I>,header=T)
</PRE></BLOCKQUOTE>
<P>Warning messages are displayed on standard error if the number of
bits in <TT><I>decoded-file</I></TT> is not a multiple of the block
length, or if <TT><I>source-file</I></TT> is too short. Newlines
in these files are ignored, even though they would normally occur
at the ends of blocks.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -0,0 +1,495 @@
#include "MessageServer.hpp"
#include <stdexcept>
#include <QUdpSocket>
#include <QString>
#include <QTimer>
#include <QHash>
#include "Radio.hpp"
#include "NetworkMessage.hpp"
#include "qt_helpers.hpp"
#include "pimpl_impl.hpp"
#include "moc_MessageServer.cpp"
class MessageServer::impl
: public QUdpSocket
{
Q_OBJECT;
public:
impl (MessageServer * self, QString const& version, QString const& revision)
: self_ {self}
, version_ {version}
, revision_ {revision}
, port_ {0u}
, clock_ {new QTimer {this}}
{
// register the required types with Qt
Radio::register_types ();
connect (this, &QIODevice::readyRead, this, &MessageServer::impl::pending_datagrams);
connect (this, static_cast<void (impl::*) (SocketError)> (&impl::error)
, [this] (SocketError /* e */)
{
Q_EMIT self_->error (errorString ());
});
connect (clock_, &QTimer::timeout, this, &impl::tick);
clock_->start (NetworkMessage::pulse * 1000);
}
enum StreamStatus {Fail, Short, OK};
void leave_multicast_group ();
void join_multicast_group ();
void parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg);
void tick ();
void pending_datagrams ();
StreamStatus check_status (QDataStream const&) const;
void send_message (QDataStream const& out, QByteArray const& message, QHostAddress const& address, port_type port)
{
if (OK == check_status (out))
{
writeDatagram (message, address, port);
}
else
{
Q_EMIT self_->error ("Error creating UDP message");
}
}
MessageServer * self_;
QString version_;
QString revision_;
port_type port_;
QHostAddress multicast_group_address_;
static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint;
struct Client
{
Client () = default;
Client (QHostAddress const& sender_address, port_type const& sender_port)
: sender_address_ {sender_address}
, sender_port_ {sender_port}
, negotiated_schema_number_ {2} // not 1 because it's broken
, last_activity_ {QDateTime::currentDateTime ()}
{
}
Client (Client const&) = default;
Client& operator= (Client const&) = default;
QHostAddress sender_address_;
port_type sender_port_;
quint32 negotiated_schema_number_;
QDateTime last_activity_;
};
QHash<QString, Client> clients_; // maps id to Client
QTimer * clock_;
};
MessageServer::impl::BindMode constexpr MessageServer::impl::bind_mode_;
#include "MessageServer.moc"
void MessageServer::impl::leave_multicast_group ()
{
if (!multicast_group_address_.isNull () && BoundState == state ())
{
leaveMulticastGroup (multicast_group_address_);
}
}
void MessageServer::impl::join_multicast_group ()
{
if (BoundState == state ()
&& !multicast_group_address_.isNull ())
{
if (IPv4Protocol == multicast_group_address_.protocol ()
&& IPv4Protocol != localAddress ().protocol ())
{
close ();
bind (QHostAddress::AnyIPv4, port_, bind_mode_);
}
if (!joinMulticastGroup (multicast_group_address_))
{
multicast_group_address_.clear ();
}
}
}
void MessageServer::impl::pending_datagrams ()
{
while (hasPendingDatagrams ())
{
QByteArray datagram;
datagram.resize (pendingDatagramSize ());
QHostAddress sender_address;
port_type sender_port;
if (0 <= readDatagram (datagram.data (), datagram.size (), &sender_address, &sender_port))
{
parse_message (sender_address, sender_port, datagram);
}
}
}
void MessageServer::impl::parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg)
{
try
{
//
// message format is described in NetworkMessage.hpp
//
NetworkMessage::Reader in {msg};
auto id = in.id ();
if (OK == check_status (in))
{
if (!clients_.contains (id))
{
auto& client = (clients_[id] = {sender, sender_port});
QByteArray client_version;
QByteArray client_revision;
if (NetworkMessage::Heartbeat == in.type ())
{
// negotiate a working schema number
in >> client.negotiated_schema_number_;
if (OK == check_status (in))
{
auto sn = NetworkMessage::Builder::schema_number;
client.negotiated_schema_number_ = std::min (sn, client.negotiated_schema_number_);
// reply to the new client informing it of the
// negotiated schema number
QByteArray message;
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id, client.negotiated_schema_number_};
hb << NetworkMessage::Builder::schema_number // maximum schema number accepted
<< version_.toUtf8 () << revision_.toUtf8 ();
if (impl::OK == check_status (hb))
{
writeDatagram (message, client.sender_address_, client.sender_port_);
}
else
{
Q_EMIT self_->error ("Error creating UDP message");
}
}
// we don't care if this fails to read
in >> client_version >> client_revision;
}
Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version),
QString::fromUtf8 (client_revision));
}
clients_[id].last_activity_ = QDateTime::currentDateTime ();
//
// message format is described in NetworkMessage.hpp
//
switch (in.type ())
{
case NetworkMessage::Heartbeat:
//nothing to do here as time out handling deals with lifetime
break;
case NetworkMessage::Clear:
Q_EMIT self_->clear_decodes (id);
break;
case NetworkMessage::Status:
{
// unpack message
Frequency f;
QByteArray mode;
QByteArray dx_call;
QByteArray report;
QByteArray tx_mode;
bool tx_enabled {false};
bool transmitting {false};
bool decoding {false};
qint32 rx_df {-1};
qint32 tx_df {-1};
QByteArray de_call;
QByteArray de_grid;
QByteArray dx_grid;
bool watchdog_timeout {false};
QByteArray sub_mode;
bool fast_mode {false};
in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting >> decoding
>> rx_df >> tx_df >> de_call >> de_grid >> dx_grid >> watchdog_timeout >> sub_mode
>> fast_mode;
if (check_status (in) != Fail)
{
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
, tx_enabled, transmitting, decoding, rx_df, tx_df
, QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid)
, QString::fromUtf8 (dx_grid), watchdog_timeout
, QString::fromUtf8 (sub_mode), fast_mode);
}
}
break;
case NetworkMessage::Decode:
{
// unpack message
bool is_new {true};
QTime time;
qint32 snr;
float delta_time;
quint32 delta_frequency;
QByteArray mode;
QByteArray message;
bool low_confidence {false};
bool off_air {false};
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode
>> message >> low_confidence >> off_air;
if (check_status (in) != Fail)
{
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence, off_air);
}
}
break;
case NetworkMessage::WSPRDecode:
{
// unpack message
bool is_new {true};
QTime time;
qint32 snr;
float delta_time;
Frequency frequency;
qint32 drift;
QByteArray callsign;
QByteArray grid;
qint32 power;
bool off_air {false};
in >> is_new >> time >> snr >> delta_time >> frequency >> drift >> callsign >> grid >> power
>> off_air;
if (check_status (in) != Fail)
{
Q_EMIT self_->WSPR_decode (is_new, id, time, snr, delta_time, frequency, drift
, QString::fromUtf8 (callsign), QString::fromUtf8 (grid)
, power, off_air);
}
}
break;
case NetworkMessage::QSOLogged:
{
QDateTime time_off;
QByteArray dx_call;
QByteArray dx_grid;
Frequency dial_frequency;
QByteArray mode;
QByteArray report_sent;
QByteArray report_received;
QByteArray tx_power;
QByteArray comments;
QByteArray name;
QDateTime time_on; // Note: LOTW uses TIME_ON for their +/- 30-minute time window
QByteArray operator_call;
QByteArray my_call;
QByteArray my_grid;
in >> time_off >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received
>> tx_power >> comments >> name >> time_on >> operator_call >> my_call >> my_grid;
if (check_status (in) != Fail)
{
Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
, QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power)
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on
, QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call)
, QString::fromUtf8 (my_grid));
}
}
break;
case NetworkMessage::Close:
Q_EMIT self_->client_closed (id);
clients_.remove (id);
break;
case NetworkMessage::LoggedADIF:
{
QByteArray ADIF;
in >> ADIF;
if (check_status (in) != Fail)
{
Q_EMIT self_->logged_ADIF (id, ADIF);
}
}
break;
default:
// Ignore
break;
}
}
else
{
Q_EMIT self_->error ("MessageServer warning: invalid UDP message received");
}
}
catch (std::exception const& e)
{
Q_EMIT self_->error (QString {"MessageServer exception: %1"}.arg (e.what ()));
}
catch (...)
{
Q_EMIT self_->error ("Unexpected exception in MessageServer");
}
}
void MessageServer::impl::tick ()
{
auto now = QDateTime::currentDateTime ();
auto iter = std::begin (clients_);
while (iter != std::end (clients_))
{
if (now > (*iter).last_activity_.addSecs (NetworkMessage::pulse))
{
Q_EMIT self_->clear_decodes (iter.key ());
Q_EMIT self_->client_closed (iter.key ());
iter = clients_.erase (iter); // safe while iterating as doesn't rehash
}
else
{
++iter;
}
}
}
auto MessageServer::impl::check_status (QDataStream const& stream) const -> StreamStatus
{
auto stat = stream.status ();
StreamStatus result {Fail};
switch (stat)
{
case QDataStream::ReadPastEnd:
result = Short;
break;
case QDataStream::ReadCorruptData:
Q_EMIT self_->error ("Message serialization error: read corrupt data");
break;
case QDataStream::WriteFailed:
Q_EMIT self_->error ("Message serialization error: write error");
break;
default:
result = OK;
break;
}
return result;
}
MessageServer::MessageServer (QObject * parent, QString const& version, QString const& revision)
: QObject {parent}
, m_ {this, version, revision}
{
}
void MessageServer::start (port_type port, QHostAddress const& multicast_group_address)
{
if (port != m_->port_
|| multicast_group_address != m_->multicast_group_address_)
{
m_->leave_multicast_group ();
if (impl::BoundState == m_->state ())
{
m_->close ();
}
m_->multicast_group_address_ = multicast_group_address;
auto address = m_->multicast_group_address_.isNull ()
|| impl::IPv4Protocol != m_->multicast_group_address_.protocol () ? QHostAddress::Any : QHostAddress::AnyIPv4;
if (port && m_->bind (address, port, m_->bind_mode_))
{
m_->port_ = port;
m_->join_multicast_group ();
}
else
{
m_->port_ = 0;
}
}
}
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, quint8 modifiers)
{
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 () << low_confidence << modifiers;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::replay (QString const& id)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Replay, id, (*iter).negotiated_schema_number_};
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::halt_tx (QString const& id, bool auto_only)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id, (*iter).negotiated_schema_number_};
out << auto_only;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::free_text (QString const& id, QString const& text, bool send)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id, (*iter).negotiated_schema_number_};
out << text.toUtf8 () << send;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::location (QString const& id, QString const& loc)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_};
out << loc.toUtf8 ();
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::highlight_callsign (QString const& id, QString const& callsign
, QColor const& bg, QColor const& fg, bool last_only)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_};
out << callsign.toUtf8 () << bg << fg << last_only;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
@@ -0,0 +1,154 @@
integer, parameter:: N=204, K=68, M=N-K
character*17 g(136)
integer colorder(N)
data g/ & !parity generator matrix for (204,68) code
"2de7435fd27c0031d", &
"f331b40671e20ea80", &
"48bd3f8cb9a24392f", &
"d4ed71c935162aa2a", &
"c437a3284ec58bce7", &
"35a806dd5be35627c", &
"396e797c33a4739a6", &
"768f331a59c15487b", &
"c214eac24ae5e1732", &
"0b5c53ff3a6da1192", &
"99624981d2703fb97", &
"e9f5447ef7f1ff6af", &
"bd8c730f0cfdf0727", &
"26f61e63e1e098f7f", &
"ef826566137b6526f", &
"af0e4fa251e9b4926", &
"75974a8b2a24292c5", &
"71caf0f2cd10f6d4f", &
"b1103f1f26e6898b7", &
"67ceb7d6f490da64f", &
"ee0e8fbefec23008a", &
"11cc2227e8bd676ca", &
"6e71626ba1e278046", &
"005d28da267e50e13", &
"a9ae4a130aaba8219", &
"d8ab72e0158d0da70", &
"56009d42b37bd66ff", &
"c39a75eca99b0e996", &
"6886de0bf7c0bf4bb", &
"1046cd8f64162f7b5", &
"da0f15843ac21e3a5", &
"e9bf9cd19f3db3913", &
"2fb9cb42d650f47a7", &
"a2b6c5a378fa75a65", &
"41a88f3cd60b79d6c", &
"fcf175794cc3ac96a", &
"8677a3447d40a9f71", &
"97a1f08c250b4bf12", &
"0168f090a1df6e8ea", &
"418a06bf372cc67d9", &
"0f17b880c1ff51239", &
"b2afd6d585deb961b", &
"60298ac5b58dbeee0", &
"8350c03c40119feff", &
"b29c964a8accf6af4", &
"9b46f036a5c178b5d", &
"917398bff051c300a", &
"5e52c03b2f8c5128c", &
"beae6c33c87ba38ab", &
"20843f7b056a02ebf", &
"66690d65acd9de598", &
"8f025841af5b54331", &
"b43cd869d3be2c3db", &
"c9c342fe63c18df50", &
"d331b40671e28ea80", &
"62406a0f4947e6ce9", &
"d67b1495883b22e1b", &
"734534c372408895b", &
"d88750e33d9677dcd", &
"6f96964da55138687", &
"80bee98bb75d50ef2", &
"c428ef3e3f06f4c56", &
"b1a1499b125883a35", &
"ac892d4b37fa9e395", &
"458dbda0f95ab11a5", &
"6f93c9e95b1094eed", &
"2e370d713914f848e", &
"758806dd5be35627c", &
"8c52e01caec798b49", &
"c286cc25bae3669cf", &
"87c56fb895c100884", &
"e89cb1376a18fd911", &
"156ffe5f30dc354e0", &
"f20d0b121d6a6b3ee", &
"7db08891b491a95d2", &
"191fac548d5077bdf", &
"023a37d7ea5660bbc", &
"6781668b363fee682", &
"bbfaf262cab7370da", &
"feea557965b7e474f", &
"c094eb223e1d305b8", &
"2be051abdd5beea35", &
"0790449880fda9d00", &
"f9029a39ec869e7b4", &
"5a29f48926ec9a552", &
"e0463306dc1470f87", &
"9251058334d790f86", &
"3019e1d4578e8a4dc", &
"887e46631502fa111", &
"c25fcd7a42465d326", &
"cf64bcc1056b555c4", &
"3e71c0fe5f0ad733b", &
"11055ec43b076e5b2", &
"3440f64dfa3c30a96", &
"2b73885b4d3299f60", &
"2e71627ba1e268046", &
"ad23743d5e6e5b80c", &
"c9757b05f29bfdc10", &
"f7112bea739247b51", &
"3664062387998b2b1", &
"90897a3b8785aefba", &
"29e126e3201fc1d46", &
"96c9001c84d5257fc", &
"067723447d40a9f71", &
"1a019cc68f7511402", &
"4bd48eb2330032763", &
"d139a5da936b37647", &
"765ab46a4dec5f04f", &
"706f475ad19b91955", &
"1755c988fa8a55e5c", &
"2fd9ed5777eb01d6a", &
"bec27d85b954d3fe8", &
"7135a3b92c45b3f8d", &
"353237872f002163a", &
"e31e4a97aef10c729", &
"da527d5e1cbc4edb6", &
"6e33cdede17c3207e", &
"ef2d2062e84dc401f", &
"8217c84c50c1bf833", &
"12ffbac7b2219c9e0", &
"3729178706f66881f", &
"2fdd748c382a608a1", &
"dd0a00076f9dcec73", &
"46b1d37bced447035", &
"7316f33a9c05ef178", &
"152c39a6de8954cc3", &
"16efffb7b62e12ba3", &
"9d9ec2bb467affd83", &
"467723445d40a9f61", &
"87994762b3bf50697", &
"b1bfa5b51526dde9b", &
"b0a6a19d709a96148", &
"990d567c0aba31a14", &
"171f190792461b1e0", &
"166011c27d2b6b8a4", &
"170c15831244ae73e"/
data colorder/ &
0, 1, 2, 3, 4, 5, 47, 6, 7, 8, 9, 10, 11, 12, 58, 55, 13, &
14, 15, 46, 17, 18, 60, 19, 20, 21, 22, 23, 24, 25, 57, 26, 27, 49, &
28, 52, 65, 16, 50, 73, 59, 68, 63, 29, 30, 31, 32, 51, 62, 56, 66, &
45, 33, 34, 53, 67, 35, 36, 37, 61, 69, 54, 38, 71, 82, 39, 77, 80, &
83, 78, 84, 48, 41, 85, 40, 64, 75, 96, 74, 72, 76, 86, 87, 89, 90, &
79, 70, 92, 99, 93,101, 95,100, 97, 94, 42, 98,103,105,102, 43,104, &
88, 44,106, 81,107,110,108,111,112,109,113,114,117,118,116,121,115, &
119,122,120,125,129,124,127,126,128, 91,123,133,131,130,134,135,137, &
136,132,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, &
153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, &
170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, &
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203/