Updated text decoding to support more commands as well as numerical options for those commands
This commit is contained in:
parent
5c84e79e5b
commit
553f2400e5
@ -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()));
|
||||||
|
@ -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){
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
61
varicode.cpp
61
varicode.cpp
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user