From 0b8f6f8b4883fd9df2213885855de67bd0252fcd Mon Sep 17 00:00:00 2001 From: Karlis Goba Date: Thu, 14 Nov 2019 13:44:19 +0200 Subject: [PATCH] Added field separation in FT8 message unpacking --- decode_ft8.cpp | 11 ++-- ft8/unpack.cpp | 149 +++++++++++++++++++++++++++---------------------- ft8/unpack.h | 9 ++- 3 files changed, 95 insertions(+), 74 deletions(-) diff --git a/decode_ft8.cpp b/decode_ft8.cpp index e147df0..001ab16 100644 --- a/decode_ft8.cpp +++ b/decode_ft8.cpp @@ -25,6 +25,7 @@ const int kMax_message_length = 25; const int kFreq_osr = 2; const int kTime_osr = 2; +const float kFSK_dev = 6.25f; // tone deviation in Hz and symbol rate void usage() { fprintf(stderr, "Decode a 15-second WAV file.\n"); @@ -178,10 +179,8 @@ int main(int argc, char **argv) { } normalize_signal(signal, num_samples); - const float fsk_dev = 6.25f; // tone deviation in Hz and symbol rate - // Compute DSP parameters that depend on the sample rate - const int num_bins = (int)(sample_rate / (2 * fsk_dev)); + const int num_bins = (int)(sample_rate / (2 * kFSK_dev)); const int block_size = 2 * num_bins; const int subblock_size = block_size / kTime_osr; const int nfft = block_size * kFreq_osr; @@ -211,8 +210,10 @@ int main(int argc, char **argv) { int num_decoded = 0; for (int idx = 0; idx < num_candidates; ++idx) { ft8::Candidate &cand = candidate_list[idx]; - float freq_hz = (cand.freq_offset + (float)cand.freq_sub / kFreq_osr) * fsk_dev; - float time_sec = (cand.time_offset + (float)cand.time_sub / kTime_osr) / fsk_dev; + if (cand.score < kMin_score) continue; + + float freq_hz = (cand.freq_offset + (float)cand.freq_sub / kFreq_osr) * kFSK_dev; + float time_sec = (cand.time_offset + (float)cand.time_sub / kTime_osr) / kFSK_dev; float log174[ft8::N]; ft8::extract_likelihood(&power, cand, ft8::kGray_map, log174); diff --git a/ft8/unpack.cpp b/ft8/unpack.cpp index 58967a9..b509de5 100644 --- a/ft8/unpack.cpp +++ b/ft8/unpack.cpp @@ -51,10 +51,13 @@ int unpack28(uint32_t n28, uint8_t ip, uint8_t i3, char *result) { n28 = n28 - NTOKENS; if (n28 < MAX22) { // This is a 22-bit hash of a result - //n22=n28 //call hash22(n22,c13) !Retrieve result from hash table // TODO: implement - strcpy(result, "<...>"); + // strcpy(result, "<...>"); + result[0] = '<'; + int_to_dd(result + 1, n28, 7); + result[8] = '>'; + result[9] = '\0'; return 0; } @@ -88,11 +91,12 @@ int unpack28(uint32_t n28, uint8_t ip, uint8_t i3, char *result) { strcat(result, "/P"); } } + return 0; // Success } -int unpack_type1(const uint8_t *a77, uint8_t i3, char *message) { +int unpack_type1(const uint8_t *a77, uint8_t i3, char *field1, char *field2, char *field3) { uint32_t n28a, n28b; uint16_t igrid4; uint8_t ir; @@ -115,76 +119,61 @@ int unpack_type1(const uint8_t *a77, uint8_t i3, char *message) { igrid4 |= (a77[9] >> 6); // Unpack both callsigns - char field_1[14]; - char field_2[14]; - if (unpack28(n28a >> 1, n28a & 0x01, i3, field_1) < 0) { + if (unpack28(n28a >> 1, n28a & 0x01, i3, field1) < 0) { return -1; } - if (unpack28(n28b >> 1, n28b & 0x01, i3, field_2) < 0) { + if (unpack28(n28b >> 1, n28b & 0x01, i3, field2) < 0) { return -2; } // Fix "CQ_" to "CQ " -> already done in unpack28() - // if (starts_with(field_1, "CQ_")) { - // field_1[2] = ' '; - // } - - // Append first two fields to the result - strcpy(message, field_1); - strcat(message, " "); - strcat(message, field_2); // TODO: add to recent calls - // if (field_1[0] != '<' && strlen(field_1) >= 4) { - // save_hash_call(field_1) + // if (field1[0] != '<' && strlen(field1) >= 4) { + // save_hash_call(field1) // } - // if (field_2[0] != '<' && strlen(field_2) >= 4) { - // save_hash_call(field_2) + // if (field2[0] != '<' && strlen(field2) >= 4) { + // save_hash_call(field2) // } - char field_3[5]; if (igrid4 <= MAXGRID4) { // Extract 4 symbol grid locator - field_3[4] = '\0'; - + char *dst = field3; uint16_t n = igrid4; - field_3[3] = '0' + (n % 10); - n /= 10; - field_3[2] = '0' + (n % 10); - n /= 10; - field_3[1] = 'A' + (n % 18); - n /= 18; - field_3[0] = 'A' + (n % 18); - - if (ir != 0) { - // In case of ir=1 add an " R " before grid - strcat(message, " R "); + if (ir > 0) { + // In case of ir=1 add an "R" before grid + dst = stpcpy(dst, "R "); } + + dst[4] = '\0'; + dst[3] = '0' + (n % 10); + n /= 10; + dst[2] = '0' + (n % 10); + n /= 10; + dst[1] = 'A' + (n % 18); + n /= 18; + dst[0] = 'A' + (n % 18); + // if(msg(1:3).eq.'CQ ' .and. ir.eq.1) unpk77_success=.false. + // if (ir > 0 && strncmp(field1, "CQ", 2) == 0) return -1; } else { // Extract report int irpt = igrid4 - MAXGRID4; // Check special cases first - if (irpt == 1) field_3[0] = '\0'; - else if (irpt == 2) strcpy(field_3, "RRR"); - else if (irpt == 3) strcpy(field_3, "RR73"); - else if (irpt == 4) strcpy(field_3, "73"); + if (irpt == 1) field3[0] = '\0'; + else if (irpt == 2) strcpy(field3, "RRR"); + else if (irpt == 3) strcpy(field3, "RR73"); + else if (irpt == 4) strcpy(field3, "73"); else if (irpt >= 5) { + char *dst = field3; // Extract signal report as a two digit number with a + or - sign - if (ir == 0) { - int_to_dd(field_3, irpt - 35, 2, true); - } - else { - field_3[0] = 'R'; - int_to_dd(field_3 + 1, irpt - 35, 2, true); + if (ir > 0) { + *dst++ = 'R'; // Add "R" before report } + int_to_dd(dst, irpt - 35, 2, true); } - } - - // Append the last field to the result - if (strlen(field_3) > 0) { - strcat(message, " "); - strcat(message, field_3); + // if(msg(1:3).eq.'CQ ' .and. irpt.ge.2) unpk77_success=.false. + // if (irpt >= 2 && strncmp(field1, "CQ", 2) == 0) return -1; } return 0; // Success @@ -246,7 +235,7 @@ int unpack_telemetry(const uint8_t *a71, char *telemetry) { //none standard for wsjt-x 2.0 //by KD8CEC -int unpack_nonstandard(const uint8_t *a77, char *message) +int unpack_nonstandard(const uint8_t *a77, char *field1, char *field2, char *field3) { /* wsjt-x 2.1.0 rc5 @@ -283,41 +272,48 @@ int unpack_nonstandard(const uint8_t *a77, char *message) char call_3[15]; // should replace with hash12(n12, call_3); - strcpy(call_3, "<...>"); + // strcpy(call_3, "<...>"); + call_3[0] = '<'; + int_to_dd(call_3 + 1, n12, 4); + call_3[5] = '>'; + call_3[6] = '\0'; char * call_1 = (iflip) ? c11 : call_3; char * call_2 = (iflip) ? call_3 : c11; //save_hash_call(c11_trimmed); if (icq == 0) { - strcpy(message, trim(call_1)); - strcat(message, " "); - strcat(message, trim(call_2)); + strcpy(field1, trim(call_1)); if (nrpt == 1) - strcat(message, " RRR"); + strcpy(field3, "RRR"); else if (nrpt == 2) - strcat(message, " RR73"); + strcpy(field3, "RR73"); else if (nrpt == 3) - strcat(message, " 73"); - + strcpy(field3, "73"); + else { + field3[0] = '\0'; + } } else { - strcpy(message, "CQ "); - strcat(message, trim(call_2)); + strcpy(field1, "CQ"); + field3[0] = '\0'; } + strcpy(field2, trim(call_2)); return 0; } -int unpack77(const uint8_t *a77, char *message) { +int unpack77_fields(const uint8_t *a77, char *field1, char *field2, char *field3) { uint8_t n3, i3; // Extract n3 (bits 71..73) and i3 (bits 74..76) n3 = ((a77[8] << 2) & 0x04) | ((a77[9] >> 6) & 0x03); i3 = (a77[9] >> 3) & 0x07; + field1[0] = field2[0] = field3[0] = '\0'; + if (i3 == 0 && n3 == 0) { // 0.0 Free text - return unpack_text(a77, message); + return unpack_text(a77, field1); } // else if (i3 == 0 && n3 == 1) { // // 0.1 K1ABC RR73; W9XYZ -11 28 28 10 5 71 DXpedition Mode @@ -331,11 +327,11 @@ int unpack77(const uint8_t *a77, char *message) { // } else if (i3 == 0 && n3 == 5) { // 0.5 0123456789abcdef01 71 71 Telemetry (18 hex) - return unpack_telemetry(a77, message); + return unpack_telemetry(a77, field1); } else if (i3 == 1 || i3 == 2) { // Type 1 (standard message) or Type 2 ("/P" form for EU VHF contest) - return unpack_type1(a77, i3, message); + return unpack_type1(a77, i3, field1, field2, field3); } // else if (i3 == 3) { // // Type 3: ARRL RTTY Contest @@ -344,15 +340,34 @@ int unpack77(const uint8_t *a77, char *message) { // // Type 4: Nonstandard calls, e.g. PJ4/KA1ABC RR73 // // One hashed call or "CQ"; one compound or nonstandard call with up // // to 11 characters; and (if not "CQ") an optional RRR, RR73, or 73. - return unpack_nonstandard(a77, message); + return unpack_nonstandard(a77, field1, field2, field3); } // else if (i3 == 5) { // // Type 5: TU; W9XYZ K1ABC R-09 FN 1 28 28 1 7 9 74 WWROF contest // } // unknown type, should never get here - message[0] = '\0'; + return -1; +} + +int unpack77(const uint8_t *a77, char *message) { + char field1[14]; + char field2[14]; + char field3[7]; + int rc = unpack77_fields(a77, field1, field2, field3); + if (rc < 0) return rc; + + char *dst = message; + // int msg_sz = strlen(field1) + strlen(field2) + strlen(field3) + 2; + + dst = stpcpy(dst, field1); + *dst++ = ' '; + dst = stpcpy(dst, field2); + *dst++ = ' '; + dst = stpcpy(dst, field3); + *dst = '\0'; + return 0; } -} // namespace \ No newline at end of file +} // namespace diff --git a/ft8/unpack.h b/ft8/unpack.h index 5d88539..89a706d 100644 --- a/ft8/unpack.h +++ b/ft8/unpack.h @@ -4,7 +4,12 @@ namespace ft8 { - // message should have at least 19 bytes allocated (18 characters + zero terminator) + // field1 - at least 14 bytes + // field2 - at least 14 bytes + // field3 - at least 7 bytes + int unpack77_fields(const uint8_t *a77, char *field1, char *field2, char *field3); + + // message should have at least 35 bytes allocated (34 characters + zero terminator) int unpack77(const uint8_t *a77, char *message); -} \ No newline at end of file +}