Merge pull request #8 from MalcolmRobb/master
Pulling in from MalcomRobb's Master
This commit is contained in:
commit
b0e0f96c94
345
dump1090.c
345
dump1090.c
|
@ -56,7 +56,7 @@
|
|||
// MinorVer changes when additional features are added, but not for bug fixes (range 00-99)
|
||||
// DayDate & Year changes for all changes, including for bug fixes. It represent the release date of the update
|
||||
//
|
||||
#define MODES_DUMP1090_VERSION "1.06.1405.13"
|
||||
#define MODES_DUMP1090_VERSION "1.06.2205.13"
|
||||
#define MODES_USER_LATITUDE_DFLT (0.0)
|
||||
#define MODES_USER_LONGITUDE_DFLT (0.0)
|
||||
|
||||
|
@ -227,6 +227,7 @@ struct {
|
|||
|
||||
/* Configuration */
|
||||
char *filename; /* Input form file, --ifile option. */
|
||||
int phase_enhance; /* Enable phase enhancement if true */
|
||||
int fix_errors; /* Single bit error correction if true. */
|
||||
int check_crc; /* Only display messages with good CRC. */
|
||||
int raw; /* Raw output format. */
|
||||
|
@ -264,7 +265,10 @@ struct {
|
|||
|
||||
/* Statistics */
|
||||
unsigned int stat_valid_preamble;
|
||||
unsigned int stat_demodulated;
|
||||
unsigned int stat_demodulated0;
|
||||
unsigned int stat_demodulated1;
|
||||
unsigned int stat_demodulated2;
|
||||
unsigned int stat_demodulated3;
|
||||
unsigned int stat_goodcrc;
|
||||
unsigned int stat_badcrc;
|
||||
unsigned int stat_fixed;
|
||||
|
@ -273,6 +277,15 @@ struct {
|
|||
unsigned int stat_http_requests;
|
||||
unsigned int stat_sbs_connections;
|
||||
unsigned int stat_out_of_phase;
|
||||
unsigned int stat_ph_demodulated0;
|
||||
unsigned int stat_ph_demodulated1;
|
||||
unsigned int stat_ph_demodulated2;
|
||||
unsigned int stat_ph_demodulated3;
|
||||
unsigned int stat_ph_goodcrc;
|
||||
unsigned int stat_ph_badcrc;
|
||||
unsigned int stat_ph_fixed;
|
||||
unsigned int stat_ph_single_bit_fix;
|
||||
unsigned int stat_ph_two_bits_fix;
|
||||
unsigned int stat_DF_Len_Corrected;
|
||||
unsigned int stat_DF_Type_Corrected;
|
||||
unsigned int stat_ModeAC;
|
||||
|
@ -296,7 +309,7 @@ struct modesMessage {
|
|||
int ca; // Responder capabilities
|
||||
int iid;
|
||||
|
||||
// DF 17
|
||||
// DF 17, DF 18
|
||||
int metype; // Extended squitter message type.
|
||||
int mesub; // Extended squitter message subtype.
|
||||
int heading; // Reported by aircraft, or computed from from EW and NS velocity
|
||||
|
@ -347,6 +360,7 @@ static uint64_t mstime(void) {
|
|||
|
||||
void sigintHandler(int dummy) {
|
||||
MODES_NOTUSED(dummy);
|
||||
signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
|
||||
Modes.exit = 1; // Signal to threads that we are done
|
||||
}
|
||||
|
||||
|
@ -549,6 +563,7 @@ void readDataFromFile(void) {
|
|||
ssize_t nread, toread;
|
||||
unsigned char *p;
|
||||
|
||||
if (Modes.exit == 1) break;
|
||||
if (Modes.data_ready) {
|
||||
pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex);
|
||||
continue;
|
||||
|
@ -596,7 +611,11 @@ void *readerThreadEntryPoint(void *arg) {
|
|||
} else {
|
||||
readDataFromFile();
|
||||
}
|
||||
return NULL;
|
||||
/* Signal to the other thread that new data is ready - dummy really so threads don't mutually lock */
|
||||
Modes.data_ready = 1;
|
||||
pthread_cond_signal(&Modes.data_cond);
|
||||
pthread_mutex_unlock(&Modes.data_mutex);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* ============================== Debugging ================================= */
|
||||
|
@ -992,7 +1011,6 @@ int detectModeA(uint16_t *m, struct modesMessage *mm)
|
|||
if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) )
|
||||
{return (ModeABits = 0);}
|
||||
|
||||
memset(mm, 0, sizeof(*mm));
|
||||
fSig = (fSig + 0x7F) >> 8;
|
||||
mm->signalLevel = ((fSig < 255) ? fSig : 255);
|
||||
|
||||
|
@ -1109,16 +1127,20 @@ uint32_t modesChecksum(unsigned char *msg, int bits) {
|
|||
uint32_t * pCRCTable = &modes_checksum_table[offset];
|
||||
int j;
|
||||
|
||||
// We don't really need to include the checksum itself
|
||||
bits -= 24;
|
||||
for(j = 0; j < bits; j++) {
|
||||
if ((j & 7) == 0)
|
||||
{theByte = *msg++; rem = (rem << 8) | theByte;}
|
||||
theByte = *msg++;
|
||||
|
||||
// If bit is set, xor with corresponding table entry.
|
||||
if (theByte & 0x80) {crc ^= *pCRCTable;}
|
||||
pCRCTable++;
|
||||
theByte = theByte << 1;
|
||||
}
|
||||
return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum.
|
||||
|
||||
rem = (msg[0] << 16) | (msg[1] << 8) | msg[2]; // message checksum
|
||||
return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum syndrome.
|
||||
}
|
||||
//
|
||||
// Given the Downlink Format (DF) of the message, return the message length in bits.
|
||||
|
@ -1258,28 +1280,24 @@ void modesInitErrorInfo() {
|
|||
uint32_t crc;
|
||||
n = 0;
|
||||
memset(bitErrorTable, 0, sizeof(bitErrorTable));
|
||||
/* First, insert infos about all possible single bit errors */
|
||||
for (i = 0; i < MODES_LONG_MSG_BITS; i++) {
|
||||
int bytepos = (i >> 3);
|
||||
int mask = 1 << (7 - (i & 7));
|
||||
memset(msg, 0, MODES_LONG_MSG_BYTES);
|
||||
msg[bytepos] ^= mask;
|
||||
// Add all possible single and double bit errors
|
||||
// don't include errors in first 5 bits (DF type)
|
||||
for (i = 5; i < MODES_LONG_MSG_BITS; i++) {
|
||||
int bytepos0 = (i >> 3);
|
||||
int mask0 = 1 << (7 - (i & 7));
|
||||
msg[bytepos0] ^= mask0; // create error0
|
||||
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
|
||||
bitErrorTable[n].syndrome = crc;
|
||||
bitErrorTable[n].syndrome = crc; // single bit error case
|
||||
bitErrorTable[n].pos0 = i;
|
||||
bitErrorTable[n].pos1 = -1;
|
||||
n += 1;
|
||||
}
|
||||
/* Add also all double bit errors */
|
||||
for (i = 0; i < MODES_LONG_MSG_BITS; i++) {
|
||||
int bytepos0 = (i >> 3);
|
||||
int mask0 = 1 << (7 - (i & 7));
|
||||
memset(msg, 0, MODES_LONG_MSG_BYTES);
|
||||
msg[bytepos0] ^= mask0;
|
||||
|
||||
if (Modes.aggressive) {
|
||||
for (j = i+1; j < MODES_LONG_MSG_BITS; j++) {
|
||||
int bytepos1 = (j >> 3);
|
||||
int mask1 = 1 << (7 - (j & 7));
|
||||
msg[bytepos1] ^= mask1;
|
||||
msg[bytepos1] ^= mask1; // create error1
|
||||
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
|
||||
if (n >= NERRORINFO) {
|
||||
/*
|
||||
|
@ -1289,12 +1307,15 @@ void modesInitErrorInfo() {
|
|||
*/
|
||||
break;
|
||||
}
|
||||
bitErrorTable[n].syndrome = crc;
|
||||
bitErrorTable[n].syndrome = crc; // two bit error case
|
||||
bitErrorTable[n].pos0 = i;
|
||||
bitErrorTable[n].pos1 = j;
|
||||
n += 1;
|
||||
msg[bytepos1] ^= mask1; // revert error1
|
||||
}
|
||||
}
|
||||
msg[bytepos0] ^= mask0; // revert error0
|
||||
}
|
||||
qsort(bitErrorTable, NERRORINFO,
|
||||
sizeof(struct errorinfo), cmpErrorInfo);
|
||||
/* Test code: report if any syndrome appears at least twice. In this
|
||||
|
@ -1319,10 +1340,10 @@ void modesInitErrorInfo() {
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* Flip a bit, but make sure that the DF field (first 5 bits)
|
||||
* is never changed
|
||||
*/
|
||||
//
|
||||
// Flip a bit, but make sure that the DF field (first 5 bits)
|
||||
// is never changed
|
||||
/*
|
||||
int flipBit(unsigned char *msg, int nbits, int bit) {
|
||||
int bytepos, mask;
|
||||
if ((bit < 0) || (bit >= nbits)) {
|
||||
|
@ -1336,12 +1357,12 @@ int flipBit(unsigned char *msg, int nbits, int bit) {
|
|||
msg[bytepos] ^= mask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Search syndrome in table and, if an entry is found, flip the necessary
|
||||
* bits. Make sure the indices fit into the array, and for 2-bit errors,
|
||||
* are different.
|
||||
* Return number of fixed bits.
|
||||
*/
|
||||
// Search syndrome in table and, if an entry is found, flip the necessary
|
||||
// bits. Make sure the indices fit into the array, and for 2-bit errors,
|
||||
// are different.
|
||||
// Return number of fixed bits.
|
||||
//
|
||||
int fixBitErrors(unsigned char *msg, int bits) {
|
||||
struct errorinfo *pei;
|
||||
struct errorinfo ei;
|
||||
|
@ -1352,34 +1373,25 @@ int fixBitErrors(unsigned char *msg, int bits) {
|
|||
pei = bsearch(&ei, bitErrorTable, NERRORINFO,
|
||||
sizeof(struct errorinfo), cmpErrorInfo);
|
||||
if (pei == NULL) {
|
||||
/* Nothing found */
|
||||
return 0; // No syndrome found
|
||||
}
|
||||
res = 0;
|
||||
offset = MODES_LONG_MSG_BITS-bits;
|
||||
bitpos0 = pei->pos0 - offset;
|
||||
if ((bitpos0 < 0) || (bitpos0 >= bits)) {
|
||||
return 0;
|
||||
}
|
||||
offset = MODES_LONG_MSG_BITS-bits;
|
||||
bitpos0 = pei->pos0;
|
||||
bitpos1 = pei->pos1;
|
||||
res = 0;
|
||||
if (bitpos1 >= 0) { /* two-bit error pattern */
|
||||
bitpos0 -= offset;
|
||||
bitpos1 -= offset;
|
||||
if ((bitpos0 < 0) || (bitpos0 >= bits) ||
|
||||
(bitpos1 < 0) || (bitpos1 >= bits)) {
|
||||
return res;
|
||||
msg[(bitpos0 >> 3)] ^= (1 << (7 - (bitpos0 & 7)));
|
||||
res++;
|
||||
if (pei->pos1 >= 0) { /* two-bit error pattern */
|
||||
bitpos1 = pei->pos1 - offset;
|
||||
if ((bitpos1 < 0) || (bitpos1 >= bits)) {
|
||||
return 0;
|
||||
}
|
||||
res +=flipBit(msg, bits, bitpos0);
|
||||
if (bitpos0 != bitpos1) {
|
||||
res += flipBit(msg, bits, bitpos1);
|
||||
return res;
|
||||
msg[(bitpos1 >> 3)] ^= (1 << (7 - (bitpos1 & 7)));
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
bitpos0 -= offset;
|
||||
if ((bitpos0 < 0) || (bitpos0 >= bits)) {
|
||||
return res;
|
||||
}
|
||||
res += flipBit(msg, bits, bitpos0);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code for testing the timing: run all possible 1- and 2-bit error
|
||||
|
@ -1653,6 +1665,18 @@ char *ca_str[8] = {
|
|||
/* 7 */ "Level 7 ???"
|
||||
};
|
||||
|
||||
// DF 18 Control field table.
|
||||
char *cf_str[8] = {
|
||||
/* 0 */ "ADS-B ES/NT device with ICAO 24-bit address",
|
||||
/* 1 */ "ADS-B ES/NT device with other address",
|
||||
/* 2 */ "Fine format TIS-B",
|
||||
/* 3 */ "Coarse format TIS-B",
|
||||
/* 4 */ "TIS-B managment message",
|
||||
/* 5 */ "TIS-B relay of ADS-B message with other address",
|
||||
/* 6 */ "ADS-B rebroadcast using DF-17 message format",
|
||||
/* 7 */ "Reserved"
|
||||
};
|
||||
|
||||
/* Flight status table. */
|
||||
char *fs_str[8] = {
|
||||
/* 0 */ "Normal, Airborne",
|
||||
|
@ -1706,11 +1730,9 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
// Get the message type ASAP as other operations depend on this
|
||||
mm->msgtype = msg[0] >> 3; // Downlink Format
|
||||
mm->msgbits = modesMessageLenByType(mm->msgtype);
|
||||
mm->correctedbits = 0; // No errors fixed
|
||||
mm->phase_corrected = 0;
|
||||
mm->crc = modesChecksum(msg, mm->msgbits);
|
||||
|
||||
if ((mm->crc) && (Modes.fix_errors) && (mm->msgtype == 17)) {
|
||||
if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 17) || (mm->msgtype == 18))) {
|
||||
// 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
|
||||
|
@ -1723,9 +1745,12 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
// IID against known good IID's. That's a TODO.
|
||||
//
|
||||
mm->correctedbits = fixBitErrors(msg, mm->msgbits);
|
||||
//if ((mm->errorbit == -1) && (Modes.aggressive)) {
|
||||
// mm->errorbit = fixTwoBitsErrors(msg, mm->msgbits);
|
||||
//}
|
||||
// If we correct, validate ICAO addr to help filter birthday paradox solutions.
|
||||
if (mm->correctedbits) {
|
||||
uint32_t addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
if (!ICAOAddressWasRecentlySeen(addr))
|
||||
mm->correctedbits = 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Note that most of the other computation happens *after* we fix the
|
||||
|
@ -1735,6 +1760,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
mm->crcok = (mm->crc < 80);
|
||||
mm->iid = mm->crc;
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Responder capabilities
|
||||
|
||||
if (0 == mm->crc) {
|
||||
// DF 11 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
|
@ -1744,15 +1770,20 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
} else if (mm->msgtype == 17) { // DF 17
|
||||
mm->crcok = (mm->crc == 0);
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Responder capabilities
|
||||
|
||||
if (0 != mm->correctedbits) {
|
||||
// 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;
|
||||
if (0 == mm->crc) {
|
||||
// DF 17 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
addRecentlySeenICAOAddr(mm->addr);
|
||||
}
|
||||
|
||||
} else if (0 == mm->crc) {
|
||||
// DF 17 : if uncorrected and crc == 0 add this address to the whitelist of
|
||||
// recently seen ICAO addresses.
|
||||
} else if (mm->msgtype == 18) { // DF 18
|
||||
mm->crcok = (mm->crc == 0);
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Control Field
|
||||
|
||||
if (0 == mm->crc) {
|
||||
// DF 18 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
addRecentlySeenICAOAddr(mm->addr);
|
||||
}
|
||||
|
||||
|
@ -1774,7 +1805,6 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
|
||||
// Fields for DF11, DF17
|
||||
if (mm->msgtype == 11 || mm->msgtype == 17) {
|
||||
mm->ca = msg[0] & 0x07; // Responder capabilities
|
||||
if (mm->ca == 4) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
} else if (mm->ca == 5) {
|
||||
|
@ -1813,8 +1843,9 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
}
|
||||
}
|
||||
|
||||
// Fields for DF17 squitter
|
||||
if (mm->msgtype == 17) {
|
||||
// Fields for DF17, DF18_CF0, DF18_CF1, DF18_CF6 squitters
|
||||
if ( (mm->msgtype == 17)
|
||||
|| ((mm->msgtype == 18) && ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) )) {
|
||||
int metype = mm->metype = msg[4] >> 3; // Extended squitter message type
|
||||
int mesub = mm->mesub = msg[4] & 7; // Extended squitter message subtype
|
||||
|
||||
|
@ -1971,7 +2002,7 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
}
|
||||
|
||||
// Show the raw message.
|
||||
if (Modes.mlat) {
|
||||
if (Modes.mlat && mm->timestampMsg) {
|
||||
printf("@");
|
||||
pTimeStamp = (unsigned char *) &mm->timestampMsg;
|
||||
for (j=5; j>=0;j--) {
|
||||
|
@ -2107,6 +2138,65 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
|
||||
} else if (mm->msgtype == 18) { // DF 18
|
||||
printf("DF 18: Extended Squitter.\n");
|
||||
printf(" Control Field : %d (%s)\n", mm->ca, cf_str[mm->ca]);
|
||||
if ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) {
|
||||
if (mm->ca == 1) {
|
||||
printf(" Other Address : %06x\n", mm->addr);
|
||||
} else {
|
||||
printf(" ICAO Address : %06x\n", mm->addr);
|
||||
}
|
||||
printf(" Extended Squitter Type: %d\n", mm->metype);
|
||||
printf(" Extended Squitter Sub : %d\n", mm->mesub);
|
||||
printf(" Extended Squitter Name: %s\n", getMEDescription(mm->metype, mm->mesub));
|
||||
|
||||
// Decode the extended squitter message
|
||||
if (mm->metype >= 1 && mm->metype <= 4) { // Aircraft identification
|
||||
printf(" Aircraft Type : %c%d\n", ('A' + 4 - mm->metype), mm->mesub);
|
||||
printf(" Identification : %s\n", mm->flight);
|
||||
|
||||
//} else if (mm->metype >= 5 && mm->metype <= 8) { // Surface position
|
||||
|
||||
} else if (mm->metype >= 9 && mm->metype <= 18) { // Airborne position Baro
|
||||
printf(" F flag : %s\n", (mm->msg[6] & 0x04) ? "odd" : "even");
|
||||
printf(" T flag : %s\n", (mm->msg[6] & 0x08) ? "UTC" : "non-UTC");
|
||||
printf(" Altitude : %d feet\n", mm->altitude);
|
||||
if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) {
|
||||
printf(" Latitude : %f\n", mm->fLat);
|
||||
printf(" Longitude: %f\n", mm->fLon);
|
||||
} else {
|
||||
printf(" Latitude : %d (not decoded)\n", mm->raw_latitude);
|
||||
printf(" Longitude: %d (not decoded)\n", mm->raw_longitude);
|
||||
}
|
||||
|
||||
} else if (mm->metype == 19) { // Airborne Velocity
|
||||
if (mm->mesub == 1 || mm->mesub == 2) {
|
||||
printf(" EW status : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" EW velocity : %d\n", mm->ew_velocity);
|
||||
printf(" NS status : %s\n", (mm->bFlags & MODES_ACFLAGS_NSSPEED_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" NS velocity : %d\n", mm->ns_velocity);
|
||||
printf(" Vertical status : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
|
||||
printf(" Vertical rate : %d\n", mm->vert_rate);
|
||||
|
||||
} else if (mm->mesub == 3 || mm->mesub == 4) {
|
||||
printf(" Heading status : %s\n", (mm->bFlags & MODES_ACFLAGS_HEADING_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" Heading : %d\n", mm->heading);
|
||||
printf(" Airspeed status : %s\n", (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" Airspeed : %d\n", mm->velocity);
|
||||
printf(" Vertical status : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable");
|
||||
printf(" Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1));
|
||||
printf(" Vertical rate : %d\n", mm->vert_rate);
|
||||
|
||||
} else {
|
||||
printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
|
||||
//} else if (mm->metype >= 20 && mm->metype <= 22) { // Airborne position GNSS
|
||||
|
||||
} else {
|
||||
printf(" Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 19) { // DF 19
|
||||
printf("DF 19: Military Extended Squitter.\n");
|
||||
|
@ -2208,11 +2298,14 @@ void applyPhaseCorrection(uint16_t *pPayload) {
|
|||
* 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_LONG_MSG_SAMPLES];
|
||||
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:
|
||||
*
|
||||
|
@ -2238,7 +2331,6 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
*/
|
||||
for (j = 0; j < mlen; j++) {
|
||||
int high, i, errors, errors56, errorsTy;
|
||||
int good_message = 0;
|
||||
uint16_t *pPreamble, *pPayload, *pPtr;
|
||||
uint8_t theByte, theErrs;
|
||||
int msglen, scanlen, sigStrength;
|
||||
|
@ -2246,12 +2338,18 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
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)
|
||||
{
|
||||
struct modesMessage mm;
|
||||
int ModeA = detectModeA(pPreamble, &mm);
|
||||
|
||||
if (ModeA) // We have found a valid ModeA/C in the data
|
||||
|
@ -2449,24 +2547,54 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
if ( (msglen)
|
||||
&& (sigStrength > MODES_MSG_SQUELCH_LEVEL)
|
||||
&& (errors <= MODES_MSG_ENCODER_ERRS) ) {
|
||||
struct modesMessage mm;
|
||||
memset(&mm, 0, sizeof(mm));
|
||||
|
||||
// Set initial mm structure details
|
||||
mm.timestampMsg = Modes.timestampBlk + (j*6);
|
||||
sigStrength = (sigStrength + 0x7F) >> 8;
|
||||
mm.signalLevel = ((sigStrength < 255) ? sigStrength : 255);
|
||||
mm.phase_corrected = use_correction;
|
||||
|
||||
// Decode the received message
|
||||
decodeModesMessage(&mm, msg);
|
||||
|
||||
// Update statistics
|
||||
if (Modes.stats) {
|
||||
if (mm.crcok || use_correction) {
|
||||
if (errors == 0) Modes.stat_demodulated++;
|
||||
if (mm.crcok || use_correction || mm.correctedbits) {
|
||||
|
||||
if (use_correction) {
|
||||
switch (errors) {
|
||||
case 0: {Modes.stat_ph_demodulated0++; break;}
|
||||
case 1: {Modes.stat_ph_demodulated1++; break;}
|
||||
case 2: {Modes.stat_ph_demodulated2++; break;}
|
||||
default:{Modes.stat_ph_demodulated3++; break;}
|
||||
}
|
||||
} else {
|
||||
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 (use_correction) {
|
||||
if (mm.crcok) {Modes.stat_ph_goodcrc++;}
|
||||
else {Modes.stat_ph_badcrc++;}
|
||||
} else {
|
||||
if (mm.crcok) {Modes.stat_goodcrc++;}
|
||||
else {Modes.stat_badcrc++;}
|
||||
}
|
||||
|
||||
} else if (use_correction) {
|
||||
Modes.stat_ph_badcrc++;
|
||||
Modes.stat_ph_fixed++;
|
||||
if (mm.correctedbits == 1) {
|
||||
Modes.stat_ph_single_bit_fix++;
|
||||
} else if (mm.correctedbits == 2) {
|
||||
Modes.stat_ph_two_bits_fix++;
|
||||
}
|
||||
|
||||
} else {
|
||||
Modes.stat_badcrc++;
|
||||
Modes.stat_fixed++;
|
||||
|
@ -2495,9 +2623,6 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
// Skip this message if we are sure it's fine
|
||||
if (mm.crcok) {
|
||||
j += (MODES_PREAMBLE_US+msglen)*2;
|
||||
good_message = 1;
|
||||
if (use_correction)
|
||||
mm.phase_corrected = 1;
|
||||
}
|
||||
|
||||
// Pass data to the next layer
|
||||
|
@ -2510,8 +2635,8 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
}
|
||||
}
|
||||
|
||||
// Retry with phase correction if possible.
|
||||
if (!good_message && !use_correction && j && detectOutOfPhase(pPreamble)) {
|
||||
// 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;
|
||||
|
@ -2539,7 +2664,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
|
|||
// processing and visualization
|
||||
//
|
||||
void useModesMessage(struct modesMessage *mm) {
|
||||
if ((Modes.check_crc == 0) || (mm->crcok)) {
|
||||
if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed
|
||||
|
||||
// Track aircrafts if...
|
||||
if ( (Modes.interactive) // in interactive mode
|
||||
|
@ -2913,7 +3038,9 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) {
|
|||
struct aircraft *interactiveReceiveData(struct modesMessage *mm) {
|
||||
struct aircraft *a, *aux;
|
||||
|
||||
if (Modes.check_crc && mm->crcok == 0) return NULL;
|
||||
// Return if (checking crc) AND (not crcok) AND (not fixed)
|
||||
if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0))
|
||||
return NULL;
|
||||
|
||||
// Loookup our aircraft or create a new one
|
||||
a = interactiveFindAircraft(mm->addr);
|
||||
|
@ -3192,14 +3319,14 @@ void snipMode(int level) {
|
|||
}
|
||||
|
||||
/* ============================= Networking =================================
|
||||
* Note: here we risregard any kind of good coding practice in favor of
|
||||
* Note: here we disregard any kind of good coding practice in favor of
|
||||
* extreme simplicity, that is:
|
||||
*
|
||||
* 1) We only rely on the kernel buffers for our I/O without any kind of
|
||||
* user space buffering.
|
||||
* 2) We don't register any kind of event handler, from time to time a
|
||||
* function gets called and we accept new connections. All the rest is
|
||||
* handled via non-blocking I/O and manually pullign clients to see if
|
||||
* handled via non-blocking I/O and manually polling clients to see if
|
||||
* they have something new to share with us when reading is needed.
|
||||
*/
|
||||
|
||||
|
@ -3354,7 +3481,7 @@ void modesSendRawOutput(struct modesMessage *mm) {
|
|||
int j;
|
||||
unsigned char * pTimeStamp;
|
||||
|
||||
if (Modes.mlat) {
|
||||
if (Modes.mlat && mm->timestampMsg) {
|
||||
*p++ = '@';
|
||||
pTimeStamp = (unsigned char *) &mm->timestampMsg;
|
||||
for (j = 5; j >= 0; j--) {
|
||||
|
@ -3426,7 +3553,7 @@ void modesSendSBSOutput(struct modesMessage *mm) {
|
|||
p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr);
|
||||
|
||||
// Fields 7 & 8 are the current time and date
|
||||
if (mm->timestampMsg != (uint64_t)(-1)) { // Make sure the records' timestamp is valid before outputing it
|
||||
if (mm->timestampMsg) { // Make sure the records' timestamp is valid before outputing it
|
||||
epocTime = Modes.stSystemTimeBlk; // This is the time of the start of the Block we're processing
|
||||
offset = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block
|
||||
offset = offset / 12000; // convert to milliseconds
|
||||
|
@ -3556,7 +3683,7 @@ int decodeHexMessage(struct client *c) {
|
|||
// Mixing of data from two or more different receivers and publishing
|
||||
// as coming from one would lead to corrupt mlat data
|
||||
// Non timemarked internet data has indeterminate delay
|
||||
mm.timestampMsg = -1;
|
||||
mm.timestampMsg = 0;
|
||||
mm.signalLevel = -1;
|
||||
|
||||
// Remove spaces on the left and on the right
|
||||
|
@ -3569,7 +3696,7 @@ int decodeHexMessage(struct client *c) {
|
|||
|
||||
// Turn the message into binary.
|
||||
// Accept *-AVR raw @-AVR/BEAST timeS+raw %-AVR timeS+raw (CRC good) <-BEAST timeS+sigL+raw
|
||||
// and some AVR recorer that we can understand
|
||||
// and some AVR records that we can understand
|
||||
if (hex[l-1] != ';') {return (0);} // not complete - abort
|
||||
|
||||
switch(hex[0]) {
|
||||
|
@ -3578,11 +3705,9 @@ int decodeHexMessage(struct client *c) {
|
|||
hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
|
||||
break;}
|
||||
|
||||
case '@':
|
||||
case '%':
|
||||
case '#':
|
||||
case '$': {
|
||||
hex += 13; l -= 14; // Skip @,%,#,$, and timestamp, and ;
|
||||
case '@': // No CRC check
|
||||
case '%': { // CRC is OK
|
||||
hex += 13; l -= 14; // Skip @,%, and timestamp, and ;
|
||||
break;}
|
||||
|
||||
case '*':
|
||||
|
@ -3905,6 +4030,7 @@ void showHelp(void) {
|
|||
"--fix Enable single-bits error correction using CRC\n"
|
||||
"--no-fix Disable single-bits error correction using CRC\n"
|
||||
"--no-crc-check Disable messages with broken CRC (discouraged)\n"
|
||||
"--phase-enhance Enable phase enhancement\n"
|
||||
"--aggressive More CPU for more messages (two bits fixes, ...)\n"
|
||||
"--mlat display raw messages in Beast ascii mode\n"
|
||||
"--stats With --ifile print stats at exit. No other output\n"
|
||||
|
@ -3983,6 +4109,8 @@ int main(int argc, char **argv) {
|
|||
Modes.aggressive = 0;
|
||||
} else if (!strcmp(argv[j],"--no-crc-check")) {
|
||||
Modes.check_crc = 0;
|
||||
} else if (!strcmp(argv[j],"--phase-enhance")) {
|
||||
Modes.phase_enhance = 1;
|
||||
} else if (!strcmp(argv[j],"--raw")) {
|
||||
Modes.raw = 1;
|
||||
} else if (!strcmp(argv[j],"--net")) {
|
||||
|
@ -4127,20 +4255,37 @@ int main(int argc, char **argv) {
|
|||
if (Modes.stats) {
|
||||
printf("\n\n");
|
||||
printf("%d ModeA/C detected\n", Modes.stat_ModeAC);
|
||||
printf("%d valid preambles\n", Modes.stat_valid_preamble);
|
||||
printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble);
|
||||
printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected);
|
||||
printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected);
|
||||
printf("%d demodulated again after phase correction\n", Modes.stat_out_of_phase);
|
||||
printf("%d demodulated with zero errors\n", Modes.stat_demodulated);
|
||||
printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0);
|
||||
printf("%d demodulated with 1 error\n", Modes.stat_demodulated1);
|
||||
printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2);
|
||||
printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3);
|
||||
printf("%d with good crc\n", Modes.stat_goodcrc);
|
||||
printf("%d with bad crc\n", Modes.stat_badcrc);
|
||||
printf("%d errors corrected\n", Modes.stat_fixed);
|
||||
printf("%d single bit errors\n", Modes.stat_single_bit_fix);
|
||||
printf("%d two bits errors\n", Modes.stat_two_bits_fix);
|
||||
printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_fixed);
|
||||
printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
|
||||
printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0);
|
||||
printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1);
|
||||
printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2);
|
||||
printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3);
|
||||
printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc);
|
||||
printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc);
|
||||
printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed);
|
||||
printf("%d phase enhanced single bit errors\n", Modes.stat_ph_single_bit_fix);
|
||||
printf("%d phase enhanced two bits errors\n", Modes.stat_ph_two_bits_fix);
|
||||
printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed);
|
||||
}
|
||||
|
||||
if (Modes.filename == NULL) {
|
||||
rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly
|
||||
rtlsdr_close(Modes.dev);
|
||||
exit (0);
|
||||
}
|
||||
pthread_cond_destroy(&Modes.data_cond); // Thread cleanup
|
||||
pthread_mutex_destroy(&Modes.data_mutex);
|
||||
pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue