diff --git a/demod_2400.c b/demod_2400.c index 8d5b978..3ecf549 100644 --- a/demod_2400.c +++ b/demod_2400.c @@ -58,6 +58,40 @@ static inline int slice_phase4(uint16_t *m) { return m[0] + 5 * m[1] - 5 * m[2] - m[3]; } +static uint32_t valid_df_short_bitset; // set of acceptable DF values for short messages +static uint32_t valid_df_long_bitset; // set of acceptable DF values for long messages + +static uint32_t generate_damage_set(uint8_t df, unsigned damage_bits) +{ + uint32_t result = (1 << df); + if (!damage_bits) + return result; + + for (unsigned bit = 0; bit < 5; ++bit) { + unsigned damaged_df = df ^ (1 << bit); + result |= generate_damage_set(damaged_df, damage_bits - 1); + } + + return result; +} + +static void init_bitsets() +{ + // DFs that we directly understand without correction + valid_df_short_bitset = (1 << 0) | (1 << 4) | (1 << 5) | (1 << 11); + valid_df_long_bitset = (1 << 16) | (1 << 17) | (1 << 18) | (1 << 20) | (1 << 21); + + if (Modes.enable_df24) + valid_df_long_bitset |= (1 << 24) | (1 << 25) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31); + + // if we can also repair DF damage, include those corrections + if (Modes.fix_df && Modes.nfix_crc) { + valid_df_short_bitset |= generate_damage_set(11, 1); + valid_df_long_bitset |= generate_damage_set(17, Modes.nfix_crc); + valid_df_long_bitset |= generate_damage_set(18, Modes.nfix_crc); + } +} + // // Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz, // try to demodulate some Mode S messages. @@ -69,6 +103,10 @@ void demodulate2400(struct mag_buf *mag) unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg; uint32_t j; + // initialize bitsets on first call + if (!valid_df_short_bitset) + init_bitsets(); + unsigned char *bestmsg; int bestscore, bestphase; @@ -173,7 +211,7 @@ void demodulate2400(struct mag_buf *mag) bestmsg = NULL; bestscore = SR_NOT_SET; bestphase = -1; for (try_phase = 4; try_phase <= 8; ++try_phase) { uint16_t *pPtr; - int phase, i, score; + int phase, score; // Decode all the next 112 bits, regardless of the actual message // size. We'll check the actual message type later @@ -181,7 +219,8 @@ void demodulate2400(struct mag_buf *mag) pPtr = &m[j+19] + (try_phase/5); phase = try_phase % 5; - for (i = 0; i < MODES_LONG_MSG_BYTES; ++i) { + unsigned bytelen = 1; + for (unsigned i = 0; i < bytelen; ++i) { uint8_t theByte = 0; switch (phase) { @@ -263,6 +302,22 @@ void demodulate2400(struct mag_buf *mag) } msg[i] = theByte; + + if (i == 0) { + // inspect DF field early, only continue processing + // messages where the DF appears valid + unsigned df = theByte >> 3; + if (valid_df_long_bitset & (1 << df)) + bytelen = MODES_LONG_MSG_BYTES; + else if (valid_df_short_bitset & (1 << df)) + bytelen = MODES_SHORT_MSG_BYTES; + } + } + + if (bytelen == 1) { + // rejected early by the DF filter + Modes.stats_current.demod_rejected_bad++; + continue; } // Score the mode S message and see if it's any good. diff --git a/dump1090.c b/dump1090.c index eaf9d27..65f352f 100644 --- a/dump1090.c +++ b/dump1090.c @@ -337,6 +337,7 @@ static void showHelp(void) "--no-fix Disable error correction using CRC\n" "--no-fix-df Disable error correction of the DF message field (reduces CPU requirements)\n" "--no-crc-check Disable messages with broken CRC (discouraged)\n" +"--enable-df24 Enable decoding of DF24 Comm-D ELM messages\n" "--mlat display raw messages in Beast ascii mode\n" "--stats With --ifile print stats at exit. No other output\n" "--stats-range Collect/show range histogram\n" @@ -547,6 +548,8 @@ int main(int argc, char **argv) { Modes.nfix_crc = 1; } else if (!strcmp(argv[j],"--fix-2bit")) { Modes.nfix_crc = 2; + } else if (!strcmp(argv[j],"--enable-df24")) { + Modes.enable_df24 = 1; } else if (!strcmp(argv[j],"--no-fix")) { Modes.nfix_crc = 0; } else if (!strcmp(argv[j],"--no-fix-df")) { diff --git a/dump1090.h b/dump1090.h index cf1ac19..81a5b25 100644 --- a/dump1090.h +++ b/dump1090.h @@ -325,6 +325,7 @@ struct _Modes { // Internal state int nfix_crc; // Number of crc bit error(s) to correct int check_crc; // Only display messages with good CRC int fix_df; // Try to correct damage to the DF field, as well as the main message body + int enable_df24; // Enable decoding of DF24..DF31 (Comm-D ELM) int raw; // Raw output format int mode_ac; // Enable decoding of SSR Modes A & C int mode_ac_auto; // allow toggling of A/C by Beast commands diff --git a/mode_s.c b/mode_s.c index a404435..617a23c 100644 --- a/mode_s.c +++ b/mode_s.c @@ -247,7 +247,9 @@ static bool isShortPIMessage(const unsigned char *msg) return (df == 11); // assume IID==0 } -static int correctMessage(const unsigned char *in, unsigned char *out) +#define UNCHECKED_SYNDROME 0xFFFFFFFFU + +static int correctMessage(const unsigned char *in, unsigned char *out, uint32_t *short_syndrome, uint32_t *long_syndrome) { // Possible DF values of the first byte of a message that could be a valid DF11/17/18 // message after correction. See tools/df-correction-arrays.py for generator code. @@ -262,6 +264,9 @@ static int correctMessage(const unsigned char *in, unsigned char *out) 0x00060000, 0x066f0006, 0x6fff066f }; + *short_syndrome = UNCHECKED_SYNDROME; + *long_syndrome = UNCHECKED_SYNDROME; + // Try to correct, including corrections to the initial 5 bit DF field // that determines message format @@ -275,27 +280,27 @@ static int correctMessage(const unsigned char *in, unsigned char *out) struct errorinfo *long_ei = NULL; if (df_correctable_long[fix_df_bits] & df_bit) { - uint32_t long_syndrome = modesChecksum(in, MODES_LONG_MSG_BITS); - if (isLongPIMessage(in) && long_syndrome == 0) { + *long_syndrome = modesChecksum(in, MODES_LONG_MSG_BITS); + if (isLongPIMessage(in) && *long_syndrome == 0) { // DF17/18 message with correct checksum memcpy(out, in, MODES_LONG_MSG_BYTES); return 0; } - long_ei = modesChecksumDiagnose(long_syndrome, MODES_LONG_MSG_BITS); + long_ei = modesChecksumDiagnose(*long_syndrome, MODES_LONG_MSG_BITS); } struct errorinfo *short_ei = NULL; if (df_correctable_short[fix_df_bits] & df_bit) { - uint32_t short_syndrome = modesChecksum(in, MODES_SHORT_MSG_BITS); - if (isShortPIMessage(in) && (short_syndrome & 0xFFFF80) == 0) { + *short_syndrome = modesChecksum(in, MODES_SHORT_MSG_BITS); + if (isShortPIMessage(in) && (*short_syndrome & 0xFFFF80) == 0) { // DF11 message with correct checksum // (low 7 bits may be IID) memcpy(out, in, MODES_SHORT_MSG_BYTES); return 0; } - short_ei = modesChecksumDiagnose(short_syndrome, MODES_SHORT_MSG_BITS); // assume IID == 0 + short_ei = modesChecksumDiagnose(*short_syndrome, MODES_SHORT_MSG_BITS); // assume IID == 0 } // Might be a damaged DF11/17/18, or might be another message type that doesn't have a full CRC @@ -344,29 +349,38 @@ static int correctMessage(const unsigned char *in, unsigned char *out) // The more positive, the more reliable the message is. score_rank scoreModesMessage(const unsigned char *uncorrected) { - // try to produce a corrected DF11/17/18, including correcting the DF bits - unsigned char corrected[14]; - int corrections = correctMessage(uncorrected, corrected); - // This is a "valid" DF0 message, but it's not useful; we discard these messages static const unsigned char all_zeros[MODES_SHORT_MSG_BYTES] = { 0, 0, 0, 0, 0, 0, 0 }; - if (!memcmp(all_zeros, corrected, sizeof(all_zeros))) + if (!memcmp(all_zeros, uncorrected, sizeof(all_zeros))) return SR_ALL_ZEROS; + // try to produce a corrected DF11/17/18, including correcting the DF bits + unsigned char corrected[14]; + uint32_t short_syndrome, long_syndrome; + int corrections = correctMessage(uncorrected, corrected, &short_syndrome, &long_syndrome); + unsigned df = getbits(corrected, 1, 5); // Downlink Format switch (df) { case 0: // short air-air surveillance case 4: // surveillance, altitude reply case 5: // surveillance, altitude reply { - uint32_t addr = modesChecksum(corrected, MODES_SHORT_MSG_BITS); - bool recent = icaoFilterTest(addr); + if (short_syndrome == UNCHECKED_SYNDROME) + short_syndrome = modesChecksum(corrected, MODES_SHORT_MSG_BITS); + bool recent = icaoFilterTest(short_syndrome); return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN; } case 16: // long air-air surveillance case 20: // Comm-B, altitude reply case 21: // Comm-B, identity reply + { + if (long_syndrome == UNCHECKED_SYNDROME) + long_syndrome = modesChecksum(corrected, MODES_LONG_MSG_BITS); + bool recent = icaoFilterTest(long_syndrome); + return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN; + } + case 24: // Comm-D (ELM) case 25: // Comm-D (ELM) case 26: // Comm-D (ELM) @@ -376,8 +390,11 @@ score_rank scoreModesMessage(const unsigned char *uncorrected) case 30: // Comm-D (ELM) case 31: // Comm-D (ELM) { - uint32_t addr = modesChecksum(corrected, MODES_LONG_MSG_BITS); - bool recent = icaoFilterTest(addr); + if (!Modes.enable_df24) + return SR_UNCORRECTABLE; + if (long_syndrome == UNCHECKED_SYNDROME) + long_syndrome = modesChecksum(corrected, MODES_LONG_MSG_BITS); + bool recent = icaoFilterTest(long_syndrome); return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN; } @@ -385,7 +402,9 @@ score_rank scoreModesMessage(const unsigned char *uncorrected) { // DF11 All-call reply uint32_t addr = getbits(corrected, 9, 32); - uint32_t iid = modesChecksum(corrected, MODES_SHORT_MSG_BITS) & 0x7F; + if (short_syndrome == UNCHECKED_SYNDROME) + short_syndrome = modesChecksum(corrected, MODES_SHORT_MSG_BITS); + uint32_t iid = short_syndrome & 0x7F; bool recent = icaoFilterTest(addr); switch (corrections) { @@ -513,13 +532,23 @@ int decodeModesMessage(struct modesMessage *mm, const unsigned char *in) memcpy(mm->verbatim, in, MODES_LONG_MSG_BYTES); // Apply corrections to our local copy - int corrections = correctMessage(in, mm->msg); + uint32_t short_syndrome, long_syndrome; + int corrections = correctMessage(in, mm->msg, &short_syndrome, &long_syndrome); const unsigned char *msg = mm->msg; // Get the message type ASAP as other operations depend on this mm->msgtype = getbits(msg, 1, 5); // Downlink Format mm->msgbits = modesMessageLenByType(mm->msgtype); - mm->crc = modesChecksum(msg, mm->msgbits); + if (mm->msgtype & 16) { + if (long_syndrome == UNCHECKED_SYNDROME) + long_syndrome = modesChecksum(mm->msg, MODES_LONG_MSG_BITS); + mm->crc = long_syndrome; + } else { + if (short_syndrome == UNCHECKED_SYNDROME) + short_syndrome = modesChecksum(mm->msg, MODES_SHORT_MSG_BITS); + mm->crc = short_syndrome; + } + mm->correctedbits = corrections > 0 ? corrections : 0; mm->addr = 0;