Updated text decoding to support more commands as well as numerical options for those commands

This commit is contained in:
Jordan Sherer 2018-07-19 23:14:11 -04:00
parent 5c84e79e5b
commit 553f2400e5
5 changed files with 109 additions and 39 deletions

View File

@ -52,6 +52,12 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
, contest_mode_ , contest_mode_
, grid_c_string.constData () , grid_c_string.constData ()
, 22, 6); , 22, 6);
// We're only going to unpack standard messages for CQs && beacons...
// TODO: jsherer - this is a hack for now...
if(is_standard_){
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
}
} }
if(!is_standard_){ if(!is_standard_){
@ -63,7 +69,6 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
if(!unpacked){ if(!unpacked){
unpacked = tryUnpackData(); unpacked = tryUnpackData();
} }
} }
} }
@ -82,8 +87,11 @@ bool DecodedText::tryUnpackDirected(){
} }
if(parts.length() == 3){ if(parts.length() == 3){
// replace it with the correct unpacked (query) // replace it with the correct unpacked (directed)
message_ = QString("%1: %2%3").arg(parts.at(0), parts.at(1), parts.at(2)); message_ = QString("%1: %2%3").arg(parts.at(0), parts.at(1), parts.at(2));
} else if(parts.length() == 4){
// replace it with the correct unpacked (directed numeric)
message_ = QString("%1: %2%3 %4").arg(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
} else { } else {
// replace it with the correct unpacked (freetext) // replace it with the correct unpacked (freetext)
message_ = QString(parts.join(QChar())); message_ = QString(parts.join(QChar()));

View File

@ -5473,6 +5473,9 @@ QPair<QStringList, QStringList> MainWindow::buildFT8MessageFrames(QString const&
int m = 0; int m = 0;
QString datFrame = Varicode::packDataMessage(line.left(21) + "\x04", &m); // 63 / 3 = 21 (maximum number of 3bit chars we could possibly stuff in here) QString datFrame = Varicode::packDataMessage(line.left(21) + "\x04", &m); // 63 / 3 = 21 (maximum number of 3bit chars we could possibly stuff in here)
qDebug() << "parsing message line" << line;
qDebug() << "-> isFree?" << isFree << n << m;
// if this parses to a standard FT8 free text message // if this parses to a standard FT8 free text message
// but it can be parsed as a directed message, then we // but it can be parsed as a directed message, then we
// should send the directed version // should send the directed version
@ -5522,7 +5525,7 @@ QPair<QStringList, QStringList> MainWindow::buildFT8MessageFrames(QString const&
} }
} }
#if 1 #if 0
qDebug() << "parsed frames:"; qDebug() << "parsed frames:";
foreach(auto frame, frames){ foreach(auto frame, frames){
qDebug() << "->" << frame << Varicode::unpackDataMessage(frame); qDebug() << "->" << frame << Varicode::unpackDataMessage(frame);
@ -5573,11 +5576,17 @@ QString MainWindow::parseFT8Message(QString input, bool *isFree){
int c = msgbytes[11]; int c = msgbytes[11];
int d = ((a & 15) << 12) + (b << 6) + c; int d = ((a & 15) << 12) + (b << 6) + c;
QString output = QString::fromLatin1(msgsent);
if(isFree){ if(isFree){
*isFree = (d >= 32768); // TODO: jsherer - lets figure out a better way to detect this for the case:
// KN4CRD 16
// this gets encoded as a standard message, but doesn't seem to make sense as to why...
// see decodedtext.cpp for the alternate decoding side of this...
*isFree = (d >= 32768) || !QRegularExpression("^(CQ|DE|QRZ)\\s").match(output).hasMatch();
} }
return QString::fromLatin1(msgsent).trimmed(); return output.trimmed();
} }
bool MainWindow::prepareNextMessageFrame() bool MainWindow::prepareNextMessageFrame()
@ -6861,13 +6870,7 @@ void MainWindow::on_snrMacroButton_clicked(){
} }
} }
void MainWindow::on_queryButton_pressed(){ void MainWindow::buildQueryMenu(QMenu * menu){
QMenu *menu = ui->queryButton->menu();
if(!menu){
menu = new QMenu(ui->queryButton);
}
menu->clear();
QString call = callsignSelected(); QString call = callsignSelected();
if(call.isEmpty()){ if(call.isEmpty()){
return; return;
@ -6877,7 +6880,6 @@ void MainWindow::on_queryButton_pressed(){
auto snrAction = menu->addAction("? - What is my signal report?"); auto snrAction = menu->addAction("? - What is my signal report?");
// TODO: jsherer - this should be extracted
connect(snrAction, &QAction::triggered, this, [this](){ connect(snrAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected(); QString selectedCall = callsignSelected();
@ -6939,7 +6941,30 @@ void MainWindow::on_queryButton_pressed(){
addMessageText(QString("%1 RR").arg(selectedCall), true); addMessageText(QString("%1 RR").arg(selectedCall), true);
}); });
auto sevenThreeAction = menu->addAction("73 - Best regards / end of contact");
auto yesAction = menu->addAction("YES - I confirm your last inquiry");
connect(yesAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected();
if(selectedCall.isEmpty()){
return;
}
addMessageText(QString("%1 YES").arg(selectedCall), true);
});
auto noAction = menu->addAction("NO - I do not confirm your last inquiry");
connect(noAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected();
if(selectedCall.isEmpty()){
return;
}
addMessageText(QString("%1 NO").arg(selectedCall), true);
});
auto sevenThreeAction = menu->addAction("73 - I send my best regards / end of contact");
connect(sevenThreeAction, &QAction::triggered, this, [this](){ connect(sevenThreeAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected(); QString selectedCall = callsignSelected();
@ -6949,6 +6974,16 @@ void MainWindow::on_queryButton_pressed(){
addMessageText(QString("%1 73").arg(selectedCall), true); addMessageText(QString("%1 73").arg(selectedCall), true);
}); });
}
void MainWindow::on_queryButton_pressed(){
QMenu *menu = ui->queryButton->menu();
if(!menu){
menu = new QMenu(ui->queryButton);
}
menu->clear();
buildQueryMenu(menu);
ui->queryButton->setMenu(menu); ui->queryButton->setMenu(menu);
ui->queryButton->showMenu(); ui->queryButton->showMenu();
@ -8194,7 +8229,9 @@ void MainWindow::displayActivity(bool force){
bool isAllCall = d.to == "ALLCALL"; bool isAllCall = d.to == "ALLCALL";
#if 0
qDebug() << "processing command" << d.from << d.to << d.cmd << d.freq; qDebug() << "processing command" << d.from << d.to << d.cmd << d.freq;
#endif
// we're only processing a subset of queries at this point // we're only processing a subset of queries at this point
if(!Varicode::isCommandAllowed(d.cmd)){ if(!Varicode::isCommandAllowed(d.cmd)){
@ -8217,7 +8254,8 @@ void MainWindow::displayActivity(bool force){
// SNR // SNR
if(d.cmd == "?"){ if(d.cmd == "?"){
// standard FT8 reply // standard FT8 reply
reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(d.snr); // reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(d.snr);
reply = QString("%1 %2").arg(d.from).arg(d.snr);
} }
// QTH // QTH
else if(d.cmd == "@" && !isAllCall){ else if(d.cmd == "@" && !isAllCall){
@ -8228,10 +8266,11 @@ void MainWindow::displayActivity(bool force){
continue; continue;
} }
// standard FT8 reply // standard FT8 reply
reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(grid); // reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(grid);
} else { qth = grid;
reply = QString("%1 %2").arg(d.from).arg(qth);
} }
reply = QString("%1 %2").arg(d.from).arg(qth);
} }
// STATION MESSAGE // STATION MESSAGE
else if(d.cmd == "&" && !isAllCall){ else if(d.cmd == "&" && !isAllCall){

View File

@ -240,6 +240,7 @@ private slots:
void on_replyMacroButton_clicked(); void on_replyMacroButton_clicked();
void on_qthMacroButton_clicked(); void on_qthMacroButton_clicked();
void on_snrMacroButton_clicked(); void on_snrMacroButton_clicked();
void buildQueryMenu(QMenu *);
void on_queryButton_pressed(); void on_queryButton_pressed();
void on_macrosMacroButton_pressed(); void on_macrosMacroButton_pressed();
void on_tableWidgetRXAll_cellClicked(int row, int col); void on_tableWidgetRXAll_cellClicked(int row, int col);

View File

@ -1123,6 +1123,9 @@ background:yellow;
</item> </item>
<item row="1" column="3"> <item row="1" column="3">
<widget class="QPushButton" name="deMacroButton"> <widget class="QPushButton" name="deMacroButton">
<property name="visible">
<bool>false</bool>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>

View File

@ -43,24 +43,26 @@ QMap<QString, int> directed_cmds = {
{"&", 3 }, // query station message {"&", 3 }, // query station message
//{"|", 4 }, // relay message //{"|", 4 }, // relay message
//{"+", 5 }, // report +snr
//{"-", 6 }, // report -snr
// ... // ...
{" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm
{" 73", 28 }, // best regards, end of contact {" 73", 28 }, // best regards, end of contact
{" RR", 29 }, // confirm message {" RR", 29 }, // confirm message
{" AGN?", 30 }, // repeat message {" AGN?", 30 }, // repeat message
{" ", 31 }, // send freetext {" ", 31 }, // send freetext
}; };
QSet<int> allowed_cmds = {0, 2, 3, 28, 29, 30, 31}; QSet<int> allowed_cmds = {0, 2, 3, 26, 27, 28, 29, 30, 31};
QRegularExpression directed_re(R"(^(?:(?<from>[A-Z0-9/]+):\s?)?(?<to>[A-Z0-9/]+)(?<cmd>(\s?(?:RR|AGN[?]|73)|[?$@&| ])))"); QRegularExpression directed_re("^"
"(?<to>[A-Z0-9/]+)"
"(?<cmd>\\s?(?:AGN[?]|RR|73|YES|NO|[?$@&| ]))"
"(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QMap<QChar, QString> huff = { QMap<QChar, QString> huff = {
// char code weight // char code weight
{' ' , "001" }, // 1300 {' ' , "000" }, // 1300
{'E' , "000" }, // 1270.2 {'E' , "001" }, // 1270.2
{'T' , "1100" }, // 905.6 {'T' , "1100" }, // 905.6
{'A' , "1010" }, // 816.7 {'A' , "1010" }, // 816.7
{'O' , "0111" }, // 750.7 {'O' , "0111" }, // 750.7
@ -517,12 +519,20 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
auto match = directed_re.match(text); auto match = directed_re.match(text);
if(match.hasMatch()){ if(match.hasMatch()){
QString from = match.captured("from"); QString from = callsign;
if(from.isEmpty()){
from = callsign;
}
QString to = match.captured("to"); QString to = match.captured("to");
QString cmd = match.captured("cmd"); QString cmd = match.captured("cmd");
QString num = match.captured("num").trimmed();
int inum = -31;
bool hasnum = false;
if(!num.isEmpty()){
inum = qMax(-30, qMin(num.toInt(&hasnum, 10), 30));
}
qDebug() << "match" << match.captured(0);
qDebug() << "groups" << from << to << cmd << num;
qDebug() << "packed num" << num << inum << hasnum;
if(to == callsign){ if(to == callsign){
*n = 0; *n = 0;
@ -535,11 +545,12 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
return frame; return frame;
} }
auto fromBytes = from.toLocal8Bit(); // TODO: jsherer - we don't need this CRC... the FT8 msg already has a 12 bit CRC...
auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU()); //auto fromBytes = from.toLocal8Bit();
//auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU());
quint8 packed_is_data = 0; quint8 packed_is_data = 0;
quint8 packed_flag = 0; quint8 packed_flag = inum < 0 ? 1 : 0;
quint32 packed_from = Varicode::packCallsign(from); quint32 packed_from = Varicode::packCallsign(from);
quint32 packed_to = Varicode::packCallsign(to); quint32 packed_to = Varicode::packCallsign(to);
@ -549,7 +560,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
} }
quint8 packed_cmd = directed_cmds[cmd]; quint8 packed_cmd = directed_cmds[cmd];
quint8 packed_extra = fromCRC; quint8 packed_extra = qAbs(inum);
// [1][2][28][28][5],[5] = 69 // [1][2][28][28][5],[5] = 69
auto bits = ( auto bits = (
@ -563,6 +574,8 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
*n = match.captured(0).length(); *n = match.captured(0).length();
return frame; return frame;
} }
return frame;
} }
QStringList Varicode::unpackDirectedMessage(const QString &text){ QStringList Varicode::unpackDirectedMessage(const QString &text){
@ -587,23 +600,29 @@ QStringList Varicode::unpackDirectedMessage(const QString &text){
QString from = Varicode::unpackCallsign(packed_from).trimmed(); QString from = Varicode::unpackCallsign(packed_from).trimmed();
auto fromBytes = from.toLocal8Bit(); // TODO: jsherer - we don't need this CRC... the FT8 msg already has a 12 bit CRC...
auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU()); //auto fromBytes = from.toLocal8Bit();
if(fromCRC != extra){ //auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU());
return unpacked; //if(fromCRC != extra){
} // return unpacked;
//}
unpacked.append(from); unpacked.append(from);
unpacked.append(Varicode::unpackCallsign(packed_to).trimmed()); unpacked.append(Varicode::unpackCallsign(packed_to).trimmed());
unpacked.append(directed_cmds.key(packed_cmd & 31)); unpacked.append(directed_cmds.key(packed_cmd & 31));
int num = (flag ? -1 : 1) * extra;
if(num != -31){
unpacked.append(QString(num > 0 ? "+%1" : "%1").arg(num));
}
return unpacked; return unpacked;
} }
QString Varicode::packDataMessage(const QString &text, int *n){ QString Varicode::packDataMessage(const QString &text, int *n){
QString frame; QString frame;
// [1][63],[5] // [1][63],[5] = 69
quint8 is_data = 1; quint8 is_data = 1;
auto frameBits = ( auto frameBits = (
Varicode::intToBits(is_data, 1) Varicode::intToBits(is_data, 1)