Refactored callsign packing to use 21 bits instead of 22, reducing our dependence on Prefix/Suffix flags added to our frame type enum

This commit is contained in:
Jordan Sherer 2018-08-01 11:25:45 -04:00
parent e316554b68
commit 479d647456
3 changed files with 85 additions and 63 deletions

View File

@ -1263,6 +1263,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ; qDebug() << packed << Varicode::unpackBeaconMessage(packed, &isCQ) << isCQ;
m_valid = false; m_valid = false;
bool isPrefix = false;
qDebug() << Varicode::packCallsignPrefixSuffix("VE3", true) << Varicode::unpackCallsignPrefixSuffix(Varicode::packCallsignPrefixSuffix("VE3", true), &isPrefix) << isPrefix;
#endif #endif
// this must be the last statement of constructor // this must be the last statement of constructor
@ -8990,7 +8993,11 @@ void MainWindow::processCommandActivity() {
} }
auto d = m_callActivity[call]; 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++; i++;
} }
reply = lines.join('\n'); reply = lines.join('\n');

View File

@ -28,12 +28,12 @@
#include "varicode.h" #include "varicode.h"
const int nalphabet = 41; const int nalphabet = 41;
QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; // alphabet to encode _into_ for FT8 freetext transmission
QString grid_pattern = {R"((?<grid>[A-R]{2}[0-9]{2})+)"}; QString grid_pattern = {R"((?<grid>[A-R]{2}[0-9]{2})+)"};
QString orig_compound_callsign_pattern = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"}; QString orig_compound_callsign_pattern = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
QString compound_callsign_pattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"}; QString compound_callsign_pattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[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 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<QString, int> directed_cmds = { QMap<QString, int> directed_cmds = {
// any changes here need to be made also in the directed regular xpression for parsing // 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 QChar EOT = '\x04'; // EOT char
quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27; quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27;
quint16 nbasegrid = 180 * 180;
quint16 nmaxgrid = (1<<15)-1;
QMap<QString, quint32> basecalls = { QMap<QString, quint32> basecalls = {
{ "<....>", nbasecall + 1 }, // incomplete callsign { "<....>", 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 // pack a 4-digit alpha-numeric + space into a 22 bit value
quint32 Varicode::packCallsignPrefixSuffix(QString const& value){ // 21 bits for the data + 1 bit for a flag indicator
quint8 mask6 = (1<<6)-1; // giving us a total of 5.5 bits per character
quint32 Varicode::packAlphaNumeric22(QString const& value, bool isFlag){
QString prefix = QString(value).replace(QRegExp("[^A-Z0-9]"), ""); QString word = QString(value).replace(QRegExp("[^A-Z0-9]"), "");
if(prefix.length() < 4){ if(word.length() < 4){
prefix = prefix + QString(".").repeated(4-prefix.length()); word = word + QString(" ").repeated(4-word.length());
} }
// [16][6] = 22 bits quint32 a = 37 * 37 * 37 * alphanumeric.indexOf(word.at(0));
auto left = prefix.left(3); quint32 b = 37 * 37 * alphanumeric.indexOf(word.at(1));
auto right = prefix.right(1); // guaranteed to be in our alphabet... 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){ QString Varicode::unpackAlphaNumeric22(quint32 packed, bool *isFlag){
quint32 mask22 = ((1<<16)-1) << 6; QChar word[4];
quint32 mask6 = ((1<<6)-1);
quint16 a = (packed & mask22) >> 6; if(isFlag) *isFlag = packed & 1;
quint16 b = packed & mask6 ; packed = packed >> 1;
return QString(Varicode::pack16bits(a) + Varicode::pack6bits(b)).replace(".", "");
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 // pack a callsign into a 28-bit value
@ -815,12 +838,12 @@ quint32 Varicode::packCallsign(QString const& value){
return packed; return packed;
} }
packed = callsign_alphabet.indexOf(matched.at(0)); packed = alphanumeric.indexOf(matched.at(0));
packed = 36*packed + callsign_alphabet.indexOf(matched.at(1)); packed = 36*packed + alphanumeric.indexOf(matched.at(1));
packed = 10*packed + callsign_alphabet.indexOf(matched.at(2)); packed = 10*packed + alphanumeric.indexOf(matched.at(2));
packed = 27*packed + callsign_alphabet.indexOf(matched.at(3)) - 10; packed = 27*packed + alphanumeric.indexOf(matched.at(3)) - 10;
packed = 27*packed + callsign_alphabet.indexOf(matched.at(4)) - 10; packed = 27*packed + alphanumeric.indexOf(matched.at(4)) - 10;
packed = 27*packed + callsign_alphabet.indexOf(matched.at(5)) - 10; packed = 27*packed + alphanumeric.indexOf(matched.at(5)) - 10;
return packed; return packed;
} }
@ -834,27 +857,27 @@ QString Varicode::unpackCallsign(quint32 value){
QChar word[6]; QChar word[6];
quint32 tmp = value % 27 + 10; quint32 tmp = value % 27 + 10;
word[5] = callsign_alphabet.at(tmp); word[5] = alphanumeric.at(tmp);
value = value/27; value = value/27;
tmp = value % 27 + 10; tmp = value % 27 + 10;
word[4] = callsign_alphabet.at(tmp); word[4] = alphanumeric.at(tmp);
value = value/27; value = value/27;
tmp = value % 27 + 10; tmp = value % 27 + 10;
word[3] = callsign_alphabet.at(tmp); word[3] = alphanumeric.at(tmp);
value = value/27; value = value/27;
tmp = value % 10; tmp = value % 10;
word[2] = callsign_alphabet.at(tmp); word[2] = alphanumeric.at(tmp);
value = value/10; value = value/10;
tmp = value % 36; tmp = value % 36;
word[1] = callsign_alphabet.at(tmp); word[1] = alphanumeric.at(tmp);
value = value/36; value = value/36;
tmp = value; tmp = value;
word[0] = callsign_alphabet.at(tmp); word[0] = alphanumeric.at(tmp);
QString callsign(word, 6); QString callsign(word, 6);
if(callsign.startsWith("3D0")){ if(callsign.startsWith("3D0")){
@ -1011,7 +1034,7 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign
fix = parsedCall.captured("suffix"); 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()){ if(extra.length() == 4 && QRegularExpression(grid_pattern).match(extra).hasMatch()){
packed_extra = Varicode::packGrid(extra); 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 Varicode::packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, bool isBeacon, quint16 num){
QString frame; QString frame;
quint8 packed_flag = 0; quint8 packed_flag = isBeacon ? FrameBeacon : FrameCompound;
if(isBeacon){
packed_flag = isPrefix ? FrameBeaconPrefix : FrameBeaconSuffix;
} else {
packed_flag = isPrefix ? FrameCompoundPrefix : FrameCompoundSuffix;
}
quint32 packed_base = Varicode::packCallsign(baseCallsign); 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){ if(packed_base == 0 || packed_fix == 0){
return frame; 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)); auto bits = Varicode::bitsToStr(Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64));
quint8 packed_5 = Varicode::unpack5bits(text.right(1)); 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))); quint8 packed_flag = Varicode::bitsToInt(Varicode::strToBits(bits.left(3)));
if(packed_flag == FrameBeaconPrefix || packed_flag == FrameCompoundPrefix){ if(packed_flag != FrameBeacon && packed_flag != FrameCompound){
is_prefix = true;
} else if (packed_flag == FrameBeaconSuffix || packed_flag == FrameCompoundSuffix){
is_suffix = true;
} else {
return unpacked; return unpacked;
} }
quint32 packed_base = Varicode::bitsToInt(Varicode::strToBits(bits.mid(3, 28))); quint32 packed_base = Varicode::bitsToInt(Varicode::strToBits(bits.mid(3, 28)));
quint32 packed_fix = Varicode::bitsToInt(Varicode::strToBits(bits.mid(31, 22))); quint32 packed_fix = Varicode::bitsToInt(Varicode::strToBits(bits.mid(31, 22)));
quint16 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 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; quint16 num = (packed_11 << 5) | packed_5;
if(pNum) *pNum = num; 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(fix);
} }
unpacked.append(base); unpacked.append(base);
if(is_suffix){ if(!isPrefix){
unpacked.append(fix); unpacked.append(fix);
} }

View File

@ -27,14 +27,14 @@ public:
}; };
enum FrameType { enum FrameType {
FrameBeaconPrefix = 0, // [000] FrameBeacon = 0, // [000]
FrameBeaconSuffix = 1, // [001] FrameCompound = 1, // [001]
FrameCompoundPrefix = 2, // [010] FrameDirectedPositive = 2, // [010]
FrameCompoundSuffix = 3, // [011] FrameDirectedNegative = 3, // [011]
FrameDirectedPositive = 4, // [100] FrameDataUnpadded = 4, // [100]
FrameDirectedNegative = 5, // [101] FrameDataPadded = 5, // [101]
FrameDataUnpadded = 6, // [110] FrameReservedA = 6, // [110]
FrameDataPadded = 7, // [111] FrameReservedB = 7, // [111]
}; };
//Varicode(); //Varicode();
@ -83,8 +83,8 @@ public:
static quint64 unpack64bits(QString const& value); static quint64 unpack64bits(QString const& value);
static QString pack64bits(quint64 packed); static QString pack64bits(quint64 packed);
static quint32 packCallsignPrefixSuffix(QString const& value); static quint32 packAlphaNumeric22(QString const& value, bool isFlag);
static QString unpackCallsignPrefixSuffix(quint32 packed); static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);
static quint32 packCallsign(QString const& value); static quint32 packCallsign(QString const& value);
static QString unpackCallsign(quint32 value); static QString unpackCallsign(quint32 value);