[hamradio-commits] [dump1090] 121/373: Major re-write of decodeModesMessage

Matthew Ernisse mernisse-guest at moszumanska.debian.org
Thu Oct 23 14:58:11 UTC 2014


This is an automated email from the git hooks/post-receive script.

mernisse-guest pushed a commit to branch backport
in repository dump1090.

commit 50cedd7fe2245d5a522ddeea8511e0e9d8115314
Author: Malcolm Robb <Support at ATTAvionics.com>
Date:   Mon Apr 29 18:53:11 2013 +0100

    Major re-write of decodeModesMessage
    
    Lots of changes to the decodeModesMessages() function, and associated
    helper functions, with the aim of speeding the code up by reducing the
    number of calls to the CRC functions. Also, only update the mm variables
    which are part of the message we're decoding.
    
    Change the way CRC's are generated and checked.
    Change the way single and double bit error is implemented.
    General tidy up of the function to make it more readable.
---
 dump1090.c | 336 ++++++++++++++++++++++++-------------------------------------
 1 file changed, 131 insertions(+), 205 deletions(-)

diff --git a/dump1090.c b/dump1090.c
index e13d3a0..21b98dc 100644
--- a/dump1090.c
+++ b/dump1090.c
@@ -303,8 +303,8 @@ void modesSendRawOutput(struct modesMessage *mm);
 void modesSendBeastOutput(struct modesMessage *mm);
 void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a);
 void useModesMessage(struct modesMessage *mm);
-int fixSingleBitErrors(unsigned char *msg, int bits, struct modesMessage *mm);
-int fixTwoBitsErrors(unsigned char *msg, int bits, struct modesMessage *mm);
+int fixSingleBitErrors(unsigned char *msg, int bits);
+int fixTwoBitsErrors(unsigned char *msg, int bits);
 int modesMessageLenByType(int type);
 
 /* ============================= Utility functions ========================== */
