diff --git a/mainwindow.cpp b/mainwindow.cpp index 0e218f1..6e516b8 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1263,6 +1263,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ; m_valid = false; + + bool isPrefix = false; + qDebug() << Varicode::packCallsignPrefixSuffix("VE3", true) << Varicode::unpackCallsignPrefixSuffix(Varicode::packCallsignPrefixSuffix("VE3", true), &isPrefix) << isPrefix; #endif // this must be the last statement of constructor @@ -8990,7 +8993,11 @@ void MainWindow::processCommandActivity() { } auto d = m_callActivity[call]; - lines.append(QString("%1 SNR %2").arg(d.call).arg(Varicode::formatSNR(d.snr))); + + + //lines.append(QString("%1 SNR %2").arg(d.call).arg(Varicode::formatSNR(d.snr))); + + i++; } reply = lines.join('\n'); diff --git a/varicode.cpp b/varicode.cpp index 9818185..5eb9981 100644 --- a/varicode.cpp +++ b/varicode.cpp @@ -28,12 +28,12 @@ #include "varicode.h" const int nalphabet = 41; -QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; +QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; // alphabet to encode _into_ for FT8 freetext transmission QString grid_pattern = {R"((?[A-R]{2}[0-9]{2})+)"}; QString orig_compound_callsign_pattern = {R"((?(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"}; QString compound_callsign_pattern = {R"((?\b(?[A-Z0-9]{1,4}\/)?(?([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?\/[A-Z0-9]{1,4})?)\b)"}; QString pack_callsign_pattern = {R"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))"}; -QString callsign_alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "}; +QString alphanumeric = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "}; // callsign and grid alphabet QMap directed_cmds = { // any changes here need to be made also in the directed regular xpression for parsing @@ -299,6 +299,8 @@ QChar ESC = '\\'; // Escape char QChar EOT = '\x04'; // EOT char quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27; +quint16 nbasegrid = 180 * 180; +quint16 nmaxgrid = (1<<15)-1; QMap basecalls = { { "<....>", nbasecall + 1 }, // incomplete callsign @@ -730,28 +732,49 @@ QString Varicode::pack64bits(quint64 packed){ // // -// pack a 4-digit alpha-numeric callsign prefix/suffix into a 22 bit value -quint32 Varicode::packCallsignPrefixSuffix(QString const& value){ - quint8 mask6 = (1<<6)-1; - - QString prefix = QString(value).replace(QRegExp("[^A-Z0-9]"), ""); - if(prefix.length() < 4){ - prefix = prefix + QString(".").repeated(4-prefix.length()); +// pack a 4-digit alpha-numeric + space into a 22 bit value +// 21 bits for the data + 1 bit for a flag indicator +// giving us a total of 5.5 bits per character +quint32 Varicode::packAlphaNumeric22(QString const& value, bool isFlag){ + QString word = QString(value).replace(QRegExp("[^A-Z0-9]"), ""); + if(word.length() < 4){ + word = word + QString(" ").repeated(4-word.length()); } - // [16][6] = 22 bits - auto left = prefix.left(3); - auto right = prefix.right(1); // guaranteed to be in our alphabet... + quint32 a = 37 * 37 * 37 * alphanumeric.indexOf(word.at(0)); + quint32 b = 37 * 37 * alphanumeric.indexOf(word.at(1)); + quint32 c = 37 * alphanumeric.indexOf(word.at(2)); + quint32 d = alphanumeric.indexOf(word.at(3)); - return ((quint32)Varicode::unpack16bits(left) << 6) | (Varicode::unpack6bits(right) & mask6); + quint32 packed = a + b + c + d; + packed = (packed << 1) + (int)isFlag; + + return packed; } -QString Varicode::unpackCallsignPrefixSuffix(quint32 packed){ - quint32 mask22 = ((1<<16)-1) << 6; - quint32 mask6 = ((1<<6)-1); - quint16 a = (packed & mask22) >> 6; - quint16 b = packed & mask6 ; - return QString(Varicode::pack16bits(a) + Varicode::pack6bits(b)).replace(".", ""); +QString Varicode::unpackAlphaNumeric22(quint32 packed, bool *isFlag){ + QChar word[4]; + + if(isFlag) *isFlag = packed & 1; + packed = packed >> 1; + + quint32 tmp = packed % 37; + word[3] = alphanumeric.at(tmp); + packed = packed / 37; + + tmp = packed % 37; + word[2] = alphanumeric.at(tmp); + packed = packed / 37; + + tmp = packed % 37; + word[1] = alphanumeric.at(tmp); + packed = packed / 37; + + tmp = packed % 37; + word[0] = alphanumeric.at(tmp); + packed = packed / 37; + + return QString(word, 4); } // pack a callsign into a 28-bit value @@ -815,12 +838,12 @@ quint32 Varicode::packCallsign(QString const& value){ return packed; } - packed = callsign_alphabet.indexOf(matched.at(0)); - packed = 36*packed + callsign_alphabet.indexOf(matched.at(1)); - packed = 10*packed + callsign_alphabet.indexOf(matched.at(2)); - packed = 27*packed + callsign_alphabet.indexOf(matched.at(3)) - 10; - packed = 27*packed + callsign_alphabet.indexOf(matched.at(4)) - 10; - packed = 27*packed + callsign_alphabet.indexOf(matched.at(5)) - 10; + packed = alphanumeric.indexOf(matched.at(0)); + packed = 36*packed + alphanumeric.indexOf(matched.at(1)); + packed = 10*packed + alphanumeric.indexOf(matched.at(2)); + packed = 27*packed + alphanumeric.indexOf(matched.at(3)) - 10; + packed = 27*packed + alphanumeric.indexOf(matched.at(4)) - 10; + packed = 27*packed + alphanumeric.indexOf(matched.at(5)) - 10; return packed; } @@ -834,27 +857,27 @@ QString Varicode::unpackCallsign(quint32 value){ QChar word[6]; quint32 tmp = value % 27 + 10; - word[5] = callsign_alphabet.at(tmp); + word[5] = alphanumeric.at(tmp); value = value/27; tmp = value % 27 + 10; - word[4] = callsign_alphabet.at(tmp); + word[4] = alphanumeric.at(tmp); value = value/27; tmp = value % 27 + 10; - word[3] = callsign_alphabet.at(tmp); + word[3] = alphanumeric.at(tmp); value = value/27; tmp = value % 10; - word[2] = callsign_alphabet.at(tmp); + word[2] = alphanumeric.at(tmp); value = value/10; tmp = value % 36; - word[1] = callsign_alphabet.at(tmp); + word[1] = alphanumeric.at(tmp); value = value/36; tmp = value; - word[0] = callsign_alphabet.at(tmp); + word[0] = alphanumeric.at(tmp); QString callsign(word, 6); if(callsign.startsWith("3D0")){ @@ -929,7 +952,7 @@ 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){ + if(grid.length() < 4){ return (1<<15)-1; } @@ -1011,7 +1034,7 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign fix = parsedCall.captured("suffix"); } - quint16 packed_extra = 180*180 + 1; // maximum grid + 1 (which will display an empty string) + quint16 packed_extra = nmaxgrid; // which will display an empty string if(extra.length() == 4 && QRegularExpression(grid_pattern).match(extra).hasMatch()){ packed_extra = Varicode::packGrid(extra); } @@ -1045,15 +1068,9 @@ QStringList Varicode::unpackBeaconMessage(const QString &text, bool *isBeacon, b QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, bool isBeacon, quint16 num){ QString frame; - quint8 packed_flag = 0; - if(isBeacon){ - packed_flag = isPrefix ? FrameBeaconPrefix : FrameBeaconSuffix; - } else { - packed_flag = isPrefix ? FrameCompoundPrefix : FrameCompoundSuffix; - } - + quint8 packed_flag = isBeacon ? FrameBeacon : FrameCompound; quint32 packed_base = Varicode::packCallsign(baseCallsign); - quint32 packed_fix = Varicode::packCallsignPrefixSuffix(fix); + quint32 packed_fix = Varicode::packAlphaNumeric22(fix, isPrefix); if(packed_base == 0 || packed_fix == 0){ return frame; @@ -1087,35 +1104,33 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, bool *isBeacon, q auto bits = Varicode::bitsToStr(Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64)); quint8 packed_5 = Varicode::unpack5bits(text.right(1)); - bool is_prefix = false; - bool is_suffix = false; quint8 packed_flag = Varicode::bitsToInt(Varicode::strToBits(bits.left(3))); - if(packed_flag == FrameBeaconPrefix || packed_flag == FrameCompoundPrefix){ - is_prefix = true; - } else if (packed_flag == FrameBeaconSuffix || packed_flag == FrameCompoundSuffix){ - is_suffix = true; - } else { + if(packed_flag != FrameBeacon && packed_flag != FrameCompound){ return unpacked; } + quint32 packed_base = Varicode::bitsToInt(Varicode::strToBits(bits.mid(3, 28))); quint32 packed_fix = Varicode::bitsToInt(Varicode::strToBits(bits.mid(31, 22))); quint16 packed_11 = Varicode::bitsToInt(Varicode::strToBits(bits.mid(53, 11))); QString base = Varicode::unpackCallsign(packed_base).trimmed(); - QString fix = Varicode::unpackCallsignPrefixSuffix(packed_fix); + + bool isPrefix = false; + QString fix = Varicode::unpackAlphaNumeric22(packed_fix, &isPrefix).trimmed(); + quint16 num = (packed_11 << 5) | packed_5; if(pNum) *pNum = num; - if(isBeacon) *isBeacon = packed_flag == FrameBeaconPrefix || packed_flag == FrameBeaconSuffix; + if(isBeacon) *isBeacon = packed_flag == FrameBeacon; - if(is_prefix){ + if(isPrefix){ unpacked.append(fix); } unpacked.append(base); - if(is_suffix){ + if(!isPrefix){ unpacked.append(fix); } diff --git a/varicode.h b/varicode.h index ce55be2..337c201 100644 --- a/varicode.h +++ b/varicode.h @@ -27,14 +27,14 @@ public: }; enum FrameType { - FrameBeaconPrefix = 0, // [000] - FrameBeaconSuffix = 1, // [001] - FrameCompoundPrefix = 2, // [010] - FrameCompoundSuffix = 3, // [011] - FrameDirectedPositive = 4, // [100] - FrameDirectedNegative = 5, // [101] - FrameDataUnpadded = 6, // [110] - FrameDataPadded = 7, // [111] + FrameBeacon = 0, // [000] + FrameCompound = 1, // [001] + FrameDirectedPositive = 2, // [010] + FrameDirectedNegative = 3, // [011] + FrameDataUnpadded = 4, // [100] + FrameDataPadded = 5, // [101] + FrameReservedA = 6, // [110] + FrameReservedB = 7, // [111] }; //Varicode(); @@ -83,8 +83,8 @@ public: static quint64 unpack64bits(QString const& value); static QString pack64bits(quint64 packed); - static quint32 packCallsignPrefixSuffix(QString const& value); - static QString unpackCallsignPrefixSuffix(quint32 packed); + static quint32 packAlphaNumeric22(QString const& value, bool isFlag); + static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag); static quint32 packCallsign(QString const& value); static QString unpackCallsign(quint32 value);