From a33e4388c9bf0424a008c649062756ba20239976 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Wed, 21 Jan 2015 12:55:24 +0000 Subject: [PATCH] Add scoreModesMessage() --- dump1090.h | 1 + mode_s.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/dump1090.h b/dump1090.h index 5a2aeee..daba080 100644 --- a/dump1090.h +++ b/dump1090.h @@ -456,6 +456,7 @@ int ModeAToModeC (unsigned int ModeA); // int modesMessageLenByType(int type); void detectModeS_oversample (uint16_t *m, uint32_t mlen); +int scoreModesMessage(unsigned char *msg, int validbits); int decodeModesMessage (struct modesMessage *mm, unsigned char *msg); void displayModesMessage(struct modesMessage *mm); void useModesMessage (struct modesMessage *mm); diff --git a/mode_s.c b/mode_s.c index 3442f1e..1b379ba 100644 --- a/mode_s.c +++ b/mode_s.c @@ -264,6 +264,137 @@ static char *getMEDescription(int metype, int mesub) { return mename; } +// Correct a decoded native-endian Address Announced field +// (from bits 8-31) if it is affected by the given error +// syndrome. Updates *addr and returns >0 if changed, 0 if +// it was unaffected. +static int correct_aa_field(uint32_t *addr, struct errorinfo *ei) +{ + int i; + int addr_errors = 0; + + if (!ei) + return 0; + + for (i = 0; i < ei->errors; ++i) { + if (ei->bit[i] >= 8 && ei->bit[i] <= 31) { + *addr ^= 1 << (31 - ei->bit[i]); + ++addr_errors; + } + } + + return addr_errors; +} + +// Score how plausible this ModeS message looks. +// The more positive, the more reliable the message is + +// 1000: DF 0/4/5/16/24 with a CRC-derived address matching a known aircraft + +// 1800: DF17/18 with good CRC and an address matching a known aircraft +// 1400: DF17/18 with good CRC and an address not matching a known aircraft +// 900: DF17/18 with 1-bit error and an address matching a known aircraft +// 700: DF17/18 with 1-bit error and an address not matching a known aircraft +// 450: DF17/18 with 2-bit error and an address matching a known aircraft +// 350: DF17/18 with 2-bit error and an address not matching a known aircraft + +// 1600: DF11 with IID==0, good CRC and an address matching a known aircraft +// 800: DF11 with IID==0, 1-bit error and an address matching a known aircraft +// 750: DF11 with IID==0, good CRC and an address not matching a known aircraft +// 400: DF11 with IID==0, 2-bit error and an address matching a known aircraft +// 375: DF11 with IID==0, 1-bit error and an address not matching a known aircraft +// 187: DF11 with IID==0, 2-bit error and an address not matching a known aircraft + +// 1000: DF11 with IID!=0, good CRC and an address matching a known aircraft +// 500: DF11 with IID!=0, 1-bit error and an address matching a known aircraft +// 250: DF11 with IID!=0, 2-bit error and an address matching a known aircraft + +// 1000: DF20/21 with a CRC-derived address matching a known aircraft +// 500: DF20/21 with a CRC-derived address matching a known aircraft (bottom 16 bits only - overlay control in use) + +// -1: bad message + +int scoreModesMessage(unsigned char *msg, int validbits) +{ + int msgtype, msgbits, crc, iid; + uint32_t addr; + struct errorinfo *ei; + + if (validbits < 56) + return -1; + + msgtype = msg[0] >> 3; // Downlink Format + msgbits = modesMessageLenByType(msgtype); + + if (validbits < msgbits) + return -1; + + crc = modesChecksum(msg, msgbits); + + switch (msgtype) { + case 0: // short air-air surveillance + case 4: // surveillance, altitude reply + case 5: // surveillance, altitude reply + case 16: // long air-air surveillance + case 24: // Comm-D (ELM) + return icaoFilterTest(crc) ? 1000 : -1; + + case 11: // All-call reply + iid = crc & 0x7f; + crc = crc & 0xffff80; + addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + + ei = modesChecksumDiagnose(crc, msgbits); + if (!ei) + return -1; // can't correct errors + + // fix any errors in the address field + correct_aa_field(&addr, ei); + + // validate address + if (iid == 0) { + if (icaoFilterTest(addr)) + return 1600 / (ei->errors + 1); + else + return 750 / (ei->errors + 1); + } else { + if (icaoFilterTest(addr)) + return 1000 / (ei->errors + 1); + else + return -1; + } + + case 17: // Extended squitter + case 18: // Extended squitter/non-transponder + ei = modesChecksumDiagnose(crc, msgbits); + if (!ei) + return -1; // can't correct errors + + // fix any errors in the address field + addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + correct_aa_field(&addr, ei); + + if (icaoFilterTest(addr)) + return 1800 / (ei->errors+1); + else + return 1400 / (ei->errors+1); + + case 20: // Comm-B, altitude reply + case 21: // Comm-B, identity reply + if (icaoFilterTest(crc)) + return 1000; // Address/Parity + + if (icaoFilterTestFuzzy(crc)) + return 500; // Data/Parity + + return -1; + + default: + // unknown message type + return -1; + } +} + // //========================================================================= //