From a6542b505bc1ece105428bd913da6fbd6c5f66c3 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Mon, 19 Jan 2015 23:47:51 +0000 Subject: [PATCH] Separate out 2MHz demodulator + support functions to a separate file. --- Makefile | 2 +- demod_2000.c | 591 +++++++++++++++++++++++++++++++++++++++++++++++++++ demod_2000.h | 38 ++++ dump1090.c | 2 +- dump1090.h | 3 +- mode_s.c | 556 ------------------------------------------------ 6 files changed, 633 insertions(+), 559 deletions(-) create mode 100644 demod_2000.c create mode 100644 demod_2000.h diff --git a/Makefile b/Makefile index 4f54027..205ff0f 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ all: dump1090 view1090 %.o: %.c dump1090.h $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< -dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o +dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o $(CC) -g -o dump1090 $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS) view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o diff --git a/demod_2000.c b/demod_2000.c new file mode 100644 index 0000000..dedfd7f --- /dev/null +++ b/demod_2000.c @@ -0,0 +1,591 @@ +// dump1090, a Mode S messages decoder for RTLSDR devices. +// +// Copyright (C) 2012 by Salvatore Sanfilippo +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "dump1090.h" + +// Mode S 2.0MHz demodulator + +// ============================== Debugging ================================= +// +// Helper function for dumpMagnitudeVector(). +// It prints a single bar used to display raw signals. +// +// Since every magnitude sample is between 0-255, the function uses +// up to 63 characters for every bar. Every character represents +// a length of 4, 3, 2, 1, specifically: +// +// "O" is 4 +// "o" is 3 +// "-" is 2 +// "." is 1 +// +static void dumpMagnitudeBar(int index, int magnitude) { + char *set = " .-o"; + char buf[256]; + int div = magnitude / 256 / 4; + int rem = magnitude / 256 % 4; + + memset(buf,'O',div); + buf[div] = set[rem]; + buf[div+1] = '\0'; + + if (index >= 0) + printf("[%.3d] |%-66s 0x%04X\n", index, buf, magnitude); + else + printf("[%.2d] |%-66s 0x%04X\n", index, buf, magnitude); +} +// +//========================================================================= +// +// Display an ASCII-art alike graphical representation of the undecoded +// message as a magnitude signal. +// +// The message starts at the specified offset in the "m" buffer. +// The function will display enough data to cover a short 56 bit message. +// +// If possible a few samples before the start of the messsage are included +// for context. +// +static void dumpMagnitudeVector(uint16_t *m, uint32_t offset) { + uint32_t padding = 5; // Show a few samples before the actual start. + uint32_t start = (offset < padding) ? 0 : offset-padding; + uint32_t end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_SHORT_MSG_SAMPLES) - 1; + uint32_t j; + + for (j = start; j <= end; j++) { + dumpMagnitudeBar(j-offset, m[j]); + } +} +// +//========================================================================= +// +// Produce a raw representation of the message as a Javascript file +// loadable by debug.html. +// +static void dumpRawMessageJS(char *descr, unsigned char *msg, + uint16_t *m, uint32_t offset, int fixable, char *bitpos) +{ + int padding = 5; // Show a few samples before the actual start. + int start = offset - padding; + int end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_LONG_MSG_SAMPLES) - 1; + FILE *fp; + int j; + + MODES_NOTUSED(fixable); + if ((fp = fopen("frames.js","a")) == NULL) { + fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno)); + exit(1); + } + + fprintf(fp,"frames.push({\"descr\": \"%s\", \"mag\": [", descr); + for (j = start; j <= end; j++) { + fprintf(fp,"%d", j < 0 ? 0 : m[j]); + if (j != end) fprintf(fp,","); + } + fprintf(fp,"], \"fix1\": %d, \"fix2\": %d, \"bits\": %d, \"hex\": \"", + bitpos[0], bitpos[1] , modesMessageLenByType(msg[0]>>3)); + for (j = 0; j < MODES_LONG_MSG_BYTES; j++) + fprintf(fp,"\\x%02x",msg[j]); + fprintf(fp,"\"});\n"); + fclose(fp); +} +// +//========================================================================= +// +// This is a wrapper for dumpMagnitudeVector() that also show the message +// in hex format with an additional description. +// +// descr is the additional message to show to describe the dump. +// msg points to the decoded message +// m is the original magnitude vector +// offset is the offset where the message starts +// +// The function also produces the Javascript file used by debug.html to +// display packets in a graphical format if the Javascript output was +// enabled. +// +static void dumpRawMessage(char *descr, unsigned char *msg, uint16_t *m, uint32_t offset) { + int j; + int msgtype = msg[0] >> 3; + int fixable = 0; + char bitpos[MODES_MAX_BITERRORS]; + + for (j = 0; j < MODES_MAX_BITERRORS; j++) { + bitpos[j] = -1; + } + if (msgtype == 17) { + fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, bitpos); + } + + if (Modes.debug & MODES_DEBUG_JS) { + dumpRawMessageJS(descr, msg, m, offset, fixable, bitpos); + return; + } + + printf("\n--- %s\n ", descr); + for (j = 0; j < MODES_LONG_MSG_BYTES; j++) { + printf("%02x",msg[j]); + if (j == MODES_SHORT_MSG_BYTES-1) printf(" ... "); + } + printf(" (DF %d, Fixable: %d)\n", msgtype, fixable); + dumpMagnitudeVector(m,offset); + printf("---\n\n"); +} + +// +//========================================================================= +// +// Return -1 if the message is out of fase left-side +// Return 1 if the message is out of fase right-size +// Return 0 if the message is not particularly out of phase. +// +// Note: this function will access pPreamble[-1], so the caller should make sure to +// call it only if we are not at the start of the current buffer +// +static int detectOutOfPhase(uint16_t *pPreamble) { + if (pPreamble[ 3] > pPreamble[2]/3) return 1; + if (pPreamble[10] > pPreamble[9]/3) return 1; + if (pPreamble[ 6] > pPreamble[7]/3) return -1; + if (pPreamble[-1] > pPreamble[1]/3) return -1; + return 0; +} + + +static uint16_t clamped_scale(uint16_t v, uint16_t scale) { + uint32_t scaled = (uint32_t)v * scale / 16384; + if (scaled > 65535) return 65535; + return (uint16_t) scaled; +} +// This function decides whether we are sampling early or late, +// and by approximately how much, by looking at the energy in +// preamble bits before and after the expected pulse locations. +// +// It then deals with one sample pair at a time, comparing samples +// to make a decision about the bit value. Based on this decision it +// modifies the sample value of the *adjacent* sample which will +// contain some of the energy from the bit we just inspected. +// +// pPayload[0] should be the start of the preamble, +// pPayload[-1 .. MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] should be accessible. +// pPayload[MODES_PREAMBLE_SAMPLES .. MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] will be updated. +static void applyPhaseCorrection(uint16_t *pPayload) { + int j; + + // we expect 1 bits at 0, 2, 7, 9 + // and 0 bits at -1, 1, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14 + // use bits -1,6 for early detection (bit 0/7 arrived a little early, our sample period starts after the bit phase so we include some of the next bit) + // use bits 3,10 for late detection (bit 2/9 arrived a little late, our sample period starts before the bit phase so we include some of the last bit) + + uint32_t onTime = (pPayload[0] + pPayload[2] + pPayload[7] + pPayload[9]); + uint32_t early = (pPayload[-1] + pPayload[6]) << 1; + uint32_t late = (pPayload[3] + pPayload[10]) << 1; + + if (onTime == 0 && early == 0 && late == 0) { + // Blah, can't do anything with this, avoid a divide-by-zero + return; + } + + if (early > late) { + // Our sample period starts late and so includes some of the next bit. + + uint16_t scaleUp = 16384 + 16384 * early / (early + onTime); // 1 + early / (early+onTime) + uint16_t scaleDown = 16384 - 16384 * early / (early + onTime); // 1 - early / (early+onTime) + + // trailing bits are 0; final data sample will be a bit low. + pPayload[MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] = + clamped_scale(pPayload[MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1], scaleUp); + for (j = MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 2; j > MODES_PREAMBLE_SAMPLES; j -= 2) { + if (pPayload[j] > pPayload[j+1]) { + // x [1 0] y + // x overlapped with the "1" bit and is slightly high + pPayload[j-1] = clamped_scale(pPayload[j-1], scaleDown); + } else { + // x [0 1] y + // x overlapped with the "0" bit and is slightly low + pPayload[j-1] = clamped_scale(pPayload[j-1], scaleUp); + } + } + } else { + // Our sample period starts early and so includes some of the previous bit. + + uint16_t scaleUp = 16384 + 16384 * late / (late + onTime); // 1 + late / (late+onTime) + uint16_t scaleDown = 16384 - 16384 * late / (late + onTime); // 1 - late / (late+onTime) + + // leading bits are 0; first data sample will be a bit low. + pPayload[MODES_PREAMBLE_SAMPLES] = clamped_scale(pPayload[MODES_PREAMBLE_SAMPLES], scaleUp); + for (j = MODES_PREAMBLE_SAMPLES; j < MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 2; j += 2) { + if (pPayload[j] > pPayload[j+1]) { + // x [1 0] y + // y overlapped with the "0" bit and is slightly low + pPayload[j+2] = clamped_scale(pPayload[j+2], scaleUp); + } else { + // x [0 1] y + // y overlapped with the "1" bit and is slightly high + pPayload[j+2] = clamped_scale(pPayload[j+2], scaleDown); + } + } + } +} +// +//========================================================================= +// +// Detect a Mode S messages inside the magnitude buffer pointed by 'm' and of +// size 'mlen' bytes. Every detected Mode S message is convert it into a +// stream of bits and passed to the function to display it. +// +void demodulate2000(uint16_t *m, uint32_t mlen) { + struct modesMessage mm; + unsigned char msg[MODES_LONG_MSG_BYTES], *pMsg; + uint16_t aux[MODES_PREAMBLE_SAMPLES+MODES_LONG_MSG_SAMPLES+1]; + uint32_t j; + int use_correction = 0; + + memset(&mm, 0, sizeof(mm)); + + // The Mode S preamble is made of impulses of 0.5 microseconds at + // the following time offsets: + // + // 0 - 0.5 usec: first impulse. + // 1.0 - 1.5 usec: second impulse. + // 3.5 - 4 usec: third impulse. + // 4.5 - 5 usec: last impulse. + // + // Since we are sampling at 2 Mhz every sample in our magnitude vector + // is 0.5 usec, so the preamble will look like this, assuming there is + // an impulse at offset 0 in the array: + // + // 0 ----------------- + // 1 - + // 2 ------------------ + // 3 -- + // 4 - + // 5 -- + // 6 - + // 7 ------------------ + // 8 -- + // 9 ------------------- + // + for (j = 0; j < mlen; j++) { + int high, i, errors, errors56, errorsTy; + uint16_t *pPreamble, *pPayload, *pPtr; + uint8_t theByte, theErrs; + int msglen, scanlen; + uint32_t sigLevel, noiseLevel; + uint16_t snr; + + pPreamble = &m[j]; + pPayload = &m[j+MODES_PREAMBLE_SAMPLES]; + + // Rather than clear the whole mm structure, just clear the parts which are required. The clear + // is required for every bit of the input stream, and we don't want to be memset-ing the whole + // modesMessage structure two million times per second if we don't have to.. + mm.bFlags = + mm.crcok = + mm.correctedbits = 0; + + if (!use_correction) // This is not a re-try with phase correction + { // so try to find a new preamble + + if (Modes.mode_ac) + { + int ModeA = detectModeA(pPreamble, &mm); + + if (ModeA) // We have found a valid ModeA/C in the data + { + mm.timestampMsg = Modes.timestampBlk + ((j+1) * 6); + + // Decode the received message + decodeModeAMessage(&mm, ModeA); + + // Pass data to the next layer + useModesMessage(&mm); + + j += MODEAC_MSG_SAMPLES; + Modes.stat_ModeAC++; + continue; + } + } + + // First check of relations between the first 10 samples + // representing a valid preamble. We don't even investigate further + // if this simple test is not passed + if (!(pPreamble[0] > pPreamble[1] && + pPreamble[1] < pPreamble[2] && + pPreamble[2] > pPreamble[3] && + pPreamble[3] < pPreamble[0] && + pPreamble[4] < pPreamble[0] && + pPreamble[5] < pPreamble[0] && + pPreamble[6] < pPreamble[0] && + pPreamble[7] > pPreamble[8] && + pPreamble[8] < pPreamble[9] && + pPreamble[9] > pPreamble[6])) + { + if (Modes.debug & MODES_DEBUG_NOPREAMBLE && + *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) + dumpRawMessage("Unexpected ratio among first 10 samples", msg, m, j); + continue; + } + + // The samples between the two spikes must be < than the average + // of the high spikes level. We don't test bits too near to + // the high levels as signals can be out of phase so part of the + // energy can be in the near samples + high = (pPreamble[0] + pPreamble[2] + pPreamble[7] + pPreamble[9]) / 6; + if (pPreamble[4] >= high || + pPreamble[5] >= high) + { + if (Modes.debug & MODES_DEBUG_NOPREAMBLE && + *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) + dumpRawMessage("Too high level in samples between 3 and 6", msg, m, j); + continue; + } + + // Similarly samples in the range 11-14 must be low, as it is the + // space between the preamble and real data. Again we don't test + // bits too near to high levels, see above + if (pPreamble[11] >= high || + pPreamble[12] >= high || + pPreamble[13] >= high || + pPreamble[14] >= high) + { + if (Modes.debug & MODES_DEBUG_NOPREAMBLE && + *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) + dumpRawMessage("Too high level in samples between 10 and 15", msg, m, j); + continue; + } + Modes.stat_valid_preamble++; + } + + else { + // If the previous attempt with this message failed, retry using + // magnitude correction + // Make a copy of the Payload, and phase correct the copy + memcpy(aux, &pPreamble[-1], sizeof(aux)); + applyPhaseCorrection(&aux[1]); + Modes.stat_out_of_phase++; + pPayload = &aux[1 + MODES_PREAMBLE_SAMPLES]; + // TODO ... apply other kind of corrections + } + + // Decode all the next 112 bits, regardless of the actual message + // size. We'll check the actual message type later + pMsg = &msg[0]; + pPtr = pPayload; + theByte = 0; + theErrs = 0; errorsTy = 0; + errors = 0; errors56 = 0; + + // We should have 4 'bits' of 0/1 and 1/0 samples in the preamble, + // so include these in the signal strength + sigLevel = pPreamble[0] + pPreamble[2] + pPreamble[7] + pPreamble[9]; + noiseLevel = pPreamble[1] + pPreamble[3] + pPreamble[4] + pPreamble[6] + pPreamble[8]; + + msglen = scanlen = MODES_LONG_MSG_BITS; + for (i = 0; i < scanlen; i++) { + uint32_t a = *pPtr++; + uint32_t b = *pPtr++; + + if (a > b) + {theByte |= 1; if (i < 56) { sigLevel += a; noiseLevel += b; }} + else if (a < b) + {/*theByte |= 0;*/ if (i < 56) { sigLevel += b; noiseLevel += a; }} + else { + if (i < 56) { sigLevel += a; noiseLevel += a; } + if (i >= MODES_SHORT_MSG_BITS) //(a == b), and we're in the long part of a frame + {errors++; /*theByte |= 0;*/} + else if (i >= 5) //(a == b), and we're in the short part of a frame + {scanlen = MODES_LONG_MSG_BITS; errors56 = ++errors;/*theByte |= 0;*/} + else if (i) //(a == b), and we're in the message type part of a frame + {errorsTy = errors56 = ++errors; theErrs |= 1; /*theByte |= 0;*/} + else //(a == b), and we're in the first bit of the message type part of a frame + {errorsTy = errors56 = ++errors; theErrs |= 1; theByte |= 1;} + } + + if ((i & 7) == 7) + {*pMsg++ = theByte;} + else if (i == 4) { + msglen = modesMessageLenByType(theByte); + if (errors == 0) + {scanlen = msglen;} + } + + theByte = theByte << 1; + if (i < 7) + {theErrs = theErrs << 1;} + + // If we've exceeded the permissible number of encoding errors, abandon ship now + if (errors > MODES_MSG_ENCODER_ERRS) { + + if (i < MODES_SHORT_MSG_BITS) { + msglen = 0; + + } else if ((errorsTy == 1) && (theErrs == 0x80)) { + // If we only saw one error in the first bit of the byte of the frame, then it's possible + // we guessed wrongly about the value of the bit. We may be able to correct it by guessing + // the other way. + // + // We guessed a '1' at bit 7, which is the DF length bit == 112 Bits. + // Inverting bit 7 will change the message type from a long to a short. + // Invert the bit, cross your fingers and carry on. + msglen = MODES_SHORT_MSG_BITS; + msg[0] ^= theErrs; errorsTy = 0; + errors = errors56; // revert to the number of errors prior to bit 56 + Modes.stat_DF_Len_Corrected++; + + } else if (i < MODES_LONG_MSG_BITS) { + msglen = MODES_SHORT_MSG_BITS; + errors = errors56; + + } else { + msglen = MODES_LONG_MSG_BITS; + } + + break; + } + } + + // Ensure msglen is consistent with the DF type + if (msglen > 0) { + i = modesMessageLenByType(msg[0] >> 3); + if (msglen > i) {msglen = i;} + else if (msglen < i) {msglen = 0;} + } + + // + // If we guessed at any of the bits in the DF type field, then look to see if our guess was sensible. + // Do this by looking to see if the original guess results in the DF type being one of the ICAO defined + // message types. If it isn't then toggle the guessed bit and see if this new value is ICAO defined. + // if the new value is ICAO defined, then update it in our message. + if ((msglen) && (errorsTy == 1) && (theErrs & 0x78)) { + // We guessed at one (and only one) of the message type bits. See if our guess is "likely" + // to be correct by comparing the DF against a list of known good DF's + int thisDF = ((theByte = msg[0]) >> 3) & 0x1f; + uint32_t validDFbits = 0x017F0831; // One bit per 32 possible DF's. Set bits 0,4,5,11,16.17.18.19,20,21,22,24 + uint32_t thisDFbit = (1 << thisDF); + if (0 == (validDFbits & thisDFbit)) { + // The current DF is not ICAO defined, so is probably an errors. + // Toggle the bit we guessed at and see if the resultant DF is more likely + theByte ^= theErrs; + thisDF = (theByte >> 3) & 0x1f; + thisDFbit = (1 << thisDF); + // if this DF any more likely? + if (validDFbits & thisDFbit) { + // Yep, more likely, so update the main message + msg[0] = theByte; + Modes.stat_DF_Type_Corrected++; + errors--; // decrease the error count so we attempt to use the modified DF. + } + } + } + + // snr = 5 * 20log10(sigLevel / noiseLevel) (in units of 0.2dB) + // = 100log10(sigLevel) - 100log10(noiseLevel) + + while (sigLevel > 65535 || noiseLevel > 65535) { + sigLevel >>= 1; + noiseLevel >>= 1; + } + snr = Modes.log10lut[sigLevel] - Modes.log10lut[noiseLevel]; + + // When we reach this point, if error is small, and the signal strength is large enough + // we may have a Mode S message on our hands. It may still be broken and the CRC may not + // be correct, but this can be handled by the next layer. + if ( (msglen) + && ((2 * snr) > (int) (MODES_MSG_SQUELCH_DB * 10)) + && (errors <= MODES_MSG_ENCODER_ERRS) ) { + // Set initial mm structure details + mm.timestampMsg = Modes.timestampBlk + (j*6); + mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr); + mm.phase_corrected = use_correction; + + // Decode the received message + decodeModesMessage(&mm, msg); + + // Update statistics + if (Modes.stats) { + struct demod_stats *dstats = (use_correction ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod); + + switch (errors) { + case 0: dstats->demodulated0++; break; + case 1: dstats->demodulated1++; break; + case 2: dstats->demodulated2++; break; + default: dstats->demodulated3++; break; + } + + if (mm.crcok) { + dstats->goodcrc++; + dstats->goodcrc_byphase[0]++; + } else if (mm.correctedbits > 0) { + dstats->badcrc++; + dstats->fixed++; + if (mm.correctedbits <= MODES_MAX_BITERRORS) + dstats->bit_fix[mm.correctedbits-1] += 1; + } else { + dstats->badcrc++; + } + } + + // Output debug mode info if needed + if (use_correction) { + if (Modes.debug & MODES_DEBUG_DEMOD) + dumpRawMessage("Demodulated with 0 errors", msg, m, j); + else if (Modes.debug & MODES_DEBUG_BADCRC && + mm.msgtype == 17 && + (!mm.crcok || mm.correctedbits != 0)) + dumpRawMessage("Decoded with bad CRC", msg, m, j); + else if (Modes.debug & MODES_DEBUG_GOODCRC && mm.crcok && + mm.correctedbits == 0) + dumpRawMessage("Decoded with good CRC", msg, m, j); + } + + // Skip this message if we are sure it's fine + if (mm.crcok || mm.correctedbits) { + j += (MODES_PREAMBLE_US+msglen)*2 - 1; + } + + // Pass data to the next layer + useModesMessage(&mm); + + } else { + if (Modes.debug & MODES_DEBUG_DEMODERR && use_correction) { + printf("The following message has %d demod errors\n", errors); + dumpRawMessage("Demodulated with errors", msg, m, j); + } + } + + // Retry with phase correction if enabled, necessary and possible. + if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) { + use_correction = 1; j--; + } else { + use_correction = 0; + } + } +} + diff --git a/demod_2000.h b/demod_2000.h new file mode 100644 index 0000000..623f47e --- /dev/null +++ b/demod_2000.h @@ -0,0 +1,38 @@ +// dump1090, a Mode S messages decoder for RTLSDR devices. +// +// Copyright (C) 2012 by Salvatore Sanfilippo +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef DUMP1090_DEMOD_2000_H +#define DUMP1090_DEMOD_2000_H + +#include + +void demodulate2000(uint16_t *m, uint32_t mlen); + +#endif diff --git a/dump1090.c b/dump1090.c index 793beef..8ac527e 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1041,7 +1041,7 @@ int main(int argc, char **argv) { if (Modes.oversample) detectModeS_oversample(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES); else - detectModeS(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES); + demodulate2000(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpu_end_time); Modes.stat_cputime.tv_sec += (cpu_end_time.tv_sec - cpu_start_time.tv_sec); diff --git a/dump1090.h b/dump1090.h index dc444a8..7892d98 100644 --- a/dump1090.h +++ b/dump1090.h @@ -72,6 +72,7 @@ #include "rtl-sdr.h" #include "anet.h" #include "crc.h" +#include "demod_2000.h" // ============================= #defines =============================== // @@ -467,7 +468,7 @@ int ModeAToModeC (unsigned int ModeA); // // Functions exported from mode_s.c // -void detectModeS (uint16_t *m, uint32_t mlen); +int modesMessageLenByType(int type); void detectModeS_oversample (uint16_t *m, uint32_t mlen); void decodeModesMessage (struct modesMessage *mm, unsigned char *msg); void displayModesMessage(struct modesMessage *mm); diff --git a/mode_s.c b/mode_s.c index bbaa8f1..7e0da53 100644 --- a/mode_s.c +++ b/mode_s.c @@ -47,132 +47,6 @@ int modesMessageLenByType(int type) { return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ; } -// ============================== Debugging ================================= -// -// Helper function for dumpMagnitudeVector(). -// It prints a single bar used to display raw signals. -// -// Since every magnitude sample is between 0-255, the function uses -// up to 63 characters for every bar. Every character represents -// a length of 4, 3, 2, 1, specifically: -// -// "O" is 4 -// "o" is 3 -// "-" is 2 -// "." is 1 -// -void dumpMagnitudeBar(int index, int magnitude) { - char *set = " .-o"; - char buf[256]; - int div = magnitude / 256 / 4; - int rem = magnitude / 256 % 4; - - memset(buf,'O',div); - buf[div] = set[rem]; - buf[div+1] = '\0'; - - if (index >= 0) - printf("[%.3d] |%-66s 0x%04X\n", index, buf, magnitude); - else - printf("[%.2d] |%-66s 0x%04X\n", index, buf, magnitude); -} -// -//========================================================================= -// -// Display an ASCII-art alike graphical representation of the undecoded -// message as a magnitude signal. -// -// The message starts at the specified offset in the "m" buffer. -// The function will display enough data to cover a short 56 bit message. -// -// If possible a few samples before the start of the messsage are included -// for context. -// -void dumpMagnitudeVector(uint16_t *m, uint32_t offset) { - uint32_t padding = 5; // Show a few samples before the actual start. - uint32_t start = (offset < padding) ? 0 : offset-padding; - uint32_t end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_SHORT_MSG_SAMPLES) - 1; - uint32_t j; - - for (j = start; j <= end; j++) { - dumpMagnitudeBar(j-offset, m[j]); - } -} -// -//========================================================================= -// -// Produce a raw representation of the message as a Javascript file -// loadable by debug.html. -// -void dumpRawMessageJS(char *descr, unsigned char *msg, - uint16_t *m, uint32_t offset, int fixable, char *bitpos) -{ - int padding = 5; // Show a few samples before the actual start. - int start = offset - padding; - int end = offset + (MODES_PREAMBLE_SAMPLES)+(MODES_LONG_MSG_SAMPLES) - 1; - FILE *fp; - int j; - - MODES_NOTUSED(fixable); - if ((fp = fopen("frames.js","a")) == NULL) { - fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno)); - exit(1); - } - - fprintf(fp,"frames.push({\"descr\": \"%s\", \"mag\": [", descr); - for (j = start; j <= end; j++) { - fprintf(fp,"%d", j < 0 ? 0 : m[j]); - if (j != end) fprintf(fp,","); - } - fprintf(fp,"], \"fix1\": %d, \"fix2\": %d, \"bits\": %d, \"hex\": \"", - bitpos[0], bitpos[1] , modesMessageLenByType(msg[0]>>3)); - for (j = 0; j < MODES_LONG_MSG_BYTES; j++) - fprintf(fp,"\\x%02x",msg[j]); - fprintf(fp,"\"});\n"); - fclose(fp); -} -// -//========================================================================= -// -// This is a wrapper for dumpMagnitudeVector() that also show the message -// in hex format with an additional description. -// -// descr is the additional message to show to describe the dump. -// msg points to the decoded message -// m is the original magnitude vector -// offset is the offset where the message starts -// -// The function also produces the Javascript file used by debug.html to -// display packets in a graphical format if the Javascript output was -// enabled. -// -void dumpRawMessage(char *descr, unsigned char *msg, uint16_t *m, uint32_t offset) { - int j; - int msgtype = msg[0] >> 3; - int fixable = 0; - char bitpos[MODES_MAX_BITERRORS]; - - for (j = 0; j < MODES_MAX_BITERRORS; j++) { - bitpos[j] = -1; - } - if (msgtype == 17) { - fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, bitpos); - } - - if (Modes.debug & MODES_DEBUG_JS) { - dumpRawMessageJS(descr, msg, m, offset, fixable, bitpos); - return; - } - - printf("\n--- %s\n ", descr); - for (j = 0; j < MODES_LONG_MSG_BYTES; j++) { - printf("%02x",msg[j]); - if (j == MODES_SHORT_MSG_BYTES-1) printf(" ... "); - } - printf(" (DF %d, Fixable: %d)\n", msgtype, fixable); - dumpMagnitudeVector(m,offset); - printf("---\n\n"); -} //========================================================================= // // Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN @@ -1029,436 +903,6 @@ void computeMagnitudeVector(uint16_t *p) { } } -// -//========================================================================= -// -// Return -1 if the message is out of fase left-side -// Return 1 if the message is out of fase right-size -// Return 0 if the message is not particularly out of phase. -// -// Note: this function will access pPreamble[-1], so the caller should make sure to -// call it only if we are not at the start of the current buffer -// -int detectOutOfPhase(uint16_t *pPreamble) { - if (pPreamble[ 3] > pPreamble[2]/3) return 1; - if (pPreamble[10] > pPreamble[9]/3) return 1; - if (pPreamble[ 6] > pPreamble[7]/3) return -1; - if (pPreamble[-1] > pPreamble[1]/3) return -1; - return 0; -} - - -uint16_t clamped_scale(uint16_t v, uint16_t scale) { - uint32_t scaled = (uint32_t)v * scale / 16384; - if (scaled > 65535) return 65535; - return (uint16_t) scaled; -} -// This function decides whether we are sampling early or late, -// and by approximately how much, by looking at the energy in -// preamble bits before and after the expected pulse locations. -// -// It then deals with one sample pair at a time, comparing samples -// to make a decision about the bit value. Based on this decision it -// modifies the sample value of the *adjacent* sample which will -// contain some of the energy from the bit we just inspected. -// -// pPayload[0] should be the start of the preamble, -// pPayload[-1 .. MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] should be accessible. -// pPayload[MODES_PREAMBLE_SAMPLES .. MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] will be updated. -void applyPhaseCorrection(uint16_t *pPayload) { - int j; - - // we expect 1 bits at 0, 2, 7, 9 - // and 0 bits at -1, 1, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14 - // use bits -1,6 for early detection (bit 0/7 arrived a little early, our sample period starts after the bit phase so we include some of the next bit) - // use bits 3,10 for late detection (bit 2/9 arrived a little late, our sample period starts before the bit phase so we include some of the last bit) - - uint32_t onTime = (pPayload[0] + pPayload[2] + pPayload[7] + pPayload[9]); - uint32_t early = (pPayload[-1] + pPayload[6]) << 1; - uint32_t late = (pPayload[3] + pPayload[10]) << 1; - - if (onTime == 0 && early == 0 && late == 0) { - // Blah, can't do anything with this, avoid a divide-by-zero - return; - } - - if (early > late) { - // Our sample period starts late and so includes some of the next bit. - - uint16_t scaleUp = 16384 + 16384 * early / (early + onTime); // 1 + early / (early+onTime) - uint16_t scaleDown = 16384 - 16384 * early / (early + onTime); // 1 - early / (early+onTime) - - // trailing bits are 0; final data sample will be a bit low. - pPayload[MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1] = - clamped_scale(pPayload[MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 1], scaleUp); - for (j = MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 2; j > MODES_PREAMBLE_SAMPLES; j -= 2) { - if (pPayload[j] > pPayload[j+1]) { - // x [1 0] y - // x overlapped with the "1" bit and is slightly high - pPayload[j-1] = clamped_scale(pPayload[j-1], scaleDown); - } else { - // x [0 1] y - // x overlapped with the "0" bit and is slightly low - pPayload[j-1] = clamped_scale(pPayload[j-1], scaleUp); - } - } - } else { - // Our sample period starts early and so includes some of the previous bit. - - uint16_t scaleUp = 16384 + 16384 * late / (late + onTime); // 1 + late / (late+onTime) - uint16_t scaleDown = 16384 - 16384 * late / (late + onTime); // 1 - late / (late+onTime) - - // leading bits are 0; first data sample will be a bit low. - pPayload[MODES_PREAMBLE_SAMPLES] = clamped_scale(pPayload[MODES_PREAMBLE_SAMPLES], scaleUp); - for (j = MODES_PREAMBLE_SAMPLES; j < MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES - 2; j += 2) { - if (pPayload[j] > pPayload[j+1]) { - // x [1 0] y - // y overlapped with the "0" bit and is slightly low - pPayload[j+2] = clamped_scale(pPayload[j+2], scaleUp); - } else { - // x [0 1] y - // y overlapped with the "1" bit and is slightly high - pPayload[j+2] = clamped_scale(pPayload[j+2], scaleDown); - } - } - } -} -// -//========================================================================= -// -// Detect a Mode S messages inside the magnitude buffer pointed by 'm' and of -// size 'mlen' bytes. Every detected Mode S message is convert it into a -// stream of bits and passed to the function to display it. -// -void detectModeS(uint16_t *m, uint32_t mlen) { - struct modesMessage mm; - unsigned char msg[MODES_LONG_MSG_BYTES], *pMsg; - uint16_t aux[MODES_PREAMBLE_SAMPLES+MODES_LONG_MSG_SAMPLES+1]; - uint32_t j; - int use_correction = 0; - - memset(&mm, 0, sizeof(mm)); - - // The Mode S preamble is made of impulses of 0.5 microseconds at - // the following time offsets: - // - // 0 - 0.5 usec: first impulse. - // 1.0 - 1.5 usec: second impulse. - // 3.5 - 4 usec: third impulse. - // 4.5 - 5 usec: last impulse. - // - // Since we are sampling at 2 Mhz every sample in our magnitude vector - // is 0.5 usec, so the preamble will look like this, assuming there is - // an impulse at offset 0 in the array: - // - // 0 ----------------- - // 1 - - // 2 ------------------ - // 3 -- - // 4 - - // 5 -- - // 6 - - // 7 ------------------ - // 8 -- - // 9 ------------------- - // - for (j = 0; j < mlen; j++) { - int high, i, errors, errors56, errorsTy; - uint16_t *pPreamble, *pPayload, *pPtr; - uint8_t theByte, theErrs; - int msglen, scanlen; - uint32_t sigLevel, noiseLevel; - uint16_t snr; - - pPreamble = &m[j]; - pPayload = &m[j+MODES_PREAMBLE_SAMPLES]; - - // Rather than clear the whole mm structure, just clear the parts which are required. The clear - // is required for every bit of the input stream, and we don't want to be memset-ing the whole - // modesMessage structure two million times per second if we don't have to.. - mm.bFlags = - mm.crcok = - mm.correctedbits = 0; - - if (!use_correction) // This is not a re-try with phase correction - { // so try to find a new preamble - - if (Modes.mode_ac) - { - int ModeA = detectModeA(pPreamble, &mm); - - if (ModeA) // We have found a valid ModeA/C in the data - { - mm.timestampMsg = Modes.timestampBlk + ((j+1) * 6); - - // Decode the received message - decodeModeAMessage(&mm, ModeA); - - // Pass data to the next layer - useModesMessage(&mm); - - j += MODEAC_MSG_SAMPLES; - Modes.stat_ModeAC++; - continue; - } - } - - // First check of relations between the first 10 samples - // representing a valid preamble. We don't even investigate further - // if this simple test is not passed - if (!(pPreamble[0] > pPreamble[1] && - pPreamble[1] < pPreamble[2] && - pPreamble[2] > pPreamble[3] && - pPreamble[3] < pPreamble[0] && - pPreamble[4] < pPreamble[0] && - pPreamble[5] < pPreamble[0] && - pPreamble[6] < pPreamble[0] && - pPreamble[7] > pPreamble[8] && - pPreamble[8] < pPreamble[9] && - pPreamble[9] > pPreamble[6])) - { - if (Modes.debug & MODES_DEBUG_NOPREAMBLE && - *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) - dumpRawMessage("Unexpected ratio among first 10 samples", msg, m, j); - continue; - } - - // The samples between the two spikes must be < than the average - // of the high spikes level. We don't test bits too near to - // the high levels as signals can be out of phase so part of the - // energy can be in the near samples - high = (pPreamble[0] + pPreamble[2] + pPreamble[7] + pPreamble[9]) / 6; - if (pPreamble[4] >= high || - pPreamble[5] >= high) - { - if (Modes.debug & MODES_DEBUG_NOPREAMBLE && - *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) - dumpRawMessage("Too high level in samples between 3 and 6", msg, m, j); - continue; - } - - // Similarly samples in the range 11-14 must be low, as it is the - // space between the preamble and real data. Again we don't test - // bits too near to high levels, see above - if (pPreamble[11] >= high || - pPreamble[12] >= high || - pPreamble[13] >= high || - pPreamble[14] >= high) - { - if (Modes.debug & MODES_DEBUG_NOPREAMBLE && - *pPreamble > MODES_DEBUG_NOPREAMBLE_LEVEL) - dumpRawMessage("Too high level in samples between 10 and 15", msg, m, j); - continue; - } - Modes.stat_valid_preamble++; - } - - else { - // If the previous attempt with this message failed, retry using - // magnitude correction - // Make a copy of the Payload, and phase correct the copy - memcpy(aux, &pPreamble[-1], sizeof(aux)); - applyPhaseCorrection(&aux[1]); - Modes.stat_out_of_phase++; - pPayload = &aux[1 + MODES_PREAMBLE_SAMPLES]; - // TODO ... apply other kind of corrections - } - - // Decode all the next 112 bits, regardless of the actual message - // size. We'll check the actual message type later - pMsg = &msg[0]; - pPtr = pPayload; - theByte = 0; - theErrs = 0; errorsTy = 0; - errors = 0; errors56 = 0; - - // We should have 4 'bits' of 0/1 and 1/0 samples in the preamble, - // so include these in the signal strength - sigLevel = pPreamble[0] + pPreamble[2] + pPreamble[7] + pPreamble[9]; - noiseLevel = pPreamble[1] + pPreamble[3] + pPreamble[4] + pPreamble[6] + pPreamble[8]; - - msglen = scanlen = MODES_LONG_MSG_BITS; - for (i = 0; i < scanlen; i++) { - uint32_t a = *pPtr++; - uint32_t b = *pPtr++; - - if (a > b) - {theByte |= 1; if (i < 56) { sigLevel += a; noiseLevel += b; }} - else if (a < b) - {/*theByte |= 0;*/ if (i < 56) { sigLevel += b; noiseLevel += a; }} - else { - if (i < 56) { sigLevel += a; noiseLevel += a; } - if (i >= MODES_SHORT_MSG_BITS) //(a == b), and we're in the long part of a frame - {errors++; /*theByte |= 0;*/} - else if (i >= 5) //(a == b), and we're in the short part of a frame - {scanlen = MODES_LONG_MSG_BITS; errors56 = ++errors;/*theByte |= 0;*/} - else if (i) //(a == b), and we're in the message type part of a frame - {errorsTy = errors56 = ++errors; theErrs |= 1; /*theByte |= 0;*/} - else //(a == b), and we're in the first bit of the message type part of a frame - {errorsTy = errors56 = ++errors; theErrs |= 1; theByte |= 1;} - } - - if ((i & 7) == 7) - {*pMsg++ = theByte;} - else if (i == 4) { - msglen = modesMessageLenByType(theByte); - if (errors == 0) - {scanlen = msglen;} - } - - theByte = theByte << 1; - if (i < 7) - {theErrs = theErrs << 1;} - - // If we've exceeded the permissible number of encoding errors, abandon ship now - if (errors > MODES_MSG_ENCODER_ERRS) { - - if (i < MODES_SHORT_MSG_BITS) { - msglen = 0; - - } else if ((errorsTy == 1) && (theErrs == 0x80)) { - // If we only saw one error in the first bit of the byte of the frame, then it's possible - // we guessed wrongly about the value of the bit. We may be able to correct it by guessing - // the other way. - // - // We guessed a '1' at bit 7, which is the DF length bit == 112 Bits. - // Inverting bit 7 will change the message type from a long to a short. - // Invert the bit, cross your fingers and carry on. - msglen = MODES_SHORT_MSG_BITS; - msg[0] ^= theErrs; errorsTy = 0; - errors = errors56; // revert to the number of errors prior to bit 56 - Modes.stat_DF_Len_Corrected++; - - } else if (i < MODES_LONG_MSG_BITS) { - msglen = MODES_SHORT_MSG_BITS; - errors = errors56; - - } else { - msglen = MODES_LONG_MSG_BITS; - } - - break; - } - } - - // Ensure msglen is consistent with the DF type - if (msglen > 0) { - i = modesMessageLenByType(msg[0] >> 3); - if (msglen > i) {msglen = i;} - else if (msglen < i) {msglen = 0;} - } - - // - // If we guessed at any of the bits in the DF type field, then look to see if our guess was sensible. - // Do this by looking to see if the original guess results in the DF type being one of the ICAO defined - // message types. If it isn't then toggle the guessed bit and see if this new value is ICAO defined. - // if the new value is ICAO defined, then update it in our message. - if ((msglen) && (errorsTy == 1) && (theErrs & 0x78)) { - // We guessed at one (and only one) of the message type bits. See if our guess is "likely" - // to be correct by comparing the DF against a list of known good DF's - int thisDF = ((theByte = msg[0]) >> 3) & 0x1f; - uint32_t validDFbits = 0x017F0831; // One bit per 32 possible DF's. Set bits 0,4,5,11,16.17.18.19,20,21,22,24 - uint32_t thisDFbit = (1 << thisDF); - if (0 == (validDFbits & thisDFbit)) { - // The current DF is not ICAO defined, so is probably an errors. - // Toggle the bit we guessed at and see if the resultant DF is more likely - theByte ^= theErrs; - thisDF = (theByte >> 3) & 0x1f; - thisDFbit = (1 << thisDF); - // if this DF any more likely? - if (validDFbits & thisDFbit) { - // Yep, more likely, so update the main message - msg[0] = theByte; - Modes.stat_DF_Type_Corrected++; - errors--; // decrease the error count so we attempt to use the modified DF. - } - } - } - - // snr = 5 * 20log10(sigLevel / noiseLevel) (in units of 0.2dB) - // = 100log10(sigLevel) - 100log10(noiseLevel) - - while (sigLevel > 65535 || noiseLevel > 65535) { - sigLevel >>= 1; - noiseLevel >>= 1; - } - snr = Modes.log10lut[sigLevel] - Modes.log10lut[noiseLevel]; - - // When we reach this point, if error is small, and the signal strength is large enough - // we may have a Mode S message on our hands. It may still be broken and the CRC may not - // be correct, but this can be handled by the next layer. - if ( (msglen) - && ((2 * snr) > (int) (MODES_MSG_SQUELCH_DB * 10)) - && (errors <= MODES_MSG_ENCODER_ERRS) ) { - // Set initial mm structure details - mm.timestampMsg = Modes.timestampBlk + (j*6); - mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr); - mm.phase_corrected = use_correction; - - // Decode the received message - decodeModesMessage(&mm, msg); - - // Update statistics - if (Modes.stats) { - struct demod_stats *dstats = (use_correction ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod); - - switch (errors) { - case 0: dstats->demodulated0++; break; - case 1: dstats->demodulated1++; break; - case 2: dstats->demodulated2++; break; - default: dstats->demodulated3++; break; - } - - if (mm.crcok) { - dstats->goodcrc++; - dstats->goodcrc_byphase[0]++; - } else if (mm.correctedbits > 0) { - dstats->badcrc++; - dstats->fixed++; - if (mm.correctedbits <= MODES_MAX_BITERRORS) - dstats->bit_fix[mm.correctedbits-1] += 1; - } else { - dstats->badcrc++; - } - } - - // Output debug mode info if needed - if (use_correction) { - if (Modes.debug & MODES_DEBUG_DEMOD) - dumpRawMessage("Demodulated with 0 errors", msg, m, j); - else if (Modes.debug & MODES_DEBUG_BADCRC && - mm.msgtype == 17 && - (!mm.crcok || mm.correctedbits != 0)) - dumpRawMessage("Decoded with bad CRC", msg, m, j); - else if (Modes.debug & MODES_DEBUG_GOODCRC && mm.crcok && - mm.correctedbits == 0) - dumpRawMessage("Decoded with good CRC", msg, m, j); - } - - // Skip this message if we are sure it's fine - if (mm.crcok || mm.correctedbits) { - j += (MODES_PREAMBLE_US+msglen)*2 - 1; - } - - // Pass data to the next layer - useModesMessage(&mm); - - } else { - if (Modes.debug & MODES_DEBUG_DEMODERR && use_correction) { - printf("The following message has %d demod errors\n", errors); - dumpRawMessage("Demodulated with errors", msg, m, j); - } - } - - // Retry with phase correction if enabled, necessary and possible. - if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) { - use_correction = 1; j--; - } else { - use_correction = 0; - } - } -} - // 2.4MHz sampling rate version // // When sampling at 2.4MHz we have exactly 6 samples per 5 symbols.