@@ -700,15 +700,13 @@ void dumpRawMessage(char *descr, unsigned char *msg,
                     uint16_t *m, uint32_t offset)
 {
     int j;
-    int msgtype = msg[0]>>3;
+    int msgtype = msg[0] >> 3;
     int fixable = -1;
 
-    if (msgtype == 11 || msgtype == 17) {
-        int msgbits = (msgtype == 11) ? MODES_SHORT_MSG_BITS :
-                                        MODES_LONG_MSG_BITS;
-        fixable = fixSingleBitErrors(msg, msgbits, NULL);
+    if (msgtype == 17) {
+        fixable = fixSingleBitErrors(msg, MODES_LONG_MSG_BITS);
         if (fixable == -1)
-            fixable = fixTwoBitsErrors(msg, msgbits, NULL);
+            fixable = fixTwoBitsErrors(msg, MODES_LONG_MSG_BITS);
     }
 
     if (Modes.debug & MODES_DEBUG_JS) {
@@ -1111,6 +1109,7 @@ uint32_t modes_checksum_table[112] = {
 
 uint32_t modesChecksum(unsigned char *msg, int bits) {
     uint32_t   crc = 0;
+    uint32_t   rem = 0;
     int        offset = (bits == 112) ? 0 : (112-56);
     uint8_t    theByte = *msg;
     uint32_t * pCRCTable = &modes_checksum_table[offset];
@@ -1118,14 +1117,14 @@ uint32_t modesChecksum(unsigned char *msg, int bits) {
 
     for(j = 0; j < bits; j++) {
         if ((j & 7) == 0)
-            {theByte = *msg++;}
+            {theByte = *msg++; rem = (rem << 8) | theByte;}
 
         // If bit is set, xor with corresponding table entry.
         if (theByte & 0x80) {crc ^= *pCRCTable;} 
         pCRCTable++;
         theByte = theByte << 1; 
     }
-    return crc; // 24 bit checksum.
+    return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum.
 }
 //
 // Given the Downlink Format (DF) of the message, return the message length in bits.
@@ -1137,97 +1136,79 @@ uint32_t modesChecksum(unsigned char *msg, int bits) {
 int modesMessageLenByType(int type) {
     return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ;
 }
-
-/* Try to fix single bit errors using the checksum. On success modifies
- * the original buffer with the fixed version, and returns the position
- * of the error bit. Otherwise if fixing failed -1 is returned. */
-int fixSingleBitErrors(unsigned char *msg, int bits, struct modesMessage *mm) {
+//
+// Try to fix single bit errors using the checksum. On success modifies
+// the original buffer with the fixed version, and returns the position
+// of the error bit. Otherwise if fixing failed -1 is returned.
+//
+int fixSingleBitErrors(unsigned char *msg, int bits) {
     int j;
     unsigned char aux[MODES_LONG_MSG_BYTES];
 
-    memcpy(aux, msg,bits/8);
-
-    for (j = 0; j < bits; j++) {
-        int byte = j/8;
-        int bitmask = 1 << (7-(j%8));
-        uint32_t crc1, crc2;
-
-        aux[byte] ^= bitmask; /* Flip j-th bit. */
-
-        crc1 = ((uint32_t)aux[(bits/8)-3] << 16) |
-               ((uint32_t)aux[(bits/8)-2] << 8) |
-                (uint32_t)aux[(bits/8)-1];
-        crc2 = modesChecksum(aux,bits);
-
-        if (crc1 == crc2) {
-            /* The error is fixed. Overwrite the original buffer with
-             * the corrected sequence, and returns the error bit
-             * position. */
-            memcpy(msg,aux,bits/8);
-            if (mm)
-               {
-               mm->crc   = crc2;
-               mm->iid   = 0;
-               mm->crcok = 1;
-               }
-            return j;
+    memcpy(aux, msg, bits/8);
+
+    // Do not attempt to error correct Bits 0-4. These contain the DF, and must
+    // be correct because we can only error correct DF17
+    for (j = 5; j < bits; j++) {
+        int byte    = j/8;
+        int bitmask = 1 << (7 - (j & 7));
+
+        aux[byte] ^= bitmask; // Flip j-th bit
+
+        if (0 == modesChecksum(aux, bits)) {
+            // The error is fixed. Overwrite the original buffer with the 
+            // corrected sequence, and returns the error bit position
+            msg[byte] = aux[byte];
+            return (j);
         }
 
-        aux[byte] ^= bitmask; /* Flip j-th bit back again. */
+        aux[byte] ^= bitmask; // Flip j-th bit back again
     }
-    return -1;
+    return (-1);
 }
-
-/* Similar to fixSingleBitErrors() but try every possible two bit combination.
- * This is very slow and should be tried only against DF17 messages that
- * don't pass the checksum, and only in Aggressive Mode. */
-int fixTwoBitsErrors(unsigned char *msg, int bits, struct modesMessage *mm) {
+//
+// Similar to fixSingleBitErrors() but try every possible two bit combination.
+// This is very slow and should be tried only against DF17 messages that
+// don't pass the checksum, and only in Aggressive Mode.
+//
+int fixTwoBitsErrors(unsigned char *msg, int bits) {
     int j, i;
     unsigned char aux[MODES_LONG_MSG_BYTES];
 
-    memcpy(aux,msg, bits/8);
+    memcpy(aux, msg, bits/8);
 
-    for (j = 0; j < bits; j++) {
-        int byte1 = j/8;
-        int bitmask1 = 1 << (7-(j%8));
-        aux[byte1] ^= bitmask1; /* Flip j-th bit. */
+    // Do not attempt to error correct Bits 0-4. These contain the DF, and must
+    // be correct because we can only error correct DF17
+    for (j = 5; j < bits; j++) {
+        int byte1    = j/8;
+        int bitmask1 = 1 << (7 - (j & 7));
+        aux[byte1] ^= bitmask1; // Flip j-th bit
 
-        /* Don't check the same pairs multiple times, so i starts from j+1 */
+        // Don't check the same pairs multiple times, so i starts from j+1
         for (i = j+1; i < bits; i++) {
-            int byte2 = i/8;
-            int bitmask2 = 1 << (7-(i%8));
-            uint32_t crc1, crc2;
-
-            aux[byte2] ^= bitmask2; /* Flip i-th bit. */
-
-            crc1 = ((uint32_t)aux[(bits/8)-3] << 16) |
-                   ((uint32_t)aux[(bits/8)-2] << 8) |
-                    (uint32_t)aux[(bits/8)-1];
-            crc2 = modesChecksum(aux,bits);
-
-            if (crc1 == crc2) {
-                /* The error is fixed. Overwrite the original buffer with
-                 * the corrected sequence, and returns the error bit
-                 * position. */
-                memcpy(msg,aux,bits/8);
-                if (mm)
-                   {
-                   mm->crc   = crc2;
-                   mm->iid   = 0;
-                   mm->crcok = 1;
-                   }
-                /* We return the two bits as a 16 bit integer by shifting
-                 * 'i' on the left. This is possible since 'i' will always
-                 * be non-zero because i starts from j+1. */
-                return j | (i<<8);
-
-            aux[byte2] ^= bitmask2; /* Flip i-th bit back. */
+            int byte2    = i/8;
+            int bitmask2 = 1 << (7 - (i & 7));
+
+            aux[byte2] ^= bitmask2; // Flip i-th bit
+
+            if (0 == modesChecksum(aux, bits)) {
+                // The error is fixed. Overwrite the original buffer with
+                // the corrected sequence, and returns the error bit position
+                msg[byte1] = aux[byte1];
+                msg[byte2] = aux[byte2];
+
+                // We return the two bits as a 16 bit integer by shifting
+                // 'i' on the left. This is possible since 'i' will always
+                // be non-zero because i starts from j+1
+                return (j | (i << 8));
+
+            aux[byte2] ^= bitmask2; // Flip i-th bit back
             }
 
-        aux[byte1] ^= bitmask1; /* Flip j-th bit back. */
+        aux[byte1] ^= bitmask1; // Flip j-th bit back
         }
     }
-    return -1;
+    return (-1);
 }
 
 /* Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN
@@ -1260,61 +1241,6 @@ int ICAOAddressWasRecentlySeen(uint32_t addr) {
 
     return a && a == addr && time(NULL)-t <= MODES_ICAO_CACHE_TTL;
 }
-
-/* If the message type has the checksum xored with the ICAO address, try to
- * brute force it using a list of recently seen ICAO addresses.
- *
- * Do this in a brute-force fashion by xoring the predicted CRC with
- * the address XOR checksum field in the message. This will recover the
- * address: if we found it in our cache, we can assume the message is ok.
- *
- * This function expects mm->msgtype and mm->msgbits to be correctly
- * populated by the caller.
- *
- * On success the correct ICAO address is stored in the modesMessage
- * structure in the addr field.
- *
- * If the function successfully recovers a message with a correct checksum
- * it returns 1. Otherwise 0 is returned. */
-int bruteForceAP(unsigned char *msg, struct modesMessage *mm) {
-    unsigned char aux[MODES_LONG_MSG_BYTES];
-    int msgtype = mm->msgtype;
-    int msgbits = mm->msgbits;
-
-    if (msgtype == 0 ||         /* Short air surveillance */
-        msgtype == 4 ||         /* Surveillance, altitude reply */
-        msgtype == 5 ||         /* Surveillance, identity reply */
-        msgtype == 16 ||        /* Long Air-Air survillance */
-        msgtype == 20 ||        /* Comm-A, altitude request */
-        msgtype == 21 ||        /* Comm-A, identity request */
-        msgtype == 24)          /* Comm-C ELM */
-    {
-        uint32_t addr;
-        uint32_t crc;
-        int lastbyte = (msgbits/8)-1;
-
-        /* Work on a copy. */
-        memcpy(aux,msg,msgbits/8);
-
-        /* Compute the CRC of the message and XOR it with the AP field
-         * so that we recover the address, because:
-         *
-         * (ADDR xor CRC) xor CRC = ADDR. */
-        crc = modesChecksum(aux,msgbits);
-        aux[lastbyte]   ^=  crc        & 0xff;
-        aux[lastbyte-1] ^= (crc >> 8)  & 0xff;
-        aux[lastbyte-2] ^= (crc >> 16) & 0xff;
-        
-        /* If the obtained address exists in our cache we consider
-         * the message valid. */
-        addr = aux[lastbyte] | (aux[lastbyte-1] << 8) | (aux[lastbyte-2] << 16);
-        if (ICAOAddressWasRecentlySeen(addr)) {
-            mm->addr = addr;
-            return (1);
-        }
-    }
-    return (0);
-}
 //
 // In the squawk (identity) field bits are interleaved as follows in
 // (message bit 20 to bit 32):
@@ -1452,39 +1378,29 @@ char *getMEDescription(int metype, int mesub) {
         mename = "Aircraft Operational Status Message";
     return mename;
 }
-
-/* Decode a raw Mode S message demodulated as a stream of bytes by
- * detectModeS(), and split it into fields populating a modesMessage
- * structure. */
+//
+// Decode a raw Mode S message demodulated as a stream of bytes by detectModeS(), 
+// and split it into fields populating a modesMessage structure.
+//
 void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
-    uint32_t crc2;   /* Computed CRC, used to verify the message CRC. */
     char *ais_charset = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????";
 
-    /* Work on our local copy */
+    // Work on our local copy
     memcpy(mm->msg, msg, MODES_LONG_MSG_BYTES);
     msg = mm->msg;
 
-    /* Get the message type ASAP as other operations depend on this */
-    mm->msgtype = msg[0] >> 3;  /* Downlink Format */
-    mm->msgbits = modesMessageLenByType(mm->msgtype);
-
-    /* CRC is always the last three bytes. */
-    mm->crc = ((uint32_t)msg[(mm->msgbits/8)-3] << 16) |
-              ((uint32_t)msg[(mm->msgbits/8)-2] << 8) |
-               (uint32_t)msg[(mm->msgbits/8)-1];
-    crc2 = modesChecksum(msg, mm->msgbits);
-    mm->iid = (mm->crc ^ crc2);
-
-    /* Check CRC and fix single bit errors using the CRC when
-     * possible (DF 11 and 17). */
-    mm->errorbit = -1;  /* No error */
-    if (mm->msgtype == 11)
-        {mm->crcok = (mm->iid < 80);}
-    else
-        {mm->crcok = (mm->iid == 0);}
+    // If we havn't already got it, get the message type ASAP as other operations depend on this
+    if (mm->msgbits == 0) {
+        mm->msgtype = msg[0] >> 3; // Downlink Format
+        mm->msgbits = modesMessageLenByType(mm->msgtype);
+        }
+
+    mm->errorbit        = -1; // No errors fixed
+    mm->phase_corrected =  0;
+    mm->crc             = modesChecksum(msg, mm->msgbits);
 
-    if (!mm->crcok && Modes.fix_errors && (mm->msgtype == 17)){
-//    if (!mm->crcok && Modes.fix_errors && ((mm->msgtype == 11) || (mm->msgtype == 17))){
+    if ((mm->crc) && (Modes.fix_errors) &&  (mm->msgtype == 17)) {
+//  if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 11) || (mm->msgtype == 17))) {
         //
         // Fixing single bit errors in DF-11 is a bit dodgy because we have no way to 
         // know for sure if the crc is supposed to be 0 or not - it could be any value 
@@ -1495,51 +1411,56 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
         // using the results. Perhaps check the ICAO against known aircraft, and check
         // IID against known good IID's. That's a TODO.
         //
-        mm->errorbit = fixSingleBitErrors(msg, mm->msgbits, mm);
+        mm->errorbit = fixSingleBitErrors(msg, mm->msgbits);
         if ((mm->errorbit == -1) && (Modes.aggressive)) {
-            mm->errorbit = fixTwoBitsErrors(msg, mm->msgbits, mm);
+            mm->errorbit = fixTwoBitsErrors(msg, mm->msgbits);
         }
     }
+    //
+    // Note that most of the other computation happens *after* we fix the 
+    // single/two bit errors, otherwise we would need to recompute the fields again.
+    //
+    if (mm->msgtype == 11) { // DF 11
+        mm->crcok = (mm->crc < 80);
+        mm->iid   =  mm->crc;
+        mm->addr  = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
 
-    /* Note that most of the other computation happens *after* we fix
-     * the single bit errors, otherwise we would need to recompute the
-     * fields again. */
-    mm->ca = msg[0] & 7;        /* Responder capabilities. */
-
-    // ICAO address
-    mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
-
-    /* DF 17 type (assuming this is a DF17, otherwise not used) */
-    mm->metype = msg[4] >> 3;   /* Extended squitter message type. */
-    mm->mesub = msg[4] & 7;     /* Extended squitter message subtype. */
+        if (0 == mm->crc) {
+            // DF 11 : if crc == 0 try to populate our ICAO addresses whitelist.
+            addRecentlySeenICAOAddr(mm->addr);
+        }
 
-    /* Fields for DF4,5,20,21 */
-    mm->fs = msg[0] & 7;        /* Flight status for DF4,5,20,21 */
-    mm->dr = msg[1] >> 3 & 31;  /* Request extraction of downlink request. */
-    mm->um = ((msg[1] & 7)<<3)| /* Request extraction of downlink request. */
-              msg[2]>>5;
+    } else if (mm->msgtype == 17) { // DF 17
+        mm->crcok = (mm->crc == 0);
+        mm->addr  = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); 
 
-    mm->modeA = decodeGillhamField((msg[2] << 8) | msg[3]);
+        if        (-1 != mm->errorbit) {
+            // DF 17 : if (error corrected) force crc = 0 but do not try to add this address 
+            //         to the whitelist of recently seen ICAO addresses.
+            mm->crc = 0;
 
-    /* DF 11 & 17: try to populate our ICAO addresses whitelist.
-     * DFs with an AP field (xored addr and crc), try to decode it. */
-    if (mm->msgtype != 11 && mm->msgtype != 17) {
-        /* Check if we can check the checksum for the Downlink Formats where
-         * the checksum is xored with the aircraft ICAO address. We try to
-         * brute force it using a list of recently seen aircraft addresses. */
-        if (bruteForceAP(msg,mm)) {
-            /* We recovered the message, mark the checksum as valid. */
-            mm->crcok = 1;
-        } else {
-            mm->crcok = 0;
-        }
-    } else {
-        /* If this is DF 11 or DF 17 and the checksum was ok,
-         * we can add this address to the list of recently seen
-         * addresses. */
-        if (mm->crcok && mm->errorbit == -1) {
+        } else if (0 == mm->crc) {
+            // DF 17 : if uncorrected and crc == 0 add this address to the whitelist of 
+            //         recently seen ICAO addresses.
             addRecentlySeenICAOAddr(mm->addr);
         }
+
+    } else { // All other DF's
+        // Compare the checksum with the whitelist of recently seen ICAO 
+        // addresses. If it matches one, then declare the message as valid
+        mm->addr  = mm->crc;
+        mm->crcok = ICAOAddressWasRecentlySeen(mm->crc);
+    }
+
+    // Fields for DF4,5,20,21
+    mm->ca =                                       // Responder capabilities
+    mm->fs =   msg[0]  & 7;                        // Flight status for DF4,5,20,21
+    mm->dr =  (msg[1] >> 3) & 0x1F;                // Request extraction of downlink request
+    mm->um = ((msg[1]  & 7) << 3) | (msg[2] >> 5); // Request extraction of downlink request
+              
+    // Fields for DF5,21 = Gillham encoded Squawk
+    if (mm->msgtype == 5  || mm->msgtype == 21) {
+        mm->modeA = decodeGillhamField((msg[2] << 8) | msg[3]);
     }
 
     // Fields for DF0, DF4, DF16, DF20 13 bit altitude
@@ -1548,9 +1469,12 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
         mm->altitude = decodeAC13Field(((msg[2] << 8) | msg[3]), &mm->unit);
     }
 
-    /* Decode extended squitter specific stuff. */
+    // Fields for DF17 squitter
     if (mm->msgtype == 17) {
-        /* Decode the extended squitter message. */
+         mm->metype = msg[4] >> 3;   // Extended squitter message type
+         mm->mesub  = msg[4]  & 7;   // Extended squitter message subtype
+
+        // Decode the extended squitter message
 
         if (mm->metype >= 1 && mm->metype <= 4) {
             /* Aircraft Identification and Category */
@@ -1612,7 +1536,6 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
             }
         }
     }
-    mm->phase_corrected = 0; /* Set to 1 by the caller if needed. */
 }
 //
 // This function gets a decoded Mode S Message and prints it on the screen
@@ -2082,7 +2005,9 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
             mm.timestampMsg = Modes.timestampBlk + (j*6);
             sigStrength    = (sigStrength + 0x7F) >> 8;
             mm.signalLevel = ((sigStrength < 255) ? sigStrength : 255);
-            decodeModesMessage(&mm,msg);
+            mm.msgbits     = msglen;
+            mm.msgtype     = msg[0] >> 3;
+            decodeModesMessage(&mm, msg);
 
             /* Update statistics. */
             if (mm.crcok || use_correction) {
@@ -3070,6 +2995,7 @@ int decodeHexMessage(struct client *c) {
     // Non timemarked internet data has indeterminate delay
     mm.timestampMsg = -1;
     mm.signalLevel  = -1;
+    mm.msgbits      =  0;
 
     // Remove spaces on the left and on the right
     while(l && isspace(hex[l-1])) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/dump1090.git



More information about the pkg-hamradio-commits mailing list