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;
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');

View File

@ -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"((?<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 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 callsign_alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "};
QString alphanumeric = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "}; // callsign and grid alphabet
QMap<QString, int> 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<QString, quint32> 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<float, float> 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);
}

View File

@ -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);