Reduce CPU further in --no-fix-df mode. Add --enable-df24 option.
This reinstates the fastpath in the 2.4MHz demodulator that aborts message demodulation early if the DF bits don't match a message type that we know how to decode, or stops early if the DF bits can only correspond to a short 56-bit message. Do this in a more general form where we test against a set of valid DF values, rather than a switch/case. Then populate the sets based on the current error-correction settings (e.g. if we are allowed to repair DF damage with 1 bit error correction, then a DF17 message could appear with any of DF=17, DF=16, DF=19, DF=21, DF=25, or DF=1 and still be correctable to a valid DF17 message) In the default case this produces a small CPU improvement as short messages might be able to stop earlier and a few DF values can be ignored early. With --no-fix-df it produces a larger improvement as relatively few DF values are valid in that mode. To further reduce CPU, the default behaviour has changed to _not_ decode DF24 messages (Comm-D ELM messages). These are rarely seen in the wild and dump1090 can't do anything useful with them. Disabling them allows us to further reduce the set of valid DF values as they effectively use all DF values from 24..31, 25% of all possible values. To re-enable DF24 decoding, use the new `--enable-df24` option. Finally, avoid doing some CRC calculations twice. This was only happening once per valid decoded message, not per demodulation attempt, so it's not such a large win.
This commit is contained in:
parent
455896e86d
commit
c433463392
59
demod_2400.c
59
demod_2400.c
|
|
@ -58,6 +58,40 @@ static inline int slice_phase4(uint16_t *m) {
|
|||
return m[0] + 5 * m[1] - 5 * m[2] - m[3];
|
||||
}
|
||||
|
||||
static uint32_t valid_df_short_bitset; // set of acceptable DF values for short messages
|
||||
static uint32_t valid_df_long_bitset; // set of acceptable DF values for long messages
|
||||
|
||||
static uint32_t generate_damage_set(uint8_t df, unsigned damage_bits)
|
||||
{
|
||||
uint32_t result = (1 << df);
|
||||
if (!damage_bits)
|
||||
return result;
|
||||
|
||||
for (unsigned bit = 0; bit < 5; ++bit) {
|
||||
unsigned damaged_df = df ^ (1 << bit);
|
||||
result |= generate_damage_set(damaged_df, damage_bits - 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void init_bitsets()
|
||||
{
|
||||
// DFs that we directly understand without correction
|
||||
valid_df_short_bitset = (1 << 0) | (1 << 4) | (1 << 5) | (1 << 11);
|
||||
valid_df_long_bitset = (1 << 16) | (1 << 17) | (1 << 18) | (1 << 20) | (1 << 21);
|
||||
|
||||
if (Modes.enable_df24)
|
||||
valid_df_long_bitset |= (1 << 24) | (1 << 25) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31);
|
||||
|
||||
// if we can also repair DF damage, include those corrections
|
||||
if (Modes.fix_df && Modes.nfix_crc) {
|
||||
valid_df_short_bitset |= generate_damage_set(11, 1);
|
||||
valid_df_long_bitset |= generate_damage_set(17, Modes.nfix_crc);
|
||||
valid_df_long_bitset |= generate_damage_set(18, Modes.nfix_crc);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz,
|
||||
// try to demodulate some Mode S messages.
|
||||
|
|
@ -69,6 +103,10 @@ void demodulate2400(struct mag_buf *mag)
|
|||
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
|
||||
uint32_t j;
|
||||
|
||||
// initialize bitsets on first call
|
||||
if (!valid_df_short_bitset)
|
||||
init_bitsets();
|
||||
|
||||
unsigned char *bestmsg;
|
||||
int bestscore, bestphase;
|
||||
|
||||
|
|
@ -173,7 +211,7 @@ void demodulate2400(struct mag_buf *mag)
|
|||
bestmsg = NULL; bestscore = SR_NOT_SET; bestphase = -1;
|
||||
for (try_phase = 4; try_phase <= 8; ++try_phase) {
|
||||
uint16_t *pPtr;
|
||||
int phase, i, score;
|
||||
int phase, score;
|
||||
|
||||
// Decode all the next 112 bits, regardless of the actual message
|
||||
// size. We'll check the actual message type later
|
||||
|
|
@ -181,7 +219,8 @@ void demodulate2400(struct mag_buf *mag)
|
|||
pPtr = &m[j+19] + (try_phase/5);
|
||||
phase = try_phase % 5;
|
||||
|
||||
for (i = 0; i < MODES_LONG_MSG_BYTES; ++i) {
|
||||
unsigned bytelen = 1;
|
||||
for (unsigned i = 0; i < bytelen; ++i) {
|
||||
uint8_t theByte = 0;
|
||||
|
||||
switch (phase) {
|
||||
|
|
@ -263,6 +302,22 @@ void demodulate2400(struct mag_buf *mag)
|
|||
}
|
||||
|
||||
msg[i] = theByte;
|
||||
|
||||
if (i == 0) {
|
||||
// inspect DF field early, only continue processing
|
||||
// messages where the DF appears valid
|
||||
unsigned df = theByte >> 3;
|
||||
if (valid_df_long_bitset & (1 << df))
|
||||
bytelen = MODES_LONG_MSG_BYTES;
|
||||
else if (valid_df_short_bitset & (1 << df))
|
||||
bytelen = MODES_SHORT_MSG_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytelen == 1) {
|
||||
// rejected early by the DF filter
|
||||
Modes.stats_current.demod_rejected_bad++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Score the mode S message and see if it's any good.
|
||||
|
|
|
|||
|
|
@ -337,6 +337,7 @@ static void showHelp(void)
|
|||
"--no-fix Disable error correction using CRC\n"
|
||||
"--no-fix-df Disable error correction of the DF message field (reduces CPU requirements)\n"
|
||||
"--no-crc-check Disable messages with broken CRC (discouraged)\n"
|
||||
"--enable-df24 Enable decoding of DF24 Comm-D ELM messages\n"
|
||||
"--mlat display raw messages in Beast ascii mode\n"
|
||||
"--stats With --ifile print stats at exit. No other output\n"
|
||||
"--stats-range Collect/show range histogram\n"
|
||||
|
|
@ -547,6 +548,8 @@ int main(int argc, char **argv) {
|
|||
Modes.nfix_crc = 1;
|
||||
} else if (!strcmp(argv[j],"--fix-2bit")) {
|
||||
Modes.nfix_crc = 2;
|
||||
} else if (!strcmp(argv[j],"--enable-df24")) {
|
||||
Modes.enable_df24 = 1;
|
||||
} else if (!strcmp(argv[j],"--no-fix")) {
|
||||
Modes.nfix_crc = 0;
|
||||
} else if (!strcmp(argv[j],"--no-fix-df")) {
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ struct _Modes { // Internal state
|
|||
int nfix_crc; // Number of crc bit error(s) to correct
|
||||
int check_crc; // Only display messages with good CRC
|
||||
int fix_df; // Try to correct damage to the DF field, as well as the main message body
|
||||
int enable_df24; // Enable decoding of DF24..DF31 (Comm-D ELM)
|
||||
int raw; // Raw output format
|
||||
int mode_ac; // Enable decoding of SSR Modes A & C
|
||||
int mode_ac_auto; // allow toggling of A/C by Beast commands
|
||||
|
|
|
|||
67
mode_s.c
67
mode_s.c
|
|
@ -247,7 +247,9 @@ static bool isShortPIMessage(const unsigned char *msg)
|
|||
return (df == 11); // assume IID==0
|
||||
}
|
||||
|
||||
static int correctMessage(const unsigned char *in, unsigned char *out)
|
||||
#define UNCHECKED_SYNDROME 0xFFFFFFFFU
|
||||
|
||||
static int correctMessage(const unsigned char *in, unsigned char *out, uint32_t *short_syndrome, uint32_t *long_syndrome)
|
||||
{
|
||||
// Possible DF values of the first byte of a message that could be a valid DF11/17/18
|
||||
// message after correction. See tools/df-correction-arrays.py for generator code.
|
||||
|
|
@ -262,6 +264,9 @@ static int correctMessage(const unsigned char *in, unsigned char *out)
|
|||
0x00060000, 0x066f0006, 0x6fff066f
|
||||
};
|
||||
|
||||
*short_syndrome = UNCHECKED_SYNDROME;
|
||||
*long_syndrome = UNCHECKED_SYNDROME;
|
||||
|
||||
// Try to correct, including corrections to the initial 5 bit DF field
|
||||
// that determines message format
|
||||
|
||||
|
|
@ -275,27 +280,27 @@ static int correctMessage(const unsigned char *in, unsigned char *out)
|
|||
|
||||
struct errorinfo *long_ei = NULL;
|
||||
if (df_correctable_long[fix_df_bits] & df_bit) {
|
||||
uint32_t long_syndrome = modesChecksum(in, MODES_LONG_MSG_BITS);
|
||||
if (isLongPIMessage(in) && long_syndrome == 0) {
|
||||
*long_syndrome = modesChecksum(in, MODES_LONG_MSG_BITS);
|
||||
if (isLongPIMessage(in) && *long_syndrome == 0) {
|
||||
// DF17/18 message with correct checksum
|
||||
memcpy(out, in, MODES_LONG_MSG_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long_ei = modesChecksumDiagnose(long_syndrome, MODES_LONG_MSG_BITS);
|
||||
long_ei = modesChecksumDiagnose(*long_syndrome, MODES_LONG_MSG_BITS);
|
||||
}
|
||||
|
||||
struct errorinfo *short_ei = NULL;
|
||||
if (df_correctable_short[fix_df_bits] & df_bit) {
|
||||
uint32_t short_syndrome = modesChecksum(in, MODES_SHORT_MSG_BITS);
|
||||
if (isShortPIMessage(in) && (short_syndrome & 0xFFFF80) == 0) {
|
||||
*short_syndrome = modesChecksum(in, MODES_SHORT_MSG_BITS);
|
||||
if (isShortPIMessage(in) && (*short_syndrome & 0xFFFF80) == 0) {
|
||||
// DF11 message with correct checksum
|
||||
// (low 7 bits may be IID)
|
||||
memcpy(out, in, MODES_SHORT_MSG_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
short_ei = modesChecksumDiagnose(short_syndrome, MODES_SHORT_MSG_BITS); // assume IID == 0
|
||||
short_ei = modesChecksumDiagnose(*short_syndrome, MODES_SHORT_MSG_BITS); // assume IID == 0
|
||||
}
|
||||
|
||||
// Might be a damaged DF11/17/18, or might be another message type that doesn't have a full CRC
|
||||
|
|
@ -344,29 +349,38 @@ static int correctMessage(const unsigned char *in, unsigned char *out)
|
|||
// The more positive, the more reliable the message is.
|
||||
score_rank scoreModesMessage(const unsigned char *uncorrected)
|
||||
{
|
||||
// try to produce a corrected DF11/17/18, including correcting the DF bits
|
||||
unsigned char corrected[14];
|
||||
int corrections = correctMessage(uncorrected, corrected);
|
||||
|
||||
// This is a "valid" DF0 message, but it's not useful; we discard these messages
|
||||
static const unsigned char all_zeros[MODES_SHORT_MSG_BYTES] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
if (!memcmp(all_zeros, corrected, sizeof(all_zeros)))
|
||||
if (!memcmp(all_zeros, uncorrected, sizeof(all_zeros)))
|
||||
return SR_ALL_ZEROS;
|
||||
|
||||
// try to produce a corrected DF11/17/18, including correcting the DF bits
|
||||
unsigned char corrected[14];
|
||||
uint32_t short_syndrome, long_syndrome;
|
||||
int corrections = correctMessage(uncorrected, corrected, &short_syndrome, &long_syndrome);
|
||||
|
||||
unsigned df = getbits(corrected, 1, 5); // Downlink Format
|
||||
switch (df) {
|
||||
case 0: // short air-air surveillance
|
||||
case 4: // surveillance, altitude reply
|
||||
case 5: // surveillance, altitude reply
|
||||
{
|
||||
uint32_t addr = modesChecksum(corrected, MODES_SHORT_MSG_BITS);
|
||||
bool recent = icaoFilterTest(addr);
|
||||
if (short_syndrome == UNCHECKED_SYNDROME)
|
||||
short_syndrome = modesChecksum(corrected, MODES_SHORT_MSG_BITS);
|
||||
bool recent = icaoFilterTest(short_syndrome);
|
||||
return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN;
|
||||
}
|
||||
|
||||
case 16: // long air-air surveillance
|
||||
case 20: // Comm-B, altitude reply
|
||||
case 21: // Comm-B, identity reply
|
||||
{
|
||||
if (long_syndrome == UNCHECKED_SYNDROME)
|
||||
long_syndrome = modesChecksum(corrected, MODES_LONG_MSG_BITS);
|
||||
bool recent = icaoFilterTest(long_syndrome);
|
||||
return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN;
|
||||
}
|
||||
|
||||
case 24: // Comm-D (ELM)
|
||||
case 25: // Comm-D (ELM)
|
||||
case 26: // Comm-D (ELM)
|
||||
|
|
@ -376,8 +390,11 @@ score_rank scoreModesMessage(const unsigned char *uncorrected)
|
|||
case 30: // Comm-D (ELM)
|
||||
case 31: // Comm-D (ELM)
|
||||
{
|
||||
uint32_t addr = modesChecksum(corrected, MODES_LONG_MSG_BITS);
|
||||
bool recent = icaoFilterTest(addr);
|
||||
if (!Modes.enable_df24)
|
||||
return SR_UNCORRECTABLE;
|
||||
if (long_syndrome == UNCHECKED_SYNDROME)
|
||||
long_syndrome = modesChecksum(corrected, MODES_LONG_MSG_BITS);
|
||||
bool recent = icaoFilterTest(long_syndrome);
|
||||
return recent ? SR_UNRELIABLE_KNOWN : SR_UNRELIABLE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
|
@ -385,7 +402,9 @@ score_rank scoreModesMessage(const unsigned char *uncorrected)
|
|||
{
|
||||
// DF11 All-call reply
|
||||
uint32_t addr = getbits(corrected, 9, 32);
|
||||
uint32_t iid = modesChecksum(corrected, MODES_SHORT_MSG_BITS) & 0x7F;
|
||||
if (short_syndrome == UNCHECKED_SYNDROME)
|
||||
short_syndrome = modesChecksum(corrected, MODES_SHORT_MSG_BITS);
|
||||
uint32_t iid = short_syndrome & 0x7F;
|
||||
bool recent = icaoFilterTest(addr);
|
||||
|
||||
switch (corrections) {
|
||||
|
|
@ -513,13 +532,23 @@ int decodeModesMessage(struct modesMessage *mm, const unsigned char *in)
|
|||
memcpy(mm->verbatim, in, MODES_LONG_MSG_BYTES);
|
||||
|
||||
// Apply corrections to our local copy
|
||||
int corrections = correctMessage(in, mm->msg);
|
||||
uint32_t short_syndrome, long_syndrome;
|
||||
int corrections = correctMessage(in, mm->msg, &short_syndrome, &long_syndrome);
|
||||
const unsigned char *msg = mm->msg;
|
||||
|
||||
// Get the message type ASAP as other operations depend on this
|
||||
mm->msgtype = getbits(msg, 1, 5); // Downlink Format
|
||||
mm->msgbits = modesMessageLenByType(mm->msgtype);
|
||||
mm->crc = modesChecksum(msg, mm->msgbits);
|
||||
if (mm->msgtype & 16) {
|
||||
if (long_syndrome == UNCHECKED_SYNDROME)
|
||||
long_syndrome = modesChecksum(mm->msg, MODES_LONG_MSG_BITS);
|
||||
mm->crc = long_syndrome;
|
||||
} else {
|
||||
if (short_syndrome == UNCHECKED_SYNDROME)
|
||||
short_syndrome = modesChecksum(mm->msg, MODES_SHORT_MSG_BITS);
|
||||
mm->crc = short_syndrome;
|
||||
}
|
||||
|
||||
mm->correctedbits = corrections > 0 ? corrections : 0;
|
||||
mm->addr = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue