First cut for sampling at 2.4MHz + phase detection.
This commit is contained in:
parent
4cf07536be
commit
5c8e6198b7
14
dump1090.c
14
dump1090.c
|
@ -94,9 +94,10 @@ void modesInit(void) {
|
||||||
pthread_cond_init(&Modes.data_cond,NULL);
|
pthread_cond_init(&Modes.data_cond,NULL);
|
||||||
|
|
||||||
// Allocate the various buffers used by Modes
|
// Allocate the various buffers used by Modes
|
||||||
|
Modes.trailing_space = Modes.oversample ? (MODES_OS_PREAMBLE_SIZE + MODES_OS_LONG_MSG_SIZE) : (MODES_PREAMBLE_SIZE + MODES_LONG_MSG_SIZE);
|
||||||
if ( ((Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2) ) == NULL) ||
|
if ( ((Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2) ) == NULL) ||
|
||||||
((Modes.pFileData = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
|
((Modes.pFileData = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
|
||||||
((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) ||
|
((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+Modes.trailing_space) ) == NULL) ||
|
||||||
((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
||||||
((Modes.log10lut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
((Modes.log10lut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
||||||
((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ||
|
((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ||
|
||||||
|
@ -109,7 +110,7 @@ void modesInit(void) {
|
||||||
// Clear the buffers that have just been allocated, just in-case
|
// Clear the buffers that have just been allocated, just in-case
|
||||||
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
|
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
|
||||||
memset(Modes.pFileData,127, MODES_ASYNC_BUF_SIZE);
|
memset(Modes.pFileData,127, MODES_ASYNC_BUF_SIZE);
|
||||||
memset(Modes.magnitude, 0, MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE);
|
memset(Modes.magnitude, 0, MODES_ASYNC_BUF_SIZE+Modes.trailing_space);
|
||||||
|
|
||||||
// Validate the users Lat/Lon home location inputs
|
// Validate the users Lat/Lon home location inputs
|
||||||
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|
||||||
|
@ -244,7 +245,8 @@ void modesInitRTLSDR(void) {
|
||||||
rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
|
rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
|
||||||
if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
|
if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
|
||||||
rtlsdr_set_center_freq(Modes.dev, Modes.freq);
|
rtlsdr_set_center_freq(Modes.dev, Modes.freq);
|
||||||
rtlsdr_set_sample_rate(Modes.dev, MODES_DEFAULT_RATE);
|
rtlsdr_set_sample_rate(Modes.dev, Modes.oversample ? MODES_OVERSAMPLE_RATE : MODES_DEFAULT_RATE);
|
||||||
|
|
||||||
rtlsdr_reset_buffer(Modes.dev);
|
rtlsdr_reset_buffer(Modes.dev);
|
||||||
fprintf(stderr, "Gain reported by device: %.2f\n",
|
fprintf(stderr, "Gain reported by device: %.2f\n",
|
||||||
rtlsdr_get_tuner_gain(Modes.dev)/10.0);
|
rtlsdr_get_tuner_gain(Modes.dev)/10.0);
|
||||||
|
@ -786,6 +788,9 @@ int main(int argc, char **argv) {
|
||||||
Modes.interactive_rtl1090 = 1;
|
Modes.interactive_rtl1090 = 1;
|
||||||
} else if (!strcmp(argv[j],"--no-decode")) {
|
} else if (!strcmp(argv[j],"--no-decode")) {
|
||||||
Modes.no_decode = 1;
|
Modes.no_decode = 1;
|
||||||
|
} else if (!strcmp(argv[j],"--oversample")) {
|
||||||
|
Modes.oversample = 1;
|
||||||
|
fprintf(stderr, "Oversampling enabled. Be very afraid.\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Unknown or not enough arguments for option '%s'.\n\n",
|
"Unknown or not enough arguments for option '%s'.\n\n",
|
||||||
|
@ -892,6 +897,9 @@ int main(int argc, char **argv) {
|
||||||
// Process data after releasing the lock, so that the capturing
|
// Process data after releasing the lock, so that the capturing
|
||||||
// thread can read data while we perform computationally expensive
|
// thread can read data while we perform computationally expensive
|
||||||
// stuff at the same time.
|
// stuff at the same time.
|
||||||
|
if (Modes.oversample)
|
||||||
|
detectModeS_oversample(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES);
|
||||||
|
else
|
||||||
detectModeS(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES);
|
detectModeS(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES);
|
||||||
|
|
||||||
// Update the timestamp ready for the next block
|
// Update the timestamp ready for the next block
|
||||||
|
|
12
dump1090.h
12
dump1090.h
|
@ -80,6 +80,7 @@
|
||||||
|
|
||||||
#define MODES_DEFAULT_PPM 52
|
#define MODES_DEFAULT_PPM 52
|
||||||
#define MODES_DEFAULT_RATE 2000000
|
#define MODES_DEFAULT_RATE 2000000
|
||||||
|
#define MODES_OVERSAMPLE_RATE 2400000
|
||||||
#define MODES_DEFAULT_FREQ 1090000000
|
#define MODES_DEFAULT_FREQ 1090000000
|
||||||
#define MODES_DEFAULT_WIDTH 1000
|
#define MODES_DEFAULT_WIDTH 1000
|
||||||
#define MODES_DEFAULT_HEIGHT 700
|
#define MODES_DEFAULT_HEIGHT 700
|
||||||
|
@ -116,6 +117,13 @@
|
||||||
#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
|
#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
|
#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
|
||||||
|
#define MODES_OS_PREAMBLE_SAMPLES (20)
|
||||||
|
#define MODES_OS_PREAMBLE_SIZE (MODES_OS_PREAMBLE_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_OS_LONG_MSG_SAMPLES (268)
|
||||||
|
#define MODES_OS_SHORT_MSG_SAMPLES (135)
|
||||||
|
#define MODES_OS_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
#define MODES_OS_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t))
|
||||||
|
|
||||||
#define MODES_RAWOUT_BUF_SIZE (1500)
|
#define MODES_RAWOUT_BUF_SIZE (1500)
|
||||||
#define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200)
|
#define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200)
|
||||||
#define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx
|
#define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx
|
||||||
|
@ -250,6 +258,8 @@ struct { // Internal state
|
||||||
int iDataReady; // Fifo content count
|
int iDataReady; // Fifo content count
|
||||||
int iDataLost; // Count of missed buffers
|
int iDataLost; // Count of missed buffers
|
||||||
|
|
||||||
|
int trailing_space; // extra trailing space needed by magnitude buffer
|
||||||
|
|
||||||
uint16_t *pFileData; // Raw IQ samples buffer (from a File)
|
uint16_t *pFileData; // Raw IQ samples buffer (from a File)
|
||||||
uint16_t *magnitude; // Magnitude vector
|
uint16_t *magnitude; // Magnitude vector
|
||||||
uint64_t timestampBlk; // Timestamp of the start of the current block
|
uint64_t timestampBlk; // Timestamp of the start of the current block
|
||||||
|
@ -287,6 +297,7 @@ struct { // Internal state
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
char *filename; // Input form file, --ifile option
|
char *filename; // Input form file, --ifile option
|
||||||
|
int oversample;
|
||||||
int phase_enhance; // Enable phase enhancement if true
|
int phase_enhance; // Enable phase enhancement if true
|
||||||
int nfix_crc; // Number of crc bit error(s) to correct
|
int nfix_crc; // Number of crc bit error(s) to correct
|
||||||
int check_crc; // Only display messages with good CRC
|
int check_crc; // Only display messages with good CRC
|
||||||
|
@ -434,6 +445,7 @@ int ModeAToModeC (unsigned int ModeA);
|
||||||
// Functions exported from mode_s.c
|
// Functions exported from mode_s.c
|
||||||
//
|
//
|
||||||
void detectModeS (uint16_t *m, uint32_t mlen);
|
void detectModeS (uint16_t *m, uint32_t mlen);
|
||||||
|
void detectModeS_oversample (uint16_t *m, uint32_t mlen);
|
||||||
void decodeModesMessage (struct modesMessage *mm, unsigned char *msg);
|
void decodeModesMessage (struct modesMessage *mm, unsigned char *msg);
|
||||||
void displayModesMessage(struct modesMessage *mm);
|
void displayModesMessage(struct modesMessage *mm);
|
||||||
void useModesMessage (struct modesMessage *mm);
|
void useModesMessage (struct modesMessage *mm);
|
||||||
|
|
401
mode_s.c
401
mode_s.c
|
@ -1439,10 +1439,10 @@ void displayModesMessage(struct modesMessage *mm) {
|
||||||
// pointed by Modes.magnitude.
|
// pointed by Modes.magnitude.
|
||||||
//
|
//
|
||||||
void computeMagnitudeVector(uint16_t *p) {
|
void computeMagnitudeVector(uint16_t *p) {
|
||||||
uint16_t *m = &Modes.magnitude[MODES_PREAMBLE_SAMPLES+MODES_LONG_MSG_SAMPLES];
|
uint16_t *m = &Modes.magnitude[Modes.trailing_space];
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
|
|
||||||
memcpy(Modes.magnitude,&Modes.magnitude[MODES_ASYNC_BUF_SAMPLES], MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE);
|
memcpy(Modes.magnitude,&Modes.magnitude[MODES_ASYNC_BUF_SAMPLES], Modes.trailing_space);
|
||||||
|
|
||||||
// Compute the magnitudo vector. It's just SQRT(I^2 + Q^2), but
|
// Compute the magnitudo vector. It's just SQRT(I^2 + Q^2), but
|
||||||
// we rescale to the 0-255 range to exploit the full resolution.
|
// we rescale to the 0-255 range to exploit the full resolution.
|
||||||
|
@ -1450,6 +1450,7 @@ void computeMagnitudeVector(uint16_t *p) {
|
||||||
*m++ = Modes.maglut[*p++];
|
*m++ = Modes.maglut[*p++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
//
|
//
|
||||||
|
@ -1933,6 +1934,402 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
||||||
Modes.net_heartbeat_count = 0;
|
Modes.net_heartbeat_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2.4MHz sampling rate version
|
||||||
|
//
|
||||||
|
// When sampling at 2.4MHz we have exactly 6 samples per 5 symbols.
|
||||||
|
// Each symbol is 500ns wide, each sample is 416.7ns wide
|
||||||
|
//
|
||||||
|
// We maintain a phase offset that is expressed in units of 1/5 of a sample i.e. 1/6 of a symbol, 83.333ns
|
||||||
|
// Each symbol we process advances the phase offset by 6 i.e. 6/5 of a sample, 500ns
|
||||||
|
//
|
||||||
|
// The correlation functions below correlate a 1-0 pair of symbols (i.e. manchester encoded 1 bit)
|
||||||
|
// starting at the given sample, and assuming that the symbol starts at a fixed 0-5 phase offset within
|
||||||
|
// m[0]. They return a correlation value, generally interpreted as >0 = 1 bit, <0 = 0 bit
|
||||||
|
|
||||||
|
static inline int correlate_phase0(uint16_t *m) {
|
||||||
|
return 5 * m[0] - 3 * m[1] - 2 * m[2];
|
||||||
|
}
|
||||||
|
static inline int correlate_phase1(uint16_t *m) {
|
||||||
|
return 4 * m[0] - 1 * m[1] - 3 * m[2];
|
||||||
|
}
|
||||||
|
static inline int correlate_phase2(uint16_t *m) {
|
||||||
|
return 3 * m[0] + 1 * m[1] - 4 * m[2];
|
||||||
|
}
|
||||||
|
static inline int correlate_phase3(uint16_t *m) {
|
||||||
|
return 2 * m[0] + 3 * m[1] - 5 * m[2];
|
||||||
|
}
|
||||||
|
static inline int correlate_phase4(uint16_t *m) {
|
||||||
|
return 1 * m[0] + 5 * m[1] - 5 * m[2] + 1 * m[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// These functions work out the correlation quality for the 10 symbols (5 bits) starting at m[0] + given phase offset.
|
||||||
|
// This is used to find the right phase offset to use for decoding.
|
||||||
|
//
|
||||||
|
|
||||||
|
static inline int correlate_check_0(uint16_t *m) {
|
||||||
|
return
|
||||||
|
abs(correlate_phase0(&m[0])) +
|
||||||
|
abs(correlate_phase2(&m[2])) +
|
||||||
|
abs(correlate_phase4(&m[4])) +
|
||||||
|
abs(correlate_phase1(&m[7])) +
|
||||||
|
abs(correlate_phase3(&m[9]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int correlate_check_1(uint16_t *m) {
|
||||||
|
return
|
||||||
|
abs(correlate_phase1(&m[0])) +
|
||||||
|
abs(correlate_phase3(&m[2])) +
|
||||||
|
abs(correlate_phase0(&m[5])) +
|
||||||
|
abs(correlate_phase2(&m[7])) +
|
||||||
|
abs(correlate_phase4(&m[9]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int correlate_check_2(uint16_t *m) {
|
||||||
|
return
|
||||||
|
abs(correlate_phase2(&m[0])) +
|
||||||
|
abs(correlate_phase4(&m[2])) +
|
||||||
|
abs(correlate_phase1(&m[5])) +
|
||||||
|
abs(correlate_phase3(&m[7])) +
|
||||||
|
abs(correlate_phase0(&m[10]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int correlate_check_3(uint16_t *m) {
|
||||||
|
return
|
||||||
|
abs(correlate_phase3(&m[0])) +
|
||||||
|
abs(correlate_phase0(&m[3])) +
|
||||||
|
abs(correlate_phase2(&m[5])) +
|
||||||
|
abs(correlate_phase4(&m[7])) +
|
||||||
|
abs(correlate_phase1(&m[10]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int correlate_check_4(uint16_t *m) {
|
||||||
|
return
|
||||||
|
abs(correlate_phase4(&m[0])) +
|
||||||
|
abs(correlate_phase1(&m[3])) +
|
||||||
|
abs(correlate_phase3(&m[5])) +
|
||||||
|
abs(correlate_phase0(&m[8])) +
|
||||||
|
abs(correlate_phase2(&m[10]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Work out the best phase offset to use for the given message.
|
||||||
|
// Note that the message may start at anywhere between
|
||||||
|
// m[19] offset 1 and m[20] offset 0
|
||||||
|
static int best_phase(uint16_t *m) {
|
||||||
|
int test;
|
||||||
|
int best = -1;
|
||||||
|
int bestval = 50; // minimum correlation quality we will accept
|
||||||
|
|
||||||
|
// look at the first 5 bits with each possible phase
|
||||||
|
test = correlate_check_1(&m[19]);
|
||||||
|
if (test > bestval) { bestval = test; best = 1; }
|
||||||
|
test = correlate_check_2(&m[19]);
|
||||||
|
if (test > bestval) { bestval = test; best = 2; }
|
||||||
|
test = correlate_check_3(&m[19]);
|
||||||
|
if (test > bestval) { bestval = test; best = 3; }
|
||||||
|
test = correlate_check_4(&m[19]);
|
||||||
|
if (test > bestval) { bestval = test; best = 4; }
|
||||||
|
test = correlate_check_0(&m[20]);
|
||||||
|
if (test > bestval) { best = 5; }
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
//
|
||||||
|
// 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_oversample(uint16_t *m, uint32_t mlen) {
|
||||||
|
struct modesMessage mm;
|
||||||
|
unsigned char msg[MODES_LONG_MSG_BYTES], *pMsg;
|
||||||
|
uint32_t j;
|
||||||
|
|
||||||
|
memset(&mm, 0, sizeof(mm));
|
||||||
|
|
||||||
|
for (j = 0; j < mlen; j++) {
|
||||||
|
uint16_t *preamble = &m[j];
|
||||||
|
int high, i, phase, errors, errors56, errorsTy;
|
||||||
|
int msglen, scanlen;
|
||||||
|
uint16_t *pPtr;
|
||||||
|
uint8_t theByte, theErrs;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Look for a message starting at sample 1 with phase offset 0-4
|
||||||
|
|
||||||
|
// Check for peaks at (1,12) or (3,9)
|
||||||
|
if (preamble[1] > preamble[0] &&
|
||||||
|
preamble[1] > preamble[2] &&
|
||||||
|
preamble[12] > preamble[11] &&
|
||||||
|
preamble[12] > preamble[13]) {
|
||||||
|
high = (preamble[1] + preamble[13]) / 2;
|
||||||
|
} else if (preamble[3] > preamble[2] &&
|
||||||
|
preamble[3] > preamble[4] &&
|
||||||
|
preamble[9] > preamble[8] &&
|
||||||
|
preamble[9] > preamble[10]) {
|
||||||
|
high = (preamble[1] + preamble[9]) / 2;
|
||||||
|
} else {
|
||||||
|
// No peaks
|
||||||
|
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
|
||||||
|
if (preamble[5] >= high ||
|
||||||
|
preamble[6] >= high ||
|
||||||
|
preamble[7] >= high ||
|
||||||
|
preamble[14] >= high ||
|
||||||
|
preamble[15] >= high ||
|
||||||
|
preamble[16] >= high ||
|
||||||
|
preamble[17] >= high ||
|
||||||
|
preamble[18] >= high)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Crosscorrelate against the first few bits to find a likely phase offset
|
||||||
|
phase = best_phase(preamble);
|
||||||
|
if (phase < 0) {
|
||||||
|
continue; // nothing satisfactory
|
||||||
|
}
|
||||||
|
|
||||||
|
Modes.stat_valid_preamble++;
|
||||||
|
|
||||||
|
// Decode all the next 112 bits, regardless of the actual message
|
||||||
|
// size. We'll check the actual message type later
|
||||||
|
|
||||||
|
pMsg = &msg[0];
|
||||||
|
pPtr = &m[j+19];
|
||||||
|
if (phase == 5) {
|
||||||
|
++pPtr;
|
||||||
|
phase = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
theByte = 0;
|
||||||
|
theErrs = 0; errorsTy = 0;
|
||||||
|
errors = 0; errors56 = 0;
|
||||||
|
msglen = scanlen = MODES_LONG_MSG_BITS;
|
||||||
|
for (i = 0; i < scanlen; i++) {
|
||||||
|
int test;
|
||||||
|
|
||||||
|
switch (phase) {
|
||||||
|
case 0:
|
||||||
|
test = correlate_phase0(pPtr);
|
||||||
|
phase = 2;
|
||||||
|
pPtr += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
test = correlate_phase1(pPtr);
|
||||||
|
phase = 3;
|
||||||
|
pPtr += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
test = correlate_phase2(pPtr);
|
||||||
|
phase = 4;
|
||||||
|
pPtr += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
test = correlate_phase3(pPtr);
|
||||||
|
phase = 0;
|
||||||
|
pPtr += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
test = correlate_phase4(pPtr);
|
||||||
|
phase = 1;
|
||||||
|
pPtr += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
test = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test > 10)
|
||||||
|
theByte |= 1;
|
||||||
|
else if (test >= -10) {
|
||||||
|
if (test > 0)
|
||||||
|
theByte |= 1; // best guess
|
||||||
|
|
||||||
|
if (i >= MODES_SHORT_MSG_BITS) { // poor correlation, and we're in the long part of a frame
|
||||||
|
errors++;
|
||||||
|
} else if (i >= 5) { // poor correlation, and we're in the short part of a frame
|
||||||
|
scanlen = MODES_LONG_MSG_BITS;
|
||||||
|
errors56 = ++errors;
|
||||||
|
} else if (i) { // poor correlation, and we're in the message type part of a frame
|
||||||
|
errorsTy = errors56 = ++errors;
|
||||||
|
theErrs |= 1;
|
||||||
|
} else { // poor correlation, and we're in the first bit of the message type part of a frame
|
||||||
|
errorsTy = errors56 = ++errors;
|
||||||
|
theErrs |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i & 7) == 7)
|
||||||
|
*pMsg++ = theByte;
|
||||||
|
|
||||||
|
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
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 > 0) && (errors <= MODES_MSG_ENCODER_ERRS) ) {
|
||||||
|
// Set initial mm structure details
|
||||||
|
mm.timestampMsg = Modes.timestampBlk + (j*5);
|
||||||
|
mm.signalLevel = 0;
|
||||||
|
mm.phase_corrected = 0;
|
||||||
|
|
||||||
|
//dumpRawMessage("decoded with oversampling", msg, m, j);
|
||||||
|
|
||||||
|
// Decode the received message
|
||||||
|
decodeModesMessage(&mm, msg);
|
||||||
|
|
||||||
|
// Update statistics
|
||||||
|
if (Modes.stats) {
|
||||||
|
if (mm.crcok || mm.correctedbits) {
|
||||||
|
switch (errors) {
|
||||||
|
case 0: {Modes.stat_demodulated0++; break;}
|
||||||
|
case 1: {Modes.stat_demodulated1++; break;}
|
||||||
|
case 2: {Modes.stat_demodulated2++; break;}
|
||||||
|
default:{Modes.stat_demodulated3++; break;}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm.correctedbits == 0) {
|
||||||
|
if (mm.crcok) {Modes.stat_goodcrc++;}
|
||||||
|
else {Modes.stat_badcrc++;}
|
||||||
|
} else {
|
||||||
|
Modes.stat_badcrc++;
|
||||||
|
Modes.stat_fixed++;
|
||||||
|
if ( (mm.correctedbits)
|
||||||
|
&& (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
|
||||||
|
Modes.stat_bit_fix[mm.correctedbits-1] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip this message if we are sure it's fine
|
||||||
|
if (mm.crcok) {
|
||||||
|
j += (16+msglen)*6/5 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass data to the next layer
|
||||||
|
useModesMessage(&mm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send any remaining partial raw buffers now
|
||||||
|
if (Modes.rawOutUsed || Modes.beastOutUsed)
|
||||||
|
{
|
||||||
|
Modes.net_output_raw_rate_count++;
|
||||||
|
if (Modes.net_output_raw_rate_count > Modes.net_output_raw_rate)
|
||||||
|
{
|
||||||
|
if (Modes.rawOutUsed) {
|
||||||
|
modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed);
|
||||||
|
Modes.rawOutUsed = 0;
|
||||||
|
}
|
||||||
|
if (Modes.beastOutUsed) {
|
||||||
|
modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed);
|
||||||
|
Modes.beastOutUsed = 0;
|
||||||
|
}
|
||||||
|
Modes.net_output_raw_rate_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( (Modes.net)
|
||||||
|
&& (Modes.net_heartbeat_rate)
|
||||||
|
&& ((++Modes.net_heartbeat_count) > Modes.net_heartbeat_rate) ) {
|
||||||
|
//
|
||||||
|
// We haven't received any Mode A/C/S messages for some time. To try and keep any TCP
|
||||||
|
// links alive, send a null frame. This will help stop any routers discarding our TCP
|
||||||
|
// link which will cause an un-recoverable link error if/when a real frame arrives.
|
||||||
|
//
|
||||||
|
// Fudge up a null message
|
||||||
|
memset(&mm, 0, sizeof(mm));
|
||||||
|
mm.msgbits = MODES_SHORT_MSG_BITS;
|
||||||
|
mm.timestampMsg = Modes.timestampBlk;
|
||||||
|
|
||||||
|
// Feed output clients
|
||||||
|
modesQueueOutput(&mm);
|
||||||
|
|
||||||
|
// Reset the heartbeat counter
|
||||||
|
Modes.net_heartbeat_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue