Overhaul mode A/C matching to be much cheaper.
The old matching process which tracked mode A values as pseudo-aircraft got very, very expensive with a large number of mode A/C messages (and with lots of single-bit errors, which seems common with a Beast doing the reception) Instead just count A/C messages directly into a 4096-entry array (which is very fast) and periodically scan the mode S aircraft list to see if we can match anything up (which is fixed overhead + cost proportional to the number of mode S aircraft)
This commit is contained in:
parent
60f1f3bcb6
commit
25ea6d398b
|
@ -105,12 +105,6 @@ typedef struct rtlsdr_dev rtlsdr_dev_t;
|
||||||
#define MODEAC_MSG_SAMPLES (25 * 2) // include up to the SPI bit
|
#define MODEAC_MSG_SAMPLES (25 * 2) // include up to the SPI bit
|
||||||
#define MODEAC_MSG_BYTES 2
|
#define MODEAC_MSG_BYTES 2
|
||||||
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit
|
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit
|
||||||
#define MODEAC_MSG_FLAG (1<<0)
|
|
||||||
#define MODEAC_MSG_MODES_HIT (1<<1)
|
|
||||||
#define MODEAC_MSG_MODEA_HIT (1<<2)
|
|
||||||
#define MODEAC_MSG_MODEC_HIT (1<<3)
|
|
||||||
#define MODEAC_MSG_MODEA_ONLY (1<<4)
|
|
||||||
#define MODEAC_MSG_MODEC_OLD (1<<5)
|
|
||||||
|
|
||||||
#define MODES_PREAMBLE_US 8 // microseconds = bits
|
#define MODES_PREAMBLE_US 8 // microseconds = bits
|
||||||
#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2)
|
#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2)
|
||||||
|
|
|
@ -111,12 +111,8 @@ void interactiveShowData(void) {
|
||||||
if ((now - a->seen) < Modes.interactive_display_ttl)
|
if ((now - a->seen) < Modes.interactive_display_ttl)
|
||||||
{
|
{
|
||||||
int msgs = a->messages;
|
int msgs = a->messages;
|
||||||
int flags = a->modeACflags;
|
|
||||||
|
|
||||||
if ( (((flags & (MODEAC_MSG_FLAG )) == 0 ) && (msgs > 1 ) )
|
if (msgs > 1) {
|
||||||
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEA_ONLY)) == MODEAC_MSG_MODEA_ONLY) && (msgs > 4 ) )
|
|
||||||
|| (((flags & (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD )) == 0 ) && (msgs > 127) )
|
|
||||||
) {
|
|
||||||
char strSquawk[5] = " ";
|
char strSquawk[5] = " ";
|
||||||
char strFl[7] = " ";
|
char strFl[7] = " ";
|
||||||
char strTt[5] = " ";
|
char strTt[5] = " ";
|
||||||
|
@ -153,13 +149,9 @@ void interactiveShowData(void) {
|
||||||
double signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
|
double signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
|
||||||
pSig[4] + pSig[5] + pSig[6] + pSig[7]) / 8.0;
|
pSig[4] + pSig[5] + pSig[6] + pSig[7]) / 8.0;
|
||||||
|
|
||||||
if ((flags & MODEAC_MSG_FLAG) == 0) {
|
|
||||||
strMode[0] = 'S';
|
strMode[0] = 'S';
|
||||||
} else if (flags & MODEAC_MSG_MODEA_ONLY) {
|
if (a->modeA_hit) {strMode[2] = 'a';}
|
||||||
strMode[0] = 'A';
|
if (a->modeC_hit) {strMode[3] = 'c';}
|
||||||
}
|
|
||||||
if (flags & MODEAC_MSG_MODEA_HIT) {strMode[2] = 'a';}
|
|
||||||
if (flags & MODEAC_MSG_MODEC_HIT) {strMode[3] = 'c';}
|
|
||||||
|
|
||||||
if (trackDataValid(&a->position_valid)) {
|
if (trackDataValid(&a->position_valid)) {
|
||||||
snprintf(strLat, 8,"%7.03f", a->lat);
|
snprintf(strLat, 8,"%7.03f", a->lat);
|
||||||
|
@ -184,6 +176,37 @@ void interactiveShowData(void) {
|
||||||
}
|
}
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Modes.interactive_rtl1090 && Modes.mode_ac) {
|
||||||
|
for (unsigned i = 1; i < 4096 && count < Modes.interactive_rows; ++i) {
|
||||||
|
if (modeAC_match[i] || modeAC_count[i] < 100)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char strMode[5] = " A ";
|
||||||
|
char strFl[7] = " ";
|
||||||
|
unsigned modeA = indexToModeA(i);
|
||||||
|
int modeC = modeAToModeC(modeA);
|
||||||
|
if (modeC != INVALID_ALTITUDE) {
|
||||||
|
strMode[3] = 'C';
|
||||||
|
snprintf(strFl, 7, "%5d ", convert_altitude(modeC * 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%7s %-4s %04x %-8s %6s %3s %3s %7s %8s %5s %5d %2s\n",
|
||||||
|
"", /* address */
|
||||||
|
strMode, /* mode */
|
||||||
|
modeA, /* squawk */
|
||||||
|
"", /* callsign */
|
||||||
|
strFl, /* altitude */
|
||||||
|
"", /* gs */
|
||||||
|
"", /* heading */
|
||||||
|
"", /* lat */
|
||||||
|
"", /* lon */
|
||||||
|
"", /* signal */
|
||||||
|
modeAC_count[i], /* messages */
|
||||||
|
""); /* seen */
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
2
mode_s.c
2
mode_s.c
|
@ -1806,7 +1806,7 @@ void useModesMessage(struct modesMessage *mm) {
|
||||||
// If this is the second message, and we
|
// If this is the second message, and we
|
||||||
// squelched the first message, then re-emit the
|
// squelched the first message, then re-emit the
|
||||||
// first message now.
|
// first message now.
|
||||||
if (!Modes.net_verbatim && a->messages == 2) {
|
if (!Modes.net_verbatim && a && a->messages == 2) {
|
||||||
modesQueueOutput(&a->first_message, a);
|
modesQueueOutput(&a->first_message, a);
|
||||||
}
|
}
|
||||||
modesQueueOutput(mm, a);
|
modesQueueOutput(mm, a);
|
||||||
|
|
8
net_io.c
8
net_io.c
|
@ -710,7 +710,7 @@ static void send_sbs_heartbeat(struct net_service *service)
|
||||||
void modesQueueOutput(struct modesMessage *mm, struct aircraft *a) {
|
void modesQueueOutput(struct modesMessage *mm, struct aircraft *a) {
|
||||||
int is_mlat = (mm->source == SOURCE_MLAT);
|
int is_mlat = (mm->source == SOURCE_MLAT);
|
||||||
|
|
||||||
if (!is_mlat && mm->correctedbits < 2) {
|
if (a && !is_mlat && mm->correctedbits < 2) {
|
||||||
// Don't ever forward 2-bit-corrected messages via SBS output.
|
// Don't ever forward 2-bit-corrected messages via SBS output.
|
||||||
// Don't ever forward mlat messages via SBS output.
|
// Don't ever forward mlat messages via SBS output.
|
||||||
modesSendSBSOutput(mm, a);
|
modesSendSBSOutput(mm, a);
|
||||||
|
@ -728,7 +728,7 @@ void modesQueueOutput(struct modesMessage *mm, struct aircraft *a) {
|
||||||
modesSendBeastOutput(mm);
|
modesSendBeastOutput(mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_mlat) {
|
if (a && !is_mlat) {
|
||||||
writeFATSVEvent(mm, a);
|
writeFATSVEvent(mm, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1027,10 +1027,6 @@ char *generateAircraftJson(const char *url_path, int *len) {
|
||||||
Modes.stats_current.messages_total + Modes.stats_alltime.messages_total);
|
Modes.stats_current.messages_total + Modes.stats_alltime.messages_total);
|
||||||
|
|
||||||
for (a = Modes.aircrafts; a; a = a->next) {
|
for (a = Modes.aircrafts; a; a = a->next) {
|
||||||
if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a->messages < 2) { // basic filter for bad decodes
|
if (a->messages < 2) { // basic filter for bad decodes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
154
track.c
154
track.c
|
@ -52,6 +52,10 @@
|
||||||
|
|
||||||
/* #define DEBUG_CPR_CHECKS */
|
/* #define DEBUG_CPR_CHECKS */
|
||||||
|
|
||||||
|
uint32_t modeAC_count[4096];
|
||||||
|
uint32_t modeAC_lastcount[4096];
|
||||||
|
uint32_t modeAC_match[4096];
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return a new aircraft structure for the linked list of tracked
|
// Return a new aircraft structure for the linked list of tracked
|
||||||
// aircraft
|
// aircraft
|
||||||
|
@ -76,16 +80,6 @@ struct aircraft *trackCreateAircraft(struct modesMessage *mm) {
|
||||||
a->fatsv_emitted_bds_30[0] = 0x30;
|
a->fatsv_emitted_bds_30[0] = 0x30;
|
||||||
a->fatsv_emitted_es_acas_ra[0] = 0xE2;
|
a->fatsv_emitted_es_acas_ra[0] = 0xE2;
|
||||||
|
|
||||||
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
|
|
||||||
// set them once here during initialisation, and don't bother to set them every
|
|
||||||
// time this ModeA/C is received again in the future
|
|
||||||
if (mm->msgtype == 32) {
|
|
||||||
a->modeACflags = MODEAC_MSG_FLAG;
|
|
||||||
if (!mm->altitude_valid) {
|
|
||||||
a->modeACflags |= MODEAC_MSG_MODEA_ONLY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the first message so we can emit it later when a second message arrives.
|
// Copy the first message so we can emit it later when a second message arrives.
|
||||||
a->first_message = *mm;
|
a->first_message = *mm;
|
||||||
|
|
||||||
|
@ -520,6 +514,13 @@ static void updatePosition(struct aircraft *a, struct modesMessage *mm, uint64_t
|
||||||
struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
{
|
{
|
||||||
struct aircraft *a;
|
struct aircraft *a;
|
||||||
|
|
||||||
|
if (mm->msgtype == 32) {
|
||||||
|
// Mode A/C, just count it (we ignore SPI)
|
||||||
|
modeAC_count[modeAToIndex(mm->squawk)]++;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t now = mstime();
|
uint64_t now = mstime();
|
||||||
|
|
||||||
// Lookup our aircraft or create a new one
|
// Lookup our aircraft or create a new one
|
||||||
|
@ -542,20 +543,20 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
a->addrtype = mm->addrtype;
|
a->addrtype = mm->addrtype;
|
||||||
|
|
||||||
if (mm->altitude_valid && mm->altitude_source == ALTITUDE_BARO && accept_data(&a->altitude_valid, mm->source, now)) {
|
if (mm->altitude_valid && mm->altitude_source == ALTITUDE_BARO && accept_data(&a->altitude_valid, mm->source, now)) {
|
||||||
unsigned modeC = (a->altitude + 49) / 100;
|
if (a->modeC_hit) {
|
||||||
if (modeC != a->altitude_modeC) {
|
int new_modeC = (a->altitude + 49) / 100;
|
||||||
a->modeCcount = 0; //....zero the hit count
|
int old_modeC = (mm->altitude + 49) / 100;
|
||||||
a->modeACflags &= ~MODEAC_MSG_MODEC_HIT;
|
if (new_modeC != old_modeC) {
|
||||||
|
a->modeC_hit = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a->altitude = mm->altitude;
|
a->altitude = mm->altitude;
|
||||||
a->altitude_modeC = modeC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mm->squawk_valid && accept_data(&a->squawk_valid, mm->source, now)) {
|
if (mm->squawk_valid && accept_data(&a->squawk_valid, mm->source, now)) {
|
||||||
if (mm->squawk != a->squawk) {
|
if (mm->squawk != a->squawk) {
|
||||||
a->modeAcount = 0; //....zero the hit count
|
a->modeA_hit = 0;
|
||||||
a->modeACflags &= ~MODEAC_MSG_MODEA_HIT;
|
|
||||||
}
|
}
|
||||||
a->squawk = mm->squawk;
|
a->squawk = mm->squawk;
|
||||||
}
|
}
|
||||||
|
@ -636,24 +637,6 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
updatePosition(a, mm, now);
|
updatePosition(a, mm, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mm->msgtype == 32) {
|
|
||||||
int flags = a->modeACflags;
|
|
||||||
if ((flags & (MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODEC_OLD)) == MODEAC_MSG_MODEC_OLD) {
|
|
||||||
//
|
|
||||||
// This Mode-C doesn't currently hit any known Mode-S, but it used to because MODEAC_MSG_MODEC_OLD is
|
|
||||||
// set So the aircraft it used to match has either changed altitude, or gone out of our receiver range
|
|
||||||
//
|
|
||||||
// We've now received this Mode-A/C again, so it must be a new aircraft. It could be another aircraft
|
|
||||||
// at the same Mode-C altitude, or it could be a new airctraft with a new Mods-A squawk.
|
|
||||||
//
|
|
||||||
// To avoid masking this aircraft from the interactive display, clear the MODEAC_MSG_MODES_OLD flag
|
|
||||||
// and set messages to 1;
|
|
||||||
//
|
|
||||||
a->modeACflags = flags & ~MODEAC_MSG_MODEC_OLD;
|
|
||||||
a->messages = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (a);
|
return (a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,85 +644,50 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
// Periodic updates of tracking state
|
// Periodic updates of tracking state
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
// Periodically match up mode A/C results with mode S results
|
||||||
//=========================================================================
|
static void trackMatchAC(uint64_t now)
|
||||||
//
|
|
||||||
// Periodically search through the list of known Mode-S aircraft and tag them if this
|
|
||||||
// Mode A/C matches their known Mode S Squawks or Altitudes(+/- 50feet).
|
|
||||||
//
|
|
||||||
// A Mode S equipped aircraft may also respond to Mode A and Mode C SSR interrogations.
|
|
||||||
// We can't tell if this is a Mode A or C, so scan through the entire aircraft list
|
|
||||||
// looking for matches on Mode A (squawk) and Mode C (altitude). Flag in the Mode S
|
|
||||||
// records that we have had a potential Mode A or Mode C response from this aircraft.
|
|
||||||
//
|
|
||||||
// If an aircraft responds to Mode A then it's highly likely to be responding to mode C
|
|
||||||
// too, and vice verca. Therefore, once the mode S record is tagged with both a Mode A
|
|
||||||
// and a Mode C flag, we can be fairly confident that this Mode A/C frame relates to that
|
|
||||||
// Mode S aircraft.
|
|
||||||
//
|
|
||||||
// Mode C's are more likely to clash than Mode A's; There could be several aircraft
|
|
||||||
// cruising at FL370, but it's less likely (though not impossible) that there are two
|
|
||||||
// aircraft on the same squawk. Therefore, give precidence to Mode A record matches
|
|
||||||
//
|
|
||||||
// Note : It's theoretically possible for an aircraft to have the same value for Mode A
|
|
||||||
// and Mode C. Therefore we have to check BOTH A AND C for EVERY S.
|
|
||||||
//
|
|
||||||
static void trackUpdateAircraftModeA(struct aircraft *a)
|
|
||||||
{
|
{
|
||||||
struct aircraft *b = Modes.aircrafts;
|
// clear match flags
|
||||||
|
for (unsigned i = 0; i < 4096; ++i) {
|
||||||
|
modeAC_match[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
while(b) {
|
// scan aircraft list, look for matches
|
||||||
if ((b->modeACflags & MODEAC_MSG_FLAG) == 0) { // skip any fudged ICAO records
|
for (struct aircraft *a = Modes.aircrafts; a; a = a->next) {
|
||||||
|
if ((now - a->seen) > 5000) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If both (a) and (b) have valid squawks...
|
// match on Mode A
|
||||||
if (trackDataValid(&a->squawk_valid) && trackDataValid(&b->squawk_valid)) {
|
if (trackDataValid(&a->squawk_valid)) {
|
||||||
// ...check for Mode-A == Mode-S Squawk matches
|
unsigned i = modeAToIndex(a->squawk);
|
||||||
if (a->squawk == b->squawk) { // If a 'real' Mode-S ICAO exists using this Mode-A Squawk
|
if ((modeAC_count[i] - modeAC_lastcount[i]) > TRACK_MODEAC_MIN_MESSAGES) {
|
||||||
b->modeAcount = a->messages;
|
a->modeA_hit = 1;
|
||||||
b->modeACflags |= MODEAC_MSG_MODEA_HIT;
|
modeAC_match[i] = (modeAC_match[i] ? 0xFFFFFFFF : a->addr);
|
||||||
a->modeACflags |= MODEAC_MSG_MODEA_HIT;
|
|
||||||
if ( (b->modeAcount > 0) &&
|
|
||||||
( (b->modeCcount > 1)
|
|
||||||
|| (a->modeACflags & MODEAC_MSG_MODEA_ONLY)) ) // Allow Mode-A only matches if this Mode-A is invalid Mode-C
|
|
||||||
{a->modeACflags |= MODEAC_MSG_MODES_HIT;} // flag this ModeA/C probably belongs to a known Mode S
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If both (a) and (b) have valid altitudes...
|
// match on Mode C
|
||||||
if (trackDataValid(&a->altitude_valid) && trackDataValid(&b->altitude_valid)) {
|
if (trackDataValid(&a->altitude_valid)) {
|
||||||
// ... check for Mode-C == Mode-S Altitude matches
|
int modeC = (a->altitude + 49) / 100;
|
||||||
if ( (a->altitude_modeC == b->altitude_modeC ) // If a 'real' Mode-S ICAO exists at this Mode-C Altitude
|
unsigned modeA = modeCToModeA(modeC);
|
||||||
|| (a->altitude_modeC == b->altitude_modeC + 1) // or this Mode-C - 100 ft
|
if (modeA) {
|
||||||
|| (a->altitude_modeC + 1 == b->altitude_modeC ) ) { // or this Mode-C + 100 ft
|
unsigned i = modeAToIndex(modeA);
|
||||||
b->modeCcount = a->messages;
|
if ((modeAC_count[i] - modeAC_lastcount[i]) > TRACK_MODEAC_MIN_MESSAGES) {
|
||||||
b->modeACflags |= MODEAC_MSG_MODEC_HIT;
|
a->modeC_hit = 1;
|
||||||
a->modeACflags |= MODEAC_MSG_MODEC_HIT;
|
modeAC_match[i] = (modeAC_match[i] ? 0xFFFFFFFF : a->addr);
|
||||||
if ( (b->modeAcount > 0) &&
|
|
||||||
(b->modeCcount > 1) )
|
|
||||||
{a->modeACflags |= (MODEAC_MSG_MODES_HIT | MODEAC_MSG_MODEC_OLD);} // flag this ModeA/C probably belongs to a known Mode S
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b = b->next;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//
|
|
||||||
//=========================================================================
|
|
||||||
//
|
|
||||||
static void trackUpdateAircraftModeS()
|
|
||||||
{
|
|
||||||
struct aircraft *a = Modes.aircrafts;
|
|
||||||
|
|
||||||
while(a) {
|
// reset counts for next time
|
||||||
int flags = a->modeACflags;
|
for (unsigned i = 0; i < 4096; ++i) {
|
||||||
if (flags & MODEAC_MSG_FLAG) { // find any fudged ICAO records
|
if ((modeAC_count[i] - modeAC_lastcount[i]) <= TRACK_MODEAC_MIN_MESSAGES) {
|
||||||
|
modeAC_lastcount[i] = modeAC_count[i] = 0;
|
||||||
// clear the current A,C and S hit bits ready for this attempt
|
} else {
|
||||||
a->modeACflags = flags & ~(MODEAC_MSG_MODEA_HIT | MODEAC_MSG_MODEC_HIT | MODEAC_MSG_MODES_HIT);
|
modeAC_lastcount[i] = modeAC_count[i];
|
||||||
|
|
||||||
trackUpdateAircraftModeA(a); // and attempt to match them with Mode-S
|
|
||||||
}
|
}
|
||||||
a = a->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,6 +756,6 @@ void trackPeriodicUpdate()
|
||||||
if (now >= next_update) {
|
if (now >= next_update) {
|
||||||
next_update = now + 1000;
|
next_update = now + 1000;
|
||||||
trackRemoveStaleAircraft(now);
|
trackRemoveStaleAircraft(now);
|
||||||
trackUpdateAircraftModeS();
|
trackMatchAC(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
track.h
18
track.h
|
@ -59,6 +59,11 @@
|
||||||
/* Maximum validity of an aircraft position */
|
/* Maximum validity of an aircraft position */
|
||||||
#define TRACK_AIRCRAFT_POSITION_TTL 60000
|
#define TRACK_AIRCRAFT_POSITION_TTL 60000
|
||||||
|
|
||||||
|
/* Minimum number of repeated Mode A/C replies with a particular Mode A code needed in a
|
||||||
|
* 1 second period before accepting that code.
|
||||||
|
*/
|
||||||
|
#define TRACK_MODEAC_MIN_MESSAGES 3
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
datasource_t source; /* where the data came from */
|
datasource_t source; /* where the data came from */
|
||||||
uint64_t updated; /* when it arrived */
|
uint64_t updated; /* when it arrived */
|
||||||
|
@ -82,7 +87,6 @@ struct aircraft {
|
||||||
|
|
||||||
data_validity altitude_valid;
|
data_validity altitude_valid;
|
||||||
int altitude; // Altitude (Baro)
|
int altitude; // Altitude (Baro)
|
||||||
unsigned altitude_modeC; // (as a Mode C value)
|
|
||||||
|
|
||||||
data_validity altitude_gnss_valid;
|
data_validity altitude_gnss_valid;
|
||||||
int altitude_gnss; // Altitude (GNSS)
|
int altitude_gnss; // Altitude (GNSS)
|
||||||
|
@ -134,9 +138,8 @@ struct aircraft {
|
||||||
double lat, lon; // Coordinated obtained from CPR encoded data
|
double lat, lon; // Coordinated obtained from CPR encoded data
|
||||||
unsigned pos_nuc; // NUCp of last computed position
|
unsigned pos_nuc; // NUCp of last computed position
|
||||||
|
|
||||||
long modeAcount; // Mode A Squawk hit Count
|
int modeA_hit; // did our squawk match a possible mode A reply in the last check period?
|
||||||
long modeCcount; // Mode C Altitude hit Count
|
int modeC_hit; // did our altitude match a possible mode C reply in the last check period?
|
||||||
int modeACflags; // Flags for mode A/C recognition
|
|
||||||
|
|
||||||
int fatsv_emitted_altitude; // last FA emitted altitude
|
int fatsv_emitted_altitude; // last FA emitted altitude
|
||||||
int fatsv_emitted_altitude_gnss; // -"- GNSS altitude
|
int fatsv_emitted_altitude_gnss; // -"- GNSS altitude
|
||||||
|
@ -159,6 +162,13 @@ struct aircraft {
|
||||||
struct modesMessage first_message; // A copy of the first message we received for this aircraft.
|
struct modesMessage first_message; // A copy of the first message we received for this aircraft.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Mode A/C tracking is done separately, not via the aircraft list,
|
||||||
|
* and via a flat array rather than a list since there are only 4k possible values
|
||||||
|
* (nb: we ignore the ident/SPI bit when tracking)
|
||||||
|
*/
|
||||||
|
extern uint32_t modeAC_count[4096];
|
||||||
|
extern uint32_t modeAC_match[4096];
|
||||||
|
|
||||||
/* is this bit of data valid? */
|
/* is this bit of data valid? */
|
||||||
static inline int trackDataValid(const data_validity *v)
|
static inline int trackDataValid(const data_validity *v)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue