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_
, grid_c_string.constData ()
, 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_){
@ -63,7 +69,6 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
if(!unpacked){
unpacked = tryUnpackData();
}
}
}
@ -82,8 +87,11 @@ bool DecodedText::tryUnpackDirected(){
}
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));
} 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 {
// replace it with the correct unpacked (freetext)
message_ = QString(parts.join(QChar()));

View File

@ -5473,6 +5473,9 @@ QPair<QStringList, QStringList> MainWindow::buildFT8MessageFrames(QString const&
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)
qDebug() << "parsing message line" << line;
qDebug() << "-> isFree?" << isFree << n << m;
// if this parses to a standard FT8 free text message
// but it can be parsed as a directed message, then we
// should send the directed version
@ -5522,7 +5525,7 @@ QPair<QStringList, QStringList> MainWindow::buildFT8MessageFrames(QString const&
}
}
#if 1
#if 0
qDebug() << "parsed frames:";
foreach(auto frame, frames){
qDebug() << "->" << frame << Varicode::unpackDataMessage(frame);
@ -5573,11 +5576,17 @@ QString MainWindow::parseFT8Message(QString input, bool *isFree){
int c = msgbytes[11];
int d = ((a & 15) << 12) + (b << 6) + c;
QString output = QString::fromLatin1(msgsent);
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()
@ -6861,13 +6870,7 @@ void MainWindow::on_snrMacroButton_clicked(){
}
}
void MainWindow::on_queryButton_pressed(){
QMenu *menu = ui->queryButton->menu();
if(!menu){
menu = new QMenu(ui->queryButton);
}
menu->clear();
void MainWindow::buildQueryMenu(QMenu * menu){
QString call = callsignSelected();
if(call.isEmpty()){
return;
@ -6877,7 +6880,6 @@ void MainWindow::on_queryButton_pressed(){
auto snrAction = menu->addAction("? - What is my signal report?");
// TODO: jsherer - this should be extracted
connect(snrAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected();
@ -6939,7 +6941,30 @@ void MainWindow::on_queryButton_pressed(){
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](){
QString selectedCall = callsignSelected();
@ -6949,6 +6974,16 @@ void MainWindow::on_queryButton_pressed(){
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->showMenu();
@ -8194,7 +8229,9 @@ void MainWindow::displayActivity(bool force){
bool isAllCall = d.to == "ALLCALL";
#if 0
qDebug() << "processing command" << d.from << d.to << d.cmd << d.freq;
#endif
// we're only processing a subset of queries at this point
if(!Varicode::isCommandAllowed(d.cmd)){
@ -8217,7 +8254,8 @@ void MainWindow::displayActivity(bool force){
// SNR
if(d.cmd == "?"){
// 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
else if(d.cmd == "@" && !isAllCall){
@ -8228,10 +8266,11 @@ void MainWindow::displayActivity(bool force){
continue;
}
// standard FT8 reply
reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(grid);
} else {
reply = QString("%1 %2").arg(d.from).arg(qth);
// reply = QString("%1 %2 %3").arg(d.from).arg(m_config.my_callsign()).arg(grid);
qth = grid;
}
reply = QString("%1 %2").arg(d.from).arg(qth);
}
// STATION MESSAGE
else if(d.cmd == "&" && !isAllCall){

View File

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

View File

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

View File

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