diff --git a/ft8/unpack.cpp b/ft8/unpack.cpp index d01ded9c8..3fabf64c1 100644 --- a/ft8/unpack.cpp +++ b/ft8/unpack.cpp @@ -211,6 +211,7 @@ void Packing::remember_call(std::string call) { hashes22[ihashcall(call, 22)] = call; hashes12[ihashcall(call, 12)] = call; + hashes10[ihashcall(call, 10)] = call; } hashes_mu.unlock(); @@ -344,6 +345,7 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal // details from wsjt-x's packjt77.f90 std::string Packing::unpack_0_0(int a77[], std::string& call1str, std::string& call2str, std::string& locstr) { + // bit fields: f71 (void) call2str; (void) locstr; // the 42 possible characters. @@ -361,6 +363,53 @@ std::string Packing::unpack_0_0(int a77[], std::string& call1str, std::string& c return msg; } +std::string Packing::unpack_0_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr) +{ + // bit fields: c28 c28 h10 r5 + int i = 0; + int tu = a77[i]; + i += 1; + int call1 = un64(a77, i, 28); // c28 + i += 28; + int call2 = un64(a77, i, 28); // c28 + + call1str = trim(unpackcall(call1)) + ";" + trim(unpackcall(call2)); + + i += 28; + int x10 = un64(a77, i, 10); + // 10-bit hash + hashes_mu.lock(); + std::string ocall; + + if (hashes10.count(x10) > 0) + { + call2str = hashes10[x10]; + ocall = "<" + call2str + ">"; + } + else + { + call2str = "<...10>"; + ocall = call2str; + } + + hashes_mu.unlock(); + i += 10; + int i5 = un64(a77, i, 5); // decode r5 + int r = 2*i5 - 30; + char tmp[32]; + + if (r >= 0) { + sprintf(tmp, "+%02d", r); + } else { + sprintf(tmp, "-%02d", -r); + } + + locstr = std::string(tmp); + std::string msg; + msg = trim(unpackcall(call1)) + " RR73;" + trim(unpackcall(call2)) + " " + ocall; + return msg; +} + // ARRL RTTY Round-Up states/provinces const char *Packing::ru_states[] = { "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", @@ -510,10 +559,19 @@ std::string Packing::unpack_0_3(int a77[], int n3, std::string& call1str, std::s // CRC and LDPC have already been checked. // details from wsjt-x's packjt77.f90 and 77bit.txt. // -std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, std::string& loc) +std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, std::string& loc, std::string& type) { int i3 = un64(a77, 74, 3); int n3 = un64(a77, 71, 3); + char tmp[64]; + + if (i3 == 0) { + sprintf(tmp, "%d.%d", i3, n3); + } else { + sprintf(tmp, "%d", i3); + } + + type = std::string(tmp); if (i3 == 0 && n3 == 0) { @@ -521,6 +579,12 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s return unpack_0_0(a77, call1, call2, loc); } + if (i3 == 0 && n3 == 1) + { + // DXpedition + return unpack_0_1(a77, call1, call2, loc); + } + if (i3 == 0 && (n3 == 3 || n3 == 4)) { // ARRL Field Day @@ -529,7 +593,7 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s if (i3 == 1 || i3 == 2) { - // ordinary message + // ordinary message or EU VHF return unpack_1(a77, call1, call2, loc); } @@ -541,11 +605,12 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s if (i3 == 4) { - // call that doesn't fit in 28 bits + // call that doesn't fit in 28 bits (non standard call) return unpack_4(a77, call1, call2, loc); } - char tmp[64]; + // TODO: i3 == 5 EU VHF missing + call1 = "UNK"; sprintf(tmp, "UNK i3=%d n3=%d", i3, n3); return std::string(tmp); diff --git a/ft8/unpack.h b/ft8/unpack.h index 2fabb3ef2..7293eb397 100644 --- a/ft8/unpack.h +++ b/ft8/unpack.h @@ -33,7 +33,7 @@ namespace FT8 { class FT8_API Packing { public: - std::string unpack(int a91[], std::string& call1str, std::string& call2str, std::string& locstr); + std::string unpack(int a91[], std::string& call1str, std::string& call2str, std::string& locstr, std::string& type); private: static int ihashcall(std::string call, int m); @@ -43,10 +43,12 @@ private: std::string unpack_4(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); std::string unpack_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); std::string unpack_0_0(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); + std::string unpack_0_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); std::string unpack_3(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr); QRecursiveMutex hashes_mu; + std::map hashes10; std::map hashes12; std::map hashes22; diff --git a/plugins/channelrx/demodft8/ft8demodworker.cpp b/plugins/channelrx/demodft8/ft8demodworker.cpp index 99edd8eda..c2f1d2d63 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.cpp +++ b/plugins/channelrx/demodft8/ft8demodworker.cpp @@ -58,7 +58,8 @@ int FT8DemodWorker::FT8Callback::hcb( std::string call1; std::string call2; std::string loc; - std::string msg = m_packing.unpack(a91, call1, call2, loc); + std::string type; + std::string msg = m_packing.unpack(a91, call1, call2, loc, type); cycle_mu.lock(); @@ -70,21 +71,42 @@ int FT8DemodWorker::FT8Callback::hcb( } cycle_already[msg] = true; - QList& ft8Messages = m_msgReportFT8Messages->getFT8Messages(); - ft8Messages.push_back(FT8Message()); - FT8Message& ft8Message = ft8Messages.back(); + FT8Message baseMessage{ + m_periodTS, + QString(type.c_str()), + pass, + (int) snr, + correct_bits, + off - 0.5, + hz0, + QString(call1.c_str()).simplified(), + QString(call2.c_str()).simplified(), + QString(loc.c_str()).simplified(), + QString(comment) + }; + + // DXpedition packs two messages in one with the two callees in the first call area separated by a semicolon + if (type == "0.1") + { + QStringList callees = QString(call1.c_str()).simplified().split(";"); + + for (int i = 0; i < 2; i++) + { + baseMessage.call1 = callees[i]; + + if (i == 0) { // first is with RR73 greetings in locator area + baseMessage.loc = "RR73"; + } + + ft8Messages.push_back(baseMessage); + } + } + else + { + ft8Messages.push_back(baseMessage); + } - ft8Message.ts = m_periodTS; - ft8Message.pass = pass; - ft8Message.snr = (int) snr; - ft8Message.nbCorrectBits = correct_bits; - ft8Message.dt = off - 0.5; - ft8Message.df = hz0; - ft8Message.call1 = QString(call1.c_str()).simplified(); - ft8Message.call2 = QString(call2.c_str()).simplified(); - ft8Message.loc = QString(loc.c_str()).simplified(); - ft8Message.decoderInfo = QString(comment); cycle_mu.unlock(); // qDebug("FT8DemodWorker::FT8Callback::hcb: %6.3f %d %3d %3d %5.2f %6.1f %s (%s)", diff --git a/sdrbase/util/ft8message.h b/sdrbase/util/ft8message.h index 2f195e9dc..30780d867 100644 --- a/sdrbase/util/ft8message.h +++ b/sdrbase/util/ft8message.h @@ -27,6 +27,7 @@ struct SDRBASE_API FT8Message { QDateTime ts; + QString type; int pass; int snr; int nbCorrectBits; diff --git a/sdrbench/test_ft8.cpp b/sdrbench/test_ft8.cpp index b8c627da5..f70c11bd5 100644 --- a/sdrbench/test_ft8.cpp +++ b/sdrbench/test_ft8.cpp @@ -71,7 +71,8 @@ int TestFT8Callback::hcb( std::string call1; std::string call2; std::string loc; - std::string msg = packing.unpack(a91, call1, call2, loc); + std::string type; + std::string msg = packing.unpack(a91, call1, call2, loc, type); cycle_mu.lock(); @@ -86,7 +87,8 @@ int TestFT8Callback::hcb( cycle_mu.unlock(); - qDebug("TestFT8Callback::hcb: %d %3d %3d %5.2f %6.1f %s [%s:%s:%s] (%s)", + qDebug("TestFT8Callback::hcb: %3s %d %3d %3d %5.2f %6.1f %s [%s:%s:%s] (%s)", + type.c_str(), pass, (int)snr, correct_bits,