diff --git a/ft8/unpack.cpp b/ft8/unpack.cpp index 65620eca8..4c13612e0 100644 --- a/ft8/unpack.cpp +++ b/ft8/unpack.cpp @@ -145,11 +145,8 @@ std::string Packing::unpackcall(int x) // unpack a 15-bit grid square &c. // 77-bit version, from inspection of packjt77.f90. // ir is the bit after the two 28+1-bit callee/caller. -// i3 is the message type, usually 1. -std::string Packing::unpackgrid(int ng, int ir, int i3) +std::string Packing::unpackgrid15(int ng, int ir) { - (void) i3; - if (ng < NGBASE) { // maidenhead grid system: @@ -203,6 +200,31 @@ std::string Packing::unpackgrid(int ng, int ir, int i3) return std::string(tmp); } +std::string Packing::unpackgrid25(int ng) +{ + int x1 = ng / (18 * 10 * 10 * 25 * 25); + ng %= (18 * 10 * 10 * 25 * 25); + int x2 = ng / (10 * 10 * 25 * 25); + ng %= (10 * 10 * 25 * 25); + int x3 = ng / (10 * 25 * 25); + ng %= (10 * 25 * 25); + int x4 = ng / (25 * 25); + ng %= (25 * 25); + int x5 = ng / (25); + ng %= (25); + int x6 = ng; + char tmp[7]; + tmp[0] = 'A' + x1; + tmp[1] = 'A' + x2; + tmp[2] = '0' + x3; + tmp[3] = '0' + x4; + tmp[4] = 'A' + x5; + tmp[5] = 'A' + x6; + tmp[6] = '\0'; + + return std::string(tmp); +} + void Packing::remember_call(std::string call) { hashes_mu.lock(); @@ -329,7 +351,7 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal call1str = trim(unpackcall(call1)); call2str = trim(unpackcall(call2)); - locstr = unpackgrid(grid, ir, i3); + locstr = unpackgrid15(grid, ir); remember_call(call1str); remember_call(call2str); @@ -339,6 +361,52 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal return call1str + (rover1 ? pr : "") + " " + call2str + (rover2 ? pr : "") + " " + locstr; } +std::string Packing::unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr) +{ + int x12 = un64(a77, 0, 12); + // 12-bit hash + hashes_mu.lock(); + std::string ocall; + + if (hashes12.count(x12) > 0) { + ocall = hashes12[x12]; + } else { + ocall = "<...12>"; + } + + call1str = std::string(ocall); + + int x22 = un64(a77, 12, 22); + + if (hashes22.count(x22) > 0) { + ocall = hashes12[x22]; + } else { + ocall = "<...22>"; + } + + call2str = std::string(ocall); + + // mext bit is alway for R + int i = 12+ 22 +1; + // r3 + int rst = un64(a77, i, 3); + rst = 52 + 10 * rst; + i += 3; + int qsonb = un64(a77, i, 11); + char report[16]; + sprintf(report, "%d%04d", rst, qsonb); + i += 11; + // g25 + int ng = un64(a77, i, 25); + locstr = unpackgrid25(ng); + + std::string msg; + msg = call1str + " " + call2str + " " + std::string(report) + " " + locstr; + call1str += " " + std::string(report); + + return msg; +} + // free text // 71 bits, 13 characters, each one of 42 choices. // reversed. @@ -408,6 +476,30 @@ std::string Packing::unpack_0_1(int a77[], std::string& call1str, std::string& c return msg; } +std::string Packing::unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr) +{ + (void) call2str; + (void) locstr; + + const char *cc = "0123456789ABCDEF"; + std::string msg = "123456789ABCDEF012"; + + // first digit is on 3 bits + int d0 = un64(a77, 0, 3); + msg[17] = cc[d0]; + // 17 hexadecimal digits = 17*4 = 68 bits + boost::multiprecision::int128_t x = un128(a77, 3, 68); + + for (int i = 0; i < 17; i++) + { + msg[17 - 1 - i] = cc[(int) (x % 4)]; + x = x / 4; + } + + call1str = msg; + return msg; +} + // ARRL RTTY Round-Up states/provinces const char *Packing::ru_states[] = { "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", @@ -589,6 +681,12 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s return unpack_0_3(a77, n3, call1, call2, loc); } + if (i3 == 0 && n3 == 5) + { + // telemetry + return unpack_0_5(a77, call1, call2, loc); + } + if (i3 == 1 || i3 == 2) { // ordinary message or EU VHF @@ -607,7 +705,11 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s return unpack_4(a77, call1, call2, loc); } - // TODO: i3 == 5 EU VHF missing + if (i3 == 5) + { + // EU VHF with 6 digits locator + return unpack_5(a77, call1, call2, loc); + } call1 = "UNK"; sprintf(tmp, "UNK i3=%d n3=%d", i3, n3); diff --git a/ft8/unpack.h b/ft8/unpack.h index bd6938c4e..090689e6d 100644 --- a/ft8/unpack.h +++ b/ft8/unpack.h @@ -38,16 +38,19 @@ public: private: static int ihashcall(std::string call, int m); std::string unpackcall(int x); - std::string unpackgrid(int ng, int ir, int i3); + std::string unpackgrid15(int ng, int ir); + std::string unpackgrid25(int ng); void remember_call(std::string call); 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); // 0.3 and 0.4 std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr); + std::string unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); // 1 and 2 std::string unpack_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_4(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); + std::string unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); QRecursiveMutex hashes_mu; std::map hashes10; diff --git a/plugins/channelrx/demodft8/readme.md b/plugins/channelrx/demodft8/readme.md index a781ceb08..44120a6b6 100644 --- a/plugins/channelrx/demodft8/readme.md +++ b/plugins/channelrx/demodft8/readme.md @@ -154,9 +154,9 @@ Example: - **3**: SNR in 2.5 kHz bandwidth - **4**: Message start delay in seconds from standard sequence start - **5**: Message carrier shift from base frequency in Hz - - **6**: First callsign area. May contain spaces (ex: "CQ DX") - - **7**: Second callsign area - - **8**: Locator area + - **6**: First callsign area. May contain spaces (ex: "CQ DX"). Note that for messages types 0.1 and 5 it is slighlty different from the standard (See C.10) + - **7**: Second callsign area and is always a callsign. This might be slighlty different from the standard (see above) + - **8**: Locator area maybe a 4 or 6 digit locator, a report, acknowledgement (RRR) or a greetings (RR73, 73) - **9**: Decoder information if any The splitting and naming of files is different from WSJT-X scheme. @@ -184,23 +184,23 @@ Displays the received messages in a table which columns are the following: - **UTC**: UTC time in HHmmss format of the FT8 slot - **Typ**: Message type according to the i3.n3 format described in the protocol (see reference at the top): - - **0.0**: Free text - - **0.1**: DXpedition. Message carries two compacted messages (one for RR73 and one for report to two different callees). They will be de-compacted for dispplay. + - **0.0**: Free text. The first call area is populated with the free text. second call and locator areas are left blank. + - **0.1**: DXpedition. Message carries two compacted messages (one for RR73 and one for report to two different callees). They will be de-compacted in two separate messages for display. This is different from the standard that yields a single message. - **0.3**: ARRL field day - **0.4**: ARRL field day - **0.5**: Telemetry - **1**: Standard message (the most common) - - **2**: European VHF (4 char locator) minor change to standard message + - **2**: European VHF (4 char locator) minor change to standard message above - **3**: Russian RTTY - **4**: Non standard call - - **5**: European VHF (6 char locator) + - **5**: European VHF (6 char locator). The report + QSO number is appended to first call area not to pollute the second call area which contains only a callsign, This is slightly diffrent from the standard. - **P**: LDPC decoder pass index that was successful (0 to 2) as there are 3 passes - **OKb**: Number of correct bits in the message before FEC correction. Maximum is 174 in which case no FEC would be needed. - **dt**: Message start time shift in seconds from standard FT8 time slot - **df**: Message frequency shift in Hz from base frequency. This is the shift of the lowest frequency symbol - **SNR**: Signal to noise ratio in dB transposed in a 2.5 kHz bandwidth (WSJT-X standard). The actual SNR is this value plus 26 dB. - - **Call1**: This is the first call area and may contain the caller callsign, a CQ or a custom 13 character message in which case the second call and locator areas are empty - - **Call2**: This is the second call area and will contain the callsign of the responding station + - **Call1**: This is the first call area and may contain the caller callsign, a CQ or a custom 13 character message in which case the second call and locator areas are empty. It may be slightly different from the standard for message type 5 (see above). + - **Call2**: This is the second call area and will contain the callsign of the responding station. This is always a callsign and this may differ slightly from the standard for messages type 5 (see above). - **Loc**: Locator area which contains the 4 character Maidenhead locator, a report, an acknowledgement (RRR) or a greetings (73 or RR73) - **Info**: FT8 decoder information if any. If OSD is active (see C.1.3) and OSD was activated it reports the OSD decoder status as `OSD-N-MM` where N is the OSD depth reached and MM is the number of correct LDPC bits.