Decoder cleanups from experimental branch.
This commit is contained in:
parent
0433ed3f5d
commit
5e522fe8db
25
demod_2000.c
25
demod_2000.c
|
@ -317,6 +317,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
int msglen, scanlen;
|
||||
uint32_t sigLevel, noiseLevel;
|
||||
uint16_t snr;
|
||||
int message_ok;
|
||||
|
||||
pPreamble = &m[j];
|
||||
pPayload = &m[j+MODES_PREAMBLE_SAMPLES];
|
||||
|
@ -325,7 +326,6 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
// 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
|
||||
|
@ -544,7 +544,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
mm.phase_corrected = use_correction;
|
||||
|
||||
// Decode the received message
|
||||
decodeModesMessage(&mm, msg);
|
||||
message_ok = (decodeModesMessage(&mm, msg) >= 0);
|
||||
|
||||
// Update statistics
|
||||
if (Modes.stats) {
|
||||
|
@ -557,16 +557,16 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
default: dstats->demodulated3++; break;
|
||||
}
|
||||
|
||||
if (mm.crcok) {
|
||||
if (!message_ok) {
|
||||
dstats->badcrc++;
|
||||
} else if (mm.correctedbits == 0) {
|
||||
dstats->goodcrc++;
|
||||
dstats->goodcrc_byphase[0]++;
|
||||
} else if (mm.correctedbits > 0) {
|
||||
} else {
|
||||
dstats->badcrc++;
|
||||
dstats->fixed++;
|
||||
if (mm.correctedbits <= MODES_MAX_BITERRORS)
|
||||
dstats->bit_fix[mm.correctedbits-1] += 1;
|
||||
} else {
|
||||
dstats->badcrc++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,22 +576,23 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
dumpRawMessage("Demodulated with 0 errors", msg, m, j);
|
||||
else if (Modes.debug & MODES_DEBUG_BADCRC &&
|
||||
mm.msgtype == 17 &&
|
||||
(!mm.crcok || mm.correctedbits != 0))
|
||||
(!message_ok || mm.correctedbits > 0))
|
||||
dumpRawMessage("Decoded with bad CRC", msg, m, j);
|
||||
else if (Modes.debug & MODES_DEBUG_GOODCRC && mm.crcok &&
|
||||
else if (Modes.debug & MODES_DEBUG_GOODCRC &&
|
||||
message_ok &&
|
||||
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) {
|
||||
if (message_ok) {
|
||||
j += (MODES_PREAMBLE_US+msglen)*2 - 1;
|
||||
}
|
||||
|
||||
// Pass data to the next layer
|
||||
useModesMessage(&mm);
|
||||
|
||||
}
|
||||
} else {
|
||||
message_ok = 0;
|
||||
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);
|
||||
|
@ -599,7 +600,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
|||
}
|
||||
|
||||
// Retry with phase correction if enabled, necessary and possible.
|
||||
if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) {
|
||||
if (Modes.phase_enhance && (!message_ok || mm.correctedbits > 0) && !use_correction && j && detectOutOfPhase(pPreamble)) {
|
||||
use_correction = 1; j--;
|
||||
} else {
|
||||
use_correction = 0;
|
||||
|
|
17
demod_2400.c
17
demod_2400.c
|
@ -273,7 +273,6 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
|
|||
// is required for every possible preamble, and we don't want to be memset-ing the whole
|
||||
// modesMessage structure if we don't have to..
|
||||
mm.bFlags =
|
||||
mm.crcok =
|
||||
mm.correctedbits = 0;
|
||||
|
||||
// Decode all the next 112 bits, regardless of the actual message
|
||||
|
@ -456,13 +455,15 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
|
|||
if ( (msglen)
|
||||
// && ((2 * snr) > (int) (MODES_MSG_SQUELCH_DB * 10))
|
||||
&& (errors <= MODES_MSG_ENCODER_ERRS) ) {
|
||||
int message_ok;
|
||||
|
||||
// Set initial mm structure details
|
||||
mm.timestampMsg = Modes.timestampBlk + (j*5) + try_phase;
|
||||
mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr);
|
||||
mm.phase_corrected = (initial_phase != try_phase);
|
||||
|
||||
// Decode the received message
|
||||
decodeModesMessage(&mm, msg);
|
||||
message_ok = (decodeModesMessage(&mm, msg) >= 0);
|
||||
|
||||
// Update statistics
|
||||
if (Modes.stats) {
|
||||
|
@ -475,16 +476,16 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
|
|||
default: dstats->demodulated3++; break;
|
||||
}
|
||||
|
||||
if (mm.crcok) {
|
||||
dstats->goodcrc++;
|
||||
dstats->goodcrc_byphase[try_phase%MODES_MAX_PHASE_STATS]++;
|
||||
if (!message_ok) {
|
||||
dstats->badcrc++;
|
||||
} 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++;
|
||||
dstats->goodcrc++;
|
||||
dstats->goodcrc_byphase[try_phase%MODES_MAX_PHASE_STATS]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,7 +495,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
|
|||
// where the preamble of the second message clobbered the last
|
||||
// few bits of the first message, but the message bits didn't
|
||||
// overlap)
|
||||
if (mm.crcok || mm.correctedbits) {
|
||||
if (message_ok) {
|
||||
j += (8 + msglen - 8)*12/5 - 1;
|
||||
}
|
||||
|
||||
|
@ -506,7 +507,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
|
|||
// where trying different phases actually helps, and is much
|
||||
// cheaper than trying it on every single candidate that passes
|
||||
// peak detection
|
||||
if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits) {
|
||||
if (Modes.phase_enhance && !message_ok) {
|
||||
if (try_phase == initial_phase)
|
||||
++Modes.stats_current.out_of_phase;
|
||||
try_phase++;
|
||||
|
|
11
dump1090.h
11
dump1090.h
|
@ -406,7 +406,6 @@ struct modesMessage {
|
|||
unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message.
|
||||
int msgbits; // Number of bits in message
|
||||
int msgtype; // Downlink format #
|
||||
int crcok; // True if CRC was valid
|
||||
uint32_t crc; // Message CRC
|
||||
int correctedbits; // No. of bits corrected
|
||||
char corrected[MODES_MAX_BITERRORS]; // corrected bit positions
|
||||
|
@ -416,7 +415,7 @@ struct modesMessage {
|
|||
int remote; // If set this message is from a remote station
|
||||
unsigned char signalLevel; // Signal Amplitude
|
||||
|
||||
// DF 11
|
||||
// DF 11, DF 17
|
||||
int ca; // Responder capabilities
|
||||
int iid;
|
||||
|
||||
|
@ -434,10 +433,16 @@ struct modesMessage {
|
|||
int vert_rate; // Vertical rate.
|
||||
int velocity; // Reported by aircraft, or computed from from EW and NS velocity
|
||||
|
||||
// DF 18
|
||||
int cf; // Control Field
|
||||
|
||||
// DF4, DF5, DF20, DF21
|
||||
int fs; // Flight status for DF4,5,20,21
|
||||
int modeA; // 13 bits identity (Squawk).
|
||||
|
||||
// DF20, DF21
|
||||
int bds; // BDS value implied if overlay control was used
|
||||
|
||||
// Fields used by multiple message types.
|
||||
int altitude;
|
||||
int unit;
|
||||
|
@ -462,7 +467,7 @@ int ModeAToModeC (unsigned int ModeA);
|
|||
//
|
||||
int modesMessageLenByType(int type);
|
||||
void detectModeS_oversample (uint16_t *m, uint32_t mlen);
|
||||
void decodeModesMessage (struct modesMessage *mm, unsigned char *msg);
|
||||
int decodeModesMessage (struct modesMessage *mm, unsigned char *msg);
|
||||
void displayModesMessage(struct modesMessage *mm);
|
||||
void useModesMessage (struct modesMessage *mm);
|
||||
void computeMagnitudeVector(uint16_t *pData);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define MODES_ICAO_FILTER_TTL 60
|
||||
|
||||
// Open-addressed hash table with linear probing.
|
||||
// We store each address twice to handle Address/Parity and Data/Parity
|
||||
// We store each address twice to handle Data/Parity
|
||||
// which need to match on a partial address (top 16 bits only).
|
||||
|
||||
// Maintain two tables and switch between them to age out entries.
|
||||
|
|
|
@ -380,13 +380,7 @@ static void updatePosition(struct aircraft *a, struct modesMessage *mm, time_t n
|
|||
|
||||
struct aircraft *interactiveReceiveData(struct modesMessage *mm) {
|
||||
struct aircraft *a, *aux;
|
||||
time_t now;
|
||||
|
||||
// Return if (checking crc) AND (not crcok) AND (not fixed)
|
||||
if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0))
|
||||
return NULL;
|
||||
|
||||
now = time(NULL);
|
||||
time_t now = time(NULL);
|
||||
|
||||
// Lookup our aircraft or create a new one
|
||||
a = interactiveFindAircraft(mm->addr);
|
||||
|
|
|
@ -385,7 +385,6 @@ void decodeModeAMessage(struct modesMessage *mm, int ModeA)
|
|||
|
||||
// Not much else we can tell from a Mode A/C reply.
|
||||
// Just fudge up a few bits to keep other code happy
|
||||
mm->crcok = 1;
|
||||
mm->correctedbits = 0;
|
||||
}
|
||||
//
|
||||
|
|
777
mode_s.c
777
mode_s.c
|
@ -82,7 +82,7 @@ int modesMessageLenByType(int type) {
|
|||
//
|
||||
// For more info: http://en.wikipedia.org/wiki/Gillham_code
|
||||
//
|
||||
int decodeID13Field(int ID13Field) {
|
||||
static int decodeID13Field(int ID13Field) {
|
||||
int hexGillham = 0;
|
||||
|
||||
if (ID13Field & 0x1000) {hexGillham |= 0x0010;} // Bit 12 = C1
|
||||
|
@ -107,7 +107,7 @@ int decodeID13Field(int ID13Field) {
|
|||
// Decode the 13 bit AC altitude field (in DF 20 and others).
|
||||
// Returns the altitude, and set 'unit' to either MODES_UNIT_METERS or MDOES_UNIT_FEETS.
|
||||
//
|
||||
int decodeAC13Field(int AC13Field, int *unit) {
|
||||
static int decodeAC13Field(int AC13Field, int *unit) {
|
||||
int m_bit = AC13Field & 0x0040; // set = meters, clear = feet
|
||||
int q_bit = AC13Field & 0x0010; // set = 25 ft encoding, clear = Gillham Mode C encoding
|
||||
|
||||
|
@ -138,7 +138,7 @@ int decodeAC13Field(int AC13Field, int *unit) {
|
|||
//
|
||||
// Decode the 12 bit AC altitude field (in DF 17 and others).
|
||||
//
|
||||
int decodeAC12Field(int AC12Field, int *unit) {
|
||||
static int decodeAC12Field(int AC12Field, int *unit) {
|
||||
int q_bit = AC12Field & 0x10; // Bit 48 = Q
|
||||
|
||||
*unit = MODES_UNIT_FEET;
|
||||
|
@ -163,7 +163,7 @@ int decodeAC12Field(int AC12Field, int *unit) {
|
|||
//
|
||||
// Decode the 7 bit ground movement field PWL exponential style scale
|
||||
//
|
||||
int decodeMovementField(int movement) {
|
||||
static int decodeMovementField(int movement) {
|
||||
int gspeed;
|
||||
|
||||
// Note : movement codes 0,125,126,127 are all invalid, but they are
|
||||
|
@ -183,19 +183,19 @@ int decodeMovementField(int movement) {
|
|||
//=========================================================================
|
||||
//
|
||||
// Capability table
|
||||
char *ca_str[8] = {
|
||||
/* 0 */ "Level 1 (Surveillance Only)",
|
||||
/* 1 */ "Level 2 (DF0,4,5,11)",
|
||||
/* 2 */ "Level 3 (DF0,4,5,11,20,21)",
|
||||
/* 3 */ "Level 4 (DF0,4,5,11,20,21,24)",
|
||||
/* 4 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7 - is on ground)",
|
||||
/* 5 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7 - is airborne)",
|
||||
/* 6 */ "Level 2+3+4 (DF0,4,5,11,20,21,24,code7)",
|
||||
/* 7 */ "Level 7 ???"
|
||||
static const char *ca_str[8] = {
|
||||
/* 0 */ "Level 1",
|
||||
/* 1 */ "reserved",
|
||||
/* 2 */ "reserved",
|
||||
/* 3 */ "reserved",
|
||||
/* 4 */ "Level 2+, ground",
|
||||
/* 5 */ "Level 2+, airborne",
|
||||
/* 6 */ "Level 2+",
|
||||
/* 7 */ "DR/Alert/SPI active"
|
||||
};
|
||||
|
||||
// DF 18 Control field table.
|
||||
char *cf_str[8] = {
|
||||
static const 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",
|
||||
|
@ -207,15 +207,15 @@ char *cf_str[8] = {
|
|||
};
|
||||
|
||||
// Flight status table
|
||||
char *fs_str[8] = {
|
||||
static const char *fs_str[8] = {
|
||||
/* 0 */ "Normal, Airborne",
|
||||
/* 1 */ "Normal, On the ground",
|
||||
/* 2 */ "ALERT, Airborne",
|
||||
/* 3 */ "ALERT, On the ground",
|
||||
/* 4 */ "ALERT & Special Position Identification. Airborne or Ground",
|
||||
/* 5 */ "Special Position Identification. Airborne or Ground",
|
||||
/* 6 */ "Value 6 is not assigned",
|
||||
/* 7 */ "Value 7 is not assigned"
|
||||
/* 6 */ "Reserved",
|
||||
/* 7 */ "Not assigned"
|
||||
};
|
||||
|
||||
// Emergency state table
|
||||
|
@ -228,13 +228,13 @@ char *es_str[8] = {
|
|||
/* 3 */ "Minimum fuel",
|
||||
/* 4 */ "No communications (squawk 7600)",
|
||||
/* 5 */ "Unlawful interference (squawk 7500)",
|
||||
/* 6 */ "Downed Aircraft",
|
||||
/* 6 */ "Reserved",
|
||||
/* 7 */ "Reserved"
|
||||
};
|
||||
//
|
||||
//=========================================================================
|
||||
//
|
||||
char *getMEDescription(int metype, int mesub) {
|
||||
static char *getMEDescription(int metype, int mesub) {
|
||||
char *mename = "Unknown";
|
||||
|
||||
if (metype >= 1 && metype <= 4)
|
||||
|
@ -263,15 +263,21 @@ char *getMEDescription(int metype, int mesub) {
|
|||
mename = "Aircraft Operational Status Message";
|
||||
return mename;
|
||||
}
|
||||
|
||||
//
|
||||
//=========================================================================
|
||||
//
|
||||
// Decode a raw Mode S message demodulated as a stream of bytes by detectModeS(),
|
||||
// and split it into fields populating a modesMessage structure.
|
||||
//
|
||||
void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
||||
char *ais_charset = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????";
|
||||
|
||||
static void decodeExtendedSquitter(struct modesMessage *mm);
|
||||
static void decodeCommB(struct modesMessage *mm);
|
||||
static char *ais_charset = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?";
|
||||
|
||||
// return 0 if all OK, -1 if the message was rejected
|
||||
int decodeModesMessage(struct modesMessage *mm, unsigned char *msg)
|
||||
{
|
||||
// Work on our local copy
|
||||
memcpy(mm->msg, msg, MODES_LONG_MSG_BYTES);
|
||||
msg = mm->msg;
|
||||
|
@ -280,109 +286,130 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
mm->msgtype = msg[0] >> 3; // Downlink Format
|
||||
mm->msgbits = modesMessageLenByType(mm->msgtype);
|
||||
mm->crc = modesChecksum(msg, mm->msgbits);
|
||||
|
||||
if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 17) || (mm->msgtype == 18))) {
|
||||
// if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 11) || (mm->msgtype == 17))) {
|
||||
//
|
||||
// Fixing single bit errors in DF-11 is a bit dodgy because we have no way to
|
||||
// know for sure if the crc is supposed to be 0 or not - it could be any value
|
||||
// less than 80. Therefore, attempting to fix DF-11 errors can result in a
|
||||
// multitude of possible crc solutions, only one of which is correct.
|
||||
//
|
||||
// We should probably perform some sanity checks on corrected DF-11's before
|
||||
// using the results. Perhaps check the ICAO against known aircraft, and check
|
||||
// IID against known good IID's. That's a TODO.
|
||||
//
|
||||
struct errorinfo *ei = modesChecksumDiagnose(mm->crc, mm->msgbits);
|
||||
if (ei != NULL && ei->errors <= Modes.nfix_crc) {
|
||||
modesChecksumFix(msg, ei);
|
||||
mm->correctedbits = ei->errors;
|
||||
}
|
||||
|
||||
// If we correct, validate ICAO addr to help filter birthday paradox solutions.
|
||||
if (mm->correctedbits) {
|
||||
uint32_t ulAddr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
if (!icaoFilterTest(ulAddr))
|
||||
mm->correctedbits = 0;
|
||||
|
||||
// Do checksum work and set fields that depend on the CRC
|
||||
switch (mm->msgtype) {
|
||||
case 0: // short air-air surveillance
|
||||
case 4: // surveillance, altitude reply
|
||||
case 5: // surveillance, altitude reply
|
||||
case 16: // long air-air surveillance
|
||||
case 24: // Comm-D (ELM)
|
||||
// These message types use Address/Parity, i.e. our CRC syndrome is the sender's ICAO address.
|
||||
// We can't tell if the CRC is correct or not as we don't know the correct address.
|
||||
// Accept the message if it appears to be from a previously-seen aircraft
|
||||
if (!icaoFilterTest(mm->crc)) {
|
||||
//fprintf(stderr, "reject: AP doesn't match known ICAO\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
mm->addr = mm->crc;
|
||||
break;
|
||||
|
||||
case 11: // All-call reply
|
||||
// This message type uses Parity/Interrogator, i.e. our CRC syndrome is CL + IC from the uplink message
|
||||
// which we can't see. So we don't know if the CRC is correct or not.
|
||||
//
|
||||
// Note that most of the other computation happens *after* we fix the
|
||||
// single/two bit errors, otherwise we would need to recompute the fields again.
|
||||
//
|
||||
if (mm->msgtype == 11) { // DF 11
|
||||
mm->iid = mm->crc;
|
||||
// however! CL + IC only occupy the lower 7 bits of the CRC. So if we ignore those bits when testing
|
||||
// the CRC we can still try to detect/correct errors.
|
||||
|
||||
mm->iid = mm->crc & 0x7f;
|
||||
if (mm->crc & 0xffff80) {
|
||||
int addr;
|
||||
struct errorinfo *ei = modesChecksumDiagnose(mm->crc & 0xffff80, mm->msgbits);
|
||||
if (!ei) {
|
||||
//fprintf(stderr, "reject: DF11 uncorrectable CRC error\n");
|
||||
return -1; // couldn't fix it
|
||||
}
|
||||
mm->correctedbits = ei->errors;
|
||||
modesChecksumFix(msg, ei);
|
||||
|
||||
// check whether the corrected message looks sensible
|
||||
addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
if (!icaoFilterTest(addr)) {
|
||||
//fprintf(stderr, "reject: DF11 CRC error, repaired address doesn't match known ICAO\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 17: // Extended squitter
|
||||
case 18: { // Extended squitter/non-transponder
|
||||
struct errorinfo *ei;
|
||||
int addr1, addr2;
|
||||
|
||||
// These message types use Parity/Interrogator, but are specified to set II=0
|
||||
|
||||
if (mm->crc == 0)
|
||||
break; // all good
|
||||
|
||||
ei = modesChecksumDiagnose(mm->crc, mm->msgbits);
|
||||
if (!ei) {
|
||||
//fprintf(stderr, "reject: DF17/18 uncorrectable CRC error\n");
|
||||
return -1; // couldn't fix it
|
||||
}
|
||||
mm->correctedbits = ei->errors;
|
||||
|
||||
addr1 = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
modesChecksumFix(msg, ei);
|
||||
addr2 = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
|
||||
// if the corrections touched the address, better validate it
|
||||
if (addr1 != addr2 && !icaoFilterTest(addr2)) {
|
||||
//fprintf(stderr, "reject: DF17/18 CRC corrected address, repaired address doesn't match known ICAO\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 20: // Comm-B, altitude reply
|
||||
case 21: // Comm-B, identity reply
|
||||
// These message types either use Address/Parity (see DF0 etc)
|
||||
// or Data Parity where the requested BDS is also xored into the top byte.
|
||||
// So not only do we not know whether the CRC is right, we also don't know if
|
||||
// the ICAO is right! Ow.
|
||||
|
||||
// Try an exact match
|
||||
if (icaoFilterTest(mm->crc)) {
|
||||
// OK.
|
||||
mm->addr = mm->crc;
|
||||
mm->bds = 0; // unknown
|
||||
break;
|
||||
}
|
||||
|
||||
// Try a fuzzy match
|
||||
if ( (mm->addr = icaoFilterTestFuzzy(mm->crc)) != 0) {
|
||||
// We have an address that would match, assume it's correct
|
||||
mm->bds = (mm->crc ^ mm->addr) >> 16; // derive the BDS value based on what we think the address is
|
||||
break;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "reject: DF20/21 address doesn't match known ICAO\n");
|
||||
return -1; // no good
|
||||
|
||||
default:
|
||||
// All other message types, we don't know how to handle their CRCs, give up
|
||||
return -1;
|
||||
}
|
||||
|
||||
// decode the bulk of the message
|
||||
|
||||
mm->bFlags = 0;
|
||||
|
||||
// AA (Address announced)
|
||||
if (mm->msgtype == 11 || mm->msgtype == 17 || mm->msgtype == 18) {
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Responder capabilities
|
||||
if (!mm->correctedbits && (mm->msgtype != 11 || mm->iid == 0)) {
|
||||
// No CRC errors seen, and either it was an DF17/18 extended squitter
|
||||
// or a DF11 acquisition squitter with II = 0. We probably have the right address.
|
||||
|
||||
if ((mm->crcok = (0 == mm->crc))) {
|
||||
// DF 11 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
icaoFilterAdd(mm->addr);
|
||||
} else if (mm->crc < 80) {
|
||||
mm->crcok = icaoFilterTest(mm->addr);
|
||||
if (mm->crcok) {
|
||||
// NB this is the only place that adds addresses!
|
||||
icaoFilterAdd(mm->addr);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 17) { // DF 17
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Responder capabilities
|
||||
|
||||
if ((mm->crcok = (0 == mm->crc))) {
|
||||
// DF 17 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
icaoFilterAdd(mm->addr);
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 18) { // DF 18
|
||||
mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
|
||||
mm->ca = (msg[0] & 0x07); // Control Field
|
||||
|
||||
if ((mm->crcok = (0 == mm->crc))) {
|
||||
// DF 18 : if crc == 0 try to populate our ICAO addresses whitelist.
|
||||
icaoFilterAdd(mm->addr);
|
||||
}
|
||||
|
||||
} else { // All other DF's
|
||||
// Compare the checksum with the whitelist of recently seen ICAO
|
||||
// addresses. If it matches one, then declare the message as valid
|
||||
mm->crcok = icaoFilterTest(mm->addr = mm->crc);
|
||||
}
|
||||
|
||||
// If we're checking CRC and the CRC is invalid, then we can't trust any
|
||||
// of the data contents, so save time and give up now.
|
||||
if ((Modes.check_crc) && (!mm->crcok) && (!mm->correctedbits)) { return;}
|
||||
|
||||
// Fields for DF0, DF16
|
||||
if (mm->msgtype == 0 || mm->msgtype == 16) {
|
||||
if (msg[0] & 0x04) { // VS Bit
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
} else {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Fields for DF11, DF17
|
||||
if (mm->msgtype == 11 || mm->msgtype == 17) {
|
||||
if (mm->ca == 4) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
} else if (mm->ca == 5) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Fields for DF5, DF21 = Gillham encoded Squawk
|
||||
if (mm->msgtype == 5 || mm->msgtype == 21) {
|
||||
int ID13Field = ((msg[2] << 8) | msg[3]) & 0x1FFF;
|
||||
if (ID13Field) {
|
||||
mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
|
||||
mm->modeA = decodeID13Field(ID13Field);
|
||||
}
|
||||
}
|
||||
|
||||
// Fields for DF0, DF4, DF16, DF20 13 bit altitude
|
||||
if (mm->msgtype == 0 || mm->msgtype == 4 ||
|
||||
mm->msgtype == 16 || mm->msgtype == 20) {
|
||||
// AC (Altitude Code)
|
||||
if (mm->msgtype == 0 || mm->msgtype == 4 || mm->msgtype == 16 || mm->msgtype == 20) {
|
||||
int AC13Field = ((msg[2] << 8) | msg[3]) & 0x1FFF;
|
||||
if (AC13Field) { // Only attempt to decode if a valid (non zero) altitude is present
|
||||
mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
|
||||
|
@ -390,46 +417,149 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
}
|
||||
}
|
||||
|
||||
// Fields for DF4, DF5, DF20, DF21
|
||||
if ((mm->msgtype == 4) || (mm->msgtype == 20) ||
|
||||
(mm->msgtype == 5) || (mm->msgtype == 21)) {
|
||||
// AF (DF19 Application Field) not decoded
|
||||
|
||||
// CA (Capability)
|
||||
if (mm->msgtype == 11 || mm->msgtype == 17) {
|
||||
mm->ca = (msg[0] & 0x07);
|
||||
if (mm->ca == 4) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
} else if (mm->ca == 5) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
// CC (Cross-link capability) not decoded
|
||||
|
||||
// CF (Control field)
|
||||
if (mm->msgtype == 18) {
|
||||
mm->cf = msg[0] & 7;
|
||||
}
|
||||
|
||||
// DR (Downlink Request) not decoded
|
||||
|
||||
// FS (Flight Status)
|
||||
if (mm->msgtype == 4 || mm->msgtype == 5 || mm->msgtype == 20 || mm->msgtype == 21) {
|
||||
mm->bFlags |= MODES_ACFLAGS_FS_VALID;
|
||||
mm->fs = msg[0] & 7; // Flight status for DF4,5,20,21
|
||||
mm->fs = msg[0] & 7;
|
||||
if (mm->fs <= 3) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
if (mm->fs & 1)
|
||||
{mm->bFlags |= MODES_ACFLAGS_AOG;}
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)) )) {
|
||||
// ID (Identity)
|
||||
if (mm->msgtype == 5 || mm->msgtype == 21) {
|
||||
// Gillham encoded Squawk
|
||||
int ID13Field = ((msg[2] << 8) | msg[3]) & 0x1FFF;
|
||||
if (ID13Field) {
|
||||
mm->bFlags |= MODES_ACFLAGS_SQUAWK_VALID;
|
||||
mm->modeA = decodeID13Field(ID13Field);
|
||||
}
|
||||
}
|
||||
|
||||
// KE (Control, ELM) not decoded
|
||||
|
||||
// MB (messsage, Comm-B)
|
||||
if (mm->msgtype == 20 || mm->msgtype == 21) {
|
||||
decodeCommB(mm);
|
||||
}
|
||||
|
||||
// MD (message, Comm-D) not decoded
|
||||
|
||||
// ME (message, extended squitter)
|
||||
if (mm->msgtype == 17 || // Extended squitter
|
||||
(mm->msgtype == 18 && // Extended squitter/non-transponder:
|
||||
(mm->cf == 0 || // ADS-B ES/NT devices that report the ICAO 24-bit address in the AA field
|
||||
mm->cf == 1 || // Reserved for ADS-B for ES/NT devices that use other addressing techniques in the AA field
|
||||
mm->cf == 5 || // TIS-B messages that relay ADS-B Messages using anonymous 24-bit addresses
|
||||
mm->cf == 6))) { // ADS-B rebroadcast using the same type codes and message formats as defined for DF = 17 ADS-B messages
|
||||
decodeExtendedSquitter(mm);
|
||||
}
|
||||
|
||||
// MV (message, ACAS) not decoded
|
||||
// ND (number of D-segment) not decoded
|
||||
// RI (Reply information) not decoded
|
||||
// SL (Sensitivity level, ACAS) not decoded
|
||||
// UM (Utility Message) not decoded
|
||||
|
||||
// VS (Vertical Status)
|
||||
if (mm->msgtype == 0 || mm->msgtype == 16) {
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
if (msg[0] & 0x04)
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG;
|
||||
}
|
||||
|
||||
// all done
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decode BDS2,0 carried in Comm-B or ES
|
||||
static void decodeBDS20(struct modesMessage *mm)
|
||||
{
|
||||
uint32_t chars1, chars2;
|
||||
unsigned char *msg = mm->msg;
|
||||
|
||||
chars1 = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
|
||||
chars2 = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
|
||||
|
||||
// A common failure mode seems to be to intermittently send
|
||||
// all zeros. Catch that here.
|
||||
if (chars1 == 0 && chars2 == 0)
|
||||
return;
|
||||
|
||||
mm->bFlags |= MODES_ACFLAGS_CALLSIGN_VALID;
|
||||
|
||||
mm->flight[3] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[2] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[1] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[0] = ais_charset[chars1 & 0x3F];
|
||||
|
||||
mm->flight[7] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[6] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[5] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[4] = ais_charset[chars2 & 0x3F];
|
||||
|
||||
mm->flight[8] = '\0';
|
||||
}
|
||||
|
||||
static void decodeExtendedSquitter(struct modesMessage *mm)
|
||||
{
|
||||
unsigned char *msg = mm->msg;
|
||||
int metype = mm->metype = msg[4] >> 3; // Extended squitter message type
|
||||
int mesub = mm->mesub = (metype == 29 ? ((msg[4]&6)>>1) : (msg[4] & 7)); // Extended squitter message subtype
|
||||
|
||||
// Decode the extended squitter message
|
||||
switch (metype) {
|
||||
case 1: case 2: case 3: case 4: {
|
||||
// Aircraft Identification and Category
|
||||
uint32_t chars1, chars2;
|
||||
|
||||
if (metype >= 1 && metype <= 4) { // Aircraft Identification and Category
|
||||
uint32_t chars;
|
||||
chars1 = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
|
||||
chars2 = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
|
||||
|
||||
// A common failure mode seems to be to intermittently send
|
||||
// all zeros. Catch that here.
|
||||
if (chars1 != 0 || chars2 != 0) {
|
||||
mm->bFlags |= MODES_ACFLAGS_CALLSIGN_VALID;
|
||||
|
||||
chars = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
|
||||
mm->flight[3] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[2] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[1] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[0] = ais_charset[chars & 0x3F];
|
||||
mm->flight[3] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[2] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[1] = ais_charset[chars1 & 0x3F]; chars1 = chars1 >> 6;
|
||||
mm->flight[0] = ais_charset[chars1 & 0x3F];
|
||||
|
||||
chars = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
|
||||
mm->flight[7] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[6] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[5] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[4] = ais_charset[chars & 0x3F];
|
||||
mm->flight[7] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[6] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[5] = ais_charset[chars2 & 0x3F]; chars2 = chars2 >> 6;
|
||||
mm->flight[4] = ais_charset[chars2 & 0x3F];
|
||||
|
||||
mm->flight[8] = '\0';
|
||||
}
|
||||
|
||||
} else if (metype == 19) { // Airborne Velocity Message
|
||||
break;
|
||||
}
|
||||
|
||||
case 19: { // Airborne Velocity Message
|
||||
// Presumably airborne if we get an Airborne Velocity Message
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
|
||||
|
@ -497,21 +627,20 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
}
|
||||
}
|
||||
|
||||
} else if (metype >= 5 && metype <= 22) { // Position Message
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: case 6: case 7: case 8: {
|
||||
// Ground position
|
||||
int movement;
|
||||
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
mm->raw_latitude = ((msg[6] & 3) << 15) | (msg[7] << 7) | (msg[8] >> 1);
|
||||
mm->raw_longitude = ((msg[8] & 1) << 16) | (msg[9] << 8) | (msg[10]);
|
||||
mm->bFlags |= (mm->msg[6] & 0x04) ? MODES_ACFLAGS_LLODD_VALID
|
||||
: MODES_ACFLAGS_LLEVEN_VALID;
|
||||
if (metype >= 9) { // Airborne
|
||||
int AC12Field = ((msg[5] << 4) | (msg[6] >> 4)) & 0x0FFF;
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
if (AC12Field) {// Only attempt to decode if a valid (non zero) altitude is present
|
||||
mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
|
||||
mm->altitude = decodeAC12Field(AC12Field, &mm->unit);
|
||||
}
|
||||
} else { // Ground
|
||||
int movement = ((msg[4] << 4) | (msg[5] >> 4)) & 0x007F;
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG;
|
||||
|
||||
movement = ((msg[4] << 4) | (msg[5] >> 4)) & 0x007F;
|
||||
if ((movement) && (movement < 125)) {
|
||||
mm->bFlags |= MODES_ACFLAGS_SPEED_VALID;
|
||||
mm->velocity = decodeMovementField(movement);
|
||||
|
@ -521,9 +650,48 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
mm->bFlags |= MODES_ACFLAGS_HEADING_VALID;
|
||||
mm->heading = ((((msg[5] << 4) | (msg[6] >> 4)) & 0x007F) * 45) >> 4;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (metype == 23) { // Test metype squawk field
|
||||
case 0: // Airborne position, baro altitude only
|
||||
case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: // Airborne position, baro
|
||||
case 20: case 21: case 22: { // Airborne position, GNSS HAE
|
||||
int AC12Field = ((msg[5] << 4) | (msg[6] >> 4)) & 0x0FFF;
|
||||
|
||||
mm->bFlags |= MODES_ACFLAGS_AOG_VALID;
|
||||
|
||||
if (metype != 0) {
|
||||
// Catch some common failure modes and don't mark them as valid
|
||||
// (so they won't be used for positioning)
|
||||
|
||||
mm->raw_latitude = ((msg[6] & 3) << 15) | (msg[7] << 7) | (msg[8] >> 1);
|
||||
mm->raw_longitude = ((msg[8] & 1) << 16) | (msg[9] << 8) | (msg[10]);
|
||||
|
||||
if (AC12Field == 0 && mm->raw_longitude == 0 && (mm->raw_latitude & 0x0fff) == 0 && mm->metype == 15) {
|
||||
// Seen from at least:
|
||||
// 400F3F (Eurocopter ECC155 B1) - Bristow Helicopters
|
||||
// 4008F3 (BAE ATP) - Atlantic Airlines
|
||||
// 400648 (BAE ATP) - Atlantic Airlines
|
||||
// altitude == 0, longitude == 0, type == 15 and zeros in latitude LSB.
|
||||
// Can alternate with valid reports having type == 14
|
||||
Modes.stats_current.cpr_filtered++;
|
||||
} else {
|
||||
// Otherwise, assume it's valid.
|
||||
mm->bFlags |= (mm->msg[6] & 0x04) ? MODES_ACFLAGS_LLODD_VALID
|
||||
: MODES_ACFLAGS_LLEVEN_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
if (AC12Field) {// Only attempt to decode if a valid (non zero) altitude is present
|
||||
mm->bFlags |= MODES_ACFLAGS_ALTITUDE_VALID;
|
||||
mm->altitude = decodeAC12Field(AC12Field, &mm->unit);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 23: { // Test message
|
||||
if (mesub == 7) { // (see 1090-WP-15-20)
|
||||
int ID13Field = (((msg[5] << 8) | msg[6]) & 0xFFF1)>>3;
|
||||
if (ID13Field) {
|
||||
|
@ -531,10 +699,13 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
mm->modeA = decodeID13Field(ID13Field);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (metype == 24) { // Reserved for Surface System Status
|
||||
case 24: // Reserved for Surface System Status
|
||||
break;
|
||||
|
||||
} else if (metype == 28) { // Extended Squitter Aircraft Status
|
||||
case 28: { // Extended Squitter Aircraft Status
|
||||
if (mesub == 1) { // Emergency status squawk field
|
||||
int ID13Field = (((msg[5] << 8) | msg[6]) & 0x1FFF);
|
||||
if (ID13Field) {
|
||||
|
@ -542,48 +713,131 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
|
|||
mm->modeA = decodeID13Field(ID13Field);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (metype == 29) { // Aircraft Trajectory Intent
|
||||
case 29: // Aircraft Trajectory Intent
|
||||
break;
|
||||
|
||||
} else if (metype == 30) { // Aircraft Operational Coordination
|
||||
case 30: // Aircraft Operational Coordination
|
||||
break;
|
||||
|
||||
} else if (metype == 31) { // Aircraft Operational Status
|
||||
|
||||
} else { // Other metypes
|
||||
case 31: // Aircraft Operational Status
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fields for DF20, DF21 Comm-B
|
||||
if ((mm->msgtype == 20) || (mm->msgtype == 21)){
|
||||
static void decodeCommB(struct modesMessage *mm)
|
||||
{
|
||||
unsigned char *msg = mm->msg;
|
||||
|
||||
if (msg[4] == 0x20) { // Aircraft Identification
|
||||
uint32_t chars;
|
||||
mm->bFlags |= MODES_ACFLAGS_CALLSIGN_VALID;
|
||||
|
||||
chars = (msg[5] << 16) | (msg[6] << 8) | (msg[7]);
|
||||
mm->flight[3] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[2] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[1] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[0] = ais_charset[chars & 0x3F];
|
||||
|
||||
chars = (msg[8] << 16) | (msg[9] << 8) | (msg[10]);
|
||||
mm->flight[7] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[6] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[5] = ais_charset[chars & 0x3F]; chars = chars >> 6;
|
||||
mm->flight[4] = ais_charset[chars & 0x3F];
|
||||
|
||||
mm->flight[8] = '\0';
|
||||
} else {
|
||||
}
|
||||
// This is a bit hairy as we don't know what the requested register was
|
||||
if (msg[4] == 0x20) { // BDS 2,0 Aircraft Identification
|
||||
decodeBDS20(mm);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//=========================================================================
|
||||
//
|
||||
// This function gets a decoded Mode S Message and prints it on the screen
|
||||
// These functions gets a decoded Mode S Message and prints it on the screen
|
||||
// in a human readable format.
|
||||
//
|
||||
static void displayExtendedSquitter(struct modesMessage *mm) {
|
||||
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 == 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 >= 5 && mm->metype <= 22) { // 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) {
|
||||
if (mm->bFlags & MODES_ACFLAGS_REL_CPR_USED)
|
||||
printf(" Local CPR decoding used.\n");
|
||||
else
|
||||
printf(" Global CPR decoding used.\n");
|
||||
printf(" Latitude : %f (%d)\n", mm->fLat, mm->raw_latitude);
|
||||
printf(" Longitude: %f (%d)\n", mm->fLon, mm->raw_longitude);
|
||||
} else {
|
||||
if (!(mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID))
|
||||
printf(" Bad position data, not decoded.\n");
|
||||
printf(" Latitude : %d (not decoded)\n", mm->raw_latitude);
|
||||
printf(" Longitude: %d (not decoded)\n", mm->raw_longitude);
|
||||
}
|
||||
} else if (mm->metype == 28) { // Extended Squitter Aircraft Status
|
||||
if (mm->mesub == 1) {
|
||||
printf(" Emergency State: %s\n", es_str[(mm->msg[5] & 0xE0) >> 5]);
|
||||
printf(" Squawk: %04x\n", mm->modeA);
|
||||
} else {
|
||||
printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
} else if (mm->metype == 23) { // Test Message
|
||||
if (mm->mesub == 7) {
|
||||
printf(" Squawk: %04x\n", mm->modeA);
|
||||
} else {
|
||||
printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
} else {
|
||||
printf(" Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
}
|
||||
|
||||
static void displayCommB(struct modesMessage *mm)
|
||||
{
|
||||
if (mm->bds != 0)
|
||||
printf(" Comm-B BDS : %02x (maybe)\n", mm->bds);
|
||||
|
||||
// Decode the extended squitter message
|
||||
if ( mm->msg[4] == 0x20) { // BDS 2,0 Aircraft identification
|
||||
printf(" BDS 2,0 Aircraft Identification : %s\n", mm->flight);
|
||||
/*
|
||||
} else if ( mm->msg[4] == 0x10) { // BDS 1,0 Datalink Capability report
|
||||
printf(" BDS 1,0 Datalink Capability report\n");
|
||||
|
||||
} else if ( mm->msg[4] == 0x30) { // BDS 3,0 ACAS Active Resolution Advisory
|
||||
printf(" BDS 3,0 ACAS Active Resolution Advisory\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 28) { // BDS 6,1 Extended Squitter Emergency/Priority Status
|
||||
printf(" BDS 6,1 Emergency/Priority Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 29) { // BDS 6,2 Target State and Status
|
||||
printf(" BDS 6,2 Target State and Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 31) { // BDS 6,5 Extended Squitter Aircraft Operational Status
|
||||
printf(" BDS 6,5 Aircraft Operational Status\n");
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void displayModesMessage(struct modesMessage *mm) {
|
||||
int j;
|
||||
unsigned char * pTimeStamp;
|
||||
|
@ -613,7 +867,7 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
}
|
||||
|
||||
if (mm->msgtype < 32)
|
||||
printf("CRC: %06x (%s)\n", (int)mm->crc, mm->crcok ? "ok" : "wrong");
|
||||
printf("CRC: %06x\n", mm->crc);
|
||||
|
||||
if (mm->correctedbits != 0)
|
||||
printf("No. of bit errors fixed: %d\n", mm->correctedbits);
|
||||
|
@ -643,30 +897,8 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
printf(" ICAO Address : %06x\n", mm->addr);
|
||||
|
||||
if (mm->msgtype == 20) {
|
||||
printf(" Comm-B BDS : %x\n", mm->msg[4]);
|
||||
|
||||
// Decode the extended squitter message
|
||||
if ( mm->msg[4] == 0x20) { // BDS 2,0 Aircraft identification
|
||||
printf(" BDS 2,0 Aircraft Identification : %s\n", mm->flight);
|
||||
/*
|
||||
} else if ( mm->msg[4] == 0x10) { // BDS 1,0 Datalink Capability report
|
||||
printf(" BDS 1,0 Datalink Capability report\n");
|
||||
|
||||
} else if ( mm->msg[4] == 0x30) { // BDS 3,0 ACAS Active Resolution Advisory
|
||||
printf(" BDS 3,0 ACAS Active Resolution Advisory\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 28) { // BDS 6,1 Extended Squitter Emergency/Priority Status
|
||||
printf(" BDS 6,1 Emergency/Priority Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 29) { // BDS 6,2 Target State and Status
|
||||
printf(" BDS 6,2 Target State and Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 31) { // BDS 6,5 Extended Squitter Aircraft Operational Status
|
||||
printf(" BDS 6,5 Aircraft Operational Status\n");
|
||||
*/
|
||||
displayCommB(mm);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 5 || mm->msgtype == 21) {
|
||||
printf("DF %d: %s, Identity Reply.\n", mm->msgtype,
|
||||
(mm->msgtype == 5) ? "Surveillance" : "Comm-B");
|
||||
|
@ -677,30 +909,8 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
printf(" ICAO Address : %06x\n", mm->addr);
|
||||
|
||||
if (mm->msgtype == 21) {
|
||||
printf(" Comm-B BDS : %x\n", mm->msg[4]);
|
||||
|
||||
// Decode the extended squitter message
|
||||
if ( mm->msg[4] == 0x20) { // BDS 2,0 Aircraft identification
|
||||
printf(" BDS 2,0 Aircraft Identification : %s\n", mm->flight);
|
||||
/*
|
||||
} else if ( mm->msg[4] == 0x10) { // BDS 1,0 Datalink Capability report
|
||||
printf(" BDS 1,0 Datalink Capability report\n");
|
||||
|
||||
} else if ( mm->msg[4] == 0x30) { // BDS 3,0 ACAS Active Resolution Advisory
|
||||
printf(" BDS 3,0 ACAS Active Resolution Advisory\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 28) { // BDS 6,1 Extended Squitter Emergency/Priority Status
|
||||
printf(" BDS 6,1 Emergency/Priority Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 29) { // BDS 6,2 Target State and Status
|
||||
printf(" BDS 6,2 Target State and Status\n");
|
||||
|
||||
} else if ((mm->msg[4] >> 3) == 31) { // BDS 6,5 Extended Squitter Aircraft Operational Status
|
||||
printf(" BDS 6,5 Aircraft Operational Status\n");
|
||||
*/
|
||||
displayCommB(mm);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 11) { // DF 11
|
||||
printf("DF 11: All Call Reply.\n");
|
||||
printf(" Capability : %d (%s)\n", mm->ca, ca_str[mm->ca]);
|
||||
|
@ -723,124 +933,17 @@ void displayModesMessage(struct modesMessage *mm) {
|
|||
printf("DF 17: ADS-B message.\n");
|
||||
printf(" Capability : %d (%s)\n", mm->ca, ca_str[mm->ca]);
|
||||
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 == 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 >= 5 && mm->metype <= 22) { // 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 == 28) { // Extended Squitter Aircraft Status
|
||||
if (mm->mesub == 1) {
|
||||
printf(" Emergency State: %s\n", es_str[(mm->msg[5] & 0xE0) >> 5]);
|
||||
printf(" Squawk: %04x\n", mm->modeA);
|
||||
} else {
|
||||
printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
|
||||
} else if (mm->metype == 23) { // Test Message
|
||||
if (mm->mesub == 7) {
|
||||
printf(" Squawk: %04x\n", mm->modeA);
|
||||
} else {
|
||||
printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
} else {
|
||||
printf(" Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
|
||||
displayExtendedSquitter(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) {
|
||||
if ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 5) || (mm->ca == 6)) {
|
||||
if (mm->ca == 1 || mm->ca == 5) {
|
||||
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 == 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 >= 5 && mm->metype <= 22) { // Ground or Airborne position, Baro or GNSS
|
||||
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 {
|
||||
printf(" Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub);
|
||||
}
|
||||
displayExtendedSquitter(mm);
|
||||
}
|
||||
|
||||
} else if (mm->msgtype == 19) { // DF 19
|
||||
|
@ -898,7 +1001,6 @@ void computeMagnitudeVector(uint16_t *p) {
|
|||
// processing and visualization
|
||||
//
|
||||
void useModesMessage(struct modesMessage *mm) {
|
||||
if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed
|
||||
++Modes.stats_current.messages_total;
|
||||
|
||||
// If we are decoding, track aircraft
|
||||
|
@ -912,7 +1014,6 @@ void useModesMessage(struct modesMessage *mm) {
|
|||
// Feed output clients
|
||||
if (Modes.net) {modesQueueOutput(mm);}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ===================== Mode S detection and decoding ===================
|
||||
|
|
14
net_io.c
14
net_io.c
|
@ -579,7 +579,12 @@ int decodeBinMessage(struct client *c, char *p) {
|
|||
if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC
|
||||
decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
|
||||
} else {
|
||||
decodeModesMessage(&mm, msg);
|
||||
if (decodeModesMessage(&mm, msg) < 0) {
|
||||
Modes.stats_current.remote_rejected++;
|
||||
return 0;
|
||||
} else {
|
||||
Modes.stats_current.remote_accepted++;
|
||||
}
|
||||
}
|
||||
|
||||
useModesMessage(&mm);
|
||||
|
@ -678,7 +683,12 @@ int decodeHexMessage(struct client *c, char *hex) {
|
|||
if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC
|
||||
decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
|
||||
} else { // Assume ModeS
|
||||
decodeModesMessage(&mm, msg);
|
||||
if (decodeModesMessage(&mm, msg) < 0) {
|
||||
Modes.stats_current.remote_rejected++;
|
||||
return 0;
|
||||
} else {
|
||||
Modes.stats_current.remote_accepted++;
|
||||
}
|
||||
}
|
||||
|
||||
useModesMessage(&mm);
|
||||
|
|
Loading…
Reference in a new issue