diff --git a/decodedtext.cpp b/decodedtext.cpp index 0b5914c..e98e4a7 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -98,7 +98,7 @@ bool DecodedText::tryUnpackCompound(){ return false; } - QStringList parts = Varicode::unpackCompoundMessage(m); + QStringList parts = Varicode::unpackCompoundMessage(m, nullptr); if(parts.isEmpty() || parts.length() < 2){ return false; diff --git a/mainwindow.cpp b/mainwindow.cpp index 33b5cf4..6e75fdb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1210,6 +1210,20 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, auto packed = Varicode::packCompoundMessage(basecall, fix, prefix, 99); qDebug() << packed << Varicode::unpackCompoundMessage(packed); + bool isCQ = false; + + auto packed = Varicode::packBeaconMessage("KN4CRD/P", "EM73", true); + qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ; + + packed = Varicode::packBeaconMessage("VE3/KN4CRD", "EM73", false); + qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ; + + + bool isCQ = false; + + auto packed = Varicode::packBeaconMessage("P/KN4CRD", "", true); + qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ; + m_valid = false; #endif @@ -5789,7 +5803,7 @@ QPair MainWindow::buildFT8MessageFrames(QString const& #if 1 qDebug() << "parsed frames:"; foreach(auto frame, frames){ - qDebug() << "->" << frame << Varicode::unpackDataMessage(frame) << Varicode::unpackDirectedMessage(frame) << Varicode::unpackCompoundMessage(frame); + qDebug() << "->" << frame << Varicode::unpackDataMessage(frame) << Varicode::unpackDirectedMessage(frame) << Varicode::unpackCompoundMessage(frame, nullptr); } qDebug() << "lines:"; diff --git a/varicode.cpp b/varicode.cpp index 19fe61f..0ad9e99 100644 --- a/varicode.cpp +++ b/varicode.cpp @@ -772,6 +772,9 @@ QPair grid2deg(QString const &grid){ // pack a 4-digit maidenhead grid locator into a 15-bit value quint16 Varicode::packGrid(QString const& grid){ // TODO: validate grid... + if(grid.length() < 4){ + return (1<<15)-1; + } // TODO: encode non-grid data... @@ -784,7 +787,7 @@ quint16 Varicode::packGrid(QString const& grid){ QString Varicode::unpackGrid(quint16 value){ if(value > 180*180){ - // TODO: decode non-grid data... + // TODO: decode non-grid data... for now just return an empty string... return ""; } @@ -802,6 +805,50 @@ bool Varicode::isCommandBuffered(const QString &cmd){ return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]); } +QString Varicode::packBeaconMessage(QString const &callsign, QString const &extra, bool isCQ){ + QString frame; + + auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign); + if(!parsedCall.hasMatch()){ + return frame; + } + + QString base = parsedCall.captured("base"); + + bool isPrefix = false; + QString fix = parsedCall.captured("prefix"); + if(!fix.isEmpty()){ + isPrefix = true; + } + + if(!isPrefix){ + fix = parsedCall.captured("suffix"); + } + + quint16 packed_extra = 180*180 + 1; // maximum grid + 1 (which will display an empty string) + if(extra.length() == 4 && QRegularExpression(grid_pattern).match(extra).hasMatch()){ + packed_extra = Varicode::packGrid(extra); + } + + if(isCQ){ + packed_extra |= (1<<15); + } + + return packCompoundMessage(base, fix, isPrefix, packed_extra); +} + +QStringList Varicode::unpackBeaconMessage(const QString &text, bool * isCQ){ + quint16 num = 0; + + QStringList unpacked = unpackCompoundMessage(text, &num); + + if(isCQ) *isCQ = (num & (1<<15)); + + unpacked.append(Varicode::unpackGrid(num & ((1<<15)-1))); + + return unpacked; +} + QString Varicode::packCompoundMessage(const QString &baseCallsign, const QString &fix, bool isPrefix, quint16 num){ QString frame; @@ -834,7 +881,7 @@ QString Varicode::packCompoundMessage(const QString &baseCallsign, const QString return Varicode::pack64bits(Varicode::bitsToInt(bits)) + Varicode::pack5bits(packed_5 % 32); } -QStringList Varicode::unpackCompoundMessage(const QString &text){ +QStringList Varicode::unpackCompoundMessage(const QString &text, quint16 *pNum){ QStringList unpacked; if(text.length() < 13 || text.contains(" ")){ @@ -856,20 +903,23 @@ QStringList Varicode::unpackCompoundMessage(const QString &text){ quint8 is_prefix = Varicode::bitsToInt(Varicode::strToBits(bits.mid(2,1))); quint32 packed_base = Varicode::bitsToInt(Varicode::strToBits(bits.mid(3, 28))); quint32 packed_fix = Varicode::bitsToInt(Varicode::strToBits(bits.mid(31, 22))); - quint8 packed_11 = Varicode::bitsToInt(Varicode::strToBits(bits.mid(53, 11))); + quint16 packed_11 = Varicode::bitsToInt(Varicode::strToBits(bits.mid(53, 11))); QString base = Varicode::unpackCallsign(packed_base).trimmed(); QString fix = Varicode::unpackCallsignPrefixSuffix(packed_fix); quint16 num = (packed_11 << 5) | packed_5; + if(pNum) *pNum = num; + if(is_prefix){ unpacked.append(fix); } + unpacked.append(base); + if(!is_prefix){ unpacked.append(fix); } - unpacked.append(QString("%1").arg(num)); return unpacked; } diff --git a/varicode.h b/varicode.h index 4887947..ff65f29 100644 --- a/varicode.h +++ b/varicode.h @@ -83,8 +83,11 @@ public: static bool isCommandAllowed(const QString &cmd); static bool isCommandBuffered(const QString &cmd); + static QString packBeaconMessage(QString const &callsign, QString const &extra, bool isCQ); + static QStringList unpackBeaconMessage(const QString &text, bool *isCQ); + static QString packCompoundMessage(const QString &baseCallsign, const QString &fix, bool isPrefix, quint16 num); - static QStringList unpackCompoundMessage(const QString &text); + static QStringList unpackCompoundMessage(const QString &text, quint16 *pNum); static QString packDirectedMessage(QString const& text, QString const& callsign, QString * pCmd, int *n); static QStringList unpackDirectedMessage(QString const& text